Merge "registration: Add ability to check if a specific extension version is loaded"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 3 Sep 2018 22:07:08 +0000 (22:07 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 3 Sep 2018 22:07:08 +0000 (22:07 +0000)
278 files changed:
.eslintrc.json
.gitignore
.phpcs.xml
RELEASE-NOTES-1.32
api.php
autoload.php
composer.json
docs/extension.schema.v1.json
docs/extension.schema.v2.json
docs/hooks.txt
includes/AjaxDispatcher.php
includes/AutoLoader.php
includes/DefaultSettings.php
includes/EditPage.php
includes/Html.php
includes/Linker.php
includes/MediaWikiServices.php
includes/OutputPage.php
includes/Revision/RenderedRevision.php [new file with mode: 0644]
includes/Revision/RevisionRenderer.php [new file with mode: 0644]
includes/ServiceWiring.php
includes/Setup.php
includes/Storage/DerivedPageDataUpdater.php
includes/Storage/MutableRevisionRecord.php
includes/Storage/NameTableStore.php
includes/Storage/PageUpdater.php
includes/Storage/RevisionStore.php
includes/Title.php
includes/actions/McrUndoAction.php [new file with mode: 0644]
includes/api/ApiComparePages.php
includes/api/ApiMain.php
includes/api/ApiParse.php
includes/api/ApiQueryDeletedRevisions.php
includes/api/ApiQueryRevisions.php
includes/api/SearchApi.php
includes/api/i18n/ar.json
includes/api/i18n/de.json
includes/api/i18n/en.json
includes/api/i18n/fr.json
includes/api/i18n/he.json
includes/api/i18n/hu.json
includes/api/i18n/ja.json
includes/api/i18n/ko.json
includes/api/i18n/nb.json
includes/api/i18n/pl.json
includes/api/i18n/pt-br.json
includes/api/i18n/pt.json
includes/api/i18n/qqq.json
includes/api/i18n/ru.json
includes/api/i18n/sv.json
includes/api/i18n/uk.json
includes/api/i18n/zh-hans.json
includes/api/i18n/zh-hant.json
includes/auth/AuthManagerAuthPlugin.php
includes/auth/AuthManagerAuthPluginUser.php [new file with mode: 0644]
includes/cache/localisation/LCStoreStaticArray.php
includes/changetags/ChangeTags.php
includes/content/AbstractContent.php
includes/content/ContentHandler.php
includes/content/TextContent.php
includes/context/DerivativeContext.php
includes/db/CloneDatabase.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/LinksUpdate.php
includes/diff/DifferenceEngine.php
includes/diff/TextSlotDiffRenderer.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/fields/HTMLCheckMatrix.php
includes/installer/DatabaseUpdater.php
includes/installer/MssqlUpdater.php
includes/installer/MysqlInstaller.php
includes/installer/MysqlUpdater.php
includes/installer/OracleUpdater.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteUpdater.php
includes/installer/i18n/bg.json
includes/installer/i18n/pl.json
includes/installer/i18n/sr-ec.json
includes/installer/i18n/tr.json
includes/jobqueue/jobs/DeleteLinksJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/json/FormatJson.php
includes/libs/RiffExtractor.php
includes/libs/StaticArrayWriter.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/exception/DBQueryError.php
includes/libs/rdbms/lbfactory/LBFactorySingle.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php
includes/page/Article.php
includes/page/WikiPage.php
includes/pager/IndexPager.php
includes/parser/CoreParserFunctions.php
includes/parser/Parser.php
includes/parser/ParserCache.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php
includes/registration/ExtensionProcessor.php
includes/registration/VersionChecker.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderSkinModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/revisiondelete/RevDelArchiveItem.php
includes/revisiondelete/RevDelArchivedFileItem.php
includes/revisiondelete/RevDelArchivedRevisionItem.php
includes/revisiondelete/RevDelFileItem.php
includes/revisiondelete/RevDelRevisionItem.php
includes/search/SearchResultSet.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specials/SpecialAncientpages.php
includes/specials/SpecialChangeCredentials.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEmailuser.php
includes/specials/SpecialExport.php
includes/specials/SpecialLinkAccounts.php
includes/specials/SpecialPreferences.php
includes/specials/SpecialUnlinkAccounts.php
includes/specials/SpecialUpload.php
includes/specials/SpecialUploadStash.php
includes/specials/forms/EditWatchlistNormalHTMLForm.php
includes/specials/pagers/ImageListPager.php
includes/widget/CheckMatrixWidget.php
languages/Language.php
languages/LanguageConverter.php
languages/data/Names.php
languages/i18n/ace.json
languages/i18n/ar.json
languages/i18n/ast.json
languages/i18n/bcl.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/ce.json
languages/i18n/ckb.json
languages/i18n/cs.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/dsb.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/fy.json
languages/i18n/gcr.json
languages/i18n/gor.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hsb.json
languages/i18n/hu.json
languages/i18n/hy.json
languages/i18n/hyw.json
languages/i18n/ia.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/lv.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/mni.json
languages/i18n/ms.json
languages/i18n/my.json
languages/i18n/nan.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/nds-nl.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/pam.json
languages/i18n/pl.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ru.json
languages/i18n/rue.json
languages/i18n/sat.json
languages/i18n/sd.json
languages/i18n/sk.json
languages/i18n/sl.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/szl.json
languages/i18n/tcy.json
languages/i18n/te.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/vec.json
languages/i18n/vi.json
languages/i18n/yi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/i18n/zh-hk.json
languages/messages/MessagesSah.php
languages/messages/MessagesSr_ec.php
maintenance/Doxyfile
maintenance/archives/patch-tc-timestamp.sql [deleted file]
maintenance/archives/patch-transcache-fix-pk.sql [deleted file]
maintenance/archives/patch-transcache.sql [deleted file]
maintenance/deduplicateArchiveRevId.php
maintenance/generateSitemap.php
maintenance/jsduck/categories.json
maintenance/mssql/tables.sql
maintenance/oracle/tables.sql
maintenance/populateArchiveRevId.php
maintenance/postgres/tables.sql
maintenance/resources/foreign-resources.yaml
maintenance/resources/manageForeignResources.php
maintenance/sqlite/archives/initial-indexes.sql
maintenance/sqlite/archives/patch-tc-timestamp.sql [deleted file]
maintenance/sqlite/archives/patch-transcache-fix-pk.sql [deleted file]
maintenance/tables.sql
maintenance/tidyUpBug37714.php [deleted file]
maintenance/tidyUpT39714.php [new file with mode: 0644]
package.json
profileinfo.php
resources/Resources.php
resources/src/mediawiki.Title/Title.js
resources/src/mediawiki.base/mediawiki.base.js
resources/src/mediawiki.inspect.js
resources/src/mediawiki.legacy/protect.js
resources/src/mediawiki.notification/notification.js
resources/src/mediawiki.special.apisandbox/apisandbox.js
resources/src/mediawiki.user.js
resources/src/startup/mediawiki.js
resources/src/startup/profiler.js [new file with mode: 0644]
resources/src/startup/startup.js
tests/phan/config.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/documentation/ReleaseNotesTest.php
tests/phpunit/includes/GitInfoTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/Revision/RenderedRevisionTest.php [new file with mode: 0644]
tests/phpunit/includes/Revision/RevisionRendererTest.php [new file with mode: 0644]
tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php
tests/phpunit/includes/Storage/McrReadNewRevisionStoreDbTest.php
tests/phpunit/includes/Storage/McrRevisionStoreDbTest.php
tests/phpunit/includes/Storage/MutableRevisionRecordTest.php
tests/phpunit/includes/Storage/NameTableStoreTest.php
tests/phpunit/includes/Storage/PageUpdaterTest.php
tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/api/ApiBlockTest.php
tests/phpunit/includes/api/ApiComparePagesTest.php
tests/phpunit/includes/api/ApiParseTest.php
tests/phpunit/includes/diff/DifferenceEngineTest.php
tests/phpunit/includes/libs/StaticArrayWriterTest.php
tests/phpunit/includes/page/ArticleViewTest.php [new file with mode: 0644]
tests/phpunit/includes/parser/ParserMethodsTest.php
tests/phpunit/includes/parser/ParserOptionsTest.php
tests/phpunit/includes/parser/ParserOutputTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderSkinModuleTest.php
tests/phpunit/includes/user/UserTest.php
tests/phpunit/maintenance/DumpTestCase.php
tests/phpunit/maintenance/backupTextPassTest.php
tests/qunit/suites/resources/mediawiki/mediawiki.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js
thumb.php

index da5d409..fbf2a5a 100644 (file)
                                "property": "map",
                                "message": "Please use Array.prototype.map instead"
                        },
+                       {
+                               "object": "$",
+                               "property": "inArray",
+                               "message": "Please use Array.prototype.indexOf instead"
+                       },
                        {
                                "object": "$",
                                "property": "isArray",
index d440e72..248931e 100644 (file)
@@ -43,7 +43,6 @@ sftp-config.json
 /maintenance/dev/data
 /AdminSettings.php
 /LocalSettings.php
-/StartProfiler.php
 
 # Building & testing
 npm-debug.log
index 10394d3..bd0ab82 100644 (file)
@@ -16,7 +16,6 @@
                <exclude name="MediaWiki.Commenting.MissingCovers.MissingCovers" />
                <exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" />
                <exclude name="MediaWiki.Usage.DbrQueryUsage.DbrQueryFound" />
-               <exclude name="MediaWiki.Usage.ExtendClassUsage.FunctionVarUsage" />
                <exclude name="MediaWiki.Usage.ForbiddenFunctions.passthru" />
                <exclude name="MediaWiki.VariableAnalysis.ForbiddenGlobalVariables.ForbiddenGlobal$wgTitle" />
                <exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
                <exclude-pattern>*/includes/api/ApiOpenSearch\.php</exclude-pattern>
                <exclude-pattern>*/includes/api/ApiRsd\.php</exclude-pattern>
                <exclude-pattern>*/includes/api/ApiUsageException\.php</exclude-pattern>
-               <exclude-pattern>*/includes/auth/AuthManagerAuthPlugin\.php</exclude-pattern>
                <exclude-pattern>*/includes/AuthPlugin\.php</exclude-pattern>
                <exclude-pattern>*/includes/cache/CacheDependency\.php</exclude-pattern>
                <exclude-pattern>*/includes/cache/CacheHelper\.php</exclude-pattern>
        <exclude-pattern type="relative">^skins/</exclude-pattern>
        <exclude-pattern>AdminSettings\.php</exclude-pattern>
        <exclude-pattern>LocalSettings\.php</exclude-pattern>
-       <exclude-pattern>StartProfiler\.php</exclude-pattern>
 </ruleset>
index 0ad2e41..34dbfd9 100644 (file)
@@ -6,40 +6,49 @@ MediaWiki 1.32 is an alpha-quality branch and is not recommended for use in
 production.
 
 === Configuration changes in 1.32 ===
-* (T115414) The $wgEnableAPI and $wgEnableWriteAPI settings, deprecated in 1.31,
-  have been removed.
-* The $wgUseAjax setting, deprecated in 1.31, is now ignored.
-* The $wgSiteSupportPage setting, unused since 1.5, was removed.
-* The $wgBrowserBlacklist setting, deprecated in 1.30, was removed.
-* The default quality of JPEG thumbnails generated by GD was reduced from 95 to
-  80. The quality of JPEG thumbnails is now configurable through the new setting
-  $wgJpegQuality (default 80). This aligns the quality to what ImageMagick uses.
-* $wgExperimentalHtmlIds, deprecated since 1.30, has been removed. The
-  'html5-legacy' value for $wgFragmentMode is no longer accepted.
-* The experimental Html5Internal and Html5Depurate tidy drivers were removed.
-  RemexHtml, which is the default, should be used instead.
-* (T135963) You can now define a Content Security Policy for your wiki. This
-  adds a defense-in-depth feature to stop an attacker who has found a bug in
-  the parser allowing them to insert malicious attributes. Disabled by default,
-  you can configure this via $wgCSPHeader and $wgCSPReportOnlyHeader.
-* New configuration variable has been added: $wgCookieSetOnIpBlock.
-  This determines whether to set a cookie when an IP user is blocked. Doing so
-  means that a blocked user, even after moving to a new IP address, will still
-  be blocked.
-* The archive table's ar_rev_id field is now unique.
-* Special:BotPasswords now requires reauthentication.
-* (T194414) The default watchlist view time has been increased from 3 to 7 days.
-* The right to edit sitewide Javascript (e.g. MediaWiki:Common.js), CSS or JSON
-  was separated from 'editinterface' and is available under
-  'editsitejs'/'editsitecss'/'editsitejson'. Having 'editinterface' is still
-  necessary to edit such pages.
-* A new user group, 'interface-admin', is added for controlling access to
-  sitewide CSS/JS (and editing other users' CSS/JS). No other group has
-  'editsitecss', 'editusercss', 'editsitejs' or 'edituserjs' by default.
-* A new grant group, 'editsiteconfig', is added for granting the above rights.
-* The $wgPasswordSenderName setting, ignored since 1.23 by MediaWiki and almost
-  all extensions, is no longer set at all. Instead, you can modify the system
+
+==== New configuration ====
+* $wgJpegQuality – The quality of JPEG thumbnails is now configurable through
+  this setting. The default is 80, which matches the quality of JPEG thumbnails
+  previously generated by ImageMagick. The quality of JPEG thumbnails generated
+  by GD was previously 95, but now uses the $wgJpegQuality setting as well.
+* $wgCookieSetOnIpBlock - This determines whether to set a cookie when an IP
+  user is blocked. Doing so means that a blocked user, even after moving to a
+  new IP address, will still be blocked.
+* $wgRawHtmlMessages – This new configuration setting is added for listing
+  messages which are displayed as raw HTML.
+* $wgCSPHeader and $wgCSPReportOnlyHeader – You can now define a
+  "Content Security Policy" for your wiki. This adds a defense-in-depth feature
+  to stop an attacker who has found a bug in the parser allowing them to insert
+  malicious attributes. Disabled by default. (T135963)
+* $wgGroupPermissions – A new user group, 'interface-admin', is added for
+  controlling access to sitewide CSS/JS (and editing other users' CSS/JS). No
+  other group has 'editsitecss', 'editusercss', 'editsitejs' or 'edituserjs'
+  by default.
+* $wgGrantPermissions – A new grant group, 'editsiteconfig', is added for
+  granting the above rights.
+
+==== Changed configuration ====
+* $wgUseAjax – This setting, deprecated in 1.31, is now ignored.
+* $wgDefaultUserOptions – The default watchlist view time (watchlistdays) has
+  been increased from 3 to 7 days. (T194414)
+* $wgGroupPermissions – The right to edit sitewide Javascript
+  (e.g. MediaWiki:Common.js), CSS or JSON was separated from 'editinterface'
+  and is available under 'editsitejs'/'editsitecss'/'editsitejson'. Having
+  'editinterface' is still necessary to edit such pages.
+
+==== Removed configuration ====
+* $wgEnableAPI and $wgEnableWriteAPI – These settings, deprecated in 1.31,
+  have been removed. (T115414)
+* $wgSiteSupportPage – This setting, unused since 1.5, was removed.
+* $wgBrowserBlacklist – This setting, deprecated in 1.30, was removed.
+* $wgExperimentalHtmlIds – This setting, deprecated since 1.30, was removed.
+  The 'html5-legacy' value for $wgFragmentMode is no longer accepted.
+* $wgPasswordSenderName - This setting, ignored since 1.23 by MediaWiki and
+  most extensions, is no longer set. Instead, you can modify the system
   message `emailsender`.
+* $wgTidyConfig – The experimental Html5Internal and Html5Depurate tidy drivers
+  were removed. RemexHtml, which is the default, should be used instead.
 
 === New features in 1.32 ===
 * (T112474) Generalized the ResourceLoader mechanism for overriding modules
@@ -75,12 +84,20 @@ production.
   render diffs between two Content objects, and DifferenceEngine::setRevisions()
   to render diffs between two custom (potentially multi-content) revisions.
   Added GetSlotDiffRenderer hook which works like GetDifferenceEngine for slots.
+* Added a temporary action=mcrundo to the web UI, as the normal undo logic
+  can't yet handle MCR and deadlines are forcing is to put off fixing that.
+  This action should be considered deprecated and should not be used directly.
+* Extensions overriding ContentHandler::getUndoContent() will need to be
+  updated for the changed method signature.
 
 === External library changes in 1.32 ===
+
+==== New external libraries ====
+* Added wikimedia/xmp-reader 0.6.0
 * …
 
-==== Upgraded external libraries ====
-* Updated QUnit from 2.4.0 to 2.6.0.
+==== Changed external libraries ====
+* Updated qunitjs from 2.4.0 to 2.6.0.
 * Updated wikimedia/scoped-callback from 1.0.0 to 2.0.0.
 ** ScopedCallback objects can no longer be serialized.
 * Updated wikimedia/wrappedstring from 2.3.0 to 3.0.1.
@@ -90,11 +107,7 @@ production.
 * Updated wikimedia/timestamp from 1.0.0 to 2.0.0.
 * Updated wikimedia/remex-html from 1.0.3 to 2.0.0.
 
-==== New external libraries ====
-* Added wikimedia/xmp-reader 0.6.0
-* …
-
-==== Removed and replaced external libraries ====
+==== Removed external libraries ====
 * …
 
 === Bug fixes in 1.32 ===
@@ -136,6 +149,18 @@ production.
 * action=query&prop=deletedrevisions, action=query&list=allrevisions, and
   action=query&list=alldeletedrevisions are changed similarly to
   &prop=revisions (see the three previous items).
+* (T174032) action=compare now supports multi-content revisions.
+  * It has a 'slots' parameter to select diffing of individual slots. The
+    default behavior is to return one combined diff.
+  * The 'fromtext', 'fromsection', 'fromcontentmodel', 'fromcontentformat',
+    'totext', 'tosection', 'tocontentmodel', and 'tocontentformat' parameters
+    are deprecated. Specify the new 'fromslots' and 'toslots' to identify which
+    slots have text supplied and the corresponding templated parameters for
+    each slot.
+  * The behavior of 'fromsection' and 'tosection' of extracting one section's
+    content is not being preserved. 'fromsection-{slot}' and 'tosection-{slot}'
+    instead expand the given text as if for a section edit. This effectively
+    declines T183823 in favor of T185723.
 
 === Action API internal changes in 1.32 ===
 * Added 'ApiParseMakeOutputPage' hook.
@@ -259,10 +284,10 @@ because of Phabricator reports.
   a no-op function since 1.30.
 * SpecialPageFactory::resetList() is a no-op.  Call overrideMwServices()
   instead.
+* MediaWiki no longer supports a StartProfiler.php file.
+  Define $wgProfiler via LocalSettings.php instead.
 
 === Deprecations in 1.32 ===
-* Use of a StartProfiler.php file is deprecated in favour of placing
-  configuration in LocalSettings.php.
 * HTMLForm::setSubmitProgressive() is deprecated. No need to call it. Submit
   button is already marked as progressive.
 * Skin::setupSkinUserCss() is deprecated. Adding of modules to load
@@ -377,6 +402,13 @@ because of Phabricator reports.
   MediaWikiServices.
 * mw.user.stickyRandomId was renamed to the more explicit
   mw.user.getPageviewToken to better capture its function.
+* Passing Revision objects to ContentHandler::getUndoContent() is deprecated,
+  Content object should be passed instead.
+* (T197179) Parameters 'notice', 'notice-messages', 'notice-message',
+  previously used by OOUI HTMLForm fields, are now deprecated. Use
+  'help', 'help-message', 'help-messages' instead.
+* (T197179) HTMLFormField::getNotices() is now deprecated.
+* The jquery.localize module is now deprecated. Use jquery.i18n instead.
 
 === Other changes in 1.32 ===
 * (T198811) The following tables have had their UNIQUE indexes turned into
@@ -385,6 +417,8 @@ because of Phabricator reports.
 * OOUI HTMLForm will now display help text inline after the input field,
   rather than in a popup. Previous behavior can be restored by using
   `'help-inline' => false`.
+* The archive table's ar_rev_id field is now unique.
+* Special:BotPasswords now requires reauthentication.
 * …
 
 == Compatibility ==
diff --git a/api.php b/api.php
index 9c5ac95..9cf7578 100644 (file)
--- a/api.php
+++ b/api.php
@@ -72,7 +72,11 @@ try {
        if ( !$processor instanceof ApiMain ) {
                throw new MWException( 'ApiBeforeMain hook set $processor to a non-ApiMain class' );
        }
-} catch ( Exception $e ) {
+} catch ( Exception $e ) { // @todo Remove this block when HHVM is no longer supported
+       // Crap. Try to report the exception in API format to be friendly to clients.
+       ApiMain::handleApiBeforeMainException( $e );
+       $processor = false;
+} catch ( Throwable $e ) {
        // Crap. Try to report the exception in API format to be friendly to clients.
        ApiMain::handleApiBeforeMainException( $e );
        $processor = false;
@@ -99,7 +103,9 @@ if ( $wgAPIRequestLog ) {
                try {
                        $manager = $processor->getModuleManager();
                        $module = $manager->getModule( $wgRequest->getVal( 'action' ), 'action' );
-               } catch ( Exception $ex ) {
+               } catch ( Exception $ex ) { // @todo Remove this block when HHVM is no longer supported
+                       $module = null;
+               } catch ( Throwable $ex ) {
                        $module = null;
                }
                if ( !$module || $module->mustBePosted() ) {
index cef68b0..dc9461e 100644 (file)
@@ -851,6 +851,7 @@ $wgAutoloadLocalClasses = [
        'MappedIterator' => __DIR__ . '/includes/libs/MappedIterator.php',
        'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
        'McTest' => __DIR__ . '/maintenance/mctest.php',
+       'McrUndoAction' => __DIR__ . '/includes/actions/McrUndoAction.php',
        'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
        'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
        'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
@@ -862,41 +863,6 @@ $wgAutoloadLocalClasses = [
        'MediaWikiSite' => __DIR__ . '/includes/site/MediaWikiSite.php',
        'MediaWikiTitleCodec' => __DIR__ . '/includes/title/MediaWikiTitleCodec.php',
        'MediaWikiVersionFetcher' => __DIR__ . '/includes/MediaWikiVersionFetcher.php',
-       'MediaWiki\\Auth\\AbstractAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AbstractPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPasswordPrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AbstractPreAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPreAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AbstractPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AbstractSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractSecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AuthManager' => __DIR__ . '/includes/auth/AuthManager.php',
-       'MediaWiki\\Auth\\AuthManagerAuthPlugin' => __DIR__ . '/includes/auth/AuthManagerAuthPlugin.php',
-       'MediaWiki\\Auth\\AuthManagerAuthPluginUser' => __DIR__ . '/includes/auth/AuthManagerAuthPlugin.php',
-       'MediaWiki\\Auth\\AuthPluginPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AuthPluginPrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\AuthenticationProvider' => __DIR__ . '/includes/auth/AuthenticationProvider.php',
-       'MediaWiki\\Auth\\AuthenticationRequest' => __DIR__ . '/includes/auth/AuthenticationRequest.php',
-       'MediaWiki\\Auth\\AuthenticationResponse' => __DIR__ . '/includes/auth/AuthenticationResponse.php',
-       'MediaWiki\\Auth\\ButtonAuthenticationRequest' => __DIR__ . '/includes/auth/ButtonAuthenticationRequest.php',
-       'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/CheckBlocksSecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\ConfirmLinkAuthenticationRequest' => __DIR__ . '/includes/auth/ConfirmLinkAuthenticationRequest.php',
-       'MediaWiki\\Auth\\ConfirmLinkSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/ConfirmLinkSecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\CreateFromLoginAuthenticationRequest' => __DIR__ . '/includes/auth/CreateFromLoginAuthenticationRequest.php',
-       'MediaWiki\\Auth\\CreatedAccountAuthenticationRequest' => __DIR__ . '/includes/auth/CreatedAccountAuthenticationRequest.php',
-       'MediaWiki\\Auth\\CreationReasonAuthenticationRequest' => __DIR__ . '/includes/auth/CreationReasonAuthenticationRequest.php',
-       'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/EmailNotificationSecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\LegacyHookPreAuthenticationProvider' => __DIR__ . '/includes/auth/LegacyHookPreAuthenticationProvider.php',
-       'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/LocalPasswordPrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\PasswordAuthenticationRequest' => __DIR__ . '/includes/auth/PasswordAuthenticationRequest.php',
-       'MediaWiki\\Auth\\PasswordDomainAuthenticationRequest' => __DIR__ . '/includes/auth/PasswordDomainAuthenticationRequest.php',
-       'MediaWiki\\Auth\\PreAuthenticationProvider' => __DIR__ . '/includes/auth/PreAuthenticationProvider.php',
-       'MediaWiki\\Auth\\PrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/PrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\RememberMeAuthenticationRequest' => __DIR__ . '/includes/auth/RememberMeAuthenticationRequest.php',
-       'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/ResetPasswordSecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\SecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/SecondaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest' => __DIR__ . '/includes/auth/TemporaryPasswordAuthenticationRequest.php',
-       'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/TemporaryPasswordPrimaryAuthenticationProvider.php',
-       'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => __DIR__ . '/includes/auth/ThrottlePreAuthenticationProvider.php',
-       'MediaWiki\\Auth\\Throttler' => __DIR__ . '/includes/auth/Throttler.php',
-       'MediaWiki\\Auth\\UserDataAuthenticationRequest' => __DIR__ . '/includes/auth/UserDataAuthenticationRequest.php',
-       'MediaWiki\\Auth\\UsernameAuthenticationRequest' => __DIR__ . '/includes/auth/UsernameAuthenticationRequest.php',
        'MediaWiki\\Config\\ConfigRepository' => __DIR__ . '/includes/config/ConfigRepository.php',
        'MediaWiki\\DB\\PatchFileLocation' => __DIR__ . '/includes/db/PatchFileLocation.php',
        'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
@@ -930,6 +896,8 @@ $wgAutoloadLocalClasses = [
        'MediaWiki\\MediaWikiServices' => __DIR__ . '/includes/MediaWikiServices.php',
        'MediaWiki\\OutputHandler' => __DIR__ . '/includes/OutputHandler.php',
        'MediaWiki\\ProcOpenError' => __DIR__ . '/includes/exception/ProcOpenError.php',
+       'MediaWiki\\Revision\\RenderedRevision' => __DIR__ . '/includes/Revision/RenderedRevision.php',
+       'MediaWiki\\Revision\\RevisionRenderer' => __DIR__ . '/includes/Revision/RevisionRenderer.php',
        'MediaWiki\\Search\\ParserOutputSearchDataExtractor' => __DIR__ . '/includes/search/ParserOutputSearchDataExtractor.php',
        'MediaWiki\\ShellDisabledError' => __DIR__ . '/includes/exception/ShellDisabledError.php',
        'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php',
@@ -1486,7 +1454,7 @@ $wgAutoloadLocalClasses = [
        'ThrottledError' => __DIR__ . '/includes/exception/ThrottledError.php',
        'ThumbnailImage' => __DIR__ . '/includes/media/MediaTransformOutput.php',
        'ThumbnailRenderJob' => __DIR__ . '/includes/jobqueue/jobs/ThumbnailRenderJob.php',
-       'TidyUpBug37714' => __DIR__ . '/maintenance/tidyUpBug37714.php',
+       'TidyUpT39714' => __DIR__ . '/maintenance/tidyUpT39714.php',
        'TiffHandler' => __DIR__ . '/includes/media/TiffHandler.php',
        'Timing' => __DIR__ . '/includes/libs/Timing.php',
        'Title' => __DIR__ . '/includes/Title.php',
index 454e27c..4284260 100644 (file)
@@ -57,6 +57,7 @@
        "require-dev": {
                "cache/integration-tests": "0.16.0",
                "composer/spdx-licenses": "1.4.0",
+               "giorgiosironi/eris": "^0.10.0",
                "hamcrest/hamcrest-php": "^2.0",
                "jakub-onderka/php-parallel-lint": "0.9.2",
                "jetbrains/phpstorm-stubs": "dev-master#38ff1a581b297f7901e961b8c923862ea80c3b96",
index c9a887d..0ff169c 100644 (file)
                                "type": "string"
                        }
                },
+               "RawHtmlMessages": {
+                       "type": "array",
+                       "description": "Messages which are rendered as raw HTML",
+                       "items": {
+                               "type": "string"
+                       }
+               },
                "callback": {
                        "type": [
                                "array",
index 24212a9..7de5ed5 100644 (file)
                                "type": "string"
                        }
                },
+               "RawHtmlMessages": {
+                       "type": "array",
+                       "description": "Messages which are rendered as raw HTML",
+                       "items": {
+                               "type": "string"
+                       }
+               },
                "callback": {
                        "type": [
                                "array",
index 9cb22d2..436131c 100644 (file)
@@ -348,6 +348,12 @@ $from: From address
 $subject: Subject of the email
 $body: Body of the message
 
+'AncientPagesQuery': Allow extensions to modify the query used by
+Special:AncientPages.
+&$tables: tables to join in the query
+&$conds: conditions for the query
+&$joinConds: join conditions for the query
+
 'APIAfterExecute': After calling the execute() method of an API module. Use
 this to extend core API modules.
 &$module: Module object
index 5f825c8..f6c9075 100644 (file)
@@ -104,6 +104,9 @@ class AjaxDispatcher {
         * they should be carefully handled in the function processing the
         * request.
         *
+        * phan-taint-check triggers as it is not smart enough to understand
+        * the early return if func_name not in AjaxExportList.
+        * @suppress SecurityCheck-XSS
         * @param User $user
         */
        function performAction( User $user ) {
index 9fc063a..c9932d6 100644 (file)
@@ -129,6 +129,7 @@ class AutoLoader {
         */
        public static function getAutoloadNamespaces() {
                return [
+                       'MediaWiki\\Auth\\' => __DIR__ . '/auth/',
                        'MediaWiki\\Edit\\' => __DIR__ . '/edit/',
                        'MediaWiki\\EditPage\\' => __DIR__ . '/editpage/',
                        'MediaWiki\\Linker\\' => __DIR__ .'/linker/',
index fdac10a..928d875 100644 (file)
@@ -3792,6 +3792,16 @@ $wgResourceLoaderMaxQueryLength = false;
  */
 $wgResourceLoaderValidateJS = true;
 
+/**
+ * When enabled, execution of JavaScript modules is profiled client-side.
+ *
+ * Instrumentation happens in mw.loader.profiler.
+ * Use `mw.inspect('time')` from the browser console to display the data.
+ *
+ * @since 1.32
+ */
+$wgResourceLoaderEnableJSProfiler = false;
+
 /**
  * Whether ResourceLoader should attempt to persist modules in localStorage on
  * browsers that support the Web Storage API.
@@ -4389,7 +4399,7 @@ $wgPreprocessorCacheThreshold = 1000;
 $wgEnableScaryTranscluding = false;
 
 /**
- * Expiry time for transcluded templates cached in transcache database table.
+ * Expiry time for transcluded templates cached in object cache.
  * Only used $wgEnableInterwikiTranscluding is set to true.
  */
 $wgTranscludeCacheExpiry = 3600;
@@ -6338,8 +6348,6 @@ $wgDeprecationReleaseLimit = false;
  * Profiler configuration.
  *
  * To use a profiler, set $wgProfiler in LocalSetings.php.
- * For backwards-compatibility, it is also allowed to set the variable from
- * a separate file called StartProfiler.php, which MediaWiki will include.
  *
  * Example:
  *
@@ -7998,6 +8006,7 @@ $wgActions = [
        'history' => true,
        'info' => true,
        'markpatrolled' => true,
+       'mcrundo' => McrUndoAction::class,
        'protect' => true,
        'purge' => true,
        'raw' => true,
@@ -8834,6 +8843,24 @@ $wgCSPHeader = false;
  */
 $wgCSPReportOnlyHeader = false;
 
+/**
+ * List of messages which might contain raw HTML.
+ * Extensions should add their messages here. The list is used for access control:
+ * changing messages listed here will require editsitecss and editsitejs rights.
+ *
+ * Message names must be given with underscores rather than spaces and with lowercase first letter.
+ *
+ * @since 1.32
+ * @var string[]
+ */
+$wgRawHtmlMessages = [
+       'copyright',
+       'history_copyright',
+       'googlesearch',
+       'feedback-terms',
+       'feedback-termsofuse',
+];
+
 /**
  * Mapping of event channels (or channel categories) to EventRelayer configuration.
  *
index d1f874e..ef111c4 100644 (file)
@@ -684,7 +684,10 @@ class EditPage {
                # checking, etc.
                if ( 'initial' == $this->formtype || $this->firsttime ) {
                        if ( $this->initialiseForm() === false ) {
-                               $this->noSuchSectionPage();
+                               $out = $this->context->getOutput();
+                               if ( $out->getRedirect() === '' ) { // mcrundo hack redirects, don't override it
+                                       $this->noSuchSectionPage();
+                               }
                                return;
                        }
 
@@ -1055,7 +1058,7 @@ class EditPage {
                                $this->sectiontitle = $request->getVal( 'preloadtitle' );
                                // Once wpSummary isn't being use for setting section titles, we should delete this.
                                $this->summary = $request->getVal( 'preloadtitle' );
-                       } elseif ( $this->section != 'new' && $request->getVal( 'summary' ) ) {
+                       } elseif ( $this->section != 'new' && $request->getVal( 'summary' ) !== '' ) {
                                $this->summary = $request->getText( 'summary' );
                                if ( $this->summary !== '' ) {
                                        $this->hasPresetSummary = true;
@@ -1220,8 +1223,13 @@ class EditPage {
                                                !$oldrev->isDeleted( Revision::DELETED_TEXT )
                                        ) {
                                                if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev ) ) {
-                                                       // Cannot yet undo edits that involve anything other the main slot.
-                                                       $undoMsg = 'main-slot-only';
+                                                       // Hack for undo while EditPage can't handle multi-slot editing
+                                                       $this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
+                                                               'action' => 'mcrundo',
+                                                               'undo' => $undo,
+                                                               'undoafter' => $undoafter,
+                                                       ] ) );
+                                                       return false;
                                                } else {
                                                        $content = $this->page->getUndoContent( $undorev, $oldrev );
 
@@ -1774,7 +1782,7 @@ ERROR;
                        if ( $this->summary === '' ) {
                                $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
                                return $this->context->msg( 'newsectionsummary' )
-                                       ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
+                                       ->plaintextParams( $cleanSectionTitle )->inContentLanguage()->text();
                        }
                } elseif ( $this->summary !== '' ) {
                        $sectionanchor = $this->guessSectionName( $this->summary );
@@ -1782,7 +1790,7 @@ ERROR;
                        # in the revision summary.
                        $cleanSummary = $wgParser->stripSectionName( $this->summary );
                        return $this->context->msg( 'newsectionsummary' )
-                               ->rawParams( $cleanSummary )->inContentLanguage()->text();
+                               ->plaintextParams( $cleanSummary )->inContentLanguage()->text();
                }
                return $this->summary;
        }
@@ -2861,7 +2869,7 @@ ERROR;
                        $this->autoSumm = md5( '' );
                }
 
-               $autosumm = $this->autoSumm ?: md5( $this->summary );
+               $autosumm = $this->autoSumm !== '' ? $this->autoSumm : md5( $this->summary );
                $out->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
 
                $out->addHTML( Html::hidden( 'oldid', $this->oldid ) );
@@ -3778,7 +3786,7 @@ ERROR;
 
        /**
         * Get the last log record of this page being deleted, if ever.  This is
-        * used to detect whether a delete occured during editing.
+        * used to detect whether a delete occurred during editing.
         * @return bool|stdClass
         */
        protected function getLastDelete() {
index dba4c67..aac492c 100644 (file)
@@ -552,10 +552,13 @@ class Html {
        }
 
        /**
-        * Output a "<script>" tag with the given contents.
+        * Output an HTML script tag with the given contents.
         *
-        * @todo do some useful escaping as well, like if $contents contains
-        * literal "</script>" or (for XML) literal "]]>".
+        * It is unsupported for the contents to contain the sequence `<script` or `</script`
+        * (case-insensitive). This ensures the script can be terminated easily and consistently.
+        * It is the responsibility of the caller to avoid such character sequence by escaping
+        * or avoiding it. If found at run-time, the contents are replaced with a comment, and
+        * a warning is logged server-side.
         *
         * @param string $contents JavaScript
         * @param string|null $nonce Nonce for CSP header, from OutputPage::getCSPNonce()
@@ -571,8 +574,9 @@ class Html {
                        }
                }
 
-               if ( preg_match( '/[<&]/', $contents ) ) {
-                       $contents = "/*<![CDATA[*/$contents/*]]>*/";
+               if ( preg_match( '/<\/?script/i', $contents ) ) {
+                       wfLogWarning( __METHOD__ . ': Illegal character sequence found in inline script.' );
+                       $contents = '/* ERROR: Invalid script */';
                }
 
                return self::rawElement( 'script', $attrs, $contents );
index 08a5724..0ee6c92 100644 (file)
@@ -431,7 +431,11 @@ class Linker {
                        $s = $thumb->toHtml( $params );
                }
                if ( $frameParams['align'] != '' ) {
-                       $s = "<div class=\"float{$frameParams['align']}\">{$s}</div>";
+                       $s = Html::rawElement(
+                               'div',
+                               [ 'class' => 'float' . $frameParams['align'] ],
+                               $s
+                       );
                }
                return str_replace( "\n", ' ', $prefix . $s . $postfix );
        }
@@ -1208,7 +1212,8 @@ class Linker {
         * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
         *  as used by WikiMap.
         *
-        * @return string
+        * @return string HTML
+        * @return-taint onlysafefor_html
         */
        public static function formatLinksInComment(
                $comment, $title = null, $local = false, $wikiId = null
index 4a6046d..5b53ad1 100644 (file)
@@ -16,6 +16,7 @@ use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
 use MediaWiki\Http\HttpRequestFactory;
 use MediaWiki\Preferences\PreferencesFactory;
 use MediaWiki\Shell\CommandFactory;
+use MediaWiki\Revision\RevisionRenderer;
 use MediaWiki\Special\SpecialPageFactory;
 use MediaWiki\Storage\BlobStore;
 use MediaWiki\Storage\BlobStoreFactory;
@@ -749,6 +750,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'RevisionLookup' );
        }
 
+       /**
+        * @since 1.32
+        * @return RevisionRenderer
+        */
+       public function getRevisionRenderer() {
+               return $this->getService( 'RevisionRenderer' );
+       }
+
        /**
         * @since 1.31
         * @return RevisionStore
index c8e18e0..4f12e0c 100644 (file)
@@ -2364,10 +2364,6 @@ class OutputPage extends ContextSource {
 
                if ( !$this->mArticleBodyOnly ) {
                        $sk = $this->getSkin();
-
-                       if ( $sk->shouldPreloadLogo() ) {
-                               $this->addLogoPreloadLinkHeaders();
-                       }
                }
 
                $linkHeader = $this->getLinkHeader();
@@ -2758,6 +2754,18 @@ class OutputPage extends ContextSource {
                                        foreach ( $this->contentOverrideCallbacks as $callback ) {
                                                $content = $callback( $title );
                                                if ( $content !== null ) {
+                                                       $text = ContentHandler::getContentText( $content );
+                                                       if ( strpos( $text, '</script>' ) !== false ) {
+                                                               // Proactively replace this so that we can display a message
+                                                               // to the user, instead of letting it go to Html::inlineScript(),
+                                                               // where it would be considered a server-side issue.
+                                                               $titleFormatted = $title->getPrefixedText();
+                                                               $content = new JavaScriptContent(
+                                                                       Xml::encodeJsCall( 'mw.log.error', [
+                                                                               "Cannot preview $titleFormatted due to script-closing tag."
+                                                                       ] )
+                                                               );
+                                                       }
                                                        return $content;
                                                }
                                        }
@@ -3915,80 +3923,6 @@ class OutputPage extends ContextSource {
                ] );
        }
 
-       /**
-        * Add Link headers for preloading the wiki's logo.
-        *
-        * @since 1.26
-        */
-       protected function addLogoPreloadLinkHeaders() {
-               $logo = ResourceLoaderSkinModule::getLogo( $this->getConfig() );
-
-               $tags = [];
-               $logosPerDppx = [];
-               $logos = [];
-
-               if ( !is_array( $logo ) ) {
-                       // No media queries required if we only have one variant
-                       $this->addLinkHeader( '<' . $logo . '>;rel=preload;as=image' );
-                       return;
-               }
-
-               if ( isset( $logo['svg'] ) ) {
-                       // No media queries required if we only have a 1x and svg variant
-                       // because all preload-capable browsers support SVGs
-                       $this->addLinkHeader( '<' . $logo['svg'] . '>;rel=preload;as=image' );
-                       return;
-               }
-
-               foreach ( $logo as $dppx => $src ) {
-                       // Keys are in this format: "1.5x"
-                       $dppx = substr( $dppx, 0, -1 );
-                       $logosPerDppx[$dppx] = $src;
-               }
-
-               // Because PHP can't have floats as array keys
-               uksort( $logosPerDppx, function ( $a , $b ) {
-                       $a = floatval( $a );
-                       $b = floatval( $b );
-                       // Sort from smallest to largest (e.g. 1x, 1.5x, 2x)
-                       return $a <=> $b;
-               } );
-
-               foreach ( $logosPerDppx as $dppx => $src ) {
-                       $logos[] = [ 'dppx' => $dppx, 'src' => $src ];
-               }
-
-               $logosCount = count( $logos );
-               // Logic must match ResourceLoaderSkinModule:
-               // - 1x applies to resolution < 1.5dppx
-               // - 1.5x applies to resolution >= 1.5dppx && < 2dppx
-               // - 2x applies to resolution >= 2dppx
-               // Note that min-resolution and max-resolution are both inclusive.
-               for ( $i = 0; $i < $logosCount; $i++ ) {
-                       if ( $i === 0 ) {
-                               // Smallest dppx
-                               // min-resolution is ">=" (larger than or equal to)
-                               // "not min-resolution" is essentially "<"
-                               $media_query = 'not all and (min-resolution: ' . $logos[ 1 ]['dppx'] . 'dppx)';
-                       } elseif ( $i !== $logosCount - 1 ) {
-                               // In between
-                               // Media query expressions can only apply "not" to the entire expression
-                               // (e.g. can't express ">= 1.5 and not >= 2).
-                               // Workaround: Use <= 1.9999 in place of < 2.
-                               $upper_bound = floatval( $logos[ $i + 1 ]['dppx'] ) - 0.000001;
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] .
-                                       'dppx) and (max-resolution: ' . $upper_bound . 'dppx)';
-                       } else {
-                               // Largest dppx
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] . 'dppx)';
-                       }
-
-                       $this->addLinkHeader(
-                               '<' . $logos[$i]['src'] . '>;rel=preload;as=image;media=' . $media_query
-                       );
-               }
-       }
-
        /**
         * Get (and set if not yet set) the CSP nonce.
         *
diff --git a/includes/Revision/RenderedRevision.php b/includes/Revision/RenderedRevision.php
new file mode 100644 (file)
index 0000000..0c052d1
--- /dev/null
@@ -0,0 +1,345 @@
+<?php
+/**
+ * This file is part of MediaWiki.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Revision;
+
+use InvalidArgumentException;
+use LogicException;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\SuppressedDataException;
+use ParserOptions;
+use ParserOutput;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+use Revision;
+use Title;
+use User;
+use Wikimedia\Assert\Assert;
+
+/**
+ * RenderedRevision represents the rendered representation of a revision. It acts as a lazy provider
+ * of ParserOutput objects for the revision's individual slots, as well as a combined ParserOutput
+ * of all slots.
+ *
+ * @since 1.32
+ */
+class RenderedRevision {
+
+       /**
+        * @var Title
+        */
+       private $title;
+
+       /** @var RevisionRecord */
+       private $revision;
+
+       /**
+        * @var ParserOptions
+        */
+       private $options;
+
+       /**
+        * @var int Audience to check when accessing content.
+        */
+       private $audience = RevisionRecord::FOR_PUBLIC;
+
+       /**
+        * @var User|null The user to use for audience checks during content access.
+        */
+       private $forUser = null;
+
+       /**
+        * @var ParserOutput|null The combined ParserOutput for the revision,
+        *      initialized lazily by getRevisionParserOutput().
+        */
+       private $revisionOutput = null;
+
+       /**
+        * @var ParserOutput[] The ParserOutput for each slot,
+        *      initialized lazily by getSlotParserOutput().
+        */
+       private $slotsOutput = [];
+
+       /**
+        * @var callable Callback for combining slot output into revision output.
+        *      Signature: function ( RenderedRevision $this ): ParserOutput.
+        */
+       private $combineOutput;
+
+       /**
+        * @var LoggerInterface For profiling ParserOutput re-use.
+        */
+       private $saveParseLogger;
+
+       /**
+        * @note Application logic should not instantiate RenderedRevision instances directly,
+        * but should use a RevisionRenderer instead.
+        *
+        * @param Title $title
+        * @param RevisionRecord $revision
+        * @param ParserOptions $options
+        * @param callable $combineOutput Callback for combining slot output into revision output.
+        *        Signature: function ( RenderedRevision $this ): ParserOutput.
+        * @param int $audience Use RevisionRecord::FOR_PUBLIC, FOR_THIS_USER, or RAW.
+        * @param User|null $forUser Required if $audience is FOR_THIS_USER.
+        */
+       public function __construct(
+               Title $title,
+               RevisionRecord $revision,
+               ParserOptions $options,
+               callable $combineOutput,
+               $audience = RevisionRecord::FOR_PUBLIC,
+               User $forUser = null
+       ) {
+               $this->title = $title;
+               $this->options = $options;
+
+               $this->setRevisionInternal( $revision );
+
+               $this->combineOutput = $combineOutput;
+               $this->saveParseLogger = new NullLogger();
+
+               if ( $audience === RevisionRecord::FOR_THIS_USER && !$forUser ) {
+                       throw new InvalidArgumentException(
+                               'User must be specified when setting audience to FOR_THIS_USER'
+                       );
+               }
+
+               $this->audience = $audience;
+               $this->forUser = $forUser;
+       }
+
+       /**
+        * @param LoggerInterface $saveParseLogger
+        */
+       public function setSaveParseLogger( LoggerInterface $saveParseLogger ) {
+               $this->saveParseLogger = $saveParseLogger;
+       }
+
+       /**
+        * @return bool Whether the revision's content has been hidden from unprivileged users.
+        */
+       public function isContentDeleted() {
+               return $this->revision->isDeleted( RevisionRecord::DELETED_TEXT );
+       }
+
+       /**
+        * @return RevisionRecord
+        */
+       public function getRevision() {
+               return $this->revision;
+       }
+
+       /**
+        * @return ParserOptions
+        */
+       public function getOptions() {
+               return $this->options;
+       }
+
+       /**
+        * @param array $hints Hints given as an associative array. Known keys:
+        *      - 'generate-html' => bool: Whether the caller is interested in output HTML (as opposed
+        *        to just meta-data). Default is to generate HTML.
+        *
+        * @return ParserOutput
+        */
+       public function getRevisionParserOutput( array $hints = [] ) {
+               $withHtml = $hints['generate-html'] ?? true;
+
+               if ( !$this->revisionOutput
+                       || ( $withHtml && !$this->revisionOutput->hasText() )
+               ) {
+                       $output = call_user_func( $this->combineOutput, $this, $hints );
+
+                       Assert::postcondition(
+                               $output instanceof ParserOutput,
+                               'Callback did not return a ParserOutput object!'
+                       );
+
+                       $this->revisionOutput = $output;
+               }
+
+               return $this->revisionOutput;
+       }
+
+       /**
+        * @param string $role
+        * @param array $hints Hints given as an associative array. Known keys:
+        *      - 'generate-html' => bool: Whether the caller is interested in output HTML (as opposed
+        *        to just meta-data). Default is to generate HTML.
+        *
+        * @throws SuppressedDataException if the content is not accessible for the audience
+        *         specified in the constructor.
+        * @return ParserOutput
+        */
+       public function getSlotParserOutput( $role, array $hints = [] ) {
+               $withHtml = $hints['generate-html'] ?? true;
+
+               if ( !isset( $this->slotsOutput[ $role ] )
+                       || ( $withHtml && !$this->slotsOutput[ $role ]->hasText() )
+               ) {
+                       $content = $this->revision->getContent( $role, $this->audience, $this->forUser );
+
+                       if ( !$content ) {
+                               throw new SuppressedDataException(
+                                       'Access to the content has been suppressed for this audience'
+                               );
+                       } else {
+                               $output = $content->getParserOutput(
+                                       $this->title,
+                                       $this->revision->getId(),
+                                       $this->options,
+                                       $withHtml
+                               );
+
+                               if ( $withHtml && !$output->hasText() ) {
+                                       throw new LogicException(
+                                               'HTML generation was requested, but '
+                                               . get_class( $content )
+                                               . '::getParserOutput() returns a ParserOutput with no text set.'
+                                       );
+                               }
+
+                               // Detach watcher, to ensure option use is not recorded in the wrong ParserOutput.
+                               $this->options->registerWatcher( null );
+                       }
+
+                       $this->slotsOutput[ $role ] = $output;
+               }
+
+               return $this->slotsOutput[$role];
+       }
+
+       /**
+        * Updates the RevisionRecord after the revision has been saved. This can be used to discard
+        * and cached ParserOutput so parser functions like {{REVISIONTIMESTAMP}} or {{REVISIONID}}
+        * are re-evaluated.
+        *
+        * @note There should be no need to call this for null-edits.
+        *
+        * @param RevisionRecord $rev
+        */
+       public function updateRevision( RevisionRecord $rev ) {
+               if ( $rev->getId() === $this->revision->getId() ) {
+                       return;
+               }
+
+               if ( $this->revision->getId() ) {
+                       throw new LogicException( 'RenderedRevision already has a revision with ID '
+                               . $this->revision->getId(), ', can\'t update to revision with ID ' . $rev->getId() );
+               }
+
+               if ( !$this->revision->getSlots()->hasSameContent( $rev->getSlots() ) ) {
+                       throw new LogicException( 'Cannot update to a revision with different content!' );
+               }
+
+               $this->setRevisionInternal( $rev );
+
+               $this->pruneRevisionSensitiveOutput( $this->revision->getId() );
+       }
+
+       /**
+        * Prune any output that depends on the revision ID.
+        *
+        * @param int|bool  $actualRevId The actual rev id, to check the used speculative rev ID
+        *        against, or false to not purge on vary-revision-id, or true to purge on
+        *        vary-revision-id unconditionally.
+        */
+       private function pruneRevisionSensitiveOutput( $actualRevId ) {
+               if ( $this->revisionOutput ) {
+                       if ( $this->outputVariesOnRevisionMetaData( $this->revisionOutput, $actualRevId ) ) {
+                               $this->revisionOutput = null;
+                       }
+               } else {
+                       $this->saveParseLogger->debug( __METHOD__ . ": no prepared revision output...\n" );
+               }
+
+               foreach ( $this->slotsOutput as $role => $output ) {
+                       if ( $this->outputVariesOnRevisionMetaData( $output, $actualRevId ) ) {
+                               unset( $this->slotsOutput[$role] );
+                       }
+               }
+       }
+
+       /**
+        * @param RevisionRecord $revision
+        */
+       private function setRevisionInternal( RevisionRecord $revision ) {
+               $this->revision = $revision;
+
+               // Make sure the parser uses the correct Revision object
+               $title = $this->title;
+               $oldCallback = $this->options->getCurrentRevisionCallback();
+               $this->options->setCurrentRevisionCallback(
+                       function ( Title $parserTitle, $parser = false ) use ( $title, $oldCallback ) {
+                               if ( $parserTitle->equals( $title ) ) {
+                                       $legacyRevision = new Revision( $this->revision );
+                                       return $legacyRevision;
+                               } else {
+                                       return call_user_func( $oldCallback, $parserTitle, $parser );
+                               }
+                       }
+               );
+       }
+
+       /**
+        * @param ParserOutput $out
+        * @param int|bool  $actualRevId The actual rev id, to check the used speculative rev ID
+        *        against, or false to not purge on vary-revision-id, or true to purge on
+        *        vary-revision-id unconditionally.
+        * @return bool
+        */
+       private function outputVariesOnRevisionMetaData( ParserOutput $out, $actualRevId ) {
+               $method = __METHOD__;
+
+               if ( $out->getFlag( 'vary-revision' ) ) {
+                       // XXX: Would be just keep the output if the speculative revision ID was correct,
+                       // but that can go wrong for some edge cases, like {{PAGEID}} during page creation.
+                       // For that specific case, it would perhaps nice to have a vary-page flag.
+                       $this->saveParseLogger->info(
+                               "$method: Prepared output has vary-revision...\n"
+                       );
+                       return true;
+               } elseif ( $out->getFlag( 'vary-revision-id' )
+                       && $actualRevId !== false
+                       && ( $actualRevId === true || $out->getSpeculativeRevIdUsed() !== $actualRevId )
+               ) {
+                       $this->saveParseLogger->info(
+                               "$method: Prepared output has vary-revision-id with wrong ID...\n"
+                       );
+                       return true;
+               } else {
+                       // NOTE: In the original fix for T135261, the output was discarded if 'vary-user' was
+                       // set for a null-edit. The reason was that the original rendering in that case was
+                       // targeting the user making the null-edit, not the user who made the original edit,
+                       // causing {{REVISIONUSER}} to return the wrong name.
+                       // This case is now expected to be handled by the code in RevisionRenderer that
+                       // constructs the ParserOptions: For a null-edit, setCurrentRevisionCallback is called
+                       // with the old, existing revision.
+
+                       wfDebug( "$method: Keeping prepared output...\n" );
+                       return false;
+               }
+       }
+
+}
diff --git a/includes/Revision/RevisionRenderer.php b/includes/Revision/RevisionRenderer.php
new file mode 100644 (file)
index 0000000..f71f9e7
--- /dev/null
@@ -0,0 +1,218 @@
+<?php
+/**
+ * This file is part of MediaWiki.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Revision;
+
+use Html;
+use InvalidArgumentException;
+use MediaWiki\Storage\RevisionRecord;
+use ParserOptions;
+use ParserOutput;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+use Title;
+use User;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * The RevisionRenderer service provides access to rendered output for revisions.
+ * It does so be acting as a factory for RenderedRevision instances, which in turn
+ * provide lazy access to ParserOutput objects.
+ *
+ * One key responsibility of RevisionRenderer is implementing the layout used to combine
+ * the output of multiple slots.
+ *
+ * @since 1.32
+ */
+class RevisionRenderer {
+
+       /** @var LoggerInterface */
+       private $saveParseLogger;
+
+       /** @var ILoadBalancer */
+       private $loadBalancer;
+
+       /** @var string|bool */
+       private $wikiId;
+
+       /**
+        * @param ILoadBalancer $loadBalancer
+        * @param bool|string $wikiId
+        */
+       public function __construct( ILoadBalancer $loadBalancer, $wikiId = false ) {
+               $this->loadBalancer = $loadBalancer;
+               $this->wikiId = $wikiId;
+
+               $this->saveParseLogger = new NullLogger();
+       }
+
+       /**
+        * @param RevisionRecord $rev
+        * @param ParserOptions|null $options
+        * @param User|null $forUser User for privileged access. Default is unprivileged (public)
+        *        access, unless the 'audience' hint is set to something else RevisionRecord::RAW.
+        * @param array $hints Hints given as an associative array. Known keys:
+        *      - 'use-master' Use master when rendering for the parser cache during save.
+        *        Default is to use a replica.
+        *      - 'audience' the audience to use for content access. Default is
+        *        RevisionRecord::FOR_PUBLIC if $forUser is not set, RevisionRecord::FOR_THIS_USER
+        *        if $forUser is set. Can be set to RevisionRecord::RAW to disable audience checks.
+        *
+        * @return RenderedRevision|null The rendered revision, or null if the audience checks fails.
+        */
+       public function getRenderedRevision(
+               RevisionRecord $rev,
+               ParserOptions $options = null,
+               User $forUser = null,
+               array $hints = []
+       ) {
+               if ( $rev->getWikiId() !== $this->wikiId ) {
+                       throw new InvalidArgumentException( 'Mismatching wiki ID ' . $rev->getWikiId() );
+               }
+
+               $audience = $hints['audience']
+                       ?? ( $forUser ? RevisionRecord::FOR_THIS_USER : RevisionRecord::FOR_PUBLIC );
+
+               if ( !$rev->audienceCan( RevisionRecord::DELETED_TEXT, $audience, $forUser ) ) {
+                       // Returning null here is awkward, but consist with the signature of
+                       // Revision::getContent() and RevisionRecord::getContent().
+                       return null;
+               }
+
+               if ( !$options ) {
+                       $options = ParserOptions::newCanonical( $forUser ?: 'canonical' );
+               }
+
+               $useMaster = $hints['use-master'] ?? false;
+
+               $dbIndex = $useMaster
+                       ? DB_MASTER // use latest values
+                       : DB_REPLICA; // T154554
+
+               $options->setSpeculativeRevIdCallback( function () use ( $dbIndex ) {
+                       return $this->getSpeculativeRevId( $dbIndex );
+               } );
+
+               $title = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
+
+               $renderedRevision = new RenderedRevision(
+                       $title,
+                       $rev,
+                       $options,
+                       function ( RenderedRevision $rrev, array $hints ) {
+                               return $this->combineSlotOutput( $rrev, $hints );
+                       },
+                       $audience,
+                       $forUser
+               );
+
+               $renderedRevision->setSaveParseLogger( $this->saveParseLogger );
+
+               return $renderedRevision;
+       }
+
+       private function getSpeculativeRevId( $dbIndex ) {
+               // Use a fresh master connection in order to see the latest data, by avoiding
+               // stale data from REPEATABLE-READ snapshots.
+               // HACK: But don't use a fresh connection in unit tests, since it would not have
+               // the fake tables. This should be handled by the LoadBalancer!
+               $flags = defined( 'MW_PHPUNIT_TEST' ) || $dbIndex === DB_REPLICA
+                       ? 0 : ILoadBalancer::CONN_TRX_AUTOCOMMIT;
+
+               $db = $this->loadBalancer->getConnectionRef( $dbIndex, [], $this->wikiId, $flags );
+
+               return 1 + (int)$db->selectField(
+                       'revision',
+                       'MAX(rev_id)',
+                       [],
+                       __METHOD__
+               );
+       }
+
+       /**
+        * This implements the layout for combining the output of multiple slots.
+        *
+        * @todo Use placement hints from SlotRoleHandlers instead of hard-coding the layout.
+        *
+        * @param RenderedRevision $rrev
+        * @param array $hints see RenderedRevision::getRevisionParserOutput()
+        *
+        * @return ParserOutput
+        */
+       private function combineSlotOutput( RenderedRevision $rrev, array $hints = [] ) {
+               $revision = $rrev->getRevision();
+               $slots = $revision->getSlots()->getSlots();
+
+               $withHtml = $hints['generate-html'] ?? true;
+
+               // short circuit if there is only the main slot
+               if ( array_keys( $slots ) === [ 'main' ] ) {
+                       return $rrev->getSlotParserOutput( 'main' );
+               }
+
+               // TODO: put fancy layout logic here, see T200915.
+
+               // move main slot to front
+               if ( isset( $slots['main'] ) ) {
+                       $slots = [ 'main' => $slots['main'] ] + $slots;
+               }
+
+               $combinedOutput = new ParserOutput( null );
+               $slotOutput = [];
+
+               $options = $rrev->getOptions();
+               $options->registerWatcher( [ $combinedOutput, 'recordOption' ] );
+
+               foreach ( $slots as $role => $slot ) {
+                       $out = $rrev->getSlotParserOutput( $role, $hints );
+                       $slotOutput[$role] = $out;
+
+                       $combinedOutput->mergeInternalMetaDataFrom( $out, $role );
+                       $combinedOutput->mergeTrackingMetaDataFrom( $out );
+               }
+
+               if ( $withHtml ) {
+                       $html = '';
+                       $first = true;
+                       /** @var ParserOutput $out */
+                       foreach ( $slotOutput as $role => $out ) {
+                               if ( $first ) {
+                                       // skip header for the first slot
+                                       $first = false;
+                               } else {
+                                       // NOTE: this placeholder is hydrated by ParserOutput::getText().
+                                       $headText = Html::element( 'mw:slotheader', [], $role );
+                                       $html .= Html::rawElement( 'h1', [ 'class' => 'mw-slot-header' ], $headText );
+                               }
+
+                               $html .= $out->getRawText();
+                               $combinedOutput->mergeHtmlMetaDataFrom( $out );
+                       }
+
+                       $combinedOutput->setText( $html );
+               }
+
+               $options->registerWatcher( null );
+               return $combinedOutput;
+       }
+
+}
index 99b2942..59cdec9 100644 (file)
@@ -51,6 +51,7 @@ use MediaWiki\Preferences\DefaultPreferencesFactory;
 use MediaWiki\Shell\CommandFactory;
 use MediaWiki\Special\SpecialPageFactory;
 use MediaWiki\Storage\BlobStore;
+use MediaWiki\Revision\RevisionRenderer;
 use MediaWiki\Storage\BlobStoreFactory;
 use MediaWiki\Storage\NameTableStore;
 use MediaWiki\Storage\RevisionFactory;
@@ -445,6 +446,10 @@ return [
                return $services->getRevisionStore();
        },
 
+       'RevisionRenderer' => function ( MediaWikiServices $services ) : RevisionRenderer {
+               return new RevisionRenderer( $services->getDBLoadBalancer() );
+       },
+
        'RevisionStore' => function ( MediaWikiServices $services ) : RevisionStore {
                return $services->getRevisionStoreFactory()->getRevisionStore();
        },
index c015eac..43bc2d8 100644 (file)
@@ -86,11 +86,6 @@ MediaWiki\HeaderCallback::register();
  * Load LocalSettings.php
  */
 
-if ( is_readable( "$IP/StartProfiler.php" ) ) {
-       // @deprecated since 1.32: Use LocalSettings.php instead.
-       require "$IP/StartProfiler.php";
-}
-
 if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
        call_user_func( MW_CONFIG_CALLBACK );
 } else {
index a00766f..2df1670 100644 (file)
@@ -36,14 +36,13 @@ use Language;
 use LinksUpdate;
 use LogicException;
 use MediaWiki\Edit\PreparedEdit;
-use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\RenderedRevision;
+use MediaWiki\Revision\RevisionRenderer;
 use MediaWiki\User\UserIdentity;
 use MessageCache;
 use ParserCache;
 use ParserOptions;
 use ParserOutput;
-use Psr\Log\LoggerInterface;
-use Psr\Log\NullLogger;
 use RecentChangesUpdateJob;
 use ResourceLoaderWikiModule;
 use Revision;
@@ -112,11 +111,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
         */
        private $contLang;
 
-       /**
-        * @var LoggerInterface
-        */
-       private $saveParseLogger;
-
        /**
         * @var JobQueueGroup
         */
@@ -177,31 +171,19 @@ class DerivedPageDataUpdater implements IDBAccessObject {
        private $slotsUpdate = null;
 
        /**
-        * @var MutableRevisionSlots|null
-        */
-       private $pstContentSlots = null;
-
-       /**
-        * @var object[] anonymous objects with two fields, using slot roles as keys:
-        *  - hasHtml: whether the output contains HTML
-        *  - ParserOutput: the slot's parser output
-        */
-       private $slotsOutput = [];
-
-       /**
-        * @var ParserOutput|null
+        * @var RevisionRecord|null
         */
-       private $canonicalParserOutput = null;
+       private $revision = null;
 
        /**
-        * @var ParserOptions|null
+        * @var RenderedRevision
         */
-       private $canonicalParserOptions = null;
+       private $renderedRevision = null;
 
        /**
-        * @var RevisionRecord
+        * @var RevisionRenderer
         */
-       private $revision = null;
+       private $revisionRenderer;
 
        /**
         * A stage identifier for managing the life cycle of this instance.
@@ -248,31 +230,29 @@ class DerivedPageDataUpdater implements IDBAccessObject {
        /**
         * @param WikiPage $wikiPage ,
         * @param RevisionStore $revisionStore
+        * @param RevisionRenderer $revisionRenderer
         * @param ParserCache $parserCache
         * @param JobQueueGroup $jobQueueGroup
         * @param MessageCache $messageCache
         * @param Language $contLang
-        * @param LoggerInterface|null $saveParseLogger
         */
        public function __construct(
                WikiPage $wikiPage,
                RevisionStore $revisionStore,
+               RevisionRenderer $revisionRenderer,
                ParserCache $parserCache,
                JobQueueGroup $jobQueueGroup,
                MessageCache $messageCache,
-               Language $contLang,
-               LoggerInterface $saveParseLogger = null
+               Language $contLang
        ) {
                $this->wikiPage = $wikiPage;
 
                $this->parserCache = $parserCache;
                $this->revisionStore = $revisionStore;
+               $this->revisionRenderer = $revisionRenderer;
                $this->jobQueueGroup = $jobQueueGroup;
                $this->messageCache = $messageCache;
                $this->contLang = $contLang;
-
-               // XXX: replace all wfDebug calls with a Logger. Do we nede more than one logger here?
-               $this->saveParseLogger = $saveParseLogger ?: new NullLogger();
        }
 
        /**
@@ -353,7 +333,9 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        return false;
                }
 
-               if ( $revision && $this->revision && $this->revision->getId() !== $revision->getId() ) {
+               if ( $revision && $this->revision && $this->revision->getId()
+                       && $this->revision->getId() !== $revision->getId()
+               ) {
                        return false;
                }
 
@@ -378,6 +360,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                if ( $this->revision
                        && $user
+                       && $this->revision->getUser( RevisionRecord::RAW )
                        && $this->revision->getUser( RevisionRecord::RAW )->getName() !== $user->getName()
                ) {
                        return false;
@@ -385,6 +368,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                if ( $revision
                        && $this->user
+                       && $this->revision->getUser( RevisionRecord::RAW )
                        && $revision->getUser( RevisionRecord::RAW )->getName() !== $this->user->getName()
                ) {
                        return false;
@@ -398,9 +382,9 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        return false;
                }
 
-               if ( $this->pstContentSlots
-                       && $revision
-                       && !$this->pstContentSlots->hasSameContent( $revision->getSlots() )
+               if ( $revision
+                       && $this->revision
+                       && !$this->revision->getSlots()->hasSameContent( $revision->getSlots() )
                ) {
                        return false;
                }
@@ -533,16 +517,18 @@ class DerivedPageDataUpdater implements IDBAccessObject {
         * @return bool
         */
        public function isContentPrepared() {
-               return $this->pstContentSlots !== null;
+               return $this->revision !== null;
        }
 
        /**
         * Whether prepareUpdate() has been called on this instance.
         *
+        * @note will also return null in case of a null-edit!
+        *
         * @return bool
         */
        public function isUpdatePrepared() {
-               return $this->revision !== null;
+               return $this->revision !== null && $this->revision->getId() !== null;
        }
 
        /**
@@ -562,17 +548,17 @@ class DerivedPageDataUpdater implements IDBAccessObject {
        }
 
        /**
-        * Whether the content of the target revision is publicly visible.
+        * Whether the content is deleted and thus not visible to the public.
         *
         * @return bool
         */
-       public function isContentPublic() {
+       public function isContentDeleted() {
                if ( $this->revision ) {
-                       // XXX: if that revision is the current revision, this can be skipped
-                       return !$this->revision->isDeleted( RevisionRecord::DELETED_TEXT );
+                       // XXX: if that revision is the current revision, this should be skipped
+                       return $this->revision->isDeleted( RevisionRecord::DELETED_TEXT );
                } else {
-                       // If the content has not been saved yet, it cannot have been suppressed yet.
-                       return true;
+                       // If the content has not been saved yet, it cannot have been deleted yet.
+                       return false;
                }
        }
 
@@ -635,7 +621,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        return false;
                }
 
-               if ( !$this->isContentPublic() ) {
+               if ( $this->isContentDeleted() ) {
                        // This should be irrelevant: countability only applies to the current revision,
                        // and the current revision is never suppressed.
                        return false;
@@ -739,7 +725,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                $this->slotsOutput = [];
                $this->canonicalParserOutput = null;
-               $this->canonicalParserOptions = null;
 
                // The edit may have already been prepared via api.php?action=stashedit
                $stashedEdit = false;
@@ -769,14 +754,13 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $this->slotsUpdate = $slotsUpdate;
 
                if ( $parentRevision ) {
-                       // start out by inheriting all parent slots
-                       $this->pstContentSlots = MutableRevisionSlots::newFromParentRevisionSlots(
-                               $parentRevision->getSlots()->getSlots()
-                       );
+                       $this->revision = MutableRevisionRecord::newFromParentRevision( $parentRevision );
                } else {
-                       $this->pstContentSlots = new MutableRevisionSlots();
+                       $this->revision = new MutableRevisionRecord( $title );
                }
 
+               $pstContentSlots = $this->revision->getSlots();
+
                foreach ( $slotsUpdate->getModifiedRoles() as $role ) {
                        $slot = $slotsUpdate->getModifiedSlot( $role );
 
@@ -793,18 +777,78 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                                $pstSlot = SlotRecord::newUnsaved( $role, $pstContent );
                        }
 
-                       $this->pstContentSlots->setSlot( $pstSlot );
+                       $pstContentSlots->setSlot( $pstSlot );
                }
 
                foreach ( $slotsUpdate->getRemovedRoles() as $role ) {
-                       $this->pstContentSlots->removeSlot( $role );
+                       $pstContentSlots->removeSlot( $role );
                }
 
                $this->options['created'] = ( $parentRevision === null );
                $this->options['changed'] = ( $parentRevision === null
-                       || !$this->pstContentSlots->hasSameContent( $parentRevision->getSlots() ) );
+                       || !$pstContentSlots->hasSameContent( $parentRevision->getSlots() ) );
 
                $this->doTransition( 'has-content' );
+
+               if ( !$this->options['changed'] ) {
+                       // null-edit!
+
+                       // TODO: move this into MutableRevisionRecord
+                       // TODO: This needs to behave differently for a forced dummy edit!
+                       $this->revision->setId( $parentRevision->getId() );
+                       $this->revision->setTimestamp( $parentRevision->getTimestamp() );
+                       $this->revision->setPageId( $parentRevision->getPageId() );
+                       $this->revision->setParentId( $parentRevision->getParentId() );
+                       $this->revision->setUser( $parentRevision->getUser( RevisionRecord::RAW ) );
+                       $this->revision->setComment( $parentRevision->getComment( RevisionRecord::RAW ) );
+                       $this->revision->setMinorEdit( $parentRevision->isMinor() );
+                       $this->revision->setVisibility( $parentRevision->getVisibility() );
+
+                       // prepareUpdate() is redundant for null-edits
+                       $this->doTransition( 'has-revision' );
+               } else {
+                       $this->revision->setUser( $user );
+               }
+       }
+
+       /**
+        * Returns the update's target revision - that is, the revision that will be the current
+        * revision after the update.
+        *
+        * @note Callers must treat the returned RevisionRecord's content as immutable, even
+        * if it is a MutableRevisionRecord instance. Other aspects of a MutableRevisionRecord
+        * returned from here, such as the user or the comment, may be changed, but may not
+        * be reflected in ParserOutput until after prepareUpdate() has been called.
+        *
+        * @todo This is currently used by PageUpdater::makeNewRevision() to construct an unsaved
+        * MutableRevisionRecord instance. Introduce something like an UnsavedRevisionFactory service
+        * for that purpose instead!
+        *
+        * @return RevisionRecord
+        */
+       public function getRevision() {
+               $this->assertPrepared( __METHOD__ );
+               return $this->revision;
+       }
+
+       /**
+        * @return RenderedRevision
+        */
+       public function getRenderedRevision() {
+               if ( !$this->renderedRevision ) {
+                       $this->assertPrepared( __METHOD__ );
+
+                       // NOTE: we want a canonical rendering, so don't pass $this->user or ParserOptions
+                       // NOTE: the revision is either new or current, so we can bypass audience checks.
+                       $this->renderedRevision = $this->revisionRenderer->getRenderedRevision(
+                               $this->revision,
+                               null,
+                               null,
+                               [ 'use-master' => $this->useMaster(), 'audience' => RevisionRecord::RAW ]
+                       );
+               }
+
+               return $this->renderedRevision;
        }
 
        private function assertHasPageState( $method ) {
@@ -817,7 +861,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
        }
 
        private function assertPrepared( $method ) {
-               if ( !$this->pstContentSlots ) {
+               if ( !$this->revision ) {
                        throw new LogicException(
                                'Must call prepareContent() or prepareUpdate() before calling ' . $method
                        );
@@ -872,11 +916,14 @@ class DerivedPageDataUpdater implements IDBAccessObject {
        /**
         * Returns the slots of the target revision, after PST.
         *
+        * @note Callers must treat the returned RevisionSlots instance as immutable, even
+        * if it is a MutableRevisionSlots instance.
+        *
         * @return RevisionSlots
         */
        public function getSlots() {
                $this->assertPrepared( __METHOD__ );
-               return $this->pstContentSlots;
+               return $this->revision->getSlots();
        }
 
        /**
@@ -888,12 +935,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $this->assertPrepared( __METHOD__ );
 
                if ( !$this->slotsUpdate ) {
-                       if ( !$this->revision ) {
-                               // This should not be possible: if assertPrepared() returns true,
-                               // at least one of $this->slotsUpdate or $this->revision should be set.
-                               throw new LogicException( 'No revision nor a slots update is known!' );
-                       }
-
                        $old = $this->getOldRevision();
                        $this->slotsUpdate = RevisionSlotsUpdate::newFromRevisionSlots(
                                $this->revision->getSlots(),
@@ -957,7 +998,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
         * - moved: bool, whether the page was moved (default false)
         * - restored: bool, whether the page was undeleted (default false)
         * - oldrevision: Revision object for the pre-update revision (default null)
-        * - parseroutput: The canonical ParserOutput of $revision (default null)
         * - triggeringuser: The user triggering the update (UserIdentity, default null)
         * - oldredirect: bool, null, or string 'no-change' (default null):
         *    - bool: whether the page was counted as a redirect before that
@@ -979,12 +1019,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        '$options["oldrevision"]',
                        'must be a RevisionRecord (or Revision)'
                );
-               Assert::parameter(
-                       !isset( $options['parseroutput'] )
-                       || $options['parseroutput'] instanceof ParserOutput,
-                       '$options["parseroutput"]',
-                       'must be a ParserOutput'
-               );
                Assert::parameter(
                        !isset( $options['triggeringuser'] )
                        || $options['triggeringuser'] instanceof UserIdentity,
@@ -998,7 +1032,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        );
                }
 
-               if ( $this->revision ) {
+               if ( $this->revision && $this->revision->getId() ) {
                        if ( $this->revision->getId() === $revision->getId() ) {
                                return; // nothing to do!
                        } else {
@@ -1011,8 +1045,8 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        }
                }
 
-               if ( $this->pstContentSlots
-                       && !$this->pstContentSlots->hasSameContent( $revision->getSlots() )
+               if ( $this->revision
+                       && !$this->revision->getSlots()->hasSameContent( $revision->getSlots() )
                ) {
                        throw new LogicException(
                                'The Revision provided has mismatching content!'
@@ -1107,7 +1141,6 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $this->options['created'] = ( $this->pageState['oldId'] === 0 );
 
                $this->revision = $revision;
-               $this->pstContentSlots = $revision->getSlots();
 
                $this->doTransition( 'has-revision' );
 
@@ -1118,74 +1151,14 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                }
 
                // Prune any output that depends on the revision ID.
-               if ( $this->canonicalParserOutput ) {
-                       if ( $this->outputVariesOnRevisionMetaData( $this->canonicalParserOutput, __METHOD__ ) ) {
-                               $this->canonicalParserOutput = null;
-                       }
-               } else {
-                       $this->saveParseLogger->debug( __METHOD__ . ": No prepared canonical output...\n" );
-               }
-
-               if ( $this->slotsOutput ) {
-                       foreach ( $this->slotsOutput as $role => $prep ) {
-                               if ( $this->outputVariesOnRevisionMetaData( $prep->output, __METHOD__ ) ) {
-                                       unset( $this->slotsOutput[$role] );
-                               }
-                       }
-               } else {
-                       $this->saveParseLogger->debug( __METHOD__ . ": No prepared output...\n" );
-               }
-
-               // reset ParserOptions, so the actual revision ID is used in future ParserOutput generation
-               $this->canonicalParserOptions = null;
-
-               // Avoid re-generating the canonical ParserOutput if it's known.
-               // We just trust that the caller is passing the correct ParserOutput!
-               if ( isset( $options['parseroutput'] ) ) {
-                       $this->canonicalParserOutput = $options['parseroutput'];
+               if ( $this->renderedRevision ) {
+                       $this->renderedRevision->updateRevision( $revision );
                }
 
                // TODO: optionally get ParserOutput from the ParserCache here.
                // Move the logic used by RefreshLinksJob here!
        }
 
-       /**
-        * @param ParserOutput $out
-        * @param string $method
-        * @return bool
-        */
-       private function outputVariesOnRevisionMetaData( ParserOutput $out, $method = __METHOD__ ) {
-               if ( $out->getFlag( 'vary-revision' ) ) {
-                       // XXX: Just keep the output if the speculative revision ID was correct, like below?
-                       $this->saveParseLogger->info(
-                               "$method: Prepared output has vary-revision...\n"
-                       );
-                       return true;
-               } elseif ( $out->getFlag( 'vary-revision-id' )
-                       && $out->getSpeculativeRevIdUsed() !== $this->revision->getId()
-               ) {
-                       $this->saveParseLogger->info(
-                               "$method: Prepared output has vary-revision-id with wrong ID...\n"
-                       );
-                       return true;
-               } elseif ( $out->getFlag( 'vary-user' )
-                       && !$this->options['changed']
-               ) {
-                       // When Alice makes a null-edit on top of Bob's edit,
-                       // {{REVISIONUSER}} must resolve to "Bob", not "Alice", see T135261.
-                       // TODO: to avoid this, we should check for null-edits in makeCanonicalparserOptions,
-                       // and set setCurrentRevisionCallback to return the existing revision when appropriate.
-                       // See also the comment there [dk 2018-05]
-                       $this->saveParseLogger->info(
-                               "$method: Prepared output has vary-user and is null-edit...\n"
-                       );
-                       return true;
-               } else {
-                       wfDebug( "$method: Keeping prepared output...\n" );
-                       return false;
-               }
-       }
-
        /**
         * @deprecated This only exists for B/C, use the getters on DerivedPageDataUpdater directly!
         * @return PreparedEdit
@@ -1198,11 +1171,11 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                $preparedEdit->popts = $this->getCanonicalParserOptions();
                $preparedEdit->output = $this->getCanonicalParserOutput();
-               $preparedEdit->pstContent = $this->pstContentSlots->getContent( 'main' );
+               $preparedEdit->pstContent = $this->revision->getContent( 'main' );
                $preparedEdit->newContent =
                        $slotsUpdate->isModifiedSlot( 'main' )
                        ? $slotsUpdate->getModifiedSlot( 'main' )->getContent()
-                       : $this->pstContentSlots->getContent( 'main' ); // XXX: can we just remove this?
+                       : $this->revision->getContent( 'main' ); // XXX: can we just remove this?
                $preparedEdit->oldContent = null; // unused. // XXX: could get this from the parent revision
                $preparedEdit->revid = $this->revision ? $this->revision->getId() : null;
                $preparedEdit->timestamp = $preparedEdit->output->getCacheTime();
@@ -1211,130 +1184,30 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                return $preparedEdit;
        }
 
-       /**
-        * @return bool
-        */
-       private function isContentAccessible() {
-               // XXX: when we move this to a RevisionHtmlProvider, the audience may be configurable!
-               return $this->isContentPublic();
-       }
-
        /**
         * @param string $role
         * @param bool $generateHtml
         * @return ParserOutput
         */
        public function getSlotParserOutput( $role, $generateHtml = true ) {
-               // TODO: factor this out into a RevisionHtmlProvider that can also be used for viewing.
-
-               $this->assertPrepared( __METHOD__ );
-
-               if ( isset( $this->slotsOutput[$role] ) ) {
-                       $entry = $this->slotsOutput[$role];
-
-                       if ( $entry->hasHtml || !$generateHtml ) {
-                               return $entry->output;
-                       }
-               }
-
-               if ( !$this->isContentAccessible() ) {
-                       // empty output
-                       $output = new ParserOutput();
-               } else {
-                       $content = $this->getRawContent( $role );
-
-                       $output = $content->getParserOutput(
-                               $this->getTitle(),
-                               $this->revision ? $this->revision->getId() : null,
-                               $this->getCanonicalParserOptions(),
-                               $generateHtml
-                       );
-               }
-
-               $this->slotsOutput[$role] = (object)[
-                       'output' => $output,
-                       'hasHtml' => $generateHtml,
-               ];
-
-               $output->setCacheTime( $this->getTimestampNow() );
-
-               return $output;
+               return $this->getRenderedRevision()->getSlotParserOutput(
+                       $role,
+                       [ 'generate-html' => $generateHtml ]
+               );
        }
 
        /**
         * @return ParserOutput
         */
        public function getCanonicalParserOutput() {
-               if ( $this->canonicalParserOutput ) {
-                       return $this->canonicalParserOutput;
-               }
-
-               // TODO: MCR: logic for combining the output of multiple slot goes here!
-               // TODO: factor this out into a RevisionHtmlProvider that can also be used for viewing.
-               $this->canonicalParserOutput = $this->getSlotParserOutput( 'main' );
-
-               return $this->canonicalParserOutput;
+               return $this->getRenderedRevision()->getRevisionParserOutput();
        }
 
        /**
         * @return ParserOptions
         */
        public function getCanonicalParserOptions() {
-               if ( $this->canonicalParserOptions ) {
-                       return $this->canonicalParserOptions;
-               }
-
-               // TODO: ParserOptions should *not* be controlled by the ContentHandler!
-               // See T190712 for how to fix this for Wikibase.
-               $this->canonicalParserOptions = $this->wikiPage->makeParserOptions( 'canonical' );
-
-               //TODO: if $this->revision is not set but we already know that we pending update is a
-               // null-edit, we should probably use the page's current revision here.
-               // That would avoid the need for the !$this->options['changed'] branch in
-               // outputVariesOnRevisionMetaData [dk 2018-05]
-
-               if ( $this->revision ) {
-                       // Make sure we use the appropriate revision ID when generating output
-                       $title = $this->getTitle();
-                       $oldCallback = $this->canonicalParserOptions->getCurrentRevisionCallback();
-                       $this->canonicalParserOptions->setCurrentRevisionCallback(
-                               function ( Title $parserTitle, $parser = false ) use ( $title, &$oldCallback ) {
-                                       if ( $parserTitle->equals( $title ) ) {
-                                               $legacyRevision = new Revision( $this->revision );
-                                               return $legacyRevision;
-                                       } else {
-                                               return call_user_func( $oldCallback, $parserTitle, $parser );
-                                       }
-                               }
-                       );
-               } else {
-                       // NOTE: we only get here without READ_LATEST if called directly by application logic
-                       $dbIndex = $this->useMaster()
-                               ? DB_MASTER // use the best possible guess
-                               : DB_REPLICA; // T154554
-
-                       $this->canonicalParserOptions->setSpeculativeRevIdCallback(
-                               function () use ( $dbIndex ) {
-                                       // TODO: inject LoadBalancer!
-                                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
-                                       // Use a fresh connection in order to see the latest data, by avoiding
-                                       // stale data from REPEATABLE-READ snapshots.
-                                       // HACK: But don't use a fresh connection in unit tests, since it would not have
-                                       // the fake tables. This should be handled by the LoadBalancer!
-                                       $flags = defined( 'MW_PHPUNIT_TEST' ) ? 0 : $lb::CONN_TRX_AUTOCOMMIT;
-                                       $db = $lb->getConnectionRef( $dbIndex, [], $this->getWikiId(), $flags );
-
-                                       return 1 + (int)$db->selectField(
-                                               'revision',
-                                               'MAX(rev_id)',
-                                               [],
-                                               __METHOD__
-                                       );
-                               }
-                       );
-               }
-
-               return $this->canonicalParserOptions;
+               return $this->getRenderedRevision()->getOptions();
        }
 
        /**
@@ -1408,21 +1281,16 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $recursive = $this->options['changed']; // T52785
                $updates = $this->getSecondaryDataUpdates( $recursive );
 
+               $triggeringUser = $this->options['triggeringuser'] ?? $this->user;
+               if ( !$triggeringUser instanceof User ) {
+                       $triggeringUser = User::newFromIdentity( $triggeringUser );
+               }
                foreach ( $updates as $update ) {
                        // TODO: make an $option field for the cause
-                       $update->setCause( 'edit-page', $this->user->getName() );
+                       $update->setCause( 'edit-page', $triggeringUser->getName() );
                        if ( $update instanceof LinksUpdate ) {
                                $update->setRevision( $legacyRevision );
-
-                               if ( !empty( $this->options['triggeringuser'] ) ) {
-                                       /** @var UserIdentity|User $triggeringUser */
-                                       $triggeringUser = $this->options['triggeringuser'];
-                                       if ( !$triggeringUser instanceof User ) {
-                                               $triggeringUser = User::newFromIdentity( $triggeringUser );
-                                       }
-
-                                       $update->setTriggeringUser( $triggeringUser );
-                               }
+                               $update->setTriggeringUser( $triggeringUser );
                        }
                        DeferredUpdates::addUpdate( $update );
                }
@@ -1495,7 +1363,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                // TODO: make search infrastructure aware of slots!
                $mainSlot = $this->revision->getSlot( 'main' );
-               if ( !$mainSlot->isInherited() && $this->isContentPublic() ) {
+               if ( !$mainSlot->isInherited() && !$this->isContentDeleted() ) {
                        DeferredUpdates::addUpdate( new SearchUpdate( $id, $dbKey, $mainSlot->getContent() ) );
                }
 
@@ -1530,7 +1398,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                if ( $title->getNamespace() == NS_MEDIAWIKI
                        && $this->getRevisionSlotsUpdate()->isModifiedSlot( 'main' )
                ) {
-                       $mainContent = $this->isContentPublic() ? $this->getRawContent( 'main' ) : null;
+                       $mainContent = $this->isContentDeleted() ? null : $this->getRawContent( 'main' );
 
                        $this->messageCache->updateMessageOverride( $title, $mainContent );
                }
index 1aa1165..72d6547 100644 (file)
@@ -314,6 +314,17 @@ class MutableRevisionRecord extends RevisionRecord {
                return $this->mSha1;
        }
 
+       /**
+        * Returns the slots defined for this revision as a MutableRevisionSlots instance,
+        * which can be modified to defined the slots for this revision.
+        *
+        * @return MutableRevisionSlots
+        */
+       public function getSlots() {
+               // Overwritten just guarantee the more narrow return type.
+               return parent::getSlots();
+       }
+
        /**
         * Invalidate cached aggregate values such as hash and size.
         */
index 52e8f5b..6c7919d 100644 (file)
@@ -27,7 +27,6 @@ use Wikimedia\Assert\Assert;
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\ILoadBalancer;
-use Wikimedia\Rdbms\LoadBalancer;
 
 /**
  * @author Addshore
@@ -35,7 +34,7 @@ use Wikimedia\Rdbms\LoadBalancer;
  */
 class NameTableStore {
 
-       /** @var LoadBalancer */
+       /** @var ILoadBalancer */
        private $loadBalancer;
 
        /** @var WANObjectCache */
@@ -159,11 +158,13 @@ class NameTableStore {
                if ( $searchResult === false ) {
                        $id = $this->store( $name );
                        if ( $id === null ) {
-                               // RACE: $name was already in the db, probably just inserted, so load from master
-                               // Use DBO_TRX to avoid missing inserts due to other threads or REPEATABLE-READs
-                               $table = $this->loadTable(
-                                       $this->getDBConnection( DB_MASTER, LoadBalancer::CONN_TRX_AUTOCOMMIT )
-                               );
+                               // RACE: $name was already in the db, probably just inserted, so load from master.
+                               // Use DBO_TRX to avoid missing inserts due to other threads or REPEATABLE-READs.
+                               // ...but not during unit tests, because we need the fake DB tables of the default
+                               // connection.
+                               $connFlags = defined( 'MW_PHPUNIT_TEST' ) ? 0 : ILoadBalancer::CONN_TRX_AUTOCOMMIT;
+                               $table = $this->reloadMap( $connFlags );
+
                                $searchResult = array_search( $name, $table, true );
                                if ( $searchResult === false ) {
                                        // Insert failed due to IGNORE flag, but DB_MASTER didn't give us the data
@@ -172,14 +173,15 @@ class NameTableStore {
                                        $this->logger->error( $m );
                                        throw new NameTableAccessException( $m );
                                }
-                               $this->purgeWANCache(
-                                       function () {
-                                               $this->cache->reap( $this->getCacheKey(), INF );
-                                       }
-                               );
+                       } elseif ( isset( $table[$id] ) ) {
+                               throw new NameTableAccessException(
+                                       "Expected unused ID from database insert for '$name' "
+                                       . " into '{$this->table}', but ID $id is already associated with"
+                                       . " the name '{$table[$id]}'! This may indicate database corruption!" );
                        } else {
                                $table[$id] = $name;
                                $searchResult = $id;
+
                                // As store returned an ID we know we inserted so delete from WAN cache
                                $this->purgeWANCache(
                                        function () {
@@ -193,6 +195,31 @@ class NameTableStore {
                return $searchResult;
        }
 
+       /**
+        * Reloads the name table from the master database, and purges the WAN cache entry.
+        *
+        * @note This should only be called in situations where the local cache has been detected
+        * to be out of sync with the database. There should be no reason to call this method
+        * from outside the NameTabelStore during normal operation. This method may however be
+        * useful in unit tests.
+        *
+        * @param int $connFlags ILoadBalancer::CONN_XXX flags. Optional.
+        *
+        * @return \string[] The freshly reloaded name map
+        */
+       public function reloadMap( $connFlags = 0 ) {
+               $this->tableCache = $this->loadTable(
+                       $this->getDBConnection( DB_MASTER, $connFlags )
+               );
+               $this->purgeWANCache(
+                       function () {
+                               $this->cache->reap( $this->getCacheKey(), INF );
+                       }
+               );
+
+               return $this->tableCache;
+       }
+
        /**
         * Get the id of the given name.
         * If the name doesn't exist this will throw.
index c6795ea..9d2f209 100644 (file)
@@ -344,13 +344,18 @@ class PageUpdater {
                // TODO: MCR: check the role and the content's model against the list of supported
                // roles, see T194046.
 
-               if ( $role !== 'main' ) {
-                       throw new InvalidArgumentException( 'Only the main slot is presently supported' );
-               }
-
                $this->slotsUpdate->modifyContent( $role, $content );
        }
 
+       /**
+        * Set the new slot for the given slot role
+        *
+        * @param SlotRecord $slot
+        */
+       public function setSlot( SlotRecord $slot ) {
+               $this->slotsUpdate->modifySlot( $slot );
+       }
+
        /**
         * Explicitly inherit a slot from some earlier revision.
         *
@@ -852,7 +857,11 @@ class PageUpdater {
                $title = $this->getTitle();
                $parent = $this->grabParentRevision();
 
-               $rev = new MutableRevisionRecord( $title, $this->getWikiId() );
+               // XXX: we expect to get a MutableRevisionRecord here, but that's a bit brittle!
+               // TODO: introduce something like an UnsavedRevisionFactory service instead!
+               /** @var MutableRevisionRecord $rev */
+               $rev = $this->derivedDataUpdater->getRevision();
+
                $rev->setPageId( $title->getArticleID() );
 
                if ( $parent ) {
@@ -867,17 +876,13 @@ class PageUpdater {
                $rev->setTimestamp( $timestamp );
                $rev->setMinorEdit( ( $flags & EDIT_MINOR ) > 0 );
 
-               foreach ( $this->derivedDataUpdater->getSlots()->getSlots() as $slot ) {
+               foreach ( $rev->getSlots()->getSlots() as $slot ) {
                        $content = $slot->getContent();
 
                        // XXX: We may push this up to the "edit controller" level, see T192777.
                        // TODO: change the signature of PrepareSave to not take a WikiPage!
                        $prepStatus = $content->prepareSave( $wikiPage, $flags, $oldid, $user );
 
-                       if ( $prepStatus->isOK() ) {
-                               $rev->setSlot( $slot );
-                       }
-
                        // TODO: MCR: record which problem arose in which slot.
                        $status->merge( $prepStatus );
                }
index 14b1820..d219267 100644 (file)
@@ -746,6 +746,76 @@ class RevisionStore
                if ( !isset( $revisionRow['rev_id'] ) ) {
                        // only if auto-increment was used
                        $revisionRow['rev_id'] = intval( $dbw->insertId() );
+
+                       if ( $dbw->getType() === 'mysql' ) {
+                               // (T202032) MySQL until 8.0 and MariaDB until some version after 10.1.34 don't save the
+                               // auto-increment value to disk, so on server restart it might reuse IDs from deleted
+                               // revisions. We can fix that with an insert with an explicit rev_id value, if necessary.
+
+                               $maxRevId = intval( $dbw->selectField( 'archive', 'MAX(ar_rev_id)', '', __METHOD__ ) );
+                               $table = 'archive';
+                               if ( $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_NEW ) ) {
+                                       $maxRevId2 = intval( $dbw->selectField( 'slots', 'MAX(slot_revision_id)', '', __METHOD__ ) );
+                                       if ( $maxRevId2 >= $maxRevId ) {
+                                               $maxRevId = $maxRevId2;
+                                               $table = 'slots';
+                                       }
+                               }
+
+                               if ( $maxRevId >= $revisionRow['rev_id'] ) {
+                                       $this->logger->debug(
+                                               '__METHOD__: Inserted revision {revid} but {table} has revisions up to {maxrevid}.'
+                                                       . ' Trying to fix it.',
+                                               [
+                                                       'revid' => $revisionRow['rev_id'],
+                                                       'table' => $table,
+                                                       'maxrevid' => $maxRevId,
+                                               ]
+                                       );
+
+                                       if ( !$dbw->lock( 'fix-for-T202032', __METHOD__ ) ) {
+                                               throw new MWException( 'Failed to get database lock for T202032' );
+                                       }
+                                       $fname = __METHOD__;
+                                       $dbw->onTransactionResolution( function ( $trigger, $dbw ) use ( $fname ) {
+                                               $dbw->unlock( 'fix-for-T202032', $fname );
+                                       } );
+
+                                       $dbw->delete( 'revision', [ 'rev_id' => $revisionRow['rev_id'] ], __METHOD__ );
+
+                                       // The locking here is mostly to make MySQL bypass the REPEATABLE-READ transaction
+                                       // isolation (weird MySQL "feature"). It does seem to block concurrent auto-incrementing
+                                       // inserts too, though, at least on MariaDB 10.1.29.
+                                       //
+                                       // Don't try to lock `revision` in this way, it'll deadlock if there are concurrent
+                                       // transactions in this code path thanks to the row lock from the original ->insert() above.
+                                       //
+                                       // And we have to use raw SQL to bypass the "aggregation used with a locking SELECT" warning
+                                       // that's for non-MySQL DBs.
+                                       $row1 = $dbw->query(
+                                               $dbw->selectSqlText( 'archive', [ 'v' => "MAX(ar_rev_id)" ], '', __METHOD__ ) . ' FOR UPDATE'
+                                       )->fetchObject();
+                                       if ( $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_NEW ) ) {
+                                               $row2 = $dbw->query(
+                                                       $dbw->selectSqlText( 'slots', [ 'v' => "MAX(slot_revision_id)" ], '', __METHOD__ )
+                                                               . ' FOR UPDATE'
+                                               )->fetchObject();
+                                       } else {
+                                               $row2 = null;
+                                       }
+                                       $maxRevId = max(
+                                               $maxRevId,
+                                               $row1 ? intval( $row1->v ) : 0,
+                                               $row2 ? intval( $row2->v ) : 0
+                                       );
+
+                                       // If we don't have SCHEMA_COMPAT_WRITE_NEW, all except the first of any concurrent
+                                       // transactions will throw a duplicate key error here. It doesn't seem worth trying
+                                       // to avoid that.
+                                       $revisionRow['rev_id'] = $maxRevId + 1;
+                                       $dbw->insert( 'revision', $revisionRow, __METHOD__ );
+                               }
+                       }
                }
 
                $commentCallback( $revisionRow['rev_id'] );
@@ -1477,6 +1547,10 @@ class RevisionStore
                $slots = [];
 
                foreach ( $res as $row ) {
+                       // resolve role names and model names from in-memory cache, instead of joining.
+                       $row->role_name = $this->slotRoleStore->getName( (int)$row->slot_role_id );
+                       $row->model_name = $this->contentModelStore->getName( (int)$row->content_model );
+
                        $contentCallback = function ( SlotRecord $slot ) use ( $queryFlags, $row ) {
                                return $this->loadSlotContent( $slot, null, null, null, $queryFlags );
                        };
@@ -2198,6 +2272,9 @@ class RevisionStore
         *
         * @param array $options Any combination of the following strings
         *  - 'content': Join with the content table, and select content meta-data fields
+        *  - 'model': Join with the content_models table, and select the model_name field.
+        *             Only applicable if 'content' is also set.
+        *  - 'role': Join with the slot_roles table, and select the role_name field
         *
         * @return array With three keys:
         *  - tables: (string[]) to include in the `$table` to `IDatabase->select()`
@@ -2234,26 +2311,39 @@ class RevisionStore
                        }
                } else {
                        $ret['tables'][] = 'slots';
-                       $ret['tables'][] = 'slot_roles';
                        $ret['fields'] = array_merge( $ret['fields'], [
                                'slot_revision_id',
                                'slot_content_id',
                                'slot_origin',
-                               'role_name'
+                               'slot_role_id',
                        ] );
-                       $ret['joins']['slot_roles'] = [ 'INNER JOIN', [ 'slot_role_id = role_id' ] ];
+
+                       if ( in_array( 'role', $options, true ) ) {
+                               // Use left join to attach role name, so we still find the revision row even
+                               // if the role name is missing. This triggers a more obvious failure mode.
+                               $ret['tables'][] = 'slot_roles';
+                               $ret['joins']['slot_roles'] = [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ];
+                               $ret['fields'][] = 'role_name';
+                       }
 
                        if ( in_array( 'content', $options, true ) ) {
                                $ret['tables'][] = 'content';
-                               $ret['tables'][] = 'content_models';
                                $ret['fields'] = array_merge( $ret['fields'], [
                                        'content_size',
                                        'content_sha1',
                                        'content_address',
-                                       'model_name'
+                                       'content_model',
                                ] );
                                $ret['joins']['content'] = [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ];
-                               $ret['joins']['content_models'] = [ 'INNER JOIN', [ 'content_model = model_id' ] ];
+
+                               if ( in_array( 'model', $options, true ) ) {
+                                       // Use left join to attach model name, so we still find the revision row even
+                                       // if the model name is missing. This triggers a more obvious failure mode.
+                                       $ret['tables'][] = 'content_models';
+                                       $ret['joins']['content_models'] = [ 'LEFT JOIN', [ 'content_model = model_id' ] ];
+                                       $ret['fields'][] = 'model_name';
+                               }
+
                        }
                }
 
index c919b18..ca62e0e 100644 (file)
@@ -1480,6 +1480,22 @@ class Title implements LinkTarget {
                );
        }
 
+       /**
+        * Is this a message which can contain raw HTML?
+        *
+        * @return bool
+        * @since 1.32
+        */
+       public function isRawHtmlMessage() {
+               global $wgRawHtmlMessages;
+
+               if ( !$this->inNamespace( NS_MEDIAWIKI ) ) {
+                       return false;
+               }
+               $message = lcfirst( $this->getRootTitle()->getDBkey() );
+               return in_array( $message, $wgRawHtmlMessages, true );
+       }
+
        /**
         * Is this a talk page of some sort?
         *
@@ -2392,6 +2408,13 @@ class Title implements LinkTarget {
                                $error = [ 'sitejsonprotected', $action ];
                        } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
                                $error = [ 'sitejsprotected', $action ];
+                       } elseif ( $this->isRawHtmlMessage() ) {
+                               // Raw HTML can be used to deploy CSS or JS so require rights for both.
+                               if ( !$user->isAllowed( 'editsitejs' ) ) {
+                                       $error = [ 'sitejsprotected', $action ];
+                               } elseif ( !$user->isAllowed( 'editsitecss' ) ) {
+                                       $error = [ 'sitecssprotected', $action ];
+                               }
                        }
 
                        if ( $error ) {
@@ -2423,25 +2446,34 @@ class Title implements LinkTarget {
                # Protect css/json/js subpages of user pages
                # XXX: this might be better using restrictions
 
-               if ( $action != 'patrol' ) {
-                       if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
-                               if (
-                                       $this->isUserCssConfigPage()
-                                       && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
-                               ) {
-                                       $errors[] = [ 'mycustomcssprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsonConfigPage()
-                                       && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
-                               ) {
-                                       $errors[] = [ 'mycustomjsonprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsConfigPage()
-                                       && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
-                               ) {
-                                       $errors[] = [ 'mycustomjsprotected', $action ];
-                               }
-                       } else {
+               if ( $action === 'patrol' ) {
+                       return [];
+               }
+
+               if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages.
+                       if (
+                               $this->isUserCssConfigPage()
+                               && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
+                       ) {
+                               $errors[] = [ 'mycustomcssprotected', $action ];
+                       } elseif (
+                               $this->isUserJsonConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
+                       ) {
+                               $errors[] = [ 'mycustomjsonprotected', $action ];
+                       } elseif (
+                               $this->isUserJsConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
+                       ) {
+                               $errors[] = [ 'mycustomjsprotected', $action ];
+                       }
+               } else {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages, except for
+                       // deletion/suppression which cannot be used for attacks and we want to avoid the
+                       // situation where an unprivileged user can post abusive content on their subpages
+                       // and only very highly privileged users could remove it.
+                       if ( !in_array( $action, [ 'delete', 'deleterevision', 'suppressrevision' ], true ) ) {
                                if (
                                        $this->isUserCssConfigPage()
                                        && !$user->isAllowed( 'editusercss' )
diff --git a/includes/actions/McrUndoAction.php b/includes/actions/McrUndoAction.php
new file mode 100644 (file)
index 0000000..90d1f68
--- /dev/null
@@ -0,0 +1,376 @@
+<?php
+/**
+ * Temporary action for MCR undos
+ * @file
+ * @ingroup Actions
+ */
+
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\SlotRecord;
+
+/**
+ * Temporary action for MCR undos
+ *
+ * This is intended to go away when real MCR support is added to EditPage and
+ * the standard undo-with-edit behavior can be implemented there instead.
+ *
+ * If this were going to be kept, we'd probably want to figure out a good way
+ * to reuse the same code for generating the headers, summary box, and buttons
+ * on EditPage and here, and to better share the diffing and preview logic
+ * between the two. But doing that now would require much of the rewriting of
+ * EditPage that we're trying to put off by doing this instead.
+ *
+ * @ingroup Actions
+ * @since 1.32
+ * @deprecated since 1.32
+ */
+class McrUndoAction extends FormAction {
+
+       private $undo = 0, $undoafter = 0, $cur = 0;
+
+       /** @param RevisionRecord|null */
+       private $curRev = null;
+
+       public function getName() {
+               return 'mcrundo';
+       }
+
+       public function getDescription() {
+               return '';
+       }
+
+       public function show() {
+               // Send a cookie so anons get talk message notifications
+               // (copied from SubmitAction)
+               MediaWiki\Session\SessionManager::getGlobalSession()->persist();
+
+               // Some stuff copied from EditAction
+               $this->useTransactionalTimeLimit();
+
+               $out = $this->getOutput();
+               $out->setRobotPolicy( 'noindex,nofollow' );
+               if ( $this->getContext()->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+                       $out->addModuleStyles( [
+                               'mediawiki.ui.input',
+                               'mediawiki.ui.checkbox',
+                       ] );
+               }
+
+               // IP warning headers copied from EditPage
+               // (should more be copied?)
+               if ( wfReadOnly() ) {
+                       $out->wrapWikiMsg(
+                               "<div id=\"mw-read-only-warning\">\n$1\n</div>",
+                               [ 'readonlywarning', wfReadOnlyReason() ]
+                       );
+               } elseif ( $this->context->getUser()->isAnon() ) {
+                       if ( !$this->getRequest()->getCheck( 'wpPreview' ) ) {
+                               $out->wrapWikiMsg(
+                                       "<div id='mw-anon-edit-warning' class='warningbox'>\n$1\n</div>",
+                                       [ 'anoneditwarning',
+                                               // Log-in link
+                                               SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( [
+                                                       'returnto' => $this->getTitle()->getPrefixedDBkey()
+                                               ] ),
+                                               // Sign-up link
+                                               SpecialPage::getTitleFor( 'CreateAccount' )->getFullURL( [
+                                                       'returnto' => $this->getTitle()->getPrefixedDBkey()
+                                               ] )
+                                       ]
+                               );
+                       } else {
+                               $out->wrapWikiMsg( "<div id=\"mw-anon-preview-warning\" class=\"warningbox\">\n$1</div>",
+                                       'anonpreviewwarning'
+                               );
+                       }
+               }
+
+               parent::show();
+       }
+
+       protected function checkCanExecute( User $user ) {
+               parent::checkCanExecute( $user );
+
+               $this->undoafter = $this->getRequest()->getInt( 'undoafter' );
+               $this->undo = $this->getRequest()->getInt( 'undo' );
+
+               if ( $this->undo == 0 || $this->undoafter == 0 ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'mcrundo-missingparam' );
+               }
+
+               $curRev = $this->page->getRevision();
+               if ( !$curRev ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'nopagetext' );
+               }
+               $this->curRev = $curRev->getRevisionRecord();
+               $this->cur = $this->getRequest()->getInt( 'cur', $this->curRev->getId() );
+
+               $revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup();
+
+               $undoRev = $revisionLookup->getRevisionById( $this->undo );
+               $oldRev = $revisionLookup->getRevisionById( $this->undoafter );
+
+               if ( $undoRev === null || $oldRev === null ||
+                       $undoRev->isDeleted( RevisionRecord::DELETED_TEXT ) ||
+                       $oldRev->isDeleted( RevisionRecord::DELETED_TEXT )
+               ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'undo-norev' );
+               }
+
+               return true;
+       }
+
+       /**
+        * @return MutableRevisionRecord
+        */
+       private function getNewRevision() {
+               $revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup();
+
+               $undoRev = $revisionLookup->getRevisionById( $this->undo );
+               $oldRev = $revisionLookup->getRevisionById( $this->undoafter );
+               $curRev = $this->curRev;
+
+               $isLatest = $curRev->getId() === $undoRev->getId();
+
+               if ( $undoRev === null || $oldRev === null ||
+                       $undoRev->isDeleted( RevisionRecord::DELETED_TEXT ) ||
+                       $oldRev->isDeleted( RevisionRecord::DELETED_TEXT )
+               ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'undo-norev' );
+               }
+
+               if ( $isLatest ) {
+                       // Short cut! Undoing the current revision means we just restore the old.
+                       return MutableRevisionRecord::newFromParentRevision( $oldRev );
+               }
+
+               $newRev = MutableRevisionRecord::newFromParentRevision( $curRev );
+
+               // Figure out the roles that need merging by first collecting all roles
+               // and then removing the ones that don't.
+               $rolesToMerge = array_unique( array_merge(
+                       $oldRev->getSlotRoles(),
+                       $undoRev->getSlotRoles(),
+                       $curRev->getSlotRoles()
+               ) );
+
+               // Any roles with the same content in $oldRev and $undoRev can be
+               // inherited because undo won't change them.
+               $rolesToMerge = array_intersect(
+                       $rolesToMerge, $oldRev->getSlots()->getRolesWithDifferentContent( $undoRev->getSlots() )
+               );
+               if ( !$rolesToMerge ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'undo-nochange' );
+               }
+
+               // Any roles with the same content in $oldRev and $curRev were already reverted
+               // and so can be inherited.
+               $rolesToMerge = array_intersect(
+                       $rolesToMerge, $oldRev->getSlots()->getRolesWithDifferentContent( $curRev->getSlots() )
+               );
+               if ( !$rolesToMerge ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'undo-nochange' );
+               }
+
+               // Any roles with the same content in $undoRev and $curRev weren't
+               // changed since and so can be reverted to $oldRev.
+               $diffRoles = array_intersect(
+                       $rolesToMerge, $undoRev->getSlots()->getRolesWithDifferentContent( $curRev->getSlots() )
+               );
+               foreach ( array_diff( $rolesToMerge, $diffRoles ) as $role ) {
+                       if ( $oldRev->hasSlot( $role ) ) {
+                               $newRev->inheritSlot( $oldRev->getSlot( $role, RevisionRecord::RAW ) );
+                       } else {
+                               $newRev->removeSlot( $role );
+                       }
+               }
+               $rolesToMerge = $diffRoles;
+
+               // Any slot additions or removals not handled by the above checks can't be undone.
+               // There will be only one of the three revisions missing the slot:
+               //  - !old means it was added in the undone revisions and modified after.
+               //    Should it be removed entirely for the undo, or should the modified version be kept?
+               //  - !undo means it was removed in the undone revisions and then readded with different content.
+               //    Which content is should be kept, the old or the new?
+               //  - !cur means it was changed in the undone revisions and then deleted after.
+               //    Did someone delete vandalized content instead of undoing (meaning we should ideally restore
+               //    it), or should it stay gone?
+               foreach ( $rolesToMerge as $role ) {
+                       if ( !$oldRev->hasSlot( $role ) || !$undoRev->hasSlot( $role ) || !$curRev->hasSlot( $role ) ) {
+                               throw new ErrorPageError( 'mcrundofailed', 'undo-failure' );
+                       }
+               }
+
+               // Try to merge anything that's left.
+               foreach ( $rolesToMerge as $role ) {
+                       $oldContent = $oldRev->getSlot( $role, RevisionRecord::RAW )->getContent();
+                       $undoContent = $undoRev->getSlot( $role, RevisionRecord::RAW )->getContent();
+                       $curContent = $curRev->getSlot( $role, RevisionRecord::RAW )->getContent();
+                       $newContent = $undoContent->getContentHandler()
+                               ->getUndoContent( $curContent, $undoContent, $oldContent, $isLatest );
+                       if ( !$newContent ) {
+                               throw new ErrorPageError( 'mcrundofailed', 'undo-failure' );
+                       }
+                       $newRev->setSlot( SlotRecord::newUnsaved( $role, $newContent ) );
+               }
+
+               return $newRev;
+       }
+
+       private function generateDiff() {
+               $newRev = $this->getNewRevision();
+               if ( $newRev->hasSameContent( $this->curRev ) ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'undo-nochange' );
+               }
+
+               $diffEngine = new DifferenceEngine( $this->context );
+               $diffEngine->setRevisions( $this->curRev, $newRev );
+
+               $oldtitle = $this->context->msg( 'currentrev' )->parse();
+               $newtitle = $this->context->msg( 'yourtext' )->parse();
+
+               if ( $this->getRequest()->getCheck( 'wpPreview' ) ) {
+                       $diffEngine->renderNewRevision();
+                       return '';
+               } else {
+                       $diffText = $diffEngine->getDiff( $oldtitle, $newtitle );
+                       $diffEngine->showDiffStyle();
+                       return '<div id="wikiDiff">' . $diffText . '</div>';
+               }
+       }
+
+       public function onSubmit( $data ) {
+               global $wgUseRCPatrol;
+
+               if ( !$this->getRequest()->getCheck( 'wpSave' ) ) {
+                       // Diff or preview
+                       return false;
+               }
+
+               $updater = $this->page->getPage()->newPageUpdater( $this->context->getUser() );
+               $curRev = $updater->grabParentRevision();
+               if ( !$curRev ) {
+                       throw new ErrorPageError( 'mcrundofailed', 'nopagetext' );
+               }
+
+               if ( $this->cur !== $curRev->getId() ) {
+                       return Status::newFatal( 'mcrundo-changed' );
+               }
+
+               $newRev = $this->getNewRevision();
+               if ( !$newRev->hasSameContent( $curRev ) ) {
+                       // Copy new slots into the PageUpdater, and remove any removed slots.
+                       // TODO: This interface is awful, there should be a way to just pass $newRev.
+                       // TODO: MCR: test this once we can store multiple slots
+                       foreach ( $newRev->getSlots()->getSlots() as $slot ) {
+                               $updater->setSlot( $slot );
+                       }
+                       foreach ( $curRev->getSlotRoles() as $role ) {
+                               if ( !$newRev->hasSlot( $role ) ) {
+                                       $updater->removeSlot( $role );
+                               }
+                       }
+
+                       $updater->setOriginalRevisionId( false );
+                       $updater->setUndidRevisionId( $this->undo );
+
+                       // TODO: Ugh.
+                       if ( $wgUseRCPatrol && $this->getTitle()->userCan( 'autopatrol', $this->getUser() ) ) {
+                               $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
+                       }
+
+                       $updater->saveRevision(
+                               CommentStoreComment::newUnsavedComment( trim( $this->getRequest()->getVal( 'wpSummary' ) ) ),
+                               EDIT_AUTOSUMMARY | EDIT_UPDATE
+                       );
+
+                       return $updater->getStatus();
+               }
+
+               return Status::newGood();
+       }
+
+       protected function usesOOUI() {
+               return true;
+       }
+
+       protected function getFormFields() {
+               $request = $this->getRequest();
+               $config = $this->context->getConfig();
+               $oldCommentSchema = $config->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD;
+               $ret = [
+                       'diff' => [
+                               'type' => 'info',
+                               'vertical-label' => true,
+                               'raw' => true,
+                               'default' => function () {
+                                       return $this->generateDiff();
+                               }
+                       ],
+                       'summary' => [
+                               'type' => 'text',
+                               'id' => 'wpSummary',
+                               'name' => 'wpSummary',
+                               'cssclass' => 'mw-summary',
+                               'label-message' => 'summary',
+                               'maxlength' => $oldCommentSchema ? 200 : CommentStore::COMMENT_CHARACTER_LIMIT,
+                               'value' => $request->getVal( 'wpSummary', '' ),
+                               'size' => 60,
+                               'spellcheck' => 'true',
+                       ],
+                       'summarypreview' => [
+                               'type' => 'info',
+                               'label-message' => 'summary-preview',
+                               'raw' => true,
+                       ],
+               ];
+
+               if ( $request->getCheck( 'wpSummary' ) ) {
+                       $ret['summarypreview']['default'] = Xml::tags( 'div', [ 'class' => 'mw-summary-preview' ],
+                               Linker::commentBlock( trim( $request->getVal( 'wpSummary' ) ), $this->getTitle(), false )
+                       );
+               } else {
+                       unset( $ret['summarypreview'] );
+               }
+
+               return $ret;
+       }
+
+       protected function alterForm( HTMLForm $form ) {
+               $form->setWrapperLegendMsg( 'confirm-mcrundo-title' );
+
+               $labelAsPublish = $this->context->getConfig()->get( 'EditSubmitButtonLabelPublish' );
+
+               $form->setSubmitName( 'wpSave' );
+               $form->setSubmitTooltip( $labelAsPublish ? 'publish' : 'save' );
+               $form->setSubmitTextMsg( $labelAsPublish ? 'publishchanges' : 'savechanges' );
+               $form->showCancel( true );
+               $form->setCancelTarget( $this->getTitle() );
+               $form->addButton( [
+                       'name' => 'wpPreview',
+                       'value' => '1',
+                       'label-message' => 'showpreview',
+                       'attribs' => Linker::tooltipAndAccesskeyAttribs( 'preview' ),
+               ] );
+               $form->addButton( [
+                       'name' => 'wpDiff',
+                       'value' => '1',
+                       'label-message' => 'showdiff',
+                       'attribs' => Linker::tooltipAndAccesskeyAttribs( 'diff' ),
+               ] );
+
+               $form->addHiddenField( 'undo', $this->undo );
+               $form->addHiddenField( 'undoafter', $this->undoafter );
+               $form->addHiddenField( 'cur', $this->curRev->getId() );
+       }
+
+       public function onSuccess() {
+               $this->getOutput()->redirect( $this->getTitle()->getFullURL() );
+       }
+
+       protected function preText() {
+               return '<div style="clear:both"></div>';
+       }
+}
index 93c35d3..6bfa35d 100644 (file)
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\RevisionStore;
+
 class ApiComparePages extends ApiBase {
 
-       private $guessed = false, $guessedTitle, $guessedModel, $props;
+       /** @var RevisionStore */
+       private $revisionStore;
+
+       private $guessedTitle = false, $props;
+
+       public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
+               parent::__construct( $mainModule, $moduleName, $modulePrefix );
+               $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+       }
 
        public function execute() {
                $params = $this->extractRequestParams();
 
                // Parameter validation
-               $this->requireAtLeastOneParameter( $params, 'fromtitle', 'fromid', 'fromrev', 'fromtext' );
-               $this->requireAtLeastOneParameter( $params, 'totitle', 'toid', 'torev', 'totext', 'torelative' );
+               $this->requireAtLeastOneParameter(
+                       $params, 'fromtitle', 'fromid', 'fromrev', 'fromtext', 'fromslots'
+               );
+               $this->requireAtLeastOneParameter(
+                       $params, 'totitle', 'toid', 'torev', 'totext', 'torelative', 'toslots'
+               );
 
                $this->props = array_flip( $params['prop'] );
 
                // Cache responses publicly by default. This may be overridden later.
                $this->getMain()->setCacheMode( 'public' );
 
-               // Get the 'from' Revision and Content
-               list( $fromRev, $fromContent, $relRev ) = $this->getDiffContent( 'from', $params );
+               // Get the 'from' RevisionRecord
+               list( $fromRev, $fromRelRev, $fromValsRev ) = $this->getDiffRevision( 'from', $params );
 
-               // Get the 'to' Revision and Content
+               // Get the 'to' RevisionRecord
                if ( $params['torelative'] !== null ) {
-                       if ( !$relRev ) {
+                       if ( !$fromRelRev ) {
                                $this->dieWithError( 'apierror-compare-relative-to-nothing' );
                        }
                        switch ( $params['torelative'] ) {
                                case 'prev':
                                        // Swap 'from' and 'to'
-                                       $toRev = $fromRev;
-                                       $toContent = $fromContent;
-                                       $fromRev = $relRev->getPrevious();
-                                       $fromContent = $fromRev
-                                               ? $fromRev->getContent( Revision::FOR_THIS_USER, $this->getUser() )
-                                               : $toContent->getContentHandler()->makeEmptyContent();
-                                       if ( !$fromContent ) {
-                                               $this->dieWithError(
-                                                       [ 'apierror-missingcontent-revid', $fromRev->getId() ], 'missingcontent'
-                                               );
-                                       }
+                                       list( $toRev, $toRelRev2, $toValsRev ) = [ $fromRev, $fromRelRev, $fromValsRev ];
+                                       $fromRev = $this->revisionStore->getPreviousRevision( $fromRelRev );
+                                       $fromRelRev = $fromRev;
+                                       $fromValsRev = $fromRev;
                                        break;
 
                                case 'next':
-                                       $toRev = $relRev->getNext();
-                                       $toContent = $toRev
-                                               ? $toRev->getContent( Revision::FOR_THIS_USER, $this->getUser() )
-                                               : $fromContent;
-                                       if ( !$toContent ) {
-                                               $this->dieWithError( [ 'apierror-missingcontent-revid', $toRev->getId() ], 'missingcontent' );
-                                       }
+                                       $toRev = $this->revisionStore->getNextRevision( $fromRelRev );
+                                       $toRelRev = $toRev;
+                                       $toValsRev = $toRev;
                                        break;
 
                                case 'cur':
-                                       $title = $relRev->getTitle();
-                                       $id = $title->getLatestRevID();
-                                       $toRev = $id ? Revision::newFromId( $id ) : null;
+                                       $title = $fromRelRev->getPageAsLinkTarget();
+                                       $toRev = $this->revisionStore->getRevisionByTitle( $title );
                                        if ( !$toRev ) {
+                                               $title = Title::newFromLinkTarget( $title );
                                                $this->dieWithError(
                                                        [ 'apierror-missingrev-title', wfEscapeWikiText( $title->getPrefixedText() ) ], 'nosuchrevid'
                                                );
                                        }
-                                       $toContent = $toRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                                       if ( !$toContent ) {
-                                               $this->dieWithError( [ 'apierror-missingcontent-revid', $toRev->getId() ], 'missingcontent' );
-                                       }
+                                       $toRelRev = $toRev;
+                                       $toValsRev = $toRev;
                                        break;
                        }
-                       $relRev2 = null;
                } else {
-                       list( $toRev, $toContent, $relRev2 ) = $this->getDiffContent( 'to', $params );
+                       list( $toRev, $toRelRev, $toValsRev ) = $this->getDiffRevision( 'to', $params );
                }
 
-               // Should never happen, but just in case...
-               if ( !$fromContent || !$toContent ) {
+               // Handle missing from or to revisions
+               if ( !$fromRev || !$toRev ) {
                        $this->dieWithError( 'apierror-baddiff' );
                }
 
-               // Extract sections, if told to
-               if ( isset( $params['fromsection'] ) ) {
-                       $fromContent = $fromContent->getSection( $params['fromsection'] );
-                       if ( !$fromContent ) {
-                               $this->dieWithError(
-                                       [ 'apierror-compare-nosuchfromsection', wfEscapeWikiText( $params['fromsection'] ) ],
-                                       'nosuchfromsection'
-                               );
-                       }
+               // Handle revdel
+               if ( !$fromRev->audienceCan(
+                       RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_THIS_USER, $this->getUser()
+               ) ) {
+                       $this->dieWithError( [ 'apierror-missingcontent-revid', $fromRev->getId() ], 'missingcontent' );
                }
-               if ( isset( $params['tosection'] ) ) {
-                       $toContent = $toContent->getSection( $params['tosection'] );
-                       if ( !$toContent ) {
-                               $this->dieWithError(
-                                       [ 'apierror-compare-nosuchtosection', wfEscapeWikiText( $params['tosection'] ) ],
-                                       'nosuchtosection'
-                               );
-                       }
+               if ( !$toRev->audienceCan(
+                       RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_THIS_USER, $this->getUser()
+               ) ) {
+                       $this->dieWithError( [ 'apierror-missingcontent-revid', $toRev->getId() ], 'missingcontent' );
                }
 
                // Get the diff
                $context = new DerivativeContext( $this->getContext() );
-               if ( $relRev && $relRev->getTitle() ) {
-                       $context->setTitle( $relRev->getTitle() );
-               } elseif ( $relRev2 && $relRev2->getTitle() ) {
-                       $context->setTitle( $relRev2->getTitle() );
+               if ( $fromRelRev && $fromRelRev->getPageAsLinkTarget() ) {
+                       $context->setTitle( Title::newFromLinkTarget( $fromRelRev->getPageAsLinkTarget() ) );
+               } elseif ( $toRelRev && $toRelRev->getPageAsLinkTarget() ) {
+                       $context->setTitle( Title::newFromLinkTarget( $toRelRev->getPageAsLinkTarget() ) );
                } else {
-                       $this->guessTitleAndModel();
-                       if ( $this->guessedTitle ) {
-                               $context->setTitle( $this->guessedTitle );
+                       $guessedTitle = $this->guessTitle();
+                       if ( $guessedTitle ) {
+                               $context->setTitle( $guessedTitle );
                        }
                }
-               $de = $fromContent->getContentHandler()->createDifferenceEngine(
-                       $context,
-                       $fromRev ? $fromRev->getId() : 0,
-                       $toRev ? $toRev->getId() : 0,
-                       /* $rcid = */ null,
-                       /* $refreshCache = */ false,
-                       /* $unhide = */ true
-               );
-               $de->setContent( $fromContent, $toContent );
-               $difftext = $de->getDiffBody();
-               if ( $difftext === false ) {
-                       $this->dieWithError( 'apierror-baddiff' );
+               $de = new DifferenceEngine( $context );
+               $de->setRevisions( $fromRev, $toRev );
+               if ( $params['slots'] === null ) {
+                       $difftext = $de->getDiffBody();
+                       if ( $difftext === false ) {
+                               $this->dieWithError( 'apierror-baddiff' );
+                       }
+               } else {
+                       $difftext = [];
+                       foreach ( $params['slots'] as $role ) {
+                               $difftext[$role] = $de->getDiffBodyForRole( $role );
+                       }
                }
 
                // Fill in the response
                $vals = [];
-               $this->setVals( $vals, 'from', $fromRev );
-               $this->setVals( $vals, 'to', $toRev );
+               $this->setVals( $vals, 'from', $fromValsRev );
+               $this->setVals( $vals, 'to', $toValsRev );
 
                if ( isset( $this->props['rel'] ) ) {
-                       if ( $fromRev ) {
-                               $rev = $fromRev->getPrevious();
+                       if ( !$fromRev instanceof MutableRevisionRecord ) {
+                               $rev = $this->revisionStore->getPreviousRevision( $fromRev );
                                if ( $rev ) {
                                        $vals['prev'] = $rev->getId();
                                }
                        }
-                       if ( $toRev ) {
-                               $rev = $toRev->getNext();
+                       if ( !$toRev instanceof MutableRevisionRecord ) {
+                               $rev = $this->revisionStore->getNextRevision( $toRev );
                                if ( $rev ) {
                                        $vals['next'] = $rev->getId();
                                }
@@ -161,10 +156,18 @@ class ApiComparePages extends ApiBase {
                }
 
                if ( isset( $this->props['diffsize'] ) ) {
-                       $vals['diffsize'] = strlen( $difftext );
+                       $vals['diffsize'] = 0;
+                       foreach ( (array)$difftext as $text ) {
+                               $vals['diffsize'] += strlen( $text );
+                       }
                }
                if ( isset( $this->props['diff'] ) ) {
-                       ApiResult::setContentValue( $vals, 'body', $difftext );
+                       if ( is_array( $difftext ) ) {
+                               ApiResult::setArrayType( $difftext, 'kvp', 'diff' );
+                               $vals['bodies'] = $difftext;
+                       } else {
+                               ApiResult::setContentValue( $vals, 'body', $difftext );
+                       }
                }
 
                // Diffs can be really big and there's little point in having
@@ -174,49 +177,55 @@ class ApiComparePages extends ApiBase {
        }
 
        /**
-        * Guess an appropriate default Title and content model for this request
+        * Load a revision by ID
         *
-        * Fills in $this->guessedTitle based on the first of 'fromrev',
-        * 'fromtitle', 'fromid', 'torev', 'totitle', and 'toid' that's present and
-        * valid.
+        * Falls back to checking the archive table if appropriate.
+        *
+        * @param int $id
+        * @return RevisionRecord|null
+        */
+       private function getRevisionById( $id ) {
+               $rev = $this->revisionStore->getRevisionById( $id );
+               if ( !$rev && $this->getUser()->isAllowedAny( 'deletedtext', 'undelete' ) ) {
+                       // Try the 'archive' table
+                       $arQuery = $this->revisionStore->getArchiveQueryInfo();
+                       $row = $this->getDB()->selectRow(
+                               $arQuery['tables'],
+                               array_merge(
+                                       $arQuery['fields'],
+                                       [ 'ar_namespace', 'ar_title' ]
+                               ),
+                               [ 'ar_rev_id' => $id ],
+                               __METHOD__,
+                               [],
+                               $arQuery['joins']
+                       );
+                       if ( $row ) {
+                               $rev = $this->revisionStore->newRevisionFromArchiveRow( $row );
+                               $rev->isArchive = true;
+                       }
+               }
+               return $rev;
+       }
+
+       /**
+        * Guess an appropriate default Title for this request
         *
-        * Fills in $this->guessedModel based on the Revision or Title used to
-        * determine $this->guessedTitle, or the 'fromcontentmodel' or
-        * 'tocontentmodel' parameters if no title was guessed.
+        * @return Title|null
         */
-       private function guessTitleAndModel() {
-               if ( $this->guessed ) {
-                       return;
+       private function guessTitle() {
+               if ( $this->guessedTitle !== false ) {
+                       return $this->guessedTitle;
                }
 
-               $this->guessed = true;
+               $this->guessedTitle = null;
                $params = $this->extractRequestParams();
 
                foreach ( [ 'from', 'to' ] as $prefix ) {
                        if ( $params["{$prefix}rev"] !== null ) {
-                               $revId = $params["{$prefix}rev"];
-                               $rev = Revision::newFromId( $revId );
-                               if ( !$rev ) {
-                                       // Titles of deleted revisions aren't secret, per T51088
-                                       $arQuery = Revision::getArchiveQueryInfo();
-                                       $row = $this->getDB()->selectRow(
-                                               $arQuery['tables'],
-                                               array_merge(
-                                                       $arQuery['fields'],
-                                                       [ 'ar_namespace', 'ar_title' ]
-                                               ),
-                                               [ 'ar_rev_id' => $revId ],
-                                               __METHOD__,
-                                               [],
-                                               $arQuery['joins']
-                                       );
-                                       if ( $row ) {
-                                               $rev = Revision::newFromArchiveRow( $row );
-                                       }
-                               }
+                               $rev = $this->getRevisionById( $params["{$prefix}rev"] );
                                if ( $rev ) {
-                                       $this->guessedTitle = $rev->getTitle();
-                                       $this->guessedModel = $rev->getContentModel();
+                                       $this->guessedTitle = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
                                        break;
                                }
                        }
@@ -238,38 +247,84 @@ class ApiComparePages extends ApiBase {
                        }
                }
 
-               if ( !$this->guessedModel ) {
-                       if ( $this->guessedTitle ) {
-                               $this->guessedModel = $this->guessedTitle->getContentModel();
-                       } elseif ( $params['fromcontentmodel'] !== null ) {
-                               $this->guessedModel = $params['fromcontentmodel'];
-                       } elseif ( $params['tocontentmodel'] !== null ) {
-                               $this->guessedModel = $params['tocontentmodel'];
+               return $this->guessedTitle;
+       }
+
+       /**
+        * Guess an appropriate default content model for this request
+        * @param string $role Slot for which to guess the model
+        * @return string|null Guessed content model
+        */
+       private function guessModel( $role ) {
+               $params = $this->extractRequestParams();
+
+               $title = null;
+               foreach ( [ 'from', 'to' ] as $prefix ) {
+                       if ( $params["{$prefix}rev"] !== null ) {
+                               $rev = $this->getRevisionById( $params["{$prefix}rev"] );
+                               if ( $rev ) {
+                                       if ( $rev->hasSlot( $role ) ) {
+                                               return $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
+                                       }
+                               }
+                       }
+               }
+
+               $guessedTitle = $this->guessTitle();
+               if ( $guessedTitle && $role === 'main' ) {
+                       // @todo: Use SlotRoleRegistry and do this for all slots
+                       return $guessedTitle->getContentModel();
+               }
+
+               if ( isset( $params["fromcontentmodel-$role"] ) ) {
+                       return $params["fromcontentmodel-$role"];
+               }
+               if ( isset( $params["tocontentmodel-$role"] ) ) {
+                       return $params["tocontentmodel-$role"];
+               }
+
+               if ( $role === 'main' ) {
+                       if ( isset( $params['fromcontentmodel'] ) ) {
+                               return $params['fromcontentmodel'];
+                       }
+                       if ( isset( $params['tocontentmodel'] ) ) {
+                               return $params['tocontentmodel'];
                        }
                }
+
+               return null;
        }
 
        /**
-        * Get the Revision and Content for one side of the diff
+        * Get the RevisionRecord for one side of the diff
         *
-        * This uses the appropriate set of 'rev', 'id', 'title', 'text', 'pst',
-        * 'contentmodel', and 'contentformat' parameters to determine what content
+        * This uses the appropriate set of parameters to determine what content
         * should be diffed.
         *
         * Returns three values:
-        * - The revision used to retrieve the content, if any
-        * - The content to be diffed
-        * - The revision specified, if any, even if not used to retrieve the
-        *   Content
+        * - A RevisionRecord holding the content
+        * - The revision specified, if any, even if content was supplied
+        * - The revision to pass to setVals(), if any
         *
         * @param string $prefix 'from' or 'to'
         * @param array $params
-        * @return array [ Revision|null, Content, Revision|null ]
+        * @return array [ RevisionRecord|null, RevisionRecord|null, RevisionRecord|null ]
         */
-       private function getDiffContent( $prefix, array $params ) {
+       private function getDiffRevision( $prefix, array $params ) {
+               // Back compat params
+               $this->requireMaxOneParameter( $params, "{$prefix}text", "{$prefix}slots" );
+               $this->requireMaxOneParameter( $params, "{$prefix}section", "{$prefix}slots" );
+               if ( $params["{$prefix}text"] !== null ) {
+                       $params["{$prefix}slots"] = [ 'main' ];
+                       $params["{$prefix}text-main"] = $params["{$prefix}text"];
+                       $params["{$prefix}section-main"] = null;
+                       $params["{$prefix}contentmodel-main"] = $params["{$prefix}contentmodel"];
+                       $params["{$prefix}contentformat-main"] = $params["{$prefix}contentformat"];
+               }
+
                $title = null;
                $rev = null;
-               $suppliedContent = $params["{$prefix}text"] !== null;
+               $suppliedContent = $params["{$prefix}slots"] !== null;
 
                // Get the revision and title, if applicable
                $revId = null;
@@ -308,94 +363,146 @@ class ApiComparePages extends ApiBase {
                        }
                }
                if ( $revId !== null ) {
-                       $rev = Revision::newFromId( $revId );
-                       if ( !$rev && $this->getUser()->isAllowedAny( 'deletedtext', 'undelete' ) ) {
-                               // Try the 'archive' table
-                               $arQuery = Revision::getArchiveQueryInfo();
-                               $row = $this->getDB()->selectRow(
-                                       $arQuery['tables'],
-                                       array_merge(
-                                               $arQuery['fields'],
-                                               [ 'ar_namespace', 'ar_title' ]
-                                       ),
-                                       [ 'ar_rev_id' => $revId ],
-                                       __METHOD__,
-                                       [],
-                                       $arQuery['joins']
-                               );
-                               if ( $row ) {
-                                       $rev = Revision::newFromArchiveRow( $row );
-                                       $rev->isArchive = true;
-                               }
-                       }
+                       $rev = $this->getRevisionById( $revId );
                        if ( !$rev ) {
                                $this->dieWithError( [ 'apierror-nosuchrevid', $revId ] );
                        }
-                       $title = $rev->getTitle();
+                       $title = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
 
                        // If we don't have supplied content, return here. Otherwise,
                        // continue on below with the supplied content.
                        if ( !$suppliedContent ) {
-                               $content = $rev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                               if ( !$content ) {
-                                       $this->dieWithError( [ 'apierror-missingcontent-revid', $revId ], 'missingcontent' );
+                               $newRev = $rev;
+
+                               // Deprecated 'fromsection'/'tosection'
+                               if ( isset( $params["{$prefix}section"] ) ) {
+                                       $section = $params["{$prefix}section"];
+                                       $newRev = MutableRevisionRecord::newFromParentRevision( $rev );
+                                       $content = $rev->getContent( 'main', RevisionRecord::FOR_THIS_USER, $this->getUser() );
+                                       if ( !$content ) {
+                                               $this->dieWithError(
+                                                       [ 'apierror-missingcontent-revid-role', $rev->getId(), 'main' ], 'missingcontent'
+                                               );
+                                       }
+                                       $content = $content ? $content->getSection( $section ) : null;
+                                       if ( !$content ) {
+                                               $this->dieWithError(
+                                                       [ "apierror-compare-nosuch{$prefix}section", wfEscapeWikiText( $section ) ],
+                                                       "nosuch{$prefix}section"
+                                               );
+                                       }
+                                       $newRev->setContent( 'main', $content );
                                }
-                               return [ $rev, $content, $rev ];
+
+                               return [ $newRev, $rev, $rev ];
                        }
                }
 
                // Override $content based on supplied text
-               $model = $params["{$prefix}contentmodel"];
-               $format = $params["{$prefix}contentformat"];
-
-               if ( !$model && $rev ) {
-                       $model = $rev->getContentModel();
-               }
-               if ( !$model && $title ) {
-                       $model = $title->getContentModel();
-               }
-               if ( !$model ) {
-                       $this->guessTitleAndModel();
-                       $model = $this->guessedModel;
-               }
-               if ( !$model ) {
-                       $model = CONTENT_MODEL_WIKITEXT;
-                       $this->addWarning( [ 'apiwarn-compare-nocontentmodel', $model ] );
-               }
-
                if ( !$title ) {
-                       $this->guessTitleAndModel();
-                       $title = $this->guessedTitle;
+                       $title = $this->guessTitle();
                }
-
-               try {
-                       $content = ContentHandler::makeContent( $params["{$prefix}text"], $title, $model, $format );
-               } catch ( MWContentSerializationException $ex ) {
-                       $this->dieWithException( $ex, [
-                               'wrap' => ApiMessage::create( 'apierror-contentserializationexception', 'parseerror' )
+               if ( $rev ) {
+                       $newRev = MutableRevisionRecord::newFromParentRevision( $rev );
+               } else {
+                       $newRev = $this->revisionStore->newMutableRevisionFromArray( [
+                               'title' => $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __METHOD__ )
                        ] );
                }
+               foreach ( $params["{$prefix}slots"] as $role ) {
+                       $text = $params["{$prefix}text-{$role}"];
+                       if ( $text === null ) {
+                               $newRev->removeSlot( $role );
+                               continue;
+                       }
+
+                       $model = $params["{$prefix}contentmodel-{$role}"];
+                       $format = $params["{$prefix}contentformat-{$role}"];
 
-               if ( $params["{$prefix}pst"] ) {
-                       if ( !$title ) {
-                               $this->dieWithError( 'apierror-compare-no-title' );
+                       if ( !$model && $rev && $rev->hasSlot( $role ) ) {
+                               $model = $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
+                       }
+                       if ( !$model && $title && $role === 'main' ) {
+                               // @todo: Use SlotRoleRegistry and do this for all slots
+                               $model = $title->getContentModel();
+                       }
+                       if ( !$model ) {
+                               $model = $this->guessModel( $role );
+                       }
+                       if ( !$model ) {
+                               $model = CONTENT_MODEL_WIKITEXT;
+                               $this->addWarning( [ 'apiwarn-compare-nocontentmodel', $model ] );
+                       }
+
+                       try {
+                               $content = ContentHandler::makeContent( $text, $title, $model, $format );
+                       } catch ( MWContentSerializationException $ex ) {
+                               $this->dieWithException( $ex, [
+                                       'wrap' => ApiMessage::create( 'apierror-contentserializationexception', 'parseerror' )
+                               ] );
+                       }
+
+                       if ( $params["{$prefix}pst"] ) {
+                               if ( !$title ) {
+                                       $this->dieWithError( 'apierror-compare-no-title' );
+                               }
+                               $popts = ParserOptions::newFromContext( $this->getContext() );
+                               $content = $content->preSaveTransform( $title, $this->getUser(), $popts );
+                       }
+
+                       $section = $params["{$prefix}section-{$role}"];
+                       if ( $section !== null && $section !== '' ) {
+                               if ( !$rev ) {
+                                       $this->dieWithError( "apierror-compare-no{$prefix}revision" );
+                               }
+                               $oldContent = $rev->getContent( $role, RevisionRecord::FOR_THIS_USER, $this->getUser() );
+                               if ( !$oldContent ) {
+                                       $this->dieWithError(
+                                               [ 'apierror-missingcontent-revid-role', $rev->getId(), wfEscapeWikiText( $role ) ],
+                                               'missingcontent'
+                                       );
+                               }
+                               if ( !$oldContent->getContentHandler()->supportsSections() ) {
+                                       $this->dieWithError( [ 'apierror-sectionsnotsupported', $content->getModel() ] );
+                               }
+                               try {
+                                       $content = $oldContent->replaceSection( $section, $content, '' );
+                               } catch ( Exception $ex ) {
+                                       // Probably a content model mismatch.
+                                       $content = null;
+                               }
+                               if ( !$content ) {
+                                       $this->dieWithError( [ 'apierror-sectionreplacefailed' ] );
+                               }
+                       }
+
+                       // Deprecated 'fromsection'/'tosection'
+                       if ( $role === 'main' && isset( $params["{$prefix}section"] ) ) {
+                               $section = $params["{$prefix}section"];
+                               $content = $content->getSection( $section );
+                               if ( !$content ) {
+                                       $this->dieWithError(
+                                               [ "apierror-compare-nosuch{$prefix}section", wfEscapeWikiText( $section ) ],
+                                               "nosuch{$prefix}section"
+                                       );
+                               }
                        }
-                       $popts = ParserOptions::newFromContext( $this->getContext() );
-                       $content = $content->preSaveTransform( $title, $this->getUser(), $popts );
-               }
 
-               return [ null, $content, $rev ];
+                       $newRev->setContent( $role, $content );
+               }
+               return [ $newRev, $rev, null ];
        }
 
        /**
-        * Set value fields from a Revision object
+        * Set value fields from a RevisionRecord object
+        *
         * @param array &$vals Result array to set data into
         * @param string $prefix 'from' or 'to'
-        * @param Revision|null $rev
+        * @param RevisionRecord|null $rev
         */
        private function setVals( &$vals, $prefix, $rev ) {
                if ( $rev ) {
-                       $title = $rev->getTitle();
+                       $title = $rev->getPageAsLinkTarget();
                        if ( isset( $this->props['ids'] ) ) {
                                $vals["{$prefix}id"] = $title->getArticleID();
                                $vals["{$prefix}revid"] = $rev->getId();
@@ -408,41 +515,42 @@ class ApiComparePages extends ApiBase {
                        }
 
                        $anyHidden = false;
-                       if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+                       if ( $rev->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
                                $vals["{$prefix}texthidden"] = true;
                                $anyHidden = true;
                        }
 
-                       if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
+                       if ( $rev->isDeleted( RevisionRecord::DELETED_USER ) ) {
                                $vals["{$prefix}userhidden"] = true;
                                $anyHidden = true;
                        }
-                       if ( isset( $this->props['user'] ) &&
-                               $rev->userCan( Revision::DELETED_USER, $this->getUser() )
-                       ) {
-                               $vals["{$prefix}user"] = $rev->getUserText( Revision::RAW );
-                               $vals["{$prefix}userid"] = $rev->getUser( Revision::RAW );
+                       if ( isset( $this->props['user'] ) ) {
+                               $user = $rev->getUser( RevisionRecord::FOR_THIS_USER, $this->getUser() );
+                               if ( $user ) {
+                                       $vals["{$prefix}user"] = $user->getName();
+                                       $vals["{$prefix}userid"] = $user->getId();
+                               }
                        }
 
-                       if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
+                       if ( $rev->isDeleted( RevisionRecord::DELETED_COMMENT ) ) {
                                $vals["{$prefix}commenthidden"] = true;
                                $anyHidden = true;
                        }
-                       if ( $rev->userCan( Revision::DELETED_COMMENT, $this->getUser() ) ) {
-                               if ( isset( $this->props['comment'] ) ) {
-                                       $vals["{$prefix}comment"] = $rev->getComment( Revision::RAW );
-                               }
-                               if ( isset( $this->props['parsedcomment'] ) ) {
+                       if ( isset( $this->props['comment'] ) || isset( $this->props['parsedcomment'] ) ) {
+                               $comment = $rev->getComment( RevisionRecord::FOR_THIS_USER, $this->getUser() );
+                               if ( $comment !== null ) {
+                                       if ( isset( $this->props['comment'] ) ) {
+                                               $vals["{$prefix}comment"] = $comment->text;
+                                       }
                                        $vals["{$prefix}parsedcomment"] = Linker::formatComment(
-                                               $rev->getComment( Revision::RAW ),
-                                               $rev->getTitle()
+                                               $comment->text, Title::newFromLinkTarget( $title )
                                        );
                                }
                        }
 
                        if ( $anyHidden ) {
                                $this->getMain()->setCacheMode( 'private' );
-                               if ( $rev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
+                               if ( $rev->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
                                        $vals["{$prefix}suppressed"] = true;
                                }
                        }
@@ -455,6 +563,12 @@ class ApiComparePages extends ApiBase {
        }
 
        public function getAllowedParams() {
+               $slotRoles = MediaWikiServices::getInstance()->getSlotRoleStore()->getMap();
+               if ( !in_array( 'main', $slotRoles, true ) ) {
+                       $slotRoles[] = 'main';
+               }
+               sort( $slotRoles, SORT_STRING );
+
                // Parameters for the 'from' and 'to' content
                $fromToParams = [
                        'title' => null,
@@ -464,24 +578,58 @@ class ApiComparePages extends ApiBase {
                        'rev' => [
                                ApiBase::PARAM_TYPE => 'integer'
                        ],
-                       'text' => [
-                               ApiBase::PARAM_TYPE => 'text'
+
+                       'slots' => [
+                               ApiBase::PARAM_TYPE => $slotRoles,
+                               ApiBase::PARAM_ISMULTI => true,
+                       ],
+                       'text-{slot}' => [
+                               ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
+                               ApiBase::PARAM_TYPE => 'text',
+                       ],
+                       'section-{slot}' => [
+                               ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
+                               ApiBase::PARAM_TYPE => 'string',
+                       ],
+                       'contentformat-{slot}' => [
+                               ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
+                               ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
+                       ],
+                       'contentmodel-{slot}' => [
+                               ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
+                               ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
                        ],
-                       'section' => null,
                        'pst' => false,
+
+                       'text' => [
+                               ApiBase::PARAM_TYPE => 'text',
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ],
                        'contentformat' => [
                                ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
+                               ApiBase::PARAM_DEPRECATED => true,
                        ],
                        'contentmodel' => [
                                ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
-                       ]
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ],
+                       'section' => [
+                               ApiBase::PARAM_DFLT => null,
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ],
                ];
 
                $ret = [];
                foreach ( $fromToParams as $k => $v ) {
+                       if ( isset( $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] ) ) {
+                               $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] = 'fromslots';
+                       }
                        $ret["from$k"] = $v;
                }
                foreach ( $fromToParams as $k => $v ) {
+                       if ( isset( $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] ) ) {
+                               $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] = 'toslots';
+                       }
                        $ret["to$k"] = $v;
                }
 
@@ -508,6 +656,12 @@ class ApiComparePages extends ApiBase {
                        ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
                ];
 
+               $ret['slots'] = [
+                       ApiBase::PARAM_TYPE => $slotRoles,
+                       ApiBase::PARAM_ISMULTI => true,
+                       ApiBase::PARAM_ALL => true,
+               ];
+
                return $ret;
        }
 
index 03d2952..3b305f9 100644 (file)
@@ -534,7 +534,11 @@ class ApiMain extends ApiBase {
                        MediaWikiServices::getInstance()->getStatsdDataFactory()->timing(
                                'api.' . $this->mModule->getModuleName() . '.executeTiming', 1000 * $runTime
                        );
-               } catch ( Exception $e ) {
+               } catch ( Exception $e ) { // @todo Remove this block when HHVM is no longer supported
+                       $this->handleException( $e );
+                       $this->logRequest( microtime( true ) - $t, $e );
+                       $isError = true;
+               } catch ( Throwable $e ) {
                        $this->handleException( $e );
                        $this->logRequest( microtime( true ) - $t, $e );
                        $isError = true;
@@ -558,9 +562,9 @@ class ApiMain extends ApiBase {
         * Handle an exception as an API response
         *
         * @since 1.23
-        * @param Exception $e
+        * @param Exception|Throwable $e
         */
-       protected function handleException( Exception $e ) {
+       protected function handleException( $e ) {
                // T65145: Rollback any open database transactions
                if ( !( $e instanceof ApiUsageException || $e instanceof UsageException ) ) {
                        // UsageExceptions are intentional, so don't rollback if that's the case
@@ -600,7 +604,10 @@ class ApiMain extends ApiBase {
                        foreach ( $ex->getStatusValue()->getErrors() as $error ) {
                                try {
                                        $this->mPrinter->addWarning( $error );
-                               } catch ( Exception $ex2 ) {
+                               } catch ( Exception $ex2 ) { // @todo Remove this block when HHVM is no longer supported
+                                       // WTF?
+                                       $this->addWarning( $error );
+                               } catch ( Throwable $ex2 ) {
                                        // WTF?
                                        $this->addWarning( $error );
                                }
@@ -631,17 +638,20 @@ class ApiMain extends ApiBase {
         * friendly to clients. If it fails, it will rethrow the exception.
         *
         * @since 1.23
-        * @param Exception $e
-        * @throws Exception
+        * @param Exception|Throwable $e
+        * @throws Exception|Throwable
         */
-       public static function handleApiBeforeMainException( Exception $e ) {
+       public static function handleApiBeforeMainException( $e ) {
                ob_start();
 
                try {
                        $main = new self( RequestContext::getMain(), false );
                        $main->handleException( $e );
                        $main->logRequest( 0, $e );
-               } catch ( Exception $e2 ) {
+               } catch ( Exception $e2 ) { // @todo Remove this block when HHVM is no longer supported
+                       // Nope, even that didn't work. Punt.
+                       throw $e;
+               } catch ( Throwable $e2 ) {
                        // Nope, even that didn't work. Punt.
                        throw $e;
                }
@@ -1009,7 +1019,7 @@ class ApiMain extends ApiBase {
         * text around the exception's (presumably English) message as a single
         * error (no warnings).
         *
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @param string $type 'error' or 'warning'
         * @return ApiMessage[]
         * @since 1.27
@@ -1054,7 +1064,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Replace the result data with the information about an exception.
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @return string[] Error codes
         */
        protected function substituteResultWithError( $e ) {
@@ -1609,7 +1619,7 @@ class ApiMain extends ApiBase {
        /**
         * Log the preceding request
         * @param float $time Time in seconds
-        * @param Exception|null $e Exception caught while processing the request
+        * @param Exception|Throwable|null $e Exception caught while processing the request
         */
        protected function logRequest( $time, $e = null ) {
                $request = $this->getRequest();
index 3a60471..5c25b5a 100644 (file)
@@ -341,7 +341,7 @@ class ApiParse extends ApiBase {
                        $result_array['text'] = $p_result->getText( [
                                'allowTOC' => !$params['disabletoc'],
                                'enableSectionEditLinks' => !$params['disableeditsection'],
-                               'unwrap' => $params['wrapoutputclass'] === '',
+                               'wrapperDivClass' => $params['wrapoutputclass'],
                                'deduplicateStyles' => !$params['disablestylededuplication'],
                        ] );
                        $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
index c3af71b..48d6f30 100644 (file)
@@ -289,7 +289,7 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
        protected function getExamplesMessages() {
                return [
                        'action=query&prop=deletedrevisions&titles=Main%20Page|Talk:Main%20Page&' .
-                               'drvprop=user|comment|content'
+                               'drvslots=*&drvprop=user|comment|content'
                                => 'apihelp-query+deletedrevisions-example-titles',
                        'action=query&prop=deletedrevisions&revids=123456'
                                => 'apihelp-query+deletedrevisions-example-revids',
index 5e7b864..8c26024 100644 (file)
@@ -486,7 +486,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
        protected function getExamplesMessages() {
                return [
                        'action=query&prop=revisions&titles=API|Main%20Page&' .
-                               'rvprop=timestamp|user|comment|content'
+                               'rvslots=*&rvprop=timestamp|user|comment|content'
                                => 'apihelp-query+revisions-example-content',
                        'action=query&prop=revisions&titles=Main%20Page&rvlimit=5&' .
                                'rvprop=timestamp|user|comment'
index fc6eddf..70942f8 100644 (file)
@@ -156,7 +156,7 @@ trait SearchApi {
                        $searchEngine = MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
                        $limit = $params['limit'];
                        $searchEngine->setNamespaces( $params['namespace'] );
-                       $offset = isset( $params['offset'] ) ? $params['offset'] : null;
+                       $offset = $params['offset'] ?? null;
                        $searchEngine->setLimitOffset( $limit, $offset );
 
                        // Initialize requested search profiles.
index 241e71a..a1740a9 100644 (file)
        "apihelp-compare-param-fromtitle": "العنوان الأول للمقارنة.",
        "apihelp-compare-param-fromid": "رقم الصفحة الأول للمقارنة.",
        "apihelp-compare-param-fromrev": "أول مراجعة للمقارنة.",
-       "apihelp-compare-param-fromtext": "استخدم هذا النص بدلا من محتوى المراجعة المحدد بواسطة <var>fromtitle</var>، <var>fromid</var> أو <var>fromrev</var>.",
-       "apihelp-compare-param-fromsection": "استخدم فقط القسم المحدد في المحتوى 'من' المحدد.",
        "apihelp-compare-param-frompst": "قم بإجراء تحويل ما قبل الحفظ على <var>fromtext</var>.",
+       "apihelp-compare-param-fromtext": "استخدم هذا النص بدلا من محتوى المراجعة المحدد بواسطة <var>fromtitle</var>، <var>fromid</var> أو <var>fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "نموذج محتوى <var>fromtext</var>، إذا لم يتم توفيره، فسيتم تخمينه استنادا إلى الوسائط الأخرى.",
        "apihelp-compare-param-fromcontentformat": "تنسيق محتوى تسلسل <var>fromtext</var>.",
+       "apihelp-compare-param-fromsection": "استخدم فقط القسم المحدد في المحتوى 'من' المحدد.",
        "apihelp-compare-param-totitle": "العنوان الثاني للمقارنة.",
        "apihelp-compare-param-toid": "رقم الصفحة الثاني للمقارنة.",
        "apihelp-compare-param-torev": "المراجعة الثانية للمقارنة.",
        "apihelp-compare-param-torelative": "استخدم مراجعة متعلقة بالمراجعة المحددة من <var>fromtitle</var> أو <var>fromid</var> أو <var>fromrev</var>، سيتم تجاهل جميع خيارات 'إلى' الأخرى.",
-       "apihelp-compare-param-totext": "استخدم هذا النص بدلا من محتوى المراجعة المحدد بواسطة <var>totitle</var> أو <var>toid</var> أو <var>torev</var>.",
-       "apihelp-compare-param-tosection": "استخدم فقط القسم المحدد في المحتوى 'إلى' المحدد.",
        "apihelp-compare-param-topst": "قم بإجراء تحويل ما قبل الحفظ على <var>totext</var>.",
+       "apihelp-compare-param-totext": "استخدم هذا النص بدلا من محتوى المراجعة المحدد بواسطة <var>totitle</var> أو <var>toid</var> أو <var>torev</var>.",
        "apihelp-compare-param-tocontentmodel": "نموذج محتوى <var>totext</var>، إذا لم يتم توفيره، فسيتم تخمينه استنادا إلى الوسائط الأخرى.",
        "apihelp-compare-param-tocontentformat": "تنسيق محتوى تسلسل <var>totext</var>.",
+       "apihelp-compare-param-tosection": "استخدم فقط القسم المحدد في المحتوى 'إلى' المحدد.",
        "apihelp-compare-param-prop": "أية قطعة من المعلومات للحصول عليها.",
        "apihelp-compare-paramvalue-prop-diff": "HTML الفرق.",
        "apihelp-compare-paramvalue-prop-diffsize": "حجم HTML الفرق، بالبايت.",
index 5bdc3c9..c3b75c3 100644 (file)
        "apihelp-query+protectedtitles-paramvalue-prop-level": "Ergänzt den Schutzstatus.",
        "apihelp-query+protectedtitles-example-simple": "Listet geschützte Titel auf.",
        "apihelp-query+querypage-param-limit": "Anzahl der zurückzugebenden Ergebnisse.",
+       "apihelp-query+random-summary": "Ruft einen Satz an zufälligen Seiten ab.",
        "apihelp-query+recentchanges-summary": "Listet die letzten Änderungen auf.",
        "apihelp-query+recentchanges-param-user": "Listet nur Änderungen von diesem Benutzer auf.",
        "apihelp-query+recentchanges-param-excludeuser": "Listet keine Änderungen von diesem Benutzer auf.",
        "apierror-badparameter": "Ungültiger Wert für den Parameter <var>$1</var>.",
        "apierror-badquery": "Ungültige Abfrage.",
        "apierror-cannot-async-upload-file": "Die Parameter <var>async</var> und <var>file</var> können nicht kombiniert werden. Falls du eine asynchrone Verarbeitung deiner hochgeladenen Datei wünschst, lade sie zuerst mithilfe des Parameters <var>stash</var> auf den Speicher hoch. Veröffentliche anschließend die gespeicherte Datei asynchron mithilfe <var>filekey</var> und <var>async</var>.",
+       "apierror-compare-nofromrevision": "Keine Version „from“. <var>fromrev</var>, <var>fromtitle</var> oder <var>fromid</var> angeben.",
+       "apierror-compare-notorevision": "Keine Version „to“. <var>torev</var>, <var>totitle</var> oder <var>toid</var> angeben.",
        "apierror-emptypage": "Das Erstellen neuer leerer Seiten ist nicht erlaubt.",
        "apierror-filedoesnotexist": "Die Datei ist nicht vorhanden.",
        "apierror-import-unknownerror": "Unbekannter Fehler beim Importieren: $1.",
        "apierror-invaliduserid": "Die Benutzerkennung <var>$1</var> ist nicht gültig.",
        "apierror-maxbytes": "Der Parameter <var>$1</var> kann nicht länger sein als {{PLURAL:$2|ein Byte|$2 Bytes}}",
        "apierror-maxchars": "Der Parameter <var>$1</var> kann nicht länger sein als {{PLURAL:$2|ein|$2}} Zeichen",
+       "apierror-missingcontent-revid-role": "Fehlender Inhalt für die Versionskennung $1 für die Rolle $2.",
        "apierror-nosuchsection": "Es gibt keinen Abschnitt $1.",
        "apierror-nosuchuserid": "Es gibt keinen Benutzer mit der Kennung $1.",
        "apierror-offline": "Aufgrund von Problemen bei der Netzwerkverbindung kannst du nicht weitermachen. Stelle sicher, dass du eine funktionierende Internetverbindung hast und versuche es erneut.",
index 3c74f25..ae2ffd3 100644 (file)
        "apihelp-compare-param-fromtitle": "First title to compare.",
        "apihelp-compare-param-fromid": "First page ID to compare.",
        "apihelp-compare-param-fromrev": "First revision to compare.",
-       "apihelp-compare-param-fromtext": "Use this text instead of the content of the revision specified by <var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var>.",
+       "apihelp-compare-param-frompst": "Do a pre-save transform on <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromslots": "Override content of the revision specified by <var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var>.\n\nThis parameter specifies the slots that are to be modified. Use <var>fromtext-&#x7B;slot}</var>, <var>fromcontentmodel-&#x7B;slot}</var>, and <var>fromcontentformat-&#x7B;slot}</var> to specify content for each slot.",
+       "apihelp-compare-param-fromtext-{slot}": "Text of the specified slot. If omitted, the slot is removed from the revision.",
+       "apihelp-compare-param-fromsection-{slot}": "When <var>fromtext-&#x7B;slot}</var> is the content of a single section, this is the section number. It will be merged into the revision specified by <var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var> as if for a section edit.",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "Content model of <var>fromtext-&#x7B;slot}</var>. If not supplied, it will be guessed based on the other parameters.",
+       "apihelp-compare-param-fromcontentformat-{slot}": "Content serialization format of <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromtext": "Specify <kbd>fromslots=main</kbd> and use <var>fromtext-main</var> instead.",
+       "apihelp-compare-param-fromcontentmodel": "Specify <kbd>fromslots=main</kbd> and use <var>fromcontentmodel-main</var> instead.",
+       "apihelp-compare-param-fromcontentformat": "Specify <kbd>fromslots=main</kbd> and use <var>fromcontentformat-main</var> instead.",
        "apihelp-compare-param-fromsection": "Only use the specified section of the specified 'from' content.",
-       "apihelp-compare-param-frompst": "Do a pre-save transform on <var>fromtext</var>.",
-       "apihelp-compare-param-fromcontentmodel": "Content model of <var>fromtext</var>. If not supplied, it will be guessed based on the other parameters.",
-       "apihelp-compare-param-fromcontentformat": "Content serialization format of <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "Second title to compare.",
        "apihelp-compare-param-toid": "Second page ID to compare.",
        "apihelp-compare-param-torev": "Second revision to compare.",
        "apihelp-compare-param-torelative": "Use a revision relative to the revision determined from <var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var>. All of the other 'to' options will be ignored.",
-       "apihelp-compare-param-totext": "Use this text instead of the content of the revision specified by <var>totitle</var>, <var>toid</var> or <var>torev</var>.",
-       "apihelp-compare-param-tosection": "Only use the specified section of the specified 'to' content.",
        "apihelp-compare-param-topst": "Do a pre-save transform on <var>totext</var>.",
-       "apihelp-compare-param-tocontentmodel": "Content model of <var>totext</var>. If not supplied, it will be guessed based on the other parameters.",
-       "apihelp-compare-param-tocontentformat": "Content serialization format of <var>totext</var>.",
+       "apihelp-compare-param-toslots": "Override content of the revision specified by <var>totitle</var>, <var>toid</var> or <var>torev</var>.\n\nThis parameter specifies the slots that are to be modified. Use <var>totext-&#x7B;slot}</var>, <var>tocontentmodel-&#x7B;slot}</var>, and <var>tocontentformat-&#x7B;slot}</var> to specify content for each slot.",
+       "apihelp-compare-param-totext-{slot}": "Text of the specified slot. If omitted, the slot is removed from the revision.",
+       "apihelp-compare-param-tosection-{slot}": "When <var>totext-&#x7B;slot}</var> is the content of a single section, this is the section number. It will be merged into the revision specified by <var>totitle</var>, <var>toid</var> or <var>torev</var> as if for a section edit.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "Content model of <var>totext-&#x7B;slot}</var>. If not supplied, it will be guessed based on the other parameters.",
+       "apihelp-compare-param-tocontentformat-{slot}": "Content serialization format of <var>totext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-totext": "Specify <kbd>toslots=main</kbd> and use <var>totext-main</var> instead.",
+       "apihelp-compare-param-tocontentmodel": "Specify <kbd>toslots=main</kbd> and use <var>tocontentmodel-main</var> instead.",
+       "apihelp-compare-param-tocontentformat": "Specify <kbd>toslots=main</kbd> and use <var>tocontentformat-main</var> instead.",
+       "apihelp-compare-param-tosection": "Only use the specified section of the specified 'to' content.",
        "apihelp-compare-param-prop": "Which pieces of information to get.",
        "apihelp-compare-paramvalue-prop-diff": "The diff HTML.",
        "apihelp-compare-paramvalue-prop-diffsize": "The size of the diff HTML, in bytes.",
@@ -88,6 +98,7 @@
        "apihelp-compare-paramvalue-prop-comment": "The comment on the 'from' and 'to' revisions.",
        "apihelp-compare-paramvalue-prop-parsedcomment": "The parsed comment on the 'from' and 'to' revisions.",
        "apihelp-compare-paramvalue-prop-size": "The size of the 'from' and 'to' revisions.",
+       "apihelp-compare-param-slots": "Return individual diffs for these slots, rather than one combined diff for all slots.",
        "apihelp-compare-example-1": "Create a diff between revision 1 and 2.",
 
        "apihelp-createaccount-summary": "Create a new user account.",
        "apierror-compare-no-title": "Cannot pre-save transform without a title. Try specifying <var>fromtitle</var> or <var>totitle</var>.",
        "apierror-compare-nosuchfromsection": "There is no section $1 in the 'from' content.",
        "apierror-compare-nosuchtosection": "There is no section $1 in the 'to' content.",
+       "apierror-compare-nofromrevision": "No 'from' revision. Specify <var>fromrev</var>, <var>fromtitle</var>, or <var>fromid</var>.",
+       "apierror-compare-notorevision": "No 'to' revision. Specify <var>torev</var>, <var>totitle</var>, or <var>toid</var>.",
        "apierror-compare-relative-to-nothing": "No 'from' revision for <var>torelative</var> to be relative to.",
        "apierror-contentserializationexception": "Content serialization failed: $1",
        "apierror-contenttoobig": "The content you supplied exceeds the article size limit of $1 {{PLURAL:$1|kilobyte|kilobytes}}.",
        "apierror-mimesearchdisabled": "MIME search is disabled in Miser Mode.",
        "apierror-missingcontent-pageid": "Missing content for page ID $1.",
        "apierror-missingcontent-revid": "Missing content for revision ID $1.",
+       "apierror-missingcontent-revid-role": "Missing content for revision ID $1 for role $2.",
        "apierror-missingparam-at-least-one-of": "{{PLURAL:$2|The parameter|At least one of the parameters}} $1 is required.",
        "apierror-missingparam-one-of": "{{PLURAL:$2|The parameter|One of the parameters}} $1 is required.",
        "apierror-missingparam": "The <var>$1</var> parameter must be set.",
index a62b2ba..2862da7 100644 (file)
        "apihelp-compare-param-fromtitle": "Premier titre à comparer.",
        "apihelp-compare-param-fromid": "ID de la première page à comparer.",
        "apihelp-compare-param-fromrev": "Première révision à comparer.",
-       "apihelp-compare-param-fromtext": "Utiliser ce texte au lieu du contenu de la révision spécifié par <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.",
+       "apihelp-compare-param-frompst": "Faire une transformation avant enregistrement sur <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromslots": "Substituer le contenu de la révision spécifiée par <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.\n\nCe paramètre spécifie les intervalles à modifier. Utilisez <var>fromtext-&#x7B;slot}</var>, <var>fromcontentmodel-&#x7B;slot}</var>, et <var>fromcontentformat-&#x7B;slot}</var> pour spécifier le contenu de chaque intervalle.",
+       "apihelp-compare-param-fromtext-{slot}": "Texte de l'intervalle spécifié. Si absent, l'intervalle est supprimé de la révision.",
+       "apihelp-compare-param-fromsection-{slot}": "Si <var>fromtext-&#x7B;slot}</var> est le contenu d'une seule section, c'est le numéro de la section. Il sera fusionné dans la révision spécifiée par <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var> comme pour les modifications de section.",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "Modèle de contenu de <var>fromtext-&#x7B;slot}</var>. Si non fourni, il sera déduit en fonction de la valeur des autres paramètres.",
+       "apihelp-compare-param-fromcontentformat-{slot}": "Format de sérialisation de contenu de <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromtext": "Spécifiez <kbd>fromslots=main</kbd> et utilisez <var>fromtext-main</var> à la place.",
+       "apihelp-compare-param-fromcontentmodel": "Spécifiez <kbd>fromslots=main</kbd> et utilisez <var>fromcontentmodel-main</var> à la place.",
+       "apihelp-compare-param-fromcontentformat": "Spécifiez <kbd>fromslots=main</kbd> et utilisez <var>fromcontentformat-main</var> à la place.",
        "apihelp-compare-param-fromsection": "N'utiliser que la section spécifiée du contenu 'from'.",
-       "apihelp-compare-param-frompst": "Faire une transformation avant enregistrement sur <var>fromtext</var>.",
-       "apihelp-compare-param-fromcontentmodel": "Modèle de contenu de <var>fromtext</var>. Si non fourni, il sera déduit d’après les autres paramètres.",
-       "apihelp-compare-param-fromcontentformat": "Sérialisation du contenu de <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "Second titre à comparer.",
        "apihelp-compare-param-toid": "ID de la seconde page à comparer.",
        "apihelp-compare-param-torev": "Seconde révision à comparer.",
        "apihelp-compare-param-torelative": "Utiliser une révision relative à la révision déterminée de <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>. Toutes les autres options 'to' seront ignorées.",
-       "apihelp-compare-param-totext": "Utiliser ce texte au lieu du contenu de la révision spécifié par <var>totitle</var>, <var>toid</var> ou <var>torev</var>.",
-       "apihelp-compare-param-tosection": "N'utiliser que la section spécifiée du contenu 'to'.",
        "apihelp-compare-param-topst": "Faire une transformation avant enregistrement sur <var>totext</var>.",
-       "apihelp-compare-param-tocontentmodel": "Modèle de contenu de <var>totext</var>. Si non fourni, il sera deviné d’après les autres paramètres.",
-       "apihelp-compare-param-tocontentformat": "Format de sérialisation du contenu de <var>totext</var>.",
+       "apihelp-compare-param-toslots": "Substitue le contenu de la révision spécifiée par <var>totitle</var>, <var>toid</var> ou <var>torev</var>.\n\nCe paramètre spécifie les intervalles qui vont être modifiés. Utilisez <var>totext-&#x7B;slot}</var>, <var>tocontentmodel-&#x7B;slot}</var>, et <var>tocontentformat-&#x7B;slot}</var> pour spécifier le contenue de chaque intervalle.",
+       "apihelp-compare-param-totext-{slot}": "Texte de la relation spécifiée. Si absent, le lien est supprimé de la révision.",
+       "apihelp-compare-param-tosection-{slot}": "Si <var>totext-&#x7B;slot}</var> est le contenu d'une seule section, c'est le numéro de la section. Il sera fusionné dans la révision spécifiée par <var>totitle</var>, <var>toid</var> ou <var>torev</var> comme pour les modifications de section.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "Modèle de contenu de <var>totext-&#x7B;slot}</var>. Si non fourni, il sera déduit en fonction de la valeur des autres paramètres.",
+       "apihelp-compare-param-tocontentformat-{slot}": "Format de sérialisation du contenu de <var>totext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-totext": "Spécifiez <kbd>toslots=main</kbd> et utilisez <var>totext-main</var> à la place.",
+       "apihelp-compare-param-tocontentmodel": "Spécifiez <kbd>toslots=main</kbd> et utilisez <var>tocontentmodel-main</var> à la place.",
+       "apihelp-compare-param-tocontentformat": "Spécifiez <kbd>toslots=main</kbd> et utilisez <var>tocontentformat-main</var> à la place.",
+       "apihelp-compare-param-tosection": "N'utiliser que la section spécifiée du contenu 'to'.",
        "apihelp-compare-param-prop": "Quelles informations obtenir.",
        "apihelp-compare-paramvalue-prop-diff": "Le diff HTML.",
        "apihelp-compare-paramvalue-prop-diffsize": "La taille du diff HTML en octets.",
        "apihelp-compare-paramvalue-prop-comment": "Le commentaire des révisions 'depuis' et 'vers'.",
        "apihelp-compare-paramvalue-prop-parsedcomment": "Le commentaire analysé des révisions 'depuis' et 'vers'.",
        "apihelp-compare-paramvalue-prop-size": "La taille des révisions 'depuis' et 'vers'.",
+       "apihelp-compare-param-slots": "Retourne les diffs individuels pour ces intervalles, plutôt qu'un diff combiné pour tous les intervalles.",
        "apihelp-compare-example-1": "Créer une différence entre les révisions 1 et 2",
        "apihelp-createaccount-summary": "Créer un nouveau compte utilisateur.",
        "apihelp-createaccount-param-preservestate": "Si <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> a retourné true pour <samp>hasprimarypreservedstate</samp>, les demandes marquées comme <samp>primary-required</samp> doivent être omises. Si elle a retourné une valeur non vide pour <samp>preservedusername</samp>, ce nom d'utilisateur doit être utilisé pour le paramètre <var>username</var>.",
        "apierror-compare-no-title": "Impossible de faire une transformation avant enregistrement sans titre. Essayez de spécifier <var>fromtitle</var> ou <var>totitle</var>.",
        "apierror-compare-nosuchfromsection": "Il n'y a pas de section $1 dans le contenu 'from'.",
        "apierror-compare-nosuchtosection": "Il n'y a pas de section $1 dans le contenu 'to'.",
+       "apierror-compare-nofromrevision": "Aucune révision 'from'. Spécifiez <var>fromrev</var>, <var>fromtitle</var>, ou <var>fromid</var>.",
+       "apierror-compare-notorevision": "Aucune révision 'to'. Spécifiez <var>torev</var>, <var>totitle</var>, ou <var>toid</var>.",
        "apierror-compare-relative-to-nothing": "Pas de révision 'depuis' pour <var>torelative</var> à laquelle se rapporter.",
        "apierror-contentserializationexception": "Échec de sérialisation du contenu : $1",
        "apierror-contenttoobig": "Le contenu que vous avez fourni dépasse la limite de taille d’un article, qui est de $1 {{PLURAL:$1|kilooctet|kilooctets}}.",
        "apierror-mimesearchdisabled": "La recherche MIME est désactivée en mode Misère.",
        "apierror-missingcontent-pageid": "Contenu manquant pour la page d’ID $1.",
        "apierror-missingcontent-revid": "Contenu de la révision d’ID $1 manquant.",
+       "apierror-missingcontent-revid-role": "Contenu absent pour l'ID de révision $1 pour le rôle $2.",
        "apierror-missingparam-at-least-one-of": "{{PLURAL:$2|Le paramètre|Au moins un des paramètres}} $1 est obligatoire.",
        "apierror-missingparam-one-of": "{{PLURAL:$2|Le paramètre|Un des paramètres}} $1 est obligatoire.",
        "apierror-missingparam": "Le paramètre <var>$1</var> doit être défini.",
index cb018dc..4bfb522 100644 (file)
        "apihelp-compare-param-fromtitle": "כותרת ראשונה להשוואה.",
        "apihelp-compare-param-fromid": "מס׳ זיהוי של הדף הראשון להשוואה.",
        "apihelp-compare-param-fromrev": "גרסה ראשונה להשוואה.",
-       "apihelp-compare-param-fromtext": "להשתמש בטקסט הזה במקום תוכן הגרסה שהוגדרה על־ידי <var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>.",
-       "apihelp-compare-param-fromsection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'from'.",
        "apihelp-compare-param-frompst": "לעשות התמרה לפני שמירה ב־<var>fromtext</var>.",
+       "apihelp-compare-param-fromtext": "להשתמש בטקסט הזה במקום תוכן הגרסה שהוגדרה על־ידי <var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "מודל התוכן של <var>fromtext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
        "apihelp-compare-param-fromcontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
+       "apihelp-compare-param-fromsection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'from'.",
        "apihelp-compare-param-totitle": "כותרת שנייה להשוואה.",
        "apihelp-compare-param-toid": "מס׳ מזהה של הדף השני להשוואה.",
        "apihelp-compare-param-torev": "גרסה שנייה להשוואה.",
        "apihelp-compare-param-torelative": "להשתמש בגרסה יחסית לגרסה שהוסקה מ<var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>. לכל אפשריות ה־\"to\" האחרות לא תהיה השפעה.",
-       "apihelp-compare-param-totext": "להשתמש בטקסט הזה במקום התוכן של הגרסה שהוגדר ב־<var dir=\"ltr\">totitle</var>, <var dir=\"ltr\">toid</var> or <var dir=\"ltr\">torev</var>.",
-       "apihelp-compare-param-tosection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'to'.",
        "apihelp-compare-param-topst": "לעשות התמרה לפני שמירה ב־<var>totext</var>.",
+       "apihelp-compare-param-totext": "להשתמש בטקסט הזה במקום התוכן של הגרסה שהוגדר ב־<var dir=\"ltr\">totitle</var>, <var dir=\"ltr\">toid</var> or <var dir=\"ltr\">torev</var>.",
        "apihelp-compare-param-tocontentmodel": "מודל התוכן של <var>totext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
        "apihelp-compare-param-tocontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
+       "apihelp-compare-param-tosection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'to'.",
        "apihelp-compare-param-prop": "אילו פריטי מידע לקבל.",
        "apihelp-compare-paramvalue-prop-diff": "ה־HTML של ההשוואה.",
        "apihelp-compare-paramvalue-prop-diffsize": "גודל ה־HTML של ההשוואה, בבתים.",
index 4451f19..1211693 100644 (file)
@@ -10,7 +10,7 @@
                        "Dj"
                ]
        },
-       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentáció]]\n* [[mw:Special:MyLanguage/API:FAQ|GYIK]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Levelezőlista]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-bejelentések]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Hibabejelentések és kérések]\n</div>\n<strong>Státusz:</strong> Minden ezen a lapon látható funkciónak működnie kell, de az API jelenleg is aktív fejlesztés alatt áll, és bármikor változhat. Iratkozz fel a [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce levelezőlistára] a frissítések követéséhez.\n\n<strong>Hibás kérések:</strong> Ha az API hibás kérést kap, egy HTTP-fejlécet küld vissza „MediaWiki-API-Error” kulccsal, és a fejléc értéke és a visszaküldött hibakód ugyanarra az értékre lesz állítva. További információért lásd: [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Hibák és figyelmeztetések]].\n\n<p class=\"mw-apisandbox-link\"><strong>Tesztelés:</strong> Az API-kérések könnyebb teszteléséhez használható az [[Special:ApiSandbox|API-homokozó]].</p>",
+       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentáció]]\n* [[mw:Special:MyLanguage/API:FAQ|GYIK]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Levelezőlista]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-bejelentések]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Hibabejelentések és kérések]\n</div>\n<strong>Állapot:</strong> A MediaWiki API egy érett és stabil interfész, ami aktív támogatásban és fejlesztésben részesül. Bár próbáljuk elkerülni, de néha szükség van visszafelé nem kompatibilis változtatásokra; iratkozz fel a [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce levelezőlistára] a frissítések követéséhez.\n\n<strong>Hibás kérések:</strong> Ha az API hibás kérést kap, egy HTTP-fejlécet küld vissza „MediaWiki-API-Error” kulccsal, és a fejléc értéke és a visszaküldött hibakód ugyanarra az értékre lesz állítva. További információért lásd: [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Hibák és figyelmeztetések]].\n\n<p class=\"mw-apisandbox-link\"><strong>Tesztelés:</strong> Az API-kérések könnyebb teszteléséhez használható az [[Special:ApiSandbox|API-homokozó]].</p>",
        "apihelp-main-param-action": "Milyen műveletet hajtson végre.",
        "apihelp-main-param-format": "A kimenet formátuma.",
        "apihelp-main-param-smaxage": "Az <code>s-maxage</code> gyorsítótár-vezérlő HTTP-fejléc beállítása ennyi másodpercre. A hibák soha nincsenek gyorsítótárazva.",
index 399fc1f..0d2d2d1 100644 (file)
@@ -13,7 +13,8 @@
                        "Kkairri",
                        "ネイ",
                        "Omotecho",
-                       "Yusuke1109"
+                       "Yusuke1109",
+                       "Suyama"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|説明文書]]\n* [[mw:Special:MyLanguage/API:FAQ|よくある質問]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api メーリングリスト]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API 告知]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R バグの報告とリクエスト]\n</div>\n<strong>状態:</strong> MediaWiki APIは、積極的にサポートされ、改善された成熟した安定したインターフェースです。避けようとはしていますが、時には壊れた変更が加えられるかもしれません。アップデートの通知を受け取るには、[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce メーリングリスト]に参加してください。\n\n<strong>誤ったリクエスト:</strong> 誤ったリクエストが API に送られた場合、\"MediaWiki-API-Error\" HTTP ヘッダーが送信され、そのヘッダーの値と送り返されるエラーコードは同じ値にセットされます。より詳しい情報は [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Errors and warnings]] を参照してください。\n\n<p class=\"mw-apisandbox-link\"><strong>テスト:</strong> API のリクエストのテストは、[[Special:ApiSandbox]]で簡単に行えます。</p>",
        "apihelp-compare-param-fromtitle": "比較する1つ目のページ名。",
        "apihelp-compare-param-fromid": "比較する1つ目のページID。",
        "apihelp-compare-param-fromrev": "比較する1つ目の版。",
-       "apihelp-compare-param-fromtext": "<var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var> で指定された版の内容の代わりに、このテキストを使用します。",
-       "apihelp-compare-param-fromsection": "'from' の内容のうち指定された節のみを使用します。",
        "apihelp-compare-param-frompst": "<var>fromtext</var>に保存前変換を行います。",
+       "apihelp-compare-param-fromtext": "<var>fromtitle</var>, <var>fromid</var> or <var>fromrev</var> で指定された版の内容の代わりに、このテキストを使用します。",
        "apihelp-compare-param-fromcontentmodel": "<var>fromtext</var>のコンテンツモデル。指定されていない場合は、他のパラメータに基づいて推測されます。",
+       "apihelp-compare-param-fromsection": "'from' の内容のうち指定された節のみを使用します。",
        "apihelp-compare-param-totitle": "比較する2つ目のページ名。",
        "apihelp-compare-param-toid": "比較する2つ目のページID。",
        "apihelp-compare-param-torev": "比較する2つ目の版。",
-       "apihelp-compare-param-tosection": "'to' の内容のうち指定された節のみを使用します。",
        "apihelp-compare-param-topst": "<var>totext</var>に保存前変換を行います。",
        "apihelp-compare-param-tocontentmodel": "<var>totext</var> のコンテンツモデル。指定されていない場合は、他のパラメータに基づいて推測されます。",
+       "apihelp-compare-param-tosection": "'to' の内容のうち指定された節のみを使用します。",
        "apihelp-compare-param-prop": "どの情報を取得するか:",
        "apihelp-compare-paramvalue-prop-diff": "差分HTML。",
        "apihelp-compare-paramvalue-prop-diffsize": "差分HTMLのサイズ (バイト数)。",
        "api-help-permissions": "{{PLURAL:$1|権限}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|権限を持つグループ}}: $2",
        "api-help-open-in-apisandbox": "<small>[サンドボックスで開く]</small>",
+       "apierror-botsnotsupported": "この API インターフェースはボットをサポートしていません。",
        "apierror-filedoesnotexist": "ファイルが存在しません。",
        "apierror-invaliduser": "無効なユーザー名「$1」。",
        "apierror-missingparam": "パラメーター <var>$1</var> を設定してください。",
index e37bbbc..5280644 100644 (file)
        "apihelp-compare-param-fromtitle": "비교할 첫 이름.",
        "apihelp-compare-param-fromid": "비교할 첫 문서 ID.",
        "apihelp-compare-param-fromrev": "비교할 첫 판.",
-       "apihelp-compare-param-fromtext": "<var>fromtitle</var>, <var>fromid</var> 또는 <var>fromrev</var>로 지정된 판의 내용 대신 이 텍스트를 사용합니다.",
+       "apihelp-compare-param-frompst": "<var>fromtext-&#x7B;slot}</var>에 사전 저장 변환을 수행합니다.",
+       "apihelp-compare-param-fromtext-{slot}": "지정된 슬롯의 텍스트입니다. 생략할 경우 판에서 슬롯이 제거됩니다.",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "<var>fromtext-&#x7B;slot}</var>의 콘텐츠 모델입니다. 지정하지 않으면 다른 변수를 참고하여 추정합니다.",
+       "apihelp-compare-param-fromcontentformat-{slot}": "<var>fromtext-&#x7B;slot}</var>의 콘텐츠 직렬화 포맷입니다.",
+       "apihelp-compare-param-fromtext": "<kbd>fromslots=main</kbd>을 지정하고 <var>fromtext-main</var>을 대신 사용합니다.",
+       "apihelp-compare-param-fromcontentmodel": "<kbd>fromslots=main</kbd>을 지정하고 <var>fromcontentmodel-main</var>을 대신 사용합니다.",
+       "apihelp-compare-param-fromcontentformat": "<kbd>fromslots=main</kbd>을 지정하고 <var>fromcontentformat-main</var>을 대신 사용합니다.",
        "apihelp-compare-param-fromsection": "지정된 'from' 내용의 지정된 문단만 사용합니다.",
-       "apihelp-compare-param-frompst": "<var>fromtext</var>에 사전 저장 변환을 수행합니다.",
-       "apihelp-compare-param-fromcontentmodel": "<var>fromtext</var>의 콘텐츠 모델입니다. 지정하지 않으면 다른 변수를 참고하여 추정합니다.",
-       "apihelp-compare-param-fromcontentformat": "<var>fromtext</var>의 콘텐츠 직렬화 포맷입니다.",
        "apihelp-compare-param-totitle": "비교할 두 번째 제목.",
        "apihelp-compare-param-toid": "비교할 두 번째 문서 ID.",
        "apihelp-compare-param-torev": "비교할 두 번째 판.",
        "apihelp-compare-param-torelative": "<var>fromtitle</var>, <var>fromid</var> 또는 <var>fromrev</var>에서 결정된 판과 상대적인 판을 사용합니다. 다른 'to' 옵션들은 모두 무시됩니다.",
-       "apihelp-compare-param-totext": "<var>totitle</var>, <var>toid</var> 또는 <var>torev</var>로 지정된 판의 내용 대신 이 텍스트를 사용합니다.",
-       "apihelp-compare-param-tosection": "지정된 'to' 내용의 지정된 문단만 사용합니다.",
        "apihelp-compare-param-topst": "<var>totext</var>에 사전 저장 변환을 수행합니다.",
-       "apihelp-compare-param-tocontentmodel": "<var>totext</var>의 콘텐츠 모델입니다. 지정하지 않으면 다른 변수를 참고하여 추정합니다.",
-       "apihelp-compare-param-tocontentformat": "<var>totext</var>의 콘텐츠 직렬화 포맷입니다.",
+       "apihelp-compare-param-totext-{slot}": "지정된 슬롯의 텍스트입니다. 생략하면 이 슬롯은 판에서 제거됩니다.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "<var>totext-&#x7B;slot}</var>의 콘텐츠 모델입니다. 지정하지 않으면 다른 변수를 참고하여 추정합니다.",
+       "apihelp-compare-param-tocontentformat-{slot}": "<var>totext-&#x7B;slot}</var>의 콘텐츠 직렬화 포맷입니다.",
+       "apihelp-compare-param-totext": "<kbd>toslots=main</kbd>을 지정하고 <var>totext-main</var>을 대신 사용합니다.",
+       "apihelp-compare-param-tocontentmodel": "<kbd>toslots=main</kbd>을 지정하고 <var>tocontentmodel-main</var>을 대신 사용합니다.",
+       "apihelp-compare-param-tocontentformat": "<kbd>toslots=main</kbd>을 지정하고 <var>tocontentformat-main</var>을 대신 사용합니다.",
+       "apihelp-compare-param-tosection": "지정된 'to' 내용의 지정된 문단만 사용합니다.",
        "apihelp-compare-param-prop": "가져올 정보입니다.",
        "apihelp-compare-paramvalue-prop-diff": "HTML의 차이입니다.",
        "apihelp-compare-paramvalue-prop-diffsize": "HTML 차이의 크기(바이트 단위)입니다.",
        "apierror-maxlag-generic": "데이터베이스 서버 대기 중: $1 {{PLURAL:$1|초}} 지연되었습니다.",
        "apierror-maxlag": "$2 대기 중: $1 {{PLURAL:$1|초}} 지연되었습니다.",
        "apierror-missingcontent-revid": "ID $1 판에 해당하는 내용이 없습니다.",
+       "apierror-missingcontent-revid-role": "역할 $2에 대해 판 ID $1의 내용이 없습니다.",
        "apierror-missingparam": "<var>$1</var> 변수는 설정해야 합니다.",
        "apierror-missingtitle": "지정한 페이지가 존재하지 않습니다.",
        "apierror-missingtitle-byname": "$1 문서가 존재하지 않습니다.",
index be6e798..8edddda 100644 (file)
        "apihelp-compare-param-fromtitle": "Første tittel å sammenligne.",
        "apihelp-compare-param-fromid": "Første side-ID å sammenligne.",
        "apihelp-compare-param-fromrev": "Første revisjon å sammenligne.",
-       "apihelp-compare-param-fromtext": "Bruk denne teksten i stedet for innholdet i revisjonen som angis med <var>fromtitle</var>, <var>fromid</var> eller <var>fromrev</var>.",
        "apihelp-compare-param-frompst": "Gjør en transformering av <var>fromtext</var> før lagring.",
+       "apihelp-compare-param-fromtext": "Bruk denne teksten i stedet for innholdet i revisjonen som angis med <var>fromtitle</var>, <var>fromid</var> eller <var>fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "Innholdsmodell for <var>fromtext</var>. Om den ikke angis vil den gjettes basert på de andre parameterne.",
        "apihelp-compare-param-fromcontentformat": "Innholdsserialiseringsformat for <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "Andre tittel å sammenligne.",
        "apihelp-compare-param-toid": "Andre side-ID å sammenligne.",
        "apihelp-compare-param-torev": "Andre revisjon å sammenligne.",
        "apihelp-compare-param-torelative": "Bruk en revisjon som er relativ til revisjonen som hentes fra <var>fromtitle</var>, <var>fromid</var> eller <var>fromrev</var>. Alle de andre «to»-alternativene vil ignoreres.",
-       "apihelp-compare-param-totext": "Bruk denne teksten i stedet for innholdet i revisjonen spesifisert av <var>totitle</var>, <var>toid</var> eller <var>torev</var>.",
        "apihelp-compare-param-topst": "Gjør en transformering av <var>totext</var> før lagring.",
+       "apihelp-compare-param-totext": "Bruk denne teksten i stedet for innholdet i revisjonen spesifisert av <var>totitle</var>, <var>toid</var> eller <var>torev</var>.",
        "apihelp-compare-param-tocontentmodel": "Innholdsmodellen til <var>totext</var>. Om denne ikke angis vil den bli gjettet ut fra andre parametere.",
        "apihelp-compare-param-tocontentformat": "Innholdsserialiseringsformat for <var>totext</var>.",
        "apihelp-compare-param-prop": "Hvilke informasjonsdeler som skal hentes.",
index 1ded789..a0429ac 100644 (file)
@@ -53,7 +53,7 @@
        "apihelp-checktoken-example-simple": "Sprawdź poprawność tokenu <kbd>csrf</kbd>.",
        "apihelp-clearhasmsg-summary": "Czyści flagę <code>hasmsg</code> dla bieżącego użytkownika.",
        "apihelp-clearhasmsg-example-1": "Wyczyść flagę <code>hasmsg</code> dla bieżącego użytkownika.",
-       "apihelp-compare-summary": "Zauważ różnicę między dwoma stronami",
+       "apihelp-compare-summary": "Pokaż porównanie dwóch stron.",
        "apihelp-compare-param-fromtitle": "Pierwszy tytuł do porównania.",
        "apihelp-compare-param-fromid": "ID pierwszej strony do porównania.",
        "apihelp-compare-param-fromrev": "Pierwsza wersja do porównania.",
index 7378ac4..2b23fee 100644 (file)
        "apihelp-compare-param-fromtitle": "Primeiro título para comparar.",
        "apihelp-compare-param-fromid": "Primeiro ID de página para comparar.",
        "apihelp-compare-param-fromrev": "Primeira revisão para comparar.",
-       "apihelp-compare-param-fromtext": "Use este texto em vez do conteúdo da revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.",
+       "apihelp-compare-param-frompst": "Fazer uma transformação anterior à gravação, de <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromslots": "Substituir o conteúdo da revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.\n\nEste parâmetro especifica os segmentos que deverão ser modificados. Use <var>fromtext-&#x7B;slot}</var>, <var>fromcontentmodel-&#x7B;slot}</var> e <var>fromcontentformat-&#x7B;slot}</var> para especificar conteúdo para cada segmento.",
+       "apihelp-compare-param-fromtext-{slot}": "Texto do slot especificado. Se omitido, o slot é removido da revisão.",
+       "apihelp-compare-param-fromsection-{slot}": "Quando <var>fromtext-&#x7B;slot}</var> é o conteúdo de uma única secção, este é o número da seção. Será fundido na revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var> tal como acontece na edição de uma secção.",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "Modelo de conteúdo de <var>fromtext-&#x7B;slot}</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
+       "apihelp-compare-param-fromcontentformat-{slot}": "Formato de serialização de conteúdo de <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromtext": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromtext-main</var>.",
+       "apihelp-compare-param-fromcontentmodel": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromcontentmodel-main</var>.",
+       "apihelp-compare-param-fromcontentformat": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromcontentformat-main</var>.",
        "apihelp-compare-param-fromsection": "Utilizar apenas a secção especificada do conteúdo 'from' especificado.",
-       "apihelp-compare-param-frompst": "Faz uma transformação pré-salvar em <var>fromtext</var>.",
-       "apihelp-compare-param-fromcontentmodel": "Modelo de conteúdo de <var>fromtext</var>. Se não for fornecido, será adivinhado com base nos outros parâmetros.",
-       "apihelp-compare-param-fromcontentformat": "Formato de serialização de conteúdo de <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "Segundo título para comparar.",
        "apihelp-compare-param-toid": "Segundo ID de página para comparar.",
        "apihelp-compare-param-torev": "Segunda revisão para comparar.",
        "apihelp-compare-param-torelative": "Use uma revisão relativa à revisão determinada de <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>. Todas as outras opções 'to' serão ignoradas.",
-       "apihelp-compare-param-totext": "Use este texto em vez do conteúdo da revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var>.",
-       "apihelp-compare-param-tosection": "Utilizar apenas a secção especificada do conteúdo 'to' especificado.",
        "apihelp-compare-param-topst": "Faz uma transformação pré-salvar em <var>totext</var>.",
-       "apihelp-compare-param-tocontentmodel": "Modelo de conteúdo de <var>totext</var>. Se não for fornecido, será adivinhado com base nos outros parâmetros.",
-       "apihelp-compare-param-tocontentformat": "Formato de serialização de conteúdo de <var>totext</var>.",
+       "apihelp-compare-param-toslots": "Substituir o conteúdo da revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var>.\n\nEste parâmetro especifica os slots que devem ser modificados. Usar <var>totext-&#x7B;slot}</var>, <var>tocontentmodel-&#x7B;slot}</var>, e <var>tocontentformat-&#x7B;slot}</var> para especificar o conteúdo de cada slot.",
+       "apihelp-compare-param-totext-{slot}": "Texto do slot especificado. Se omitido, o slot é removido da revisão.",
+       "apihelp-compare-param-tosection-{slot}": "Quando <var>totext-&#x7B;slot}</var> é o conteúdo de uma única secção, este é o número da secção. Será fundido na revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var> tal como acontece na edição de uma secção.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "Modelo de conteúdo de <var>totext-&#x7B;slot}</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
+       "apihelp-compare-param-tocontentformat-{slot}": "Formato de seriação do conteúdo de <var>totext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-totext": "Especificar <kbd>toslots=main</kbd> e usar <var>totext-main</var>.",
+       "apihelp-compare-param-tocontentmodel": "Especificar <kbd>toslots=main</kbd> e usar <var>tocontentmodel-main</var>.",
+       "apihelp-compare-param-tocontentformat": "Especificar <kbd>toslots=main</kbd> e usar <var>tocontentformat-main</var>.",
+       "apihelp-compare-param-tosection": "Utilizar apenas a secção especificada do conteúdo 'to' especificado.",
        "apihelp-compare-param-prop": "Quais peças de informação incluir.",
        "apihelp-compare-paramvalue-prop-diff": "O dif do HTML.",
        "apihelp-compare-paramvalue-prop-diffsize": "O tamanho do diff HTML, em bytes.",
        "apihelp-compare-paramvalue-prop-comment": "O comentário das revisões 'from' e 'to'.",
        "apihelp-compare-paramvalue-prop-parsedcomment": "O comentário analisado sobre as revisões 'from' e 'to'.",
        "apihelp-compare-paramvalue-prop-size": "O tamanho das revisões 'from' e 'to'.",
+       "apihelp-compare-param-slots": "Devolve os diffs individuais para estes slots, em vez de um diff combinado para todos os slots.",
        "apihelp-compare-example-1": "Criar um diff entre a revisão 1 e 2.",
        "apihelp-createaccount-summary": "Criar uma nova conta de usuário.",
        "apihelp-createaccount-param-preservestate": "Se <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> retornar true para <samp>hasprimarypreservedstate</samp>, pedidos marcados como <samp>hasprimarypreservedstate</samp> devem ser omitidos. Se retornou um valor não vazio para <samp>preservedusername</samp>, esse nome de usuário deve ser usado pelo parâmetro <var>username</var>.",
        "apierror-compare-no-title": "Não é possível pré-salvar a transformação sem um título. Tente especificar <var>fromtitle</var> ou <var>totitle</var>.",
        "apierror-compare-nosuchfromsection": "Não há nenhuma secção $1 no conteúdo 'from'.",
        "apierror-compare-nosuchtosection": "Não há nenhuma seção $1 no conteúdo 'to'.",
+       "apierror-compare-nofromrevision": "Não foi especificada uma revisão 'from'. Especificar <var>fromrev</var>, <var>fromtitle</var> ou <var>fromid</var>.",
+       "apierror-compare-notorevision": "Não foi especificada uma revisão 'to'. Especificar <var>torev</var>, <var>totitle</var> ou <var>toid</var>.",
        "apierror-compare-relative-to-nothing": "Nenhuma revisão 'from' para <var>torelative</var> para ser relativa à.",
        "apierror-contentserializationexception": "Falha na serialização de conteúdo: $1",
        "apierror-contenttoobig": "O conteúdo fornecido excede o limite de tamanho do artigo de $1 {{PLURAL: $1|kilobyte|kilobytes}}.",
        "apierror-mimesearchdisabled": "A pesquisa MIME está desativada no Miser Mode.",
        "apierror-missingcontent-pageid": "Falta conteúdo para a ID da página $1.",
        "apierror-missingcontent-revid": "Falta conteúdo para a ID de revisão $1.",
+       "apierror-missingcontent-revid-role": "Conteúdo ausente para o ID de revisão $1 para a função $2.",
        "apierror-missingparam-at-least-one-of": "{{PLURAL:$2|O parâmetro|Ao menos um dos parâmetros}} $1 é necessário.",
        "apierror-missingparam-one-of": "{{PLURAL:$2|O parâmetro|Um dos parâmetros}} $1 é necessário.",
        "apierror-missingparam": "O parâmetro <var>$1</var> precisa ser definido.",
index 0733a2a..5197dc0 100644 (file)
        "apihelp-compare-param-fromtitle": "Primeiro título a comparar.",
        "apihelp-compare-param-fromid": "Primeiro identificador de página a comparar.",
        "apihelp-compare-param-fromrev": "Primeira revisão a comparar.",
-       "apihelp-compare-param-fromtext": "Usar este texto em vez do conteúdo da revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.",
+       "apihelp-compare-param-frompst": "Fazer uma transformação anterior à gravação, de <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromslots": "Substituir o conteúdo da revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>.\n\nEste parâmetro especifica os segmentos que deverão ser modificados. Use <var>fromtext-&#x7B;slot}</var>, <var>fromcontentmodel-&#x7B;slot}</var> e <var>fromcontentformat-&#x7B;slot}</var> para especificar conteúdo para cada segmento.",
+       "apihelp-compare-param-fromtext-{slot}": "Texto do segmento especificado. Se for omitido, o segmento é removido da revisão.",
+       "apihelp-compare-param-fromsection-{slot}": "Quando <var>fromtext-&#x7B;slot}</var> é o conteúdo de uma única secção, este é o número da secção. Será fundido na revisão especificada por <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var> tal como acontece na edição de uma secção.",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "Modelo de conteúdo de <var>fromtext-&#x7B;slot}</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
+       "apihelp-compare-param-fromcontentformat-{slot}": "Formato de seriação do conteúdo de <var>fromtext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-fromtext": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromtext-main</var>.",
+       "apihelp-compare-param-fromcontentmodel": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromcontentmodel-main</var>.",
+       "apihelp-compare-param-fromcontentformat": "Especificar <kbd>fromslots=main</kbd> e usar <var>fromcontentformat-main</var>.",
        "apihelp-compare-param-fromsection": "Utilizar apenas a secção especificada do conteúdo 'from' especificado.",
-       "apihelp-compare-param-frompst": "Fazer uma transformação anterior à gravação, de <var>fromtext</var>.",
-       "apihelp-compare-param-fromcontentmodel": "Modelo de conteúdo de <var>fromtext</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
-       "apihelp-compare-param-fromcontentformat": "Formato de seriação do conteúdo de <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "Segundo título a comparar.",
        "apihelp-compare-param-toid": "Segundo identificador de página a comparar.",
        "apihelp-compare-param-torev": "Segunda revisão a comparar.",
        "apihelp-compare-param-torelative": "Usar uma revisão relativa à revisão determinada a partir de <var>fromtitle</var>, <var>fromid</var> ou <var>fromrev</var>. Todas as outras opções 'to' serão ignoradas.",
-       "apihelp-compare-param-totext": "Usar este texto em vez do conteúdo da revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var>.",
-       "apihelp-compare-param-tosection": "Utilizar apenas a secção especificada do conteúdo 'to' especificado.",
        "apihelp-compare-param-topst": "Fazer uma transformação anterior à gravação, de <var>totext</var>.",
-       "apihelp-compare-param-tocontentmodel": "Modelo de conteúdo de <var>totext</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
-       "apihelp-compare-param-tocontentformat": "Formato de seriação do conteúdo de <var>totext</var>.",
+       "apihelp-compare-param-toslots": "Substituir o conteúdo da revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var>.\n\nEste parâmetro especifica os segmentos que deverão ser modificados. Use <var>totext-&#x7B;slot}</var>, <var>tocontentmodel-&#x7B;slot}</var> e <var>tocontentformat-&#x7B;slot}</var> para especificar conteúdo para cada segmento.",
+       "apihelp-compare-param-totext-{slot}": "Texto do segmento especificado. Se for omitido, o segmento é removido da revisão.",
+       "apihelp-compare-param-tosection-{slot}": "Quando <var>totext-&#x7B;slot}</var> é o conteúdo de uma única secção, este é o número da secção. Será fundido na revisão especificada por <var>totitle</var>, <var>toid</var> ou <var>torev</var> tal como acontece na edição de uma secção.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "Modelo de conteúdo de <var>totext-&#x7B;slot}</var>. Se não for fornecido, ele será deduzido a partir dos outros parâmetros.",
+       "apihelp-compare-param-tocontentformat-{slot}": "Formato de seriação do conteúdo de <var>totext-&#x7B;slot}</var>.",
+       "apihelp-compare-param-totext": "Especificar <kbd>toslots=main</kbd> e usar <var>totext-main</var>.",
+       "apihelp-compare-param-tocontentmodel": "Especificar <kbd>toslots=main</kbd> e usar <var>tocontentmodel-main</var>.",
+       "apihelp-compare-param-tocontentformat": "Especificar <kbd>toslots=main</kbd> e usar <var>tocontentformat-main</var>.",
+       "apihelp-compare-param-tosection": "Utilizar apenas a secção especificada do conteúdo 'to' especificado.",
        "apihelp-compare-param-prop": "As informações que devem ser obtidas.",
        "apihelp-compare-paramvalue-prop-diff": "O HTML da lista de diferenças.",
        "apihelp-compare-paramvalue-prop-diffsize": "O tamanho do HTML da lista de diferenças, em bytes.",
@@ -86,6 +96,7 @@
        "apihelp-compare-paramvalue-prop-comment": "O comentário das revisões 'from' e 'to'.",
        "apihelp-compare-paramvalue-prop-parsedcomment": "O comentário após análise sintática, das revisões 'from' e 'to'.",
        "apihelp-compare-paramvalue-prop-size": "O tamanho das revisões 'from' e 'to'.",
+       "apihelp-compare-param-slots": "Devolver as diferenças individuais destes segmentos, em vez de uma lista combinada para todos os segmentos.",
        "apihelp-compare-example-1": "Criar uma lista de diferenças entre as revisões 1 e 2.",
        "apihelp-createaccount-summary": "Criar uma conta de utilizador nova.",
        "apihelp-createaccount-param-preservestate": "Se <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> devolveu o valor verdadeiro para <samp>hasprimarypreservedstate</samp>, pedidos marcados como <samp>primary-required</samp> devem ser omitidos. Se devolveu um valor não vazio em <samp>preservedusername</samp>, esse nome de utilizador tem de ser usado no parâmetro <var>username</var>.",
        "apihelp-query+imageinfo-param-badfilecontexttitle": "Se <kbd>$2prop=badfile</kbd> estiver definido, este é o título da página usado ao calcular a [[MediaWiki:Bad image list]]",
        "apihelp-query+imageinfo-param-localonly": "Procurar ficheiros só no repositório local.",
        "apihelp-query+imageinfo-example-simple": "Obter informação sobre a versão atual do ficheiro [[:File:Albert Einstein Head.jpg]].",
-       "apihelp-query+imageinfo-example-dated": "Obter informação sobre as versões de [[:File:Test.jpg]] a partir de 2008.",
+       "apihelp-query+imageinfo-example-dated": "Obter informação sobre as versões de [[:File:Test.jpg]] desde 2008.",
        "apihelp-query+images-summary": "Devolve todos os ficheiros contidos nas páginas indicadas.",
        "apihelp-query+images-param-limit": "O número de ficheiros a serem devolvidos.",
        "apihelp-query+images-param-images": "Listar só estes ficheiros. Útil para verificar se uma determinada página tem um determinado ficheiro.",
        "apierror-compare-no-title": "Não é possível transformar antes da gravação, sem um título. Tente especificar <var>fromtitle</var> ou <var>totitle</var>.",
        "apierror-compare-nosuchfromsection": "Não há nenhuma secção $1 no conteúdo 'from'.",
        "apierror-compare-nosuchtosection": "Não há nenhuma secção $1 no conteúdo 'to'.",
+       "apierror-compare-nofromrevision": "Não foi especificada uma revisão 'from'. Especificar <var>fromrev</var>, <var>fromtitle</var> ou <var>fromid</var>.",
+       "apierror-compare-notorevision": "Não foi especificada uma revisão 'to'. Especificar <var>torev</var>, <var>totitle</var> ou <var>toid</var>.",
        "apierror-compare-relative-to-nothing": "Não existe uma revisão 'from' em relação à qual <var>torelative</var> possa ser relativo.",
        "apierror-contentserializationexception": "A seriação do conteúdo falhou: $1",
        "apierror-contenttoobig": "O conteúdo que forneceu excede o tamanho máximo dos artigos que é $1 {{PLURAL:$1|kilobyte|kilobytes}}.",
        "apierror-mimesearchdisabled": "A pesquisa MIME é desativada no modo avarento.",
        "apierror-missingcontent-pageid": "Conteúdo em falta para a página com o identificador $1.",
        "apierror-missingcontent-revid": "Conteúdo em falta para a revisão com o identificador $1.",
+       "apierror-missingcontent-revid-role": "O identificador de revisão $1 para a função $2 não tem conteúdo.",
        "apierror-missingparam-at-least-one-of": "{{PLURAL:$2|O parâmetro|Pelo menos um dos parâmetros}} $1 é obrigatório.",
        "apierror-missingparam-one-of": "{{PLURAL:$2|O parâmetro|Um dos parâmetros}} $1 é obrigatório.",
        "apierror-missingparam": "O parâmetro <var>$1</var> tem de ser definido.",
index f158f27..33f6613 100644 (file)
        "apihelp-compare-param-fromtitle": "{{doc-apihelp-param|compare|fromtitle}}",
        "apihelp-compare-param-fromid": "{{doc-apihelp-param|compare|fromid}}",
        "apihelp-compare-param-fromrev": "{{doc-apihelp-param|compare|fromrev}}",
-       "apihelp-compare-param-fromtext": "{{doc-apihelp-param|compare|fromtext}}",
-       "apihelp-compare-param-fromsection": "{{doc-apihelp-param|compare|fromsection}}",
        "apihelp-compare-param-frompst": "{{doc-apihelp-param|compare|frompst}}",
+       "apihelp-compare-param-fromslots": "{{doc-apihelp-param|compare|fromslots}}",
+       "apihelp-compare-param-fromtext-{slot}": "{{doc-apihelp-param|compare|fromtext-&#x7B;slot} }}",
+       "apihelp-compare-param-fromsection-{slot}": "{{doc-apihelp-param|compare|fromsection-&#x7B;slot} }}",
+       "apihelp-compare-param-fromcontentmodel-{slot}": "{{doc-apihelp-param|compare|fromcontentmodel-&#x7B;slot} }}",
+       "apihelp-compare-param-fromcontentformat-{slot}": "{{doc-apihelp-param|compare|fromcontentformat-&#x7B;slot} }}",
+       "apihelp-compare-param-fromtext": "{{doc-apihelp-param|compare|fromtext}}",
        "apihelp-compare-param-fromcontentmodel": "{{doc-apihelp-param|compare|fromcontentmodel}}",
        "apihelp-compare-param-fromcontentformat": "{{doc-apihelp-param|compare|fromcontentformat}}",
+       "apihelp-compare-param-fromsection": "{{doc-apihelp-param|compare|fromsection}}",
        "apihelp-compare-param-totitle": "{{doc-apihelp-param|compare|totitle}}",
        "apihelp-compare-param-toid": "{{doc-apihelp-param|compare|toid}}",
        "apihelp-compare-param-torev": "{{doc-apihelp-param|compare|torev}}",
        "apihelp-compare-param-torelative": "{{doc-apihelp-param|compare|torelative}}",
-       "apihelp-compare-param-totext": "{{doc-apihelp-param|compare|totext}}",
-       "apihelp-compare-param-tosection": "{{doc-apihelp-param|compare|tosection}}",
        "apihelp-compare-param-topst": "{{doc-apihelp-param|compare|topst}}",
+       "apihelp-compare-param-toslots": "{{doc-apihelp-param|compare|toslots}}",
+       "apihelp-compare-param-totext-{slot}": "{{doc-apihelp-param|compare|totext-&#x7B;slot} }}",
+       "apihelp-compare-param-tosection-{slot}": "{{doc-apihelp-param|compare|tosection-&#x7B;slot} }}",
+       "apihelp-compare-param-tocontentmodel-{slot}": "{{doc-apihelp-param|compare|tocontentmodel-&#x7B;slot} }}",
+       "apihelp-compare-param-tocontentformat-{slot}": "{{doc-apihelp-param|compare|tocontentformat-&#x7B;slot} }}",
+       "apihelp-compare-param-totext": "{{doc-apihelp-param|compare|totext}}",
        "apihelp-compare-param-tocontentmodel": "{{doc-apihelp-param|compare|tocontentmodel}}",
        "apihelp-compare-param-tocontentformat": "{{doc-apihelp-param|compare|tocontentformat}}",
+       "apihelp-compare-param-tosection": "{{doc-apihelp-param|compare|tosection}}",
        "apihelp-compare-param-prop": "{{doc-apihelp-param|compare|prop}}",
        "apihelp-compare-paramvalue-prop-diff": "{{doc-apihelp-paramvalue|compare|prop|diff}}",
        "apihelp-compare-paramvalue-prop-diffsize": "{{doc-apihelp-paramvalue|compare|prop|diffsize}}",
        "apihelp-compare-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|compare|prop|comment}}",
        "apihelp-compare-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|compare|prop|parsedcomment}}",
        "apihelp-compare-paramvalue-prop-size": "{{doc-apihelp-paramvalue|compare|prop|size}}",
+       "apihelp-compare-param-slots": "{{doc-apihelp-param|compare|slots}}",
        "apihelp-compare-example-1": "{{doc-apihelp-example|compare}}",
        "apihelp-createaccount-summary": "{{doc-apihelp-summary|createaccount}}",
        "apihelp-createaccount-param-preservestate": "{{doc-apihelp-param|createaccount|preservestate|info=This message is displayed in addition to {{msg-mw|api-help-authmanagerhelper-preservestate}}.}}",
        "apierror-compare-no-title": "{{doc-apierror}}",
        "apierror-compare-nosuchfromsection": "{{doc-apierror}}\n\nParameters:\n* $1 - Section identifier. Probably a number or \"T-\" followed by a number.",
        "apierror-compare-nosuchtosection": "{{doc-apierror}}\n\nParameters:\n* $1 - Section identifier. Probably a number or \"T-\" followed by a number.",
+       "apierror-compare-nofromrevision": "{{doc-apierror}}",
+       "apierror-compare-notorevision": "{{doc-apierror}}",
        "apierror-compare-relative-to-nothing": "{{doc-apierror}}",
        "apierror-contentserializationexception": "{{doc-apierror}}\n\nParameters:\n* $1 - Exception text, may end with punctuation. Currently this is probably English, hopefully we'll fix that in the future.",
        "apierror-contenttoobig": "{{doc-apierror}}\n\nParameters:\n* $1 - Maximum article size in kilobytes.",
        "apierror-mimesearchdisabled": "{{doc-apierror}}",
        "apierror-missingcontent-pageid": "{{doc-apierror}}\n\nParameters:\n* $1 - Page ID number.",
        "apierror-missingcontent-revid": "{{doc-apierror}}\n\nParameters:\n* $1 - Revision ID number",
+       "apierror-missingcontent-revid-role": "{{doc-apierror}}\n\nParameters:\n* $1 - Revision ID number\n* $2 - Role name",
        "apierror-missingparam-at-least-one-of": "{{doc-apierror}}\n\nParameters:\n* $1 - List of parameter names.\n* $2 - Number of parameters.",
        "apierror-missingparam-one-of": "{{doc-apierror}}\n\nParameters:\n* $1 - List of parameter names.\n* $2 - Number of parameters.",
        "apierror-missingparam": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter name.",
index d712765..4450b6c 100644 (file)
        "apihelp-compare-param-fromtitle": "Заголовок первой сравниваемой страницы.",
        "apihelp-compare-param-fromid": "Идентификатор первой сравниваемой страницы.",
        "apihelp-compare-param-fromrev": "Первая сравниваемая версия.",
-       "apihelp-compare-param-fromtext": "Используйте этот текст вместо содержимого версии, заданной <var>fromtitle</var>, <var>fromid</var> или <var>fromrev</var>.",
-       "apihelp-compare-param-fromsection": "Использовать только указанную секцию из содержимого «from».",
        "apihelp-compare-param-frompst": "Выполнить преобразование перед записью правки (PST) над <var>fromtext</var>.",
+       "apihelp-compare-param-fromtext": "Используйте этот текст вместо содержимого версии, заданной <var>fromtitle</var>, <var>fromid</var> или <var>fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "Модель содержимого <var>fromtext</var>. Если не задана, будет угадана по другим параметрам.",
        "apihelp-compare-param-fromcontentformat": "Формат сериализации содержимого <var>fromtext</var>.",
+       "apihelp-compare-param-fromsection": "Использовать только указанную секцию из содержимого «from».",
        "apihelp-compare-param-totitle": "Заголовок второй сравниваемой страницы.",
        "apihelp-compare-param-toid": "Идентификатор второй сравниваемой страницы.",
        "apihelp-compare-param-torev": "Вторая сравниваемая версия.",
        "apihelp-compare-param-torelative": "Использовать версию, относящуюся к определённой <var>fromtitle</var>, <var>fromid</var> или <var>fromrev</var>. Все другие опции 'to' будут проигнорированы.",
-       "apihelp-compare-param-totext": "Используйте этот текст вместо содержимого версии, заданной <var>totitle</var>, <var>toid</var> или <var>torev</var>.",
-       "apihelp-compare-param-tosection": "Использовать только указанную секцию из содержимого «to».",
        "apihelp-compare-param-topst": "Выполнить преобразование перед записью правки (PST) над <var>totext</var>.",
+       "apihelp-compare-param-tocontentmodel-{slot}": "Модель содержимого <var>totext-&#x7B;slot}</var>. Если не задана, будет угадана по другим параметрам.",
+       "apihelp-compare-param-totext": "Используйте этот текст вместо содержимого версии, заданной <var>totitle</var>, <var>toid</var> или <var>torev</var>.",
        "apihelp-compare-param-tocontentmodel": "Модель содержимого <var>totext</var>. Если не задана, будет угадана по другим параметрам.",
        "apihelp-compare-param-tocontentformat": "Формат сериализации содержимого <var>totext</var>.",
+       "apihelp-compare-param-tosection": "Использовать только указанную секцию из содержимого «to».",
        "apihelp-compare-param-prop": "Какую информацию получить.",
        "apihelp-compare-paramvalue-prop-diff": "HTML-код разницы.",
        "apihelp-compare-paramvalue-prop-diffsize": "Размер HTML-кода разницы в байтах.",
index 20dc919..1cb6f5c 100644 (file)
@@ -16,7 +16,8 @@
                        "Rockyfelle",
                        "Macofe",
                        "Magol",
-                       "Bengtsson96"
+                       "Bengtsson96",
+                       "Larske"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentation]]\n* [[mw:Special:MyLanguage/API:FAQ|Vanliga frågor]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Sändlista]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-nyheter]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Buggar och begäran]\n</div>\n<strong>Status:</strong> Alla funktioner som visas på denna sida bör fungera, men API:et är fortfarande under utveckling och kan ändras när som helst. Prenumerera på [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ sändlistan mediawiki-api-announce] för uppdateringsaviseringar.\n\n<strong>Felaktiga begäran:</strong> När felaktiga begäran skickas till API:et kommer en HTTP-header skickas med nyckeln \"MediaWiki-API-Error\" och sedan kommer både värdet i headern och felkoden som skickades tillbaka anges som samma värde. För mer information se [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Fel och varningar]].\n\n<p class=\"mw-apisandbox-link\"><strong>Testning:</strong> För enkelt testning av API-begäran, se [[Special:ApiSandbox]].</p>",
        "apihelp-query+images-param-limit": "Hur många filer att returnera.",
        "apihelp-query+images-param-dir": "Riktningen att lista mot.",
        "apihelp-query+images-example-simple": "Hämta en lista över filer som används på [[Main Page]].",
-       "apihelp-query+imageusage-summary": "Hitta alla sidor som användare angiven bildtitel.",
+       "apihelp-query+imageusage-summary": "Hitta alla sidor som använder angiven bildtitel.",
        "apihelp-query+imageusage-param-dir": "Riktningen att lista mot.",
        "apihelp-query+imageusage-example-simple": "Visa sidor med hjälp av [[:File:Albert Einstein Head.jpg]].",
        "apihelp-query+imageusage-example-generator": "Hämta information om sidor med hjälp av [[:File:Albert Einstein Head.jpg]].",
index e9078e0..cd1ccc5 100644 (file)
        "apihelp-compare-param-fromtitle": "Перший заголовок для порівняння.",
        "apihelp-compare-param-fromid": "Перший ID сторінки для порівняння.",
        "apihelp-compare-param-fromrev": "Перша версія для порівняння.",
-       "apihelp-compare-param-fromtext": "Використати цей текст замість контенту версії, вказаної через <var>fromtitle</var>, <var>fromid</var> або <var>fromrev</var>.",
-       "apihelp-compare-param-fromsection": "Використовувати лише вказану секцію із заданого вмісту «from».",
        "apihelp-compare-param-frompst": "Зробити трансформацію перед збереженням на <var>fromtext</var>.",
+       "apihelp-compare-param-fromtext": "Використати цей текст замість контенту версії, вказаної через <var>fromtitle</var>, <var>fromid</var> або <var>fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "Контентна модель <var>fromtext</var>. Якщо не вказано, буде використано припущення на основі інших параметрів.",
        "apihelp-compare-param-fromcontentformat": "Формат серіалізації контенту <var>fromtext</var>.",
+       "apihelp-compare-param-fromsection": "Використовувати лише вказану секцію із заданого вмісту «from».",
        "apihelp-compare-param-totitle": "Другий заголовок для порівняння.",
        "apihelp-compare-param-toid": "Другий ID сторінки для порівняння.",
        "apihelp-compare-param-torev": "Друга версія для порівняння.",
        "apihelp-compare-param-torelative": "Використати версію, яка стосується версії, визначеної через <var>fromtitle</var>, <var>fromid</var> або <var>fromrev</var>. Усі інші опції 'to' буде проігноровано.",
-       "apihelp-compare-param-totext": "Використати цей текст замість контенту версії, вказаної через <var>totitle</var>, <var>toid</var> або <var>torev</var>.",
-       "apihelp-compare-param-tosection": "Використовувати лише вказану секцію із заданого вмісту «to».",
        "apihelp-compare-param-topst": "Виконати трансформацію перед збереженням на <var>totext</var>.",
+       "apihelp-compare-param-totext": "Використати цей текст замість контенту версії, вказаної через <var>totitle</var>, <var>toid</var> або <var>torev</var>.",
        "apihelp-compare-param-tocontentmodel": "Контентна модель <var>totext</var>. Якщо не вказано, буде використано припущення на основі інших параметрів.",
        "apihelp-compare-param-tocontentformat": "Формат серіалізації контенту <var>totext</var>.",
+       "apihelp-compare-param-tosection": "Використовувати лише вказану секцію із заданого вмісту «to».",
        "apihelp-compare-param-prop": "Які уривки інформації отримати.",
        "apihelp-compare-paramvalue-prop-diff": "HTML різниці версій.",
        "apihelp-compare-paramvalue-prop-diffsize": "Розмір HTML різниці версій, у байтах.",
index 8d618ea..60cf575 100644 (file)
@@ -25,7 +25,8 @@
                        "Umherirrender",
                        "NeverBehave",
                        "Wbxshiori",
-                       "Wxyveronica"
+                       "Wxyveronica",
+                       "WhitePhosphorus"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|文档]]\n* [[mw:Special:MyLanguage/API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>MediaWiki API是一个成熟稳定的,不断受到支持和改进的界面。尽管我们尽力避免,但偶尔也需要作出重大更新;请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:Special:MyLanguage/API:Errors_and_warnings|API:错误与警告]]。\n\n<p class=\"mw-apisandbox-link\"><strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。</p>",
        "apihelp-compare-param-fromtitle": "要比较的第一个标题。",
        "apihelp-compare-param-fromid": "要比较的第一个页面 ID。",
        "apihelp-compare-param-fromrev": "要比较的第一个修订版本。",
-       "apihelp-compare-param-fromtext": "使用该文本而不是由<var>fromtitle</var>、<var>fromid</var>或<var>fromrev</var>指定的修订版本内容。",
-       "apihelp-compare-param-fromsection": "只使用指定“from”内容的指定章节。",
        "apihelp-compare-param-frompst": "在<var>fromtext</var>执行预保存转变。",
+       "apihelp-compare-param-fromtext": "使用该文本而不是由<var>fromtitle</var>、<var>fromid</var>或<var>fromrev</var>指定的修订版本内容。",
        "apihelp-compare-param-fromcontentmodel": "<var>fromtext</var>的内容模型。如果未指定,这将基于其他参数猜想。",
        "apihelp-compare-param-fromcontentformat": "<var>fromtext</var>的内容序列化格式。",
+       "apihelp-compare-param-fromsection": "只使用指定“from”内容的指定章节。",
        "apihelp-compare-param-totitle": "要比较的第二个标题。",
        "apihelp-compare-param-toid": "要比较的第二个页面 ID。",
        "apihelp-compare-param-torev": "要比较的第二个修订版本。",
        "apihelp-compare-param-torelative": "使用与定义自<var>fromtitle</var>、<var>fromid</var>或<var>fromrev</var>的修订版本相关的修订版本。所有其他“to”的选项将被忽略。",
-       "apihelp-compare-param-totext": "使用该文本而不是由<var>totitle</var>、<var>toid</var>或<var>torev</var>指定的修订版本内容。",
-       "apihelp-compare-param-tosection": "只使用指定“to”内容的指定章节。",
        "apihelp-compare-param-topst": "在<var>totext</var>执行预保存转换。",
+       "apihelp-compare-param-totext": "使用该文本而不是由<var>totitle</var>、<var>toid</var>或<var>torev</var>指定的修订版本内容。",
        "apihelp-compare-param-tocontentmodel": "<var>totext</var>的内容模型。如果未指定,这将基于其他参数猜想。",
        "apihelp-compare-param-tocontentformat": "<var>totext</var>的内容序列化格式。",
+       "apihelp-compare-param-tosection": "只使用指定“to”内容的指定章节。",
        "apihelp-compare-param-prop": "要获取的信息束。",
        "apihelp-compare-paramvalue-prop-diff": "差异HTML。",
        "apihelp-compare-paramvalue-prop-diffsize": "差异HTML的大小(字节)。",
        "apihelp-query+redirects-example-generator": "获取所有重定向至[[Main Page]]的信息。",
        "apihelp-query+revisions-summary": "获取修订版本信息。",
        "apihelp-query+revisions-extended-description": "可用于以下几个方面:\n# 通过设置标题或页面ID获取一批页面(最新修订)的数据。\n# 通过使用带start、end或limit的标题或页面ID获取给定页面的多个修订。\n# 通过revid设置一批修订的ID获取它们的数据。",
-       "apihelp-query+revisions-paraminfo-singlepageonly": "å\8f¯è\83½å\8fªè\83½ä¸\8eå\8d\95ä¸\80页é\9d¢使用(模式#2)。",
+       "apihelp-query+revisions-paraminfo-singlepageonly": "å\8fªè\83½å\9c¨å\8d\95ä¸\80页é\9d¢æ¨¡å¼\8f中使用(模式#2)。",
        "apihelp-query+revisions-param-startid": "从这个修订版本时间戳开始列举。修订版本必须存在,但未必与该页面相关。",
        "apihelp-query+revisions-param-endid": "在这个修订版本时间戳停止列举。修订版本必须存在,但未必与该页面相关。",
        "apihelp-query+revisions-param-start": "从哪个修订版本时间戳开始列举。",
        "apierror-mustbeloggedin-linkaccounts": "您必须登录以链接账户。",
        "apierror-mustbeloggedin-removeauth": "您必须登录以移除身份验证数据。",
        "apierror-mustbeloggedin-uploadstash": "上传暂存功能只对已登录用户可用。",
-       "apierror-mustbeloggedin": "您必须登录$1。",
+       "apierror-mustbeloggedin": "您必须登录才能$1。",
        "apierror-mustbeposted": "<kbd>$1</kbd>模块需要POST请求。",
        "apierror-mustpostparams": "以下{{PLURAL:$2|参数}}在查询字符串中被找到,但必须在POST正文中:$1。",
        "apierror-noapiwrite": "通过API编辑此wiki已禁用。请确保<code>$wgEnableWriteAPI=true;</code>声明包含在wiki的<code>LocalSettings.php</code>文件中。",
index 82b3ea8..f989ce4 100644 (file)
@@ -16,7 +16,8 @@
                        "Wwycheuk",
                        "Wbxshiori",
                        "Sanmosa",
-                       "Kly"
+                       "Kly",
+                       "WhitePhosphorus"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|說明文件]]\n* [[mw:Special:MyLanguage/API:FAQ|常見問題]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 郵寄清單]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 報告錯誤及請求功能]\n</div>\n<strong>狀態資訊:</strong>MediaWiki API 已是成熟、穩定,並積極支援以改善的介面。儘管我們儘可能避免,但仍偶有需要重大變更的情況,請訂閱[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 郵寄清單]以便獲得更新通知。\n\n<strong>錯誤的請求:</strong>當 API 收到錯誤的請求,會發出以「MediaWiki-API-Error」為鍵的 HTTP 標頭欄位,隨後標頭欄位的值,以及傳回的錯誤碼會設為相同值。詳細資訊請參閱 [[mw:Special:MyLanguage/API:Errors_and_warnings|API: 錯誤與警告]]。\n\n<p class=\"mw-apisandbox-link\"><strong>測試:</strong>要簡化 API 請求的測試過程,請見 [[Special:ApiSandbox]]。</p>",
@@ -32,6 +33,7 @@
        "apihelp-main-param-responselanginfo": "在結果中包括<var>uselang</var>和<var>errorlang</var>所用的語言。",
        "apihelp-block-summary": "封鎖使用者。",
        "apihelp-block-param-user": "要封鎖的使用者名稱、IP 位址或 IP 範圍。不能與 <var>$1userid</var> 一起使用",
+       "apihelp-block-param-userid": "要封鎖的使用者 ID。不可與 <var>$1user</var> 一同使用。",
        "apihelp-block-param-reason": "封鎖原因。",
        "apihelp-block-param-anononly": "僅封鎖匿名使用者 (禁止這個 IP 位址的匿名使用者編輯)。",
        "apihelp-block-param-nocreate": "禁止建立帳號。",
@@ -61,7 +63,7 @@
        "apihelp-compare-param-totitle": "要比對的第二個標題。",
        "apihelp-compare-param-toid": "要比對的第二個頁面 ID。",
        "apihelp-compare-param-torev": "要比對的第二個修訂。",
-       "apihelp-compare-param-tocontentformat": "<var>totext</var> 的內容序列化格式。",
+       "apihelp-compare-param-tocontentformat": "指定 <kbd>toslots=main</kbd> 並改使用 <var>tocontentformat-main</var>。",
        "apihelp-compare-param-prop": "要取得的資訊部份。",
        "apihelp-compare-paramvalue-prop-diff": "HTML 差異。",
        "apihelp-compare-paramvalue-prop-diffsize": "以位元組為單位的 HTML 差異大小。",
        "apihelp-edit-param-nocreate": "若頁面不存在,則產生錯誤。",
        "apihelp-edit-param-watch": "加入目前頁面至您的監視清單。",
        "apihelp-edit-param-unwatch": "從您的監視清單中移除目前頁面。",
+       "apihelp-edit-param-prependtext": "添加此文字至頁面開頭。覆蓋$1text。",
        "apihelp-edit-param-redirect": "自動化解決重新導向。",
        "apihelp-edit-param-contentformat": "用於輸入文字的內容序列化格式。",
        "apihelp-edit-param-contentmodel": "新內容的內容模組。",
        "apihelp-expandtemplates-param-text": "要轉換的 Wikitext。",
        "apihelp-feedcontributions-summary": "回傳使用者貢獻 Feed。",
        "apihelp-feedcontributions-param-feedformat": "Feed 的格式。",
+       "apihelp-feedcontributions-param-user": "要取得哪些使用者的貢獻。",
        "apihelp-feedcontributions-param-year": "起始年份(更早之前)。",
        "apihelp-feedcontributions-param-month": "起始月份(更早之前)。",
        "apihelp-feedcontributions-param-deletedonly": "僅顯示已刪除的貢獻。",
        "apihelp-feedcontributions-param-toponly": "只顯示最新修訂的編輯。",
        "apihelp-feedcontributions-param-newonly": "只顯示建立頁面的編輯。",
-       "apihelp-feedcontributions-param-hideminor": "隱藏小修改。",
+       "apihelp-feedcontributions-param-hideminor": "隱藏小編輯。",
        "apihelp-feedcontributions-param-showsizediff": "顯示修訂版本之間的差異大小。",
        "apihelp-feedcontributions-example-simple": "返回使用者<kbd>Example</kbd>的貢獻。",
        "apihelp-feedrecentchanges-summary": "返回最近變更摘要。",
        "apihelp-feedrecentchanges-param-days": "用於限制結果的天數。",
        "apihelp-feedrecentchanges-param-limit": "回傳的結果數量上限。",
        "apihelp-feedrecentchanges-param-from": "顯示自那時以來的更改。",
-       "apihelp-feedrecentchanges-param-hideminor": "隱藏小編輯。",
+       "apihelp-feedrecentchanges-param-hideminor": "隱藏小更改。",
        "apihelp-feedrecentchanges-param-hidebots": "隱藏由機器人做的變更。",
        "apihelp-feedrecentchanges-param-hideanons": "隱藏匿名使用者做的變更。",
        "apihelp-feedrecentchanges-param-hideliu": "隱藏已註冊使用者做的變更。",
        "apihelp-feedrecentchanges-example-30days": "顯示近期30天內的變動",
        "apihelp-feedwatchlist-summary": "返回監視清單 feed。",
        "apihelp-feedwatchlist-param-feedformat": "Feed 的格式。",
+       "apihelp-feedwatchlist-param-linktosections": "若可以的話,直接連結至更改過的段落。",
+       "apihelp-filerevert-param-filename": "目標檔案名稱,不需包含「File:」這樣的前綴字元。",
        "apihelp-filerevert-param-comment": "上載意見。",
        "apihelp-help-summary": "顯示指定模組的說明。",
        "apihelp-help-example-main": "主模組使用說明",
        "apihelp-help-example-query": "兩個查詢子模組的說明。",
        "apihelp-imagerotate-summary": "旋轉一張或多張圖片。",
        "apihelp-imagerotate-param-rotation": "順時針旋轉圖片的度數。",
+       "apihelp-imagerotate-param-tags": "在更新日誌裡套用到項目的標籤。",
+       "apihelp-imagerotate-example-simple": "<kbd>90</kbd> 度旋轉 <kbd>File:Example.png</kbd>。",
+       "apihelp-imagerotate-example-generator": "<kbd>180</kbd> 度旋轉所有在 <kbd>Category:Flip</kbd> 裡的圖片。",
        "apihelp-import-summary": "從其它 wiki 或 XML 檔案來匯入頁面。",
        "apihelp-import-param-summary": "匯入摘要。",
        "apihelp-import-param-xml": "上載的 XML 檔。",
        "apihelp-opensearch-param-suggest": "若<var>[[mw:Special:MyLanguage/Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var>設定為false,則不做任何事。",
        "apihelp-opensearch-param-redirects": "如何處理重定向:\n;return:傳回重定向本身。\n;resolve:傳回目標頁面,傳回的結果數目可能少於$1limit。\n由於歷史原因,$1format=json的預設值為「return」,其他格式則為「resolve」。",
        "apihelp-opensearch-param-format": "輸出的格式。",
+       "apihelp-opensearch-example-te": "找出以 <kbd>Te</kbd> 為開頭的頁面。",
        "apihelp-options-summary": "更改目前使用者的偏好設定。",
        "apihelp-options-param-reset": "重設偏好設定為網站預設值。",
+       "apihelp-options-param-optionvalue": "由 <var>$1optionname</var> 所指定,用於選項的值。",
        "apihelp-options-example-reset": "重設所有偏好設定",
        "apihelp-options-example-change": "更改<kbd>skin</kbd>和<kbd>hideminor</kbd>偏好設定。",
+       "apihelp-options-example-complex": "重置所有偏好設定,然後再設定 <kbd>skin</kbd> 與 <kbd>nickname</kbd>。",
        "apihelp-paraminfo-summary": "獲得有關 API 模組的資訊。",
        "apihelp-paraminfo-param-helpformat": "說明字串的格式。",
+       "apihelp-parse-summary": "解析內容併回傳解析器輸出。",
        "apihelp-parse-param-summary": "解析摘要。",
        "apihelp-parse-param-pageid": "解析此頁面的內容。覆蓋 <var>$1page</var>。",
        "apihelp-parse-param-redirects": "若 <var>$1page</var> 或者 <var>$1pageid</var> 被設定成重新導向,則解析它。",
        "apihelp-parse-param-prop": "要取得的資訊部份:",
+       "apihelp-parse-paramvalue-prop-categorieshtml": "提供分類的 HTML 版本。",
+       "apihelp-parse-paramvalue-prop-revid": "添加已解析頁面的修訂 ID。",
        "apihelp-parse-paramvalue-prop-headhtml": "取得頁面已解析的 <code>&lt;head&gt;</code>。",
        "apihelp-parse-param-disablepp": "請改用<var>$1disablelimitreport</var>。",
        "apihelp-parse-param-preview": "在預覽模式下解析。",
        "apihelp-protect-param-watch": "如果被設定,就將被(解除)保護的頁面加至目前使用者的監視列表。",
        "apihelp-protect-param-watchlist": "無條件地將該頁面加入至或移除自目前使用者的監視列表、使用偏好設定或不更改監視。",
        "apihelp-protect-example-protect": "保護一個頁面。",
+       "apihelp-protect-example-unprotect": "透過設定為 <kbd>all</kbd>(註:代表任何人都可以執行操作),來解除對頁面的保護。",
+       "apihelp-protect-example-unprotect2": "透過設定為沒有限制,來解除對頁面的保護。",
        "apihelp-purge-summary": "為指定標題清除快取。",
        "apihelp-purge-param-forcelinkupdate": "更新連結表格。",
        "apihelp-purge-example-generator": "重新整理主要命名空間的前10個頁面。",
        "apihelp-query-param-prop": "替已查詢頁面所要取得的屬性。",
        "apihelp-query-param-list": "要取得的清單。",
        "apihelp-query-param-meta": "要取得的詮釋資料。",
+       "apihelp-query-param-iwurl": "若標題是跨 wiki 連結,是否取得完整的 URL。",
+       "apihelp-query-param-rawcontinue": "回傳原始的 <samp>query-continue</samp> 資料來繼續。",
+       "apihelp-query-example-revisions": "索取 <kbd>Main Page</kbd> 的[[Special:ApiHelp/query+siteinfo|站台資訊]]與[[Special:ApiHelp/query+revisions|修訂]]。",
+       "apihelp-query-example-allpages": "索取以 <kbd>API/</kbd> 為開頭的頁面修訂。",
        "apihelp-query+allcategories-summary": "列舉所有分類。",
        "apihelp-query+allcategories-param-from": "起始列舉的分類。",
        "apihelp-query+allcategories-param-to": "終止列舉的分類。",
        "apihelp-query+alldeletedrevisions-param-from": "在此標題開始列出。",
        "apihelp-query+alldeletedrevisions-param-to": "在此標題停止列出。",
        "apihelp-query+alldeletedrevisions-param-prefix": "搜尋以此值為開頭的所有頁面標題。",
+       "apihelp-query+alldeletedrevisions-param-tag": "僅列出以此標籤所標記的修訂。",
        "apihelp-query+alldeletedrevisions-param-user": "此列出由該使用者作出的修訂。",
        "apihelp-query+alldeletedrevisions-param-excludeuser": "不要列出由該使用者作出的修訂。",
        "apihelp-query+alldeletedrevisions-param-namespace": "僅列出此命名空間的頁面。",
+       "apihelp-query+allfileusages-summary": "列出所有檔案用途,包含不存在的。",
+       "apihelp-query+allfileusages-param-from": "要起始列舉的檔案標題。",
+       "apihelp-query+allfileusages-param-to": "要終止列舉的檔案標題。",
        "apihelp-query+allfileusages-param-prefix": "搜尋以此值為開頭的所有檔案標題。",
        "apihelp-query+allfileusages-param-prop": "要包含到的資訊部份:",
        "apihelp-query+allfileusages-paramvalue-prop-title": "添加檔案標題。",
        "apihelp-query+allimages-summary": "按順序列舉所有圖片。",
        "apihelp-query+allimages-param-sort": "作為排序順序的屬性。",
        "apihelp-query+allimages-param-dir": "列出時所採用的方向。",
+       "apihelp-query+allimages-param-from": "要開始列舉的圖片標題。僅能與 $1sort=name 一起使用。",
+       "apihelp-query+allimages-param-to": "要停止列舉的圖片標題。僅能與 $1sort=name 一起使用。",
+       "apihelp-query+allimages-param-start": "要開始列舉的時間戳記。僅能與 $1sort=timestamp 一起使用。",
+       "apihelp-query+allimages-param-end": "要停止列舉的時間戳記。僅能與 $1sort=timestamp 一起使用。",
        "apihelp-query+allimages-param-minsize": "限制圖片至少要有這樣多的位元組。",
        "apihelp-query+allimages-param-maxsize": "限制圖片最多只能這樣多的位元組。",
        "apihelp-query+allimages-param-sha1": "圖片的 SHA1 雜湊值。覆蓋 $1sha1base36。",
        "apihelp-query+allimages-param-limit": "要回傳的圖片總數。",
        "apihelp-query+allimages-example-B": "搜尋以字母 <kbd>B</kbd> 為開頭的所有檔案清單。",
        "apihelp-query+allimages-example-recent": "顯示近期已上傳檔案的清單,類似於 [[Special:NewFiles]]。",
+       "apihelp-query+allimages-example-generator": "顯示 4 個以 <kbd>T</kbd> 為開頭的檔案之資訊。",
        "apihelp-query+alllinks-param-from": "要起始列舉的連結標題。",
        "apihelp-query+alllinks-param-to": "要終止列舉的連結標題。",
+       "apihelp-query+alllinks-param-prefix": "搜尋以此值為開頭的所有連結標題。",
        "apihelp-query+alllinks-param-prop": "要包含的資訊部份:",
        "apihelp-query+alllinks-paramvalue-prop-title": "添加連結標題。",
        "apihelp-query+alllinks-param-namespace": "要列舉的命名空間。",
        "apihelp-query+alllinks-example-generator": "取得包含連結的頁面。",
        "apihelp-query+allmessages-summary": "返回來自該網站的訊息。",
        "apihelp-query+allmessages-param-prop": "要取得的屬性。",
+       "apihelp-query+allmessages-param-filter": "僅回傳名稱包含此字串的訊息。",
+       "apihelp-query+allmessages-param-customised": "僅回傳在此自定義狀況下的訊息。",
        "apihelp-query+allmessages-param-lang": "以此語言來回傳訊息。",
        "apihelp-query+allmessages-param-from": "以此訊息來回傳訊息開頭。",
        "apihelp-query+allmessages-param-to": "以此訊息來回傳訊息結尾。",
        "apihelp-query+allmessages-param-prefix": "回傳帶有前綴的訊息。",
        "apihelp-query+allmessages-example-ipb": "顯示以 <kbd>ipb-</kbd> 起始的訊息。",
        "apihelp-query+allmessages-example-de": "顯示在德語裡的 <kbd>august</kbd> 與 <kbd>mainpage</kbd> 訊息。",
+       "apihelp-query+allpages-summary": "依序列舉在指定命名空間的所有頁面。",
        "apihelp-query+allpages-param-from": "起始列舉的頁面標題。",
        "apihelp-query+allpages-param-to": "終止列舉的頁面標題。",
        "apihelp-query+allpages-param-prefix": "搜尋以此值為開頭的所有頁面標題。",
        "apihelp-query+allpages-param-prtype": "僅限受保護的頁面。",
        "apihelp-query+allpages-param-limit": "要回傳的頁面總數。",
        "apihelp-query+allpages-param-dir": "列出時所採用的方向。",
+       "apihelp-query+allpages-example-B": "顯示以字母 <kbd>B</kbd> 為開頭的所有頁面清單。",
+       "apihelp-query+allpages-example-generator": "顯示 4 個以 <kbd>T</kbd> 為開頭的頁面之資訊。",
        "apihelp-query+allredirects-summary": "列出至命名空間的所有重新導向。",
        "apihelp-query+allredirects-param-from": "要起始列舉的重新導向標題。",
        "apihelp-query+allredirects-param-to": "要終止列舉的重新導向標題。",
        "apihelp-query+allrevisions-param-user": "此列出由該使用者作出的修訂。",
        "apihelp-query+allrevisions-param-excludeuser": "不要列出由該使用者作出的修訂。",
        "apihelp-query+allrevisions-param-namespace": "僅列出此命名空間的頁面。",
+       "apihelp-query+allrevisions-example-ns-main": "列出在主命名空間的前 50 個修訂。",
        "apihelp-query+mystashedfiles-param-prop": "要索取的檔案屬性。",
        "apihelp-query+mystashedfiles-paramvalue-prop-size": "索取檔案大小與圖片尺寸。",
        "apihelp-query+mystashedfiles-paramvalue-prop-type": "索取檔案的 MIME 類型以及媒體類型。",
        "apihelp-query+mystashedfiles-param-limit": "要取得的檔案數量。",
+       "apihelp-query+alltransclusions-param-prop": "要包含到的資訊部份:",
        "apihelp-query+alltransclusions-param-namespace": "要列舉的命名空間。",
        "apihelp-query+alltransclusions-param-limit": "要回傳的項目總數。",
        "apihelp-query+alltransclusions-param-dir": "列出時所採用的方向。",
        "apihelp-query+allusers-param-group": "僅包含在指定群組的使用者。",
        "apihelp-query+allusers-param-excludegroup": "排除指定群組中的使用者",
        "apihelp-query+allusers-param-prop": "要包含的資訊部份:",
+       "apihelp-query+allusers-paramvalue-prop-blockinfo": "添加有關使用者目前封鎖的資訊。",
        "apihelp-query+allusers-paramvalue-prop-rights": "列出使用者所擁有的權限。",
        "apihelp-query+allusers-paramvalue-prop-editcount": "添加使用者的編輯次數。",
+       "apihelp-query+allusers-param-limit": "要回傳的使用者名稱總數。",
        "apihelp-query+allusers-param-witheditsonly": "僅列出有做過編輯的使用者。",
        "apihelp-query+allusers-example-Y": "列出以<kbd>Y</kbd>開頭的使用者。",
        "apihelp-query+authmanagerinfo-summary": "取得目前身分核對狀態的資訊。",
        "apihelp-query+blocks-summary": "列出所有被封鎖使用者與 IP 位址。",
        "apihelp-query+blocks-param-start": "起始列舉的時間戳記。",
        "apihelp-query+blocks-param-end": "終止列舉的時間戳記。",
+       "apihelp-query+blocks-param-ids": "要列出的封鎖 ID 清單(可選)。",
+       "apihelp-query+blocks-param-users": "要搜尋的使用者清單(可選)。",
        "apihelp-query+blocks-param-prop": "要取得的屬性。",
        "apihelp-query+blocks-paramvalue-prop-id": "添加封鎖 ID。",
        "apihelp-query+blocks-paramvalue-prop-user": "添加已封鎖使用者的使用者名稱。",
        "apihelp-query+categories-summary": "列出頁面隸屬的所有分類。",
        "apihelp-query+categories-param-show": "要顯示出的分類種類。",
        "apihelp-query+categories-param-limit": "要回傳的分類數量。",
+       "apihelp-query+categories-param-dir": "列出時所採用的方向。",
+       "apihelp-query+categories-example-simple": "取得屬於在頁面 <kbd>Albert Einstein</kbd> 的分類清單。",
+       "apihelp-query+categories-example-generator": "取得使用在 <kbd>Albert Einstein</kbd> 頁面裡所有分類的相關資訊。",
        "apihelp-query+categoryinfo-summary": "回傳有關指定分類的資訊。",
+       "apihelp-query+categoryinfo-example-simple": "取得有關 <kbd>Category:Foo</kbd> 與 <kbd>Category:Bar</kbd> 的資訊。",
        "apihelp-query+categorymembers-summary": "在指定的分類中列出所有頁面。",
        "apihelp-query+categorymembers-param-prop": "要包含的資訊部份:",
        "apihelp-query+categorymembers-paramvalue-prop-ids": "添加頁面 ID。",
        "apihelp-query+categorymembers-param-startsortkey": "請改用 $1starthexsortkey。",
        "apihelp-query+categorymembers-param-endsortkey": "請改用 $1endhexsortkey。",
        "apihelp-query+categorymembers-example-simple": "取得在 <kbd>Category:Physics</kbd> 裡前 10 項的頁面。",
+       "apihelp-query+categorymembers-example-generator": "取得在 <kbd>Category:Physics</kbd> 裡前 10 個頁面的頁面資訊。",
        "apihelp-query+contributors-param-limit": "要回傳的貢獻人員數量。",
+       "apihelp-query+contributors-example-simple": "顯示頁面 <kbd>Main Page</kbd> 的貢獻者。",
        "apihelp-query+deletedrevisions-summary": "取得已刪除修訂的資訊。",
        "apihelp-query+deletedrevisions-param-tag": "僅列出以此標籤所標記的修訂。",
        "apihelp-query+deletedrevisions-param-user": "此列出由該使用者作出的修訂。",
        "apihelp-query+deletedrevisions-param-excludeuser": "不要列出由該使用者作出的修訂。",
+       "apihelp-query+deletedrevisions-example-revids": "列出已刪除修訂 <kbd>123456</kbd> 的資訊。",
        "apihelp-query+deletedrevs-summary": "列出已刪除的修訂。",
        "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|模式|模式}}:$2",
        "apihelp-query+deletedrevs-param-start": "起始列舉的時間戳記。",
        "apihelp-query+deletedrevs-param-end": "終止列舉的時間戳記。",
        "apihelp-query+deletedrevs-param-from": "在此標題開始列出。",
        "apihelp-query+deletedrevs-param-to": "在此標題停止列出。",
+       "apihelp-query+deletedrevs-param-unique": "各頁面僅列出一個修訂。",
        "apihelp-query+deletedrevs-param-tag": "僅列出以此標籤所標記的修訂。",
        "apihelp-query+deletedrevs-param-user": "此列出由該使用者作出的修訂。",
        "apihelp-query+deletedrevs-param-excludeuser": "不要列出由該使用者作出的修訂。",
        "apihelp-query+deletedrevs-param-namespace": "僅列出此命名空間的頁面。",
+       "apihelp-query+deletedrevs-param-limit": "修訂能列出的最大數量。",
        "apihelp-query+disabled-summary": "已停用此查詢模組。",
        "apihelp-query+duplicatefiles-param-limit": "要回傳的重複檔案數量。",
        "apihelp-query+duplicatefiles-param-dir": "列出時所採用的方向。",
+       "apihelp-query+duplicatefiles-example-simple": "尋找重複 [[:File:Albert Einstein Head.jpg]] 的檔案。",
        "apihelp-query+duplicatefiles-example-generated": "查看全部有重複到的檔案。",
        "apihelp-query+embeddedin-param-namespace": "要列舉的命名空間。",
        "apihelp-query+embeddedin-param-dir": "列出時所採用的方向。",
        "apihelp-query+embeddedin-param-limit": "要回傳的頁面總數。",
        "apihelp-query+extlinks-summary": "回傳所有指定頁面的外部 URL (非 interwiki)。",
        "apihelp-query+extlinks-param-limit": "要回傳的連結數量。",
+       "apihelp-query+extlinks-example-simple": "取得 <kbd>Main Page</kbd> 的外部連結清單。",
+       "apihelp-query+exturlusage-summary": "列舉包含指定 URL 的頁面。",
        "apihelp-query+exturlusage-param-prop": "要包含的資訊部份:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "添加頁面 ID。",
        "apihelp-query+exturlusage-paramvalue-prop-title": "添加標題與頁面的命名空間 ID。",
        "apihelp-query+exturlusage-paramvalue-prop-url": "添加用於頁面的 URL。",
        "apihelp-query+exturlusage-param-namespace": "要列舉的頁面命名空間。",
        "apihelp-query+exturlusage-param-limit": "要回傳的頁面數量。",
+       "apihelp-query+exturlusage-example-simple": "顯示連結至 <kbd>https://www.mediawiki.org</kbd> 的頁面。",
        "apihelp-query+filearchive-param-from": "起始列舉的圖片標題。",
        "apihelp-query+filearchive-param-to": "終止列舉的圖片標題。",
        "apihelp-query+filearchive-param-limit": "要回傳的圖片總數。",
        "apihelp-query+filearchive-param-sha1": "圖片的 SHA1 雜湊值。覆蓋 $1sha1base36。",
        "apihelp-query+filearchive-param-prop": "要取得的圖片資訊:",
        "apihelp-query+filearchive-paramvalue-prop-sha1": "替圖片添加 SHA-1 雜湊值。",
+       "apihelp-query+filearchive-paramvalue-prop-timestamp": "添加上傳版本的時間戳記。",
+       "apihelp-query+filearchive-paramvalue-prop-user": "添加上傳該圖片版本的使用者。",
        "apihelp-query+filearchive-paramvalue-prop-description": "添加圖片版本的描述。",
        "apihelp-query+filearchive-paramvalue-prop-parseddescription": "解析版本的描述。",
        "apihelp-query+filearchive-paramvalue-prop-mime": "添加圖片的 MIME。",
        "apihelp-query+filearchive-paramvalue-prop-metadata": "列出圖片版本的 Exif 詮釋資料。",
        "apihelp-query+filearchive-paramvalue-prop-bitdepth": "添加版本的位元深度。",
        "apihelp-query+filearchive-example-simple": "顯示所有已刪除檔案的清單。",
+       "apihelp-query+filerepoinfo-paramvalue-prop-initialCapital": "檔案是否隱式地以大寫字母開頭。",
        "apihelp-query+filerepoinfo-paramvalue-prop-url": "公共區域 URL 路徑。",
+       "apihelp-query+fileusage-summary": "尋找使用到指定檔案的所有頁面。",
        "apihelp-query+fileusage-param-prop": "要取得的屬性。",
        "apihelp-query+fileusage-paramvalue-prop-pageid": "各頁面的頁面 ID。",
        "apihelp-query+fileusage-paramvalue-prop-title": "各頁面的標題。",
        "apihelp-query+fileusage-paramvalue-prop-redirect": "若頁面為重新導向,則做出標記。",
        "apihelp-query+fileusage-param-namespace": "僅包含這些命名空間的頁面。",
        "apihelp-query+fileusage-param-limit": "要回傳的數量。",
+       "apihelp-query+fileusage-param-show": "僅顯示符合這些準則的項目:\n;redirect:僅顯示重新導向。\n;!redirect:僅顯示非重新導向。",
+       "apihelp-query+fileusage-example-simple": "取得使用到 [[:File:Example.jpg]] 的頁面清單。",
+       "apihelp-query+fileusage-example-generator": "取得使用到 [[:File:Example.jpg]] 的頁面相關資訊。",
        "apihelp-query+imageinfo-summary": "回傳檔案資訊與上傳日誌。",
        "apihelp-query+imageinfo-param-prop": "要取得的檔案資訊:",
+       "apihelp-query+imageinfo-paramvalue-prop-timestamp": "添加上傳版本的時間戳記。",
+       "apihelp-query+imageinfo-paramvalue-prop-comment": "版本的註釋。",
+       "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "解析版本上的註釋。",
        "apihelp-query+imageinfo-paramvalue-prop-sha1": "替檔案添加 SHA-1 雜湊值。",
        "apihelp-query+imageinfo-paramvalue-prop-mime": "替檔案添加 MIME 類型。",
        "apihelp-query+imageinfo-paramvalue-prop-mediatype": "添加檔案的媒體類型。",
        "apihelp-query+imageinfo-param-limit": "每個檔案要回傳的檔案修訂數量。",
+       "apihelp-query+imageinfo-param-start": "列出的起始時間戳記。",
+       "apihelp-query+imageinfo-param-end": "列出的終止時間戳記。",
+       "apihelp-query+imageinfo-param-urlheight": "與 $1urlwidth 相似。",
        "apihelp-query+images-summary": "回傳指定頁面中包含的所有檔案。",
        "apihelp-query+images-param-limit": "要回傳的檔案數量。",
        "apihelp-query+images-param-dir": "列出時所採用的方向。",
        "apihelp-query+images-example-simple": "取得使用在 [[Main Page]] 的檔案清單。",
+       "apihelp-query+imageusage-summary": "尋找使用到指定圖片標題的所有頁面。",
+       "apihelp-query+imageusage-param-title": "要搜尋的標題。不能與 $1pageid 一起使用。",
+       "apihelp-query+imageusage-param-pageid": "要搜尋的頁面 ID。不能與 $1title 一起使用。",
        "apihelp-query+imageusage-param-namespace": "要列舉的命名空間。",
        "apihelp-query+imageusage-param-dir": "列出時所採用的方向。",
+       "apihelp-query+imageusage-example-simple": "顯示有使用 [[:File:Albert Einstein Head.jpg]] 的頁面。",
+       "apihelp-query+imageusage-example-generator": "取得關於有使用到 [[:File:Albert Einstein Head.jpg]] 的頁面資訊.",
        "apihelp-query+info-summary": "取得基本頁面訊息。",
        "apihelp-query+info-param-prop": "要取得的額外屬性:",
        "apihelp-query+info-paramvalue-prop-protection": "列出各頁面的保護層級。",
+       "apihelp-query+info-paramvalue-prop-watched": "列出各頁面的監視狀態。",
+       "apihelp-query+info-paramvalue-prop-watchers": "監視者的數目,如有允許的話。",
+       "apihelp-query+info-paramvalue-prop-visitingwatchers": "有訪問頁面近期編輯數的各頁面監視者數目,如有允許的話。",
        "apihelp-query+info-paramvalue-prop-readable": "使用者是否可閱讀此頁面。",
+       "apihelp-query+info-example-simple": "取得有關頁面 <kbd>Main Page</kbd> 的資訊。",
+       "apihelp-query+iwbacklinks-summary": "找出連結至指定跨 wiki 連結的所有頁面。",
+       "apihelp-query+iwbacklinks-param-prefix": "跨 wiki 前綴。",
+       "apihelp-query+iwbacklinks-param-limit": "要回傳的頁面總數。",
        "apihelp-query+iwbacklinks-param-prop": "要取得的屬性。",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "添加跨 wiki 前綴。",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "添加跨 wiki 標題。",
+       "apihelp-query+iwbacklinks-param-dir": "列出時所採用的方向。",
+       "apihelp-query+iwbacklinks-example-simple": "取得連結至 [[wikibooks:Test]] 的頁面。",
        "apihelp-query+iwlinks-summary": "回傳指定頁面的所有 interwiki 連結。",
+       "apihelp-query+iwlinks-param-url": "是否取得完整的 URL(不能與 $1prop 一同使用)。",
        "apihelp-query+iwlinks-paramvalue-prop-url": "添加完整的 URL。",
        "apihelp-query+iwlinks-param-limit": "要回傳的跨 Wiki 連結數量。",
+       "apihelp-query+iwlinks-param-prefix": "僅回傳帶有此前綴的跨 wiki 連結。",
        "apihelp-query+iwlinks-param-dir": "列出時所採用的方向。",
+       "apihelp-query+iwlinks-example-simple": "從頁面 <kbd>Main Page</kbd> 取得跨 wiki 連結。",
+       "apihelp-query+langbacklinks-summary": "找出連結至指定語言連結的所有頁面。",
+       "apihelp-query+langbacklinks-param-lang": "用於語言的語言連結。",
+       "apihelp-query+langbacklinks-param-title": "要搜尋的語言連結。必須與$1lang一同使用。",
        "apihelp-query+langbacklinks-param-limit": "要回傳的頁面總數。",
        "apihelp-query+langbacklinks-param-prop": "要取得的屬性。",
+       "apihelp-query+langbacklinks-paramvalue-prop-lllang": "添加用於語言連結的語言代碼。",
+       "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "添加語言連結標題。",
        "apihelp-query+langbacklinks-param-dir": "列出時所採用的方向。",
+       "apihelp-query+langbacklinks-example-simple": "取得連結至 [[:fr:Test]] 的頁面。",
+       "apihelp-query+langbacklinks-example-generator": "取得連結至 [[:fr:Test]] 的頁面相關資訊。",
        "apihelp-query+langlinks-summary": "回傳指定頁面的所有跨語言連結。",
        "apihelp-query+langlinks-param-limit": "要回傳的 langlinks 數量。",
+       "apihelp-query+langlinks-param-url": "是否取得完整的 URL(不能與 <var>$1prop</var> 一同使用)。",
        "apihelp-query+langlinks-paramvalue-prop-url": "添加完整的 URL。",
+       "apihelp-query+langlinks-paramvalue-prop-autonym": "添加本地語言名稱。",
+       "apihelp-query+langlinks-param-lang": "僅回傳帶有此語言代碼的語言連結。",
        "apihelp-query+langlinks-param-dir": "列出時所採用的方向。",
        "apihelp-query+langlinks-param-inlanguagecode": "用於本地化語言名稱的語言代碼。",
        "apihelp-query+links-summary": "回傳指定頁面的所有連結。",
+       "apihelp-query+links-param-namespace": "僅顯示在這些命名空間的連結。",
        "apihelp-query+links-param-limit": "要回傳的連結數量。",
+       "apihelp-query+links-param-dir": "列出時所採用的方向。",
+       "apihelp-query+links-example-simple": "從頁面 <kbd>Main Page</kbd> 取得連結。",
+       "apihelp-query+linkshere-summary": "找出連結至指定頁面的所有頁面。",
        "apihelp-query+linkshere-param-prop": "要取得的屬性。",
        "apihelp-query+linkshere-paramvalue-prop-pageid": "各頁面的頁面 ID。",
        "apihelp-query+linkshere-paramvalue-prop-title": "各頁面的標題。",
        "apihelp-query+linkshere-paramvalue-prop-redirect": "若頁面為重新導向,則做出標記。",
        "apihelp-query+linkshere-param-namespace": "僅包含這些命名空間的頁面。",
        "apihelp-query+linkshere-param-limit": "要回傳的數量。",
+       "apihelp-query+linkshere-param-show": "僅顯示符合這些準則的項目:\n;redirect:僅顯示重新導向。\n;!redirect:僅顯示非重新導向。",
+       "apihelp-query+linkshere-example-simple": "取得連結至 [[Main Page]] 的頁面清單。",
+       "apihelp-query+linkshere-example-generator": "取得連結至 [[Main Page]] 的相關頁面資訊。",
        "apihelp-query+logevents-summary": "從日誌中獲取事件。",
        "apihelp-query+logevents-param-prop": "要取得的屬性。",
+       "apihelp-query+logevents-paramvalue-prop-ids": "添加日誌事件的 ID。",
+       "apihelp-query+logevents-paramvalue-prop-title": "添加日誌事件的頁面標題。",
+       "apihelp-query+logevents-paramvalue-prop-type": "添加日誌事件的類型。",
+       "apihelp-query+logevents-param-type": "篩選僅為此類型的日誌項目。",
        "apihelp-query+logevents-param-start": "起始列舉的時間戳記。",
        "apihelp-query+logevents-param-end": "結束列舉的時間戳記。",
+       "apihelp-query+logevents-param-user": "篩選由指定使用者所產生出的項目。",
+       "apihelp-query+logevents-param-title": "篩選與這些頁面關聯的項目。",
+       "apihelp-query+logevents-param-namespace": "篩選在這些指定命名空間裡的項目。",
+       "apihelp-query+logevents-param-prefix": "篩選以此前綴為開頭的項目。",
+       "apihelp-query+logevents-param-tag": "僅列出以此標籤所標記的事件項目。",
        "apihelp-query+logevents-param-limit": "要回傳的事件項目總數。",
+       "apihelp-query+logevents-example-simple": "列出近期日誌事件。",
        "apihelp-query+pagepropnames-param-limit": "回傳的名稱數量上限。",
        "apihelp-query+pagepropnames-example-simple": "取得前 10 個屬性名稱。",
+       "apihelp-query+pageprops-example-simple": "取得頁面 <kbd>Main Page</kbd> 與 <kbd>MediaWiki</kbd> 的屬性。",
+       "apihelp-query+pageswithprop-summary": "列出使用到指定頁面屬性的所有頁面。",
+       "apihelp-query+pageswithprop-param-prop": "要包含到的資訊部份:",
        "apihelp-query+pageswithprop-paramvalue-prop-ids": "添加頁面 ID。",
+       "apihelp-query+pageswithprop-paramvalue-prop-title": "添加標題與頁面的命名空間 ID。",
+       "apihelp-query+pageswithprop-paramvalue-prop-value": "添加頁面屬性的值。",
        "apihelp-query+pageswithprop-param-limit": "回傳的頁面數量上限。",
        "apihelp-query+prefixsearch-param-search": "搜尋字串。",
        "apihelp-query+prefixsearch-param-namespace": "搜尋的命名空間。若 <var>$1search</var> 以有效的命名空間前綴為開頭則會被忽略。",
        "apihelp-query+prefixsearch-param-limit": "回傳的結果數量上限。",
        "apihelp-query+prefixsearch-param-offset": "要略過的結果數量。",
+       "apihelp-query+prefixsearch-example-simple": "搜尋開頭為 <kbd>meaning</kbd> 的頁面標題。",
        "apihelp-query+protectedtitles-param-namespace": "僅列出這些命名空間的標題。",
        "apihelp-query+protectedtitles-param-level": "僅列出具有這些保護層級的標題。",
        "apihelp-query+protectedtitles-param-limit": "要回傳的頁面總數。",
        "apihelp-query+protectedtitles-param-prop": "要取得的屬性。",
        "apihelp-query+protectedtitles-paramvalue-prop-level": "添加保護層級。",
        "apihelp-query+protectedtitles-example-simple": "列出已保護的標題。",
+       "apihelp-query+querypage-param-page": "特殊頁面的名稱。註:區分大小寫。",
        "apihelp-query+querypage-param-limit": "回傳的結果數量。",
        "apihelp-query+random-summary": "取得隨機頁面集合",
        "apihelp-query+random-param-namespace": "僅回傳在這些命名空間的頁面。",
        "apihelp-query+random-param-redirect": "請改用 <kbd>$1filterredir=redirects</kbd>。",
        "apihelp-query+random-param-filterredir": "如何過濾重新導向。",
+       "apihelp-query+random-example-simple": "從主命名空間回傳兩個隨機頁面。",
+       "apihelp-query+random-example-generator": "從主命名空間回傳兩個隨機頁面的相關頁面資訊。",
        "apihelp-query+recentchanges-summary": "列舉出最近變更。",
        "apihelp-query+recentchanges-param-start": "起始列舉的時間戳記。",
        "apihelp-query+recentchanges-param-end": "結束列舉的時間戳記。",
+       "apihelp-query+recentchanges-param-namespace": "篩選僅為這些命名空間的更改。",
        "apihelp-query+recentchanges-param-user": "此列出由該使用者作出的更改。",
        "apihelp-query+recentchanges-param-excludeuser": "不要列出由該使用者作出的更改。",
+       "apihelp-query+recentchanges-param-tag": "僅列出以此標籤所標記的更改。",
+       "apihelp-query+recentchanges-param-prop": "包含的額外資訊部份:",
        "apihelp-query+recentchanges-paramvalue-prop-flags": "添加編輯的標籤。",
        "apihelp-query+recentchanges-paramvalue-prop-timestamp": "添加編輯的時間戳記。",
        "apihelp-query+recentchanges-paramvalue-prop-title": "添加編輯的頁面標題。",
        "apihelp-query+recentchanges-paramvalue-prop-tags": "列出項目的標籤。",
        "apihelp-query+recentchanges-param-limit": "要回傳變更總數。",
-       "apihelp-query+recentchanges-param-type": "更改的顯示類型。",
+       "apihelp-query+recentchanges-param-type": "要顯示的更改類型。",
+       "apihelp-query+recentchanges-param-toponly": "僅列出最新修訂的更改。",
+       "apihelp-query+recentchanges-param-title": "篩選與這些頁面關聯的項目。",
        "apihelp-query+recentchanges-example-simple": "最近變更清單",
        "apihelp-query+redirects-summary": "回傳連結至指定頁面的所有重新導向。",
        "apihelp-query+redirects-param-prop": "要取得的屬性。",
        "apihelp-query+redirects-paramvalue-prop-pageid": "各重新導向的頁面 ID。",
        "apihelp-query+redirects-paramvalue-prop-title": "各重新導向的標題。",
+       "apihelp-query+redirects-paramvalue-prop-fragment": "各重新導向的片段,若有的話。",
        "apihelp-query+redirects-param-namespace": "僅包含這些命名空間的頁面。",
        "apihelp-query+redirects-param-limit": "要回傳的重新導向數量。",
+       "apihelp-query+redirects-example-simple": "取得 [[Main Page]] 的重新導向清單",
+       "apihelp-query+redirects-example-generator": "取得所有重新導向至 [[Main Page]] 的資訊。",
        "apihelp-query+revisions-summary": "取得修訂的資訊。",
+       "apihelp-query+revisions-param-user": "僅包含由使用者做出的修訂。",
+       "apihelp-query+revisions-param-excludeuser": "不包含由使用者做出的修訂。",
+       "apihelp-query+revisions-param-tag": "僅列出以此標籤所標記的修訂。",
        "apihelp-query+revisions-example-content": "取得用於標題 <kbd>API</kbd> 與 <kbd>Main Page</kbd> 最新修訂內容的資料。",
        "apihelp-query+revisions-example-last5": "取得 <kbd>Main Page</kbd> 的最近 5 筆修訂。",
        "apihelp-query+revisions-example-first5": "取得 <kbd>Main Page</kbd> 的最早前 5 筆修訂。",
        "apihelp-query+revisions-example-first5-not-localhost": "取得 <kbd>Main Page</kbd> 裡並非由匿名使用者 <kbd>127.0.0.1</kbd> 所做出的最早前 5 筆修訂。",
        "apihelp-query+revisions-example-first5-user": "取得 <kbd>Main Page</kbd> 裡由使用者 <kbd>MediaWiki default</kbd> 所做出的最早前 5 筆修訂。",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "修訂 ID。",
+       "apihelp-query+revisions+base-paramvalue-prop-flags": "修訂標籤(小修改)。",
+       "apihelp-query+revisions+base-paramvalue-prop-user": "做出修訂的使用者。",
+       "apihelp-query+revisions+base-paramvalue-prop-size": "修訂的長度(位元組)。",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "修訂標籤。",
        "apihelp-query+search-summary": "執行全文搜尋。",
        "apihelp-query+search-param-what": "要執行的搜尋類型。",
        "apihelp-query+search-paramvalue-prop-score": "已忽略",
        "apihelp-query+search-paramvalue-prop-hasrelated": "已忽略",
        "apihelp-query+search-param-limit": "要回傳的頁面總數。",
+       "apihelp-query+search-example-simple": "搜尋 <kbd>meaning</kbd>。",
+       "apihelp-query+search-example-text": "搜尋 <kbd>meaning</kbd> 的文字。",
+       "apihelp-query+siteinfo-param-prop": "要取得的資訊:",
        "apihelp-query+siteinfo-paramvalue-prop-general": "全面系統資訊。",
        "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "特殊頁面別名清單。",
        "apihelp-query+siteinfo-param-numberingroup": "列出在使用者群組裡的使用者數目。",
        "apihelp-query+siteinfo-example-simple": "索取站台資訊。",
        "apihelp-query+siteinfo-example-interwiki": "索取本地端跨 wiki 前綴的清單。",
+       "apihelp-query+siteinfo-example-replag": "檢查目前的響應延遲。",
        "apihelp-query+stashimageinfo-summary": "回傳多筆儲藏檔案的檔案資訊。",
        "apihelp-query+stashimageinfo-example-simple": "回傳儲藏檔案的檔案資訊。",
        "apihelp-query+tags-summary": "列出變更標記。",
        "apihelp-query+tags-paramvalue-prop-description": "添加標籤的描述。",
        "apihelp-query+tags-example-simple": "列出可用標籤。",
        "apihelp-query+templates-summary": "回傳指定頁面中所有引用的頁面。",
+       "apihelp-query+templates-param-namespace": "僅顯示在這些命名空間的模板。",
        "apihelp-query+templates-param-limit": "要回傳的模板數量。",
        "apihelp-query+templates-param-dir": "列出時所採用的方向。",
+       "apihelp-query+templates-example-simple": "取得在頁面 <kbd>Main Page</kbd> 使用到的模坂。",
        "apihelp-query+tokens-param-type": "要求的權杖類型。",
        "apihelp-query+tokens-example-simple": "接收 csrf 密鑰 (預設)。",
        "apihelp-query+tokens-example-types": "接收監視密鑰以及巡邏密鑰。",
        "apihelp-query+transcludedin-paramvalue-prop-pageid": "各頁面的頁面 ID。",
        "apihelp-query+transcludedin-paramvalue-prop-title": "各頁面的標題。",
        "apihelp-query+transcludedin-paramvalue-prop-redirect": "若頁面為重新導向,則做出標記。",
+       "apihelp-query+transcludedin-param-namespace": "僅包含這些命名空間的頁面。",
        "apihelp-query+transcludedin-param-limit": "回傳的數量。",
        "apihelp-query+usercontribs-summary": "按使用者來取得所有編輯。",
        "apihelp-query+usercontribs-param-limit": "回傳的貢獻數量上限。",
+       "apihelp-query+usercontribs-param-namespace": "僅列出這些命名空間的貢獻。",
+       "apihelp-query+usercontribs-param-prop": "包含的額外資訊部份:",
        "apihelp-query+usercontribs-paramvalue-prop-ids": "添加頁面 ID 與修訂 ID。",
        "apihelp-query+usercontribs-paramvalue-prop-title": "添加標題與頁面的命名空間 ID。",
        "apihelp-query+usercontribs-paramvalue-prop-timestamp": "添加編輯的時間戳記。",
        "apihelp-query+usercontribs-paramvalue-prop-comment": "添加編輯的註釋。",
        "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "添加編輯的已解析註解。",
        "apihelp-query+usercontribs-paramvalue-prop-size": "添加編輯的新大小。",
+       "apihelp-query+usercontribs-paramvalue-prop-tags": "列出編輯的標籤。",
+       "apihelp-query+usercontribs-example-user": "顯示使用者 <kbd>Example</kbd> 的貢獻。",
        "apihelp-query+userinfo-summary": "取得目前使用者的資訊。",
        "apihelp-query+userinfo-param-prop": "要包含的資訊部份:",
+       "apihelp-query+userinfo-paramvalue-prop-groups": "列出目前使用者所隸屬的所有群組。",
+       "apihelp-query+userinfo-paramvalue-prop-rights": "列出目前使用者所擁有的權限。",
+       "apihelp-query+userinfo-paramvalue-prop-options": "列出目前使用者已設定過的所有偏好設定。",
+       "apihelp-query+userinfo-paramvalue-prop-editcount": "添加目前使用者的編輯數。",
        "apihelp-query+userinfo-paramvalue-prop-realname": "添加使用者的真實姓名。",
        "apihelp-query+userinfo-paramvalue-prop-email": "添加使用者的電子郵件地址與電子郵件驗證日期。",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "添加使用者的註冊日期。",
        "apihelp-query+userinfo-example-data": "取得目前使用者的額外資訊。",
        "apihelp-query+users-summary": "取得有關使用者清單的資訊。",
        "apihelp-query+users-param-prop": "要包含的資訊部份:",
+       "apihelp-query+users-paramvalue-prop-rights": "列出各使用者所擁有的權限。",
+       "apihelp-query+users-paramvalue-prop-editcount": "添加使用者的編輯數。",
+       "apihelp-query+users-paramvalue-prop-registration": "添加使用者的註冊時間戳記。",
        "apihelp-query+watchlist-param-start": "起始列舉的時間戳記。",
        "apihelp-query+watchlist-param-end": "結束列舉的時間戳記。",
+       "apihelp-query+watchlist-param-user": "此列出由該使用者作出的更改。",
+       "apihelp-query+watchlist-param-excludeuser": "不要列出由該使用者作出的更改。",
        "apihelp-query+watchlist-param-limit": "每個請求要回傳的結果總數。",
+       "apihelp-query+watchlist-param-prop": "要取得的額外屬性:",
+       "apihelp-query+watchlist-paramvalue-prop-ids": "添加修訂 ID 與頁面 ID。",
        "apihelp-query+watchlist-paramvalue-prop-title": "添加頁面標題。",
        "apihelp-query+watchlist-paramvalue-prop-flags": "添加編輯的標籤。",
+       "apihelp-query+watchlist-paramvalue-prop-user": "添加有做出編輯的使用者。",
+       "apihelp-query+watchlist-paramvalue-prop-userid": "添加有做出編輯的使用者 ID。",
        "apihelp-query+watchlist-paramvalue-prop-tags": "列出項目的標籤。",
+       "apihelp-query+watchlist-param-type": "要顯示的更改類型:",
+       "apihelp-query+watchlist-paramvalue-type-edit": "一般頁面編輯。",
+       "apihelp-query+watchlist-paramvalue-type-external": "外部更改。",
        "apihelp-query+watchlist-paramvalue-type-new": "頁面建立。",
        "apihelp-query+watchlist-paramvalue-type-log": "日誌項目。",
        "apihelp-query+watchlist-paramvalue-type-categorize": "分類成員更改。",
+       "apihelp-query+watchlistraw-summary": "列出在目前使用者的監視清單裡頭所有頁面。",
+       "apihelp-query+watchlistraw-param-namespace": "僅列出在指定命名空間的頁面。",
        "apihelp-query+watchlistraw-param-limit": "每個請求要回傳的結果總數。",
+       "apihelp-query+watchlistraw-param-prop": "要取得的額外屬性:",
+       "apihelp-query+watchlistraw-param-show": "僅列出符合這些準則的項目。",
        "apihelp-query+watchlistraw-param-dir": "列出時所採用的方向。",
+       "apihelp-query+watchlistraw-example-simple": "列出在目前使用者的監視清單裡頭頁面。",
        "apihelp-removeauthenticationdata-summary": "為目前使用者移除身分核對資料。",
+       "apihelp-resetpassword-summary": "寄送重新設定密碼的電子郵件給使用者。",
+       "apihelp-resetpassword-example-user": "向使用者 <kbd>Example</kbd> 寄送重新設定密碼用的電子郵件。",
        "apihelp-revisiondelete-summary": "刪除和取消刪除修訂。",
+       "apihelp-revisiondelete-param-hide": "各修訂所要隱藏的內容。",
+       "apihelp-revisiondelete-param-show": "各修訂所要取消隱藏的內容。",
+       "apihelp-revisiondelete-param-reason": "刪除或取消刪除的原因。",
        "apihelp-rollback-summary": "撤修頁面的最後一次編輯。",
+       "apihelp-setnotificationtimestamp-param-entirewatchlist": "在所有已監視頁面運作。",
        "apihelp-setpagelanguage-summary": "更改頁面的語言。",
        "apihelp-setpagelanguage-param-reason": "變更的原因。",
+       "apihelp-setpagelanguage-example-language": "更改 <kbd>Main Page</kbd> 的語言成巴斯克語。",
        "apihelp-stashedit-param-title": "正在編輯此頁面的標題。",
        "apihelp-stashedit-param-text": "頁面內容。",
+       "apihelp-stashedit-param-contentmodel": "新內容的內容模組。",
+       "apihelp-stashedit-param-contentformat": "用於輸入文字的內容序列化格式。",
+       "apihelp-stashedit-param-baserevid": "基本修訂的修訂 ID。",
+       "apihelp-stashedit-param-summary": "更改摘要。",
+       "apihelp-tag-param-reason": "變更的原因。",
        "apihelp-tokens-summary": "取得資料修改動作的密鑰。",
        "apihelp-tokens-extended-description": "此模組已因支援 [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] 而停用。",
        "apihelp-unblock-summary": "解除封鎖一位使用者。",
        "apihelp-unblock-example-id": "解除封銷 ID #<kbd>105</kbd>。",
        "apihelp-undelete-param-title": "要恢復的頁面標題。",
        "apihelp-undelete-param-reason": "還原的原因。",
+       "apihelp-undelete-example-page": "取消刪除頁面 <kbd>Main Page</kbd>。",
+       "apihelp-undelete-example-revisions": "取消刪除 <kbd>Main Page</kbd> 的兩筆修訂。",
        "apihelp-upload-param-filename": "目標檔案名稱。",
        "apihelp-upload-param-comment": "上傳註釋。如果 <var>$1text</var> 未指定的話,也會作為新檔案用的初始頁面文字。",
+       "apihelp-upload-param-text": "用於新檔案的初始頁面文字。",
        "apihelp-upload-param-watch": "監視頁面。",
        "apihelp-upload-param-ignorewarnings": "忽略所有警告。",
        "apihelp-upload-param-file": "檔案內容。",
+       "apihelp-upload-param-url": "索取檔案的來源 URL。",
+       "apihelp-upload-param-chunk": "大量內容。",
+       "apihelp-upload-param-async": "在可能的情況下讓潛在的大型檔案非同步處理。",
        "apihelp-upload-example-url": "從 URL 上傳。",
        "apihelp-userrights-summary": "變更一位使用者的群組成員。",
        "apihelp-userrights-param-user": "使用者名稱。",
        "apihelp-userrights-param-remove": "從這些群組移除使用者。",
        "apihelp-userrights-param-reason": "變更的原因。",
        "apihelp-validatepassword-param-password": "要驗證的密碼。",
+       "apihelp-validatepassword-param-email": "電子郵件地址,用於當測試帳號建立時使用。",
+       "apihelp-validatepassword-param-realname": "真實姓名,用於當測試帳號建立時使用。",
        "apihelp-watch-example-watch": "監視頁面 <kbd>Main Page</kbd>。",
+       "apihelp-watch-example-unwatch": "取消監視頁面 <kbd>Main Page</kbd>。",
        "apihelp-format-example-generic": "以 $1 格式傳回查詢結果。",
        "apihelp-json-summary": "使用 JSON 格式輸出資料。",
        "apihelp-jsonfm-summary": "使用 JSON 格式輸出資料 (使用 HTML 格式顯示)。",
        "apihelp-phpfm-summary": "使用序列化 PHP 格式輸出資料 (使用 HTML 格式顯示)。",
        "apihelp-rawfm-summary": "使用 JSON 格式的除錯元素輸出資料 (使用 HTML 格式顯示)。",
        "apihelp-xml-summary": "使用 XML 格式輸出資料。",
+       "apihelp-xml-param-includexmlnamespace": "若有指定,添加一個 XML 命名空間。",
        "apihelp-xmlfm-summary": "使用 XML 格式輸出資料 (使用 HTML 格式顯示)。",
        "api-format-title": "MediaWiki API 結果",
        "api-format-prettyprint-header": "這是$1格式的HTML呈現。HTML適合用於除錯,但不適合應用程式使用。\n\n指定<var>format</var>參數以更改輸出格式。要檢視$1格式的非HTML呈現,設定<kbd>format=$2</kbd>。\n\n參考 [[mw:Special:MyLanguage/API|完整說明文件]] 或 [[Special:ApiHelp/main|API說明]] 以取得更多資訊。",
        "api-format-prettyprint-header-only-html": "這是用來除錯的HTML呈現,不適合實際應用。\n\n參見[[mw:Special:MyLanguage/API|完整文件]]或[[Special:ApiHelp/main|API幫助]]以取得更多資訊。",
        "api-format-prettyprint-header-hyperlinked": "這是$1格式的HTML實現。HTML對除錯很有用,但不適合應用程式使用。\n\n指定<var>format</var>參數以更改輸出格式。要查看$1格式的非HTML實現,設置[$3 <kbd>format=$2</kbd>]。\n\n參見[[mw:API|完整文件]],或[[Special:ApiHelp/main|API幫助]]以獲取更多信息。",
        "api-format-prettyprint-status": "此回應將會傳回HTTP狀態$1 $2。",
+       "api-login-fail-badsessionprovider": "當使用$1無法登入。",
        "api-pageset-param-titles": "要使用的標題清單。",
        "api-pageset-param-pageids": "要使用的頁面 ID 清單。",
        "api-pageset-param-revids": "要使用的修訂 ID 清單。",
        "api-help-title": "MediaWiki API 說明",
        "api-help-lead": "此頁為自動產生的 MediaWiki API 說明文件頁面。\n\n說明文件與範例:https://www.mediawiki.org/wiki/API",
        "api-help-main-header": "主要模組",
+       "api-help-undocumented-module": "沒有用於模組 $1 的說明文件。",
        "api-help-flag-deprecated": "此模組已停用。",
        "api-help-flag-internal": "<strong>此模組是內部的或不穩定的。</strong>它的操作可能更改而不另行通知。",
        "api-help-flag-readrights": "此模組需要讀取權限。",
        "api-help-param-direction": "列舉的方向:\n;newer:最舊的優先。注意:$1start應在$1end之前。\n;older:最新的優先(預設)。注意:$1start應在$1end之後。",
        "api-help-param-continue": "當有更多結果可用時,使用這個繼續。",
        "api-help-param-no-description": "<span class=\"apihelp-empty\">(無描述)</span>",
+       "api-help-param-maxbytes": "不能超過 $1 {{PLURAL:$1|位元組|位元組}}。",
+       "api-help-param-maxchars": "不能超過 $1 個{{PLURAL:$1|字元|字元}}。",
        "api-help-examples": "{{PLURAL:$1|範例}}:",
        "api-help-permissions": "{{PLURAL:$1|權限}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|已授權給}}: $2",
        "api-help-authmanagerhelper-returnurl": "為第三方身份驗證流程傳回URL,必須為絕對值。需要此值或<var>$1continue</var>兩者之一。\n\n在接收<samp>REDIRECT</samp>回應時,一般狀況下您將打開瀏覽器或網站瀏覽功能到特定的<samp>redirecttarget</samp> URL以進行第三方身份驗證流程。當它完成時,第三方會將瀏覽器或網站瀏覽功能送至此URL。您應當提取任何來自URL的查詢或POST參數,並將之作為<var>$1continue</var>請求傳遞至此API模組。",
        "api-help-authmanagerhelper-continue": "此請求是在先前的<samp>UI</samp>或<samp>REDIRECT</samp>回應之後的後續動作。必須為此值或<var>$1returnurl</var>。",
        "api-help-authmanagerhelper-additional-params": "此模組允許額外參數,取決於可用的身份驗證請求。使用<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd>与<kbd>amirequestsfor=$1</kbd>(或之前來自此模組的回應,如果合適)以決定可用請求及其使用的欄位。",
+       "apierror-articleexists": "您所嘗試建立的條目剛剛已被創建。",
+       "apierror-badgenerator-unknown": "未知的 <kbd>generator=$1</kbd>。",
        "apierror-badip": "IP 參數無效。",
        "apierror-badmd5": "提供的 MD5 雜湊不正確。",
        "apierror-badquery": "無效的查詢。",
+       "apierror-blockedfrommail": "您已被封鎖,無法發送電子郵件。",
+       "apierror-blocked": "您已被封鎖,無法編輯。",
+       "apierror-botsnotsupported": "此介面不支援機器人。",
+       "apierror-cannotviewtitle": "您不被允許檢視$1。",
+       "apierror-cantblock": "您沒有權限來解封使用者。",
+       "apierror-cantimport-upload": "您沒有權限來匯入已上傳頁面。",
+       "apierror-cantimport": "您沒有權限來匯入頁面。",
+       "apierror-changeauth-norequest": "建立更改請求失敗。",
+       "apierror-contentserializationexception": "內容序列化失敗:$1",
        "apierror-copyuploadbadurl": "不允許從此 URL 來上傳。",
+       "apierror-csp-report": "處理 CSP 報告時錯誤:$1。",
        "apierror-filedoesnotexist": "檔案不存在。",
        "apierror-filenopath": "無法取得本地端檔案路徑。",
        "apierror-filetypecannotberotated": "無法旋轉的檔案類型。",
        "apierror-imageusage-badtitle": "<kbd>$1</kbd>的標題必須是檔案。",
        "apierror-import-unknownerror": "未知的匯入錯誤:$1",
+       "apierror-invalidcategory": "您所輸入的分類名稱無效。",
+       "apierror-invalidparammix": "{{PLURAL:$2|參數}} $1 不能一起使用。",
+       "apierror-invalidsha1base36hash": "所提供的 SHA1Base36 雜湊無效。",
        "apierror-invalidsha1hash": "所提供的 SHA1 雜湊無效。",
+       "apierror-invalidtitle": "錯誤標題「$1」。",
        "apierror-invaliduser": "無效的使用者名稱「$1」。",
        "apierror-invaliduserid": "使用者 ID <var>$1</var> 無效。",
+       "apierror-missingcontent-pageid": "遺失頁面 ID 為 $1 的內容。",
+       "apierror-missingcontent-revid": "遺失修訂 ID 為 $1 的內容。",
        "apierror-missingparam": "<var>$1</var>參數必須被設定。",
+       "apierror-missingrev-pageid": "沒有頁面 ID 為 $1 的目前修訂。",
+       "apierror-missingrev-title": "沒有標題為$1的目前修訂。",
        "apierror-missingtitle": "您所指定的頁面不存在。",
+       "apierror-missingtitle-byname": "頁面$1不存在。",
        "apierror-mustbeloggedin-changeauth": "必須登入,才能變更身分核對資取。",
        "apierror-mustbeloggedin-generic": "您必須登入。",
        "apierror-mustbeloggedin-linkaccounts": "您必須登入到連結帳號。",
        "apierror-mustbeloggedin-removeauth": "必須登入,才能移除身分核對資取。",
+       "apierror-mustbeloggedin": "您必須登入才能$1。",
        "apierror-nodeleteablefile": "沒有這樣檔案的舊版本。",
        "apierror-noedit-anon": "匿名使用者不可編輯頁面。",
        "apierror-noedit": "您沒有權限來編輯頁面。",
        "apierror-permissiondenied": "您沒有權限$1。",
        "apierror-permissiondenied-generic": "權限不足。",
        "apierror-permissiondenied-unblock": "您沒有權限來解封使用者。",
+       "apierror-protect-invalidaction": "無效的保護類型「$1」。",
+       "apierror-protect-invalidlevel": "無效的保護層級「$1」。",
        "apierror-readapidenied": "您需要有閱讀權限來使用此模組。",
        "apierror-readonly": "Wiki 目前為唯讀模式。",
        "apierror-reauthenticate": "於本工作階段還未核對身分,請重新核對。",
+       "apierror-revwrongpage": "r$1 不是$2的修訂。",
        "apierror-searchdisabled": "<var>$1</var>搜尋已停用。",
+       "apierror-sizediffdisabled": "大小差異功能在 Miser 模式裡已停用。",
        "apierror-stashwrongowner": "錯誤擁有者:$1",
+       "apierror-systemblocked": "您已被 MediaWiki 給自動封鎖。",
        "apierror-timeout": "伺服器未有在預計的時間內回應。",
        "apierror-unknownerror-editpage": "不明編輯頁面錯誤:$1。",
        "apierror-unknownerror-nocode": "不明錯誤。",
        "apierror-unknownerror": "不明錯誤:\"$1\"。",
        "apierror-unknownformat": "無法識別的格式\"$1\"。",
+       "apierror-unrecognizedparams": "無法識別的{{PLURAL:$2|參數|參數}}:$1。",
        "apierror-upload-missingresult": "狀態資料裡沒有結果。",
        "apiwarn-deprecation-httpsexpected": "當應為 HTTPS 時,HTTP 要被使用。",
        "apiwarn-invalidcategory": "「$1」不是一個分類。",
index 4f84b4c..01d992f 100644 (file)
@@ -199,33 +199,3 @@ class AuthManagerAuthPlugin extends \AuthPlugin {
                return [];
        }
 }
-
-/**
- * @since 1.27
- * @deprecated since 1.27
- */
-class AuthManagerAuthPluginUser extends \AuthPluginUser {
-       /** @var User */
-       private $user;
-
-       function __construct( $user ) {
-               $this->user = $user;
-       }
-
-       public function getId() {
-               return $this->user->getId();
-       }
-
-       public function isLocked() {
-               return $this->user->isLocked();
-       }
-
-       public function isHidden() {
-               return $this->user->isHidden();
-       }
-
-       public function resetAuthToken() {
-               \MediaWiki\Session\SessionManager::singleton()->invalidateSessionsForUser( $this->user );
-               return true;
-       }
-}
diff --git a/includes/auth/AuthManagerAuthPluginUser.php b/includes/auth/AuthManagerAuthPluginUser.php
new file mode 100644 (file)
index 0000000..e31be60
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Auth;
+
+use User;
+
+/**
+ * @since 1.27
+ * @deprecated since 1.27
+ */
+class AuthManagerAuthPluginUser extends \AuthPluginUser {
+       /** @var User */
+       private $user;
+
+       function __construct( $user ) {
+               $this->user = $user;
+       }
+
+       public function getId() {
+               return $this->user->getId();
+       }
+
+       public function isLocked() {
+               return $this->user->isLocked();
+       }
+
+       public function isHidden() {
+               return $this->user->isHidden();
+       }
+
+       public function resetAuthToken() {
+               \MediaWiki\Session\SessionManager::singleton()->invalidateSessionsForUser( $this->user );
+               return true;
+       }
+}
index 38700b8..3b6da73 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use Wikimedia\StaticArrayWriter;
+
 /**
  * @since 1.26
  */
@@ -84,9 +86,7 @@ class LCStoreStaticArray implements LCStore {
                }
                if ( is_array( $value ) ) {
                        // [A]rray
-                       return [ 'a', array_map( function ( $v ) {
-                               return LCStoreStaticArray::encode( $v );
-                       }, $value ) ];
+                       return [ 'a', array_map( 'LCStoreStaticArray::encode', $value ) ];
                }
 
                throw new RuntimeException( 'Cannot encode ' . var_export( $value, true ) );
@@ -109,9 +109,7 @@ class LCStoreStaticArray implements LCStore {
                        case 's':
                                return unserialize( $data );
                        case 'a':
-                               return array_map( function ( $v ) {
-                                       return LCStoreStaticArray::decode( $v );
-                               }, $data );
+                               return array_map( 'LCStoreStaticArray::decode', $data );
                        default:
                                throw new RuntimeException(
                                        'Unable to decode ' . var_export( $encoded, true ) );
@@ -119,13 +117,12 @@ class LCStoreStaticArray implements LCStore {
        }
 
        public function finishWrite() {
-               file_put_contents(
-                       $this->fname,
-                       "<?php\n" .
-                       "// Generated by LCStoreStaticArray.php -- do not edit!\n" .
-                       "return " .
-                       var_export( $this->data[$this->currentLang], true ) . ';'
+               $writer = new StaticArrayWriter();
+               $out = $writer->create(
+                       $this->data[$this->currentLang],
+                       'Generated by LCStoreStaticArray.php -- do not edit!'
                );
+               file_put_contents( $this->fname, $out );
                $this->currentLang = null;
                $this->fname = null;
        }
index dd29c10..0bb8484 100644 (file)
@@ -342,11 +342,10 @@ class ChangeTags {
                }
 
                // insert a row into change_tag for each new tag
+               $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
                if ( count( $tagsToAdd ) ) {
                        $changeTagMapping = [];
                        if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) {
-                               $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
-
                                foreach ( $tagsToAdd as $tag ) {
                                        $changeTagMapping[$tag] = $changeTagDefStore->acquireId( $tag );
                                }
@@ -361,13 +360,18 @@ class ChangeTags {
 
                        $tagsRows = [];
                        foreach ( $tagsToAdd as $tag ) {
+                               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                                       $tagName = null;
+                               } else {
+                                       $tagName = $tag;
+                               }
                                // Filter so we don't insert NULLs as zero accidentally.
                                // Keep in mind that $rc_id === null means "I don't care/know about the
                                // rc_id, just delete $tag on this revision/log entry". It doesn't
                                // mean "only delete tags on this revision/log WHERE rc_id IS NULL".
                                $tagsRows[] = array_filter(
                                        [
-                                               'ct_tag' => $tag,
+                                               'ct_tag' => $tagName,
                                                'ct_rc_id' => $rc_id,
                                                'ct_log_id' => $log_id,
                                                'ct_rev_id' => $rev_id,
@@ -384,12 +388,20 @@ class ChangeTags {
                // delete from change_tag
                if ( count( $tagsToRemove ) ) {
                        foreach ( $tagsToRemove as $tag ) {
+                               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                                       $tagName = null;
+                                       $tagId = $changeTagDefStore->getId( $tag );
+                               } else {
+                                       $tagName = $tag;
+                                       $tagId = null;
+                               }
                                $conds = array_filter(
                                        [
-                                               'ct_tag' => $tag,
+                                               'ct_tag' => $tagName,
                                                'ct_rc_id' => $rc_id,
                                                'ct_log_id' => $log_id,
-                                               'ct_rev_id' => $rev_id
+                                               'ct_rev_id' => $rev_id,
+                                               'ct_tag_id' => $tagId,
                                        ]
                                );
                                $dbw->delete( 'change_tag', $conds, __METHOD__ );
@@ -769,7 +781,7 @@ class ChangeTags {
        public static function modifyDisplayQuery( &$tables, &$fields, &$conds,
                &$join_conds, &$options, $filter_tag = ''
        ) {
-               global $wgUseTagFilter;
+               global $wgUseTagFilter, $wgChangeTagsSchemaMigrationStage;
 
                // Normalize to arrays
                $tables = (array)$tables;
@@ -790,8 +802,16 @@ class ChangeTags {
                        throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' );
                }
 
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tables[] = 'change_tag_def';
+                       $join_cond = [ $join_cond, 'ct_tag_id=ctd_id' ];
+                       $field = 'ctd_name';
+               } else {
+                       $field = 'ct_tag';
+               }
+
                $fields['ts_tags'] = wfGetDB( DB_REPLICA )->buildGroupConcatField(
-                       ',', 'change_tag', 'ct_tag', $join_cond
+                       ',', 'change_tag', $field, $join_cond
                );
 
                if ( $wgUseTagFilter && $filter_tag ) {
@@ -800,7 +820,14 @@ class ChangeTags {
 
                        $tables[] = 'change_tag';
                        $join_conds['change_tag'] = [ 'INNER JOIN', $join_cond ];
-                       $conds['ct_tag'] = $filter_tag;
+                       if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                               $tables[] = 'change_tag_def';
+                               $join_conds['change_tag_def'] = [ 'INNER JOIN', 'ct_tag_id=ctd_id' ];
+                               $conds['ctd_name'] = $filter_tag;
+                       } else {
+                               $conds['ct_tag'] = $filter_tag;
+                       }
+
                        if (
                                is_array( $filter_tag ) && count( $filter_tag ) > 1 &&
                                !in_array( 'DISTINCT', $options )
@@ -1236,10 +1263,17 @@ class ChangeTags {
                // delete from valid_tag and/or set ctd_user_defined = 0
                self::undefineTag( $tag );
 
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag );
+                       $conditions = [ 'ct_tag_id' => $tagId ];
+               } else {
+                       $conditions = [ 'ct_tag' => $tag ];
+               }
+
                // find out which revisions use this tag, so we can delete from tag_summary
                $result = $dbw->select( 'change_tag',
-                       [ 'ct_rc_id', 'ct_log_id', 'ct_rev_id', 'ct_tag' ],
-                       [ 'ct_tag' => $tag ],
+                       [ 'ct_rc_id', 'ct_log_id', 'ct_rev_id' ],
+                       $conditions,
                        __METHOD__ );
                foreach ( $result as $row ) {
                        // remove the tag from the relevant row of tag_summary
@@ -1250,7 +1284,12 @@ class ChangeTags {
                }
 
                // delete from change_tag
-               $dbw->delete( 'change_tag', [ 'ct_tag' => $tag ], __METHOD__ );
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag );
+                       $dbw->delete( 'change_tag', [ 'ct_tag_id' => $tagId ], __METHOD__ );
+               } else {
+                       $dbw->delete( 'change_tag', [ 'ct_tag' => $tag ], __METHOD__ );
+               }
 
                if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) {
                        $dbw->delete( 'change_tag_def', [ 'ctd_name' => $tag ], __METHOD__ );
index b6211b0..733d85a 100644 (file)
@@ -505,6 +505,7 @@ abstract class AbstractContent implements Content {
                }
 
                $po = new ParserOutput();
+               $options->registerWatcher( [ $po, 'recordOption' ] );
 
                if ( Hooks::run( 'ContentGetParserOutput',
                        [ $this, $title, $revId, $options, $generateHtml, &$po ] )
@@ -518,6 +519,7 @@ abstract class AbstractContent implements Content {
                }
 
                Hooks::run( 'ContentAlterParserOutput', [ $this, $title, $po ] );
+               $options->registerWatcher( null );
 
                return $po;
        }
index b3286a9..344d040 100644 (file)
@@ -1,9 +1,4 @@
 <?php
-
-use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\MediaWikiServices;
-use MediaWiki\Search\ParserOutputSearchDataExtractor;
-
 /**
  * Base class for content handling.
  *
@@ -29,6 +24,12 @@ use MediaWiki\Search\ParserOutputSearchDataExtractor;
  *
  * @author Daniel Kinzler
  */
+
+use Wikimedia\Assert\Assert;
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Search\ParserOutputSearchDataExtractor;
+
 /**
  * A content handler knows how do deal with a specific type of content on a wiki
  * page. Content is stored in the database in a serialized form (using a
@@ -664,7 +665,7 @@ abstract class ContentHandler {
                        $differenceEngine = $this->createDifferenceEngine( $context );
                        if ( get_class( $differenceEngine ) !== DifferenceEngine::class ) {
                                // TODO turn this into a deprecation warning in a later release
-                               LoggerFactory::getInstance( 'diff' )->notice(
+                               LoggerFactory::getInstance( 'diff' )->info(
                                        'Falling back to DifferenceEngineSlotDiffRenderer', [
                                                'modelID' => $this->getModelID(),
                                                'DifferenceEngine' => get_class( $differenceEngine ),
@@ -1129,31 +1130,52 @@ abstract class ContentHandler {
         * must exist and must not be deleted.
         *
         * @since 1.21
+        * @since 1.32 accepts Content objects for all parameters instead of Revision objects.
+        *  Passing Revision objects is deprecated.
         *
-        * @param Revision $current The current text
-        * @param Revision $undo The revision to undo
-        * @param Revision $undoafter Must be an earlier revision than $undo
+        * @param Revision|Content $current The current text
+        * @param Revision|Content $undo The content of the revision to undo
+        * @param Revision|Content $undoafter Must be from an earlier revision than $undo
+        * @param bool $undoIsLatest Set true if $undo is from the current revision (since 1.32)
         *
         * @return mixed Content on success, false on failure
         */
-       public function getUndoContent( Revision $current, Revision $undo, Revision $undoafter ) {
-               $cur_content = $current->getContent();
+       public function getUndoContent( $current, $undo, $undoafter, $undoIsLatest = false ) {
+               Assert::parameterType( Revision::class . '|' . Content::class, $current, '$current' );
+               if ( $current instanceof Content ) {
+                       Assert::parameter( $undo instanceof Content, '$undo',
+                               'Must be Content when $current is Content' );
+                       Assert::parameter( $undoafter instanceof Content, '$undoafter',
+                               'Must be Content when $current is Content' );
+                       $cur_content = $current;
+                       $undo_content = $undo;
+                       $undoafter_content = $undoafter;
+               } else {
+                       Assert::parameter( $undo instanceof Revision, '$undo',
+                               'Must be Revision when $current is Revision' );
+                       Assert::parameter( $undoafter instanceof Revision, '$undoafter',
+                               'Must be Revision when $current is Revision' );
 
-               if ( empty( $cur_content ) ) {
-                       return false; // no page
-               }
+                       $cur_content = $current->getContent();
 
-               $undo_content = $undo->getContent();
-               $undoafter_content = $undoafter->getContent();
+                       if ( empty( $cur_content ) ) {
+                               return false; // no page
+                       }
+
+                       $undo_content = $undo->getContent();
+                       $undoafter_content = $undoafter->getContent();
+
+                       if ( !$undo_content || !$undoafter_content ) {
+                               return false; // no content to undo
+                       }
 
-               if ( !$undo_content || !$undoafter_content ) {
-                       return false; // no content to undo
+                       $undoIsLatest = $current->getId() === $undo->getId();
                }
 
                try {
                        $this->checkModelID( $cur_content->getModel() );
                        $this->checkModelID( $undo_content->getModel() );
-                       if ( $current->getId() !== $undo->getId() ) {
+                       if ( !$undoIsLatest ) {
                                // If we are undoing the most recent revision,
                                // its ok to revert content model changes. However
                                // if we are undoing a revision in the middle, then
index 20bce37..0198a0d 100644 (file)
@@ -253,6 +253,7 @@ class TextContent extends AbstractContent {
                        $html = '';
                }
 
+               $output->clearWrapperDivClass();
                $output->setText( $html );
        }
 
index acf6fcb..9817c3f 100644 (file)
@@ -296,6 +296,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
        public function msg( $key ) {
                $args = func_get_args();
 
+               // phpcs:ignore MediaWiki.Usage.ExtendClassUsage.FunctionVarUsage
                return wfMessage( ...$args )->setContext( $this );
        }
 }
index 1564fab..5f09555 100644 (file)
@@ -52,6 +52,9 @@ class CloneDatabase {
        public function __construct( IMaintainableDatabase $db, array $tablesToClone,
                $newTablePrefix, $oldTablePrefix = null, $dropCurrentTables = true
        ) {
+               if ( !$tablesToClone ) {
+                       throw new InvalidArgumentException( 'Empty list of tables to clone' );
+               }
                $this->db = $db;
                $this->tablesToClone = $tablesToClone;
                $this->newTablePrefix = $newTablePrefix;
index f370e43..5ab83c6 100644 (file)
@@ -71,6 +71,9 @@ class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate {
                        // Make sure all links update threads see the changes of each other.
                        // This handles the case when updates have to batched into several COMMITs.
                        $scopedLock = LinksUpdate::acquirePageLock( $this->getDB(), $id );
+                       if ( !$scopedLock ) {
+                               throw new RuntimeException( "Could not acquire lock for page ID '{$id}'." );
+                       }
                }
 
                $title = $this->page->getTitle();
index 5b1be6d..dbe387b 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use Wikimedia\Rdbms\IDatabase;
+use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
 use Wikimedia\ScopedCallback;
 
@@ -163,6 +164,9 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                        // Make sure all links update threads see the changes of each other.
                        // This handles the case when updates have to batched into several COMMITs.
                        $scopedLock = self::acquirePageLock( $this->getDB(), $this->mId );
+                       if ( !$scopedLock ) {
+                               throw new RuntimeException( "Could not acquire lock for page ID '{$this->mId}'." );
+                       }
                }
 
                // Avoid PHP 7.1 warning from passing $this by reference
@@ -190,15 +194,19 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
         * @param IDatabase $dbw
         * @param int $pageId
         * @param string $why One of (job, atomicity)
-        * @return ScopedCallback
-        * @throws RuntimeException
+        * @return ScopedCallback|null
         * @since 1.27
         */
        public static function acquirePageLock( IDatabase $dbw, $pageId, $why = 'atomicity' ) {
                $key = "LinksUpdate:$why:pageid:$pageId";
                $scopedLock = $dbw->getScopedLockAndFlush( $key, __METHOD__, 15 );
                if ( !$scopedLock ) {
-                       throw new RuntimeException( "Could not acquire lock '$key'." );
+                       $logger = LoggerFactory::getInstance( 'SecondaryDataUpdate' );
+                       $logger->info( "Could not acquire lock '{key}' for page ID '{page_id}'.", [
+                               'key' => $key,
+                               'page_id' => $pageId,
+                       ] );
+                       return null;
                }
 
                return $scopedLock;
index 2ceda21..0254458 100644 (file)
@@ -57,29 +57,41 @@ class DifferenceEngine extends ContextSource {
         */
        const DIFF_VERSION = '1.12';
 
-       /** @var int Revision ID or 0 for current */
+       /**
+        * Revision ID for the old revision. 0 for the revision previous to $mNewid, false
+        * if the diff does not have an old revision (e.g. 'oldid=<first revision of page>&diff=prev'),
+        * or the revision does not exist, null if the revision is unsaved.
+        * @var int|false|null
+        */
        protected $mOldid;
 
-       /** @var int|string Revision ID or null for current or an alias such as 'next' */
+       /**
+        * Revision ID for the new revision. 0 for the last revision of the current page
+        * (as defined by the request context), false if the revision does not exist, null
+        * if it is unsaved, or an alias such as 'next'.
+        * @var int|string|false|null
+        */
        protected $mNewid;
 
-       private $mOldTags;
-       private $mNewTags;
-
        /**
         * Old revision (left pane).
         * Allowed to be an unsaved revision, unlikely that's ever needed though.
-        * Null when the old revision does not exist; this can happen when using
-        * diff=prev on the first revision.
+        * False when the old revision does not exist; this can happen when using
+        * diff=prev on the first revision. Null when the revision should exist but
+        * doesn't (e.g. load failure); loadRevisionData() will return false in that
+        * case. Also null until lazy-loaded. Ignored completely when isContentOverridden
+        * is set.
         * Since 1.32 public access is deprecated.
-        * @var Revision|null
+        * @var Revision|null|false
         */
        protected $mOldRev;
 
        /**
         * New revision (right pane).
         * Note that this might be an unsaved revision (e.g. for edit preview).
-        * Null only in case of load failure; diff methods will just return an error message in that case.
+        * Null in case of load failure; diff methods will just return an error message in that case,
+        * and loadRevisionData() will return false. Also null until lazy-loaded. Ignored completely
+        * when isContentOverridden is set.
         * Since 1.32 public access is deprecated.
         * @var Revision|null
         */
@@ -99,6 +111,18 @@ class DifferenceEngine extends ContextSource {
         */
        protected $mNewPage;
 
+       /**
+        * Change tags of $mOldRev or null if it does not exist / is not saved.
+        * @var string[]|null
+        */
+       private $mOldTags;
+
+       /**
+        * Change tags of $mNewRev or null if it does not exist / is not saved.
+        * @var string[]|null
+        */
+       private $mNewTags;
+
        /**
         * @var Content|null
         * @deprecated since 1.32, content slots are now handled by the corresponding SlotDiffRenderer.
@@ -244,7 +268,7 @@ class DifferenceEngine extends ContextSource {
        /**
         * Get the old and new content objects for all slots.
         * This method does not do any permission checks.
-        * @return array [ role => [ 'old' => SlotRecord, 'new' => SlotRecord ], ... ]
+        * @return array [ role => [ 'old' => SlotRecord|null, 'new' => SlotRecord|null ], ... ]
         */
        protected function getSlotContents() {
                if ( $this->isContentOverridden ) {
@@ -254,16 +278,21 @@ class DifferenceEngine extends ContextSource {
                                        'new' => $this->mNewContent,
                                ]
                        ];
+               } elseif ( !$this->loadRevisionData() ) {
+                       return [];
                }
 
-               $oldRev = $this->mOldRev->getRevisionRecord();
-               $newRev = $this->mNewRev->getRevisionRecord();
+               $newSlots = $this->mNewRev->getRevisionRecord()->getSlots()->getSlots();
+               if ( $this->mOldRev ) {
+                       $oldSlots = $this->mOldRev->getRevisionRecord()->getSlots()->getSlots();
+               } else {
+                       $oldSlots = [];
+               }
                // The order here will determine the visual order of the diff. The current logic is
-               // changed first, then added, then deleted. This is ad hoc and should not be relied on
-               // - in the future we may want the ordering to depend on the page type.
-               $roles = array_merge( $newRev->getSlotRoles(), $oldRev->getSlotRoles() );
-               $oldSlots = $oldRev->getSlots()->getSlots();
-               $newSlots = $newRev->getSlots()->getSlots();
+               // slots of the new revision first in natural order, then deleted ones. This is ad hoc
+               // and should not be relied on - in the future we may want the ordering to depend
+               // on the page type.
+               $roles = array_merge( array_keys( $newSlots ), array_keys( $oldSlots ) );
 
                $slots = [];
                foreach ( $roles as $role ) {
@@ -311,7 +340,11 @@ class DifferenceEngine extends ContextSource {
        }
 
        /**
-        * @return int
+        * Get the ID of old revision (left pane) of the diff. 0 for the revision
+        * previous to getNewid(), false if the old revision does not exist, null
+        * if it's unsaved.
+        * To get a real revision ID instead of 0, call loadRevisionData() first.
+        * @return int|false|null
         */
        public function getOldid() {
                $this->loadRevisionIds();
@@ -320,7 +353,10 @@ class DifferenceEngine extends ContextSource {
        }
 
        /**
-        * @return bool|int
+        * Get the ID of new revision (right pane) of the diff. 0 for the current revision,
+        * false if the new revision does not exist, null if it's unsaved.
+        * To get a real revision ID instead of 0, call loadRevisionData() first.
+        * @return int|false|null
         */
        public function getNewid() {
                $this->loadRevisionIds();
@@ -1014,6 +1050,34 @@ class DifferenceEngine extends ContextSource {
                return $difftext;
        }
 
+       /**
+        * Get the diff table body for one slot, without header
+        *
+        * @param string $role
+        * @return string|false
+        */
+       public function getDiffBodyForRole( $role ) {
+               $diffRenderers = $this->getSlotDiffRenderers();
+               if ( !isset( $diffRenderers[$role] ) ) {
+                       return false;
+               }
+
+               $slotContents = $this->getSlotContents();
+               $slotDiff = $diffRenderers[$role]->getDiff( $slotContents[$role]['old'],
+                       $slotContents[$role]['new'] );
+               if ( !$slotDiff ) {
+                       return false;
+               }
+
+               if ( $role !== 'main' ) {
+                       // TODO use human-readable role name at least
+                       $slotTitle = $role;
+                       $slotDiff = $this->getSlotHeader( $slotTitle ) . $slotDiff;
+               }
+
+               return $this->localiseDiff( $slotDiff );
+       }
+
        /**
         * Get a slot header for inclusion in a diff body (as a table row).
         *
@@ -1548,7 +1612,8 @@ class DifferenceEngine extends ContextSource {
                        $this->mOldContent = $oldRevision ? $oldRevision->getContent( 'main',
                                RevisionRecord::FOR_THIS_USER, $this->getUser() ) : null;
                } else {
-                       $this->mOldRev = $this->mOldid = $this->mOldPage = null;
+                       $this->mOldPage = null;
+                       $this->mOldRev = $this->mOldid = false;
                }
                $this->mNewRev = new Revision( $newRevision );
                $this->mNewid = $newRevision->getId();
@@ -1582,7 +1647,7 @@ class DifferenceEngine extends ContextSource {
         * @param int $old Revision id, e.g. from URL parameter 'oldid'
         * @param int|string $new Revision id or strings 'next' or 'prev', e.g. from URL parameter 'diff'
         *
-        * @return int[] List of two revision ids, older first, later second.
+        * @return array List of two revision ids, older first, later second.
         *     Zero signifies invalid argument passed.
         *     false signifies that there is no previous/next revision ($old is the oldest/newest one).
         */
@@ -1630,20 +1695,21 @@ class DifferenceEngine extends ContextSource {
        }
 
        /**
-        * Load revision metadata for the specified articles. If newid is 0, then compare
-        * the old article in oldid to the current article; if oldid is 0, then
-        * compare the current article to the immediately previous one (ignoring the
-        * value of newid).
+        * Load revision metadata for the specified revisions. If newid is 0, then compare
+        * the old revision in oldid to the current revision of the current page (as defined
+        * by the request context); if oldid is 0, then compare the revision in newid to the
+        * immediately previous one.
         *
         * If oldid is false, leave the corresponding revision object set
-        * to false. This is impossible via ordinary user input, and is provided for
-        * API convenience.
+        * to false. This can happen with 'diff=prev' pointing to a non-existent revision,
+        * and is also used directly by the API.
         *
-        * @return bool Whether both revisions were loaded successfully.
+        * @return bool Whether both revisions were loaded successfully. Setting mOldRev
+        *   to false counts as successful loading.
         */
        public function loadRevisionData() {
                if ( $this->mRevisionsLoaded ) {
-                       return $this->isContentOverridden || $this->mNewRev && $this->mOldRev;
+                       return $this->isContentOverridden || $this->mNewRev && !is_null( $this->mOldRev );
                }
 
                // Whether it succeeds or fails, we don't want to try again
@@ -1724,12 +1790,16 @@ class DifferenceEngine extends ContextSource {
 
        /**
         * Load the text of the revisions, as well as revision data.
+        * When the old revision is missing (mOldRev is false), loading mOldContent is not attempted.
         *
         * @return bool Whether the content of both revisions could be loaded successfully.
+        *   (When mOldRev is false, that still counts as a success.)
+        *
         */
        public function loadText() {
                if ( $this->mTextLoaded == 2 ) {
-                       return $this->loadRevisionData() && $this->mOldContent && $this->mNewContent;
+                       return $this->loadRevisionData() && ( $this->mOldRev === false || $this->mOldContent )
+                               && $this->mNewContent;
                }
 
                // Whether it succeeds or fails, we don't want to try again
@@ -1746,12 +1816,10 @@ class DifferenceEngine extends ContextSource {
                        }
                }
 
-               if ( $this->mNewRev ) {
-                       $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                       Hooks::run( 'DifferenceEngineLoadTextAfterNewContentIsLoaded', [ $this ] );
-                       if ( $this->mNewContent === null ) {
-                               return false;
-                       }
+               $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
+               Hooks::run( 'DifferenceEngineLoadTextAfterNewContentIsLoaded', [ $this ] );
+               if ( $this->mNewContent === null ) {
+                       return false;
                }
 
                return true;
index baedcf0..9c60705 100644 (file)
@@ -209,7 +209,8 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
                        $wikidiff2Version = phpversion( 'wikidiff2' );
                        if (
                                $wikidiff2Version !== false &&
-                               version_compare( $wikidiff2Version, '1.5.0', '>=' )
+                               version_compare( $wikidiff2Version, '1.5.0', '>=' ) &&
+                               version_compare( $wikidiff2Version, '1.8.0', '<' )
                        ) {
                                $text = wikidiff2_do_diff(
                                        $oldText,
@@ -218,7 +219,7 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
                                        $this->wikiDiff2MovedParagraphDetectionCutoff
                                );
                        } else {
-                               // Don't pass the 4th parameter for compatibility with older versions of wikidiff2
+                               // Don't pass the 4th parameter introduced in version 1.5.0 and removed in version 1.8.0
                                $text = wikidiff2_do_diff(
                                        $oldText,
                                        $newText,
index 0fa0406..52a18eb 100644 (file)
@@ -57,10 +57,12 @@ use Wikimedia\ObjectFactory;
  *    'cssclass'            -- CSS class
  *    'csshelpclass'        -- CSS class used to style help text
  *    'dir'                 -- Direction of the element.
- *    'options'             -- associative array mapping labels to values.
+ *    'options'             -- associative array mapping raw text labels to values.
  *                             Some field types support multi-level arrays.
+ *                             Overwrites 'options-message'.
  *    'options-messages'    -- associative array mapping message keys to values.
  *                             Some field types support multi-level arrays.
+ *                             Overwrites 'options' and 'options-message'.
  *    'options-message'     -- message key or object to be parsed to extract the list of
  *                             options (like 'ipbreason-dropdown').
  *    'label-message'       -- message key or object for a message to use as the label.
@@ -79,11 +81,9 @@ use Wikimedia\ObjectFactory;
  *    'help-inline'         -- Whether help text (defined using options above) will be shown
  *                             inline after the input field, rather than in a popup.
  *                             Defaults to true. Only used by OOUI form fields.
- *    'notice'              -- message text for a message to use as a notice in the field.
- *                             Currently used by OOUI form fields only.
- *    'notice-messages'     -- array of message keys/objects to use for notice.
- *                             Overrides 'notice'.
- *    'notice-message'      -- message key or object to use as a notice.
+ *    'notice'              -- (deprecated, use 'help' instead)
+ *    'notice-messages'     -- (deprecated, use 'help-messages' instead)
+ *    'notice-message'      -- (deprecated, use 'help-message' instead)
  *    'required'            -- passed through to the object, indicating that it
  *                             is a required field.
  *    'size'                -- the length of text fields
@@ -1029,6 +1029,7 @@ class HTMLForm extends ContextSource {
         * @param bool|string|array|Status $submitResult Output from HTMLForm::trySubmit()
         *
         * @return string HTML
+        * @return-taint escaped
         */
        public function getHTML( $submitResult ) {
                # For good measure (it is the default)
@@ -1832,7 +1833,7 @@ class HTMLForm extends ContextSource {
         *
         * @param string $key
         *
-        * @return string
+        * @return string Plain text (not HTML-escaped)
         */
        public function getLegend( $key ) {
                return $this->msg( "{$this->mMessagePrefix}-$key" )->text();
index f5d6e8c..8902995 100644 (file)
@@ -462,6 +462,16 @@ abstract class HTMLFormField {
                if ( isset( $params['hide-if'] ) ) {
                        $this->mHideIf = $params['hide-if'];
                }
+
+               if ( isset( $this->mParams['notice-message'] ) ) {
+                       wfDeprecated( "'notice-message' parameter in HTMLForm", '1.32' );
+               }
+               if ( isset( $this->mParams['notice-messages'] ) ) {
+                       wfDeprecated( "'notice-messages' parameter in HTMLForm", '1.32' );
+               }
+               if ( isset( $this->mParams['notice'] ) ) {
+                       wfDeprecated( "'notice' parameter in HTMLForm", '1.32' );
+               }
        }
 
        /**
@@ -607,7 +617,7 @@ abstract class HTMLFormField {
                        $error = new OOUI\HtmlSnippet( $error );
                }
 
-               $notices = $this->getNotices();
+               $notices = $this->getNotices( 'skip deprecation' );
                foreach ( $notices as &$notice ) {
                        $notice = new OOUI\HtmlSnippet( $notice );
                }
@@ -861,15 +871,20 @@ abstract class HTMLFormField {
         * @return bool
         */
        public function isHelpInline() {
-               return isset( $this->mParams['help-inline'] ) ? $this->mParams['help-inline'] : true;
+               return $this->mParams['help-inline'] ?? true;
        }
 
        /**
         * Determine form errors to display and their classes
         * @since 1.20
         *
+        * phan-taint-check gets confused with returning both classes
+        * and errors and thinks double escaping is happening, so specify
+        * that return value has no taint.
+        *
         * @param string $value The value of the input
         * @return array array( $errors, $errorClass )
+        * @return-taint none
         */
        public function getErrorsAndErrorClass( $value ) {
                $errors = $this->validate( $value, $this->mParent->mFieldData );
@@ -915,9 +930,16 @@ abstract class HTMLFormField {
         * Determine notices to display for the field.
         *
         * @since 1.28
+        * @deprecated since 1.32
+        * @param string $skipDeprecation Pass 'skip deprecation' to avoid the deprecation
+        *   warning (since 1.32)
         * @return string[]
         */
-       public function getNotices() {
+       public function getNotices( $skipDeprecation = null ) {
+               if ( $skipDeprecation !== 'skip deprecation' ) {
+                       wfDeprecated( __METHOD__, '1.32' );
+               }
+
                $notices = [];
 
                if ( isset( $this->mParams['notice-message'] ) ) {
@@ -1132,6 +1154,12 @@ abstract class HTMLFormField {
         * Formats one or more errors as accepted by field validation-callback.
         *
         * @param string|Message|array $errors Array of strings or Message instances
+        * To work around limitations in phan-taint-check the calling
+        * class has taintedness disabled. So instead we pretend that
+        * this method outputs html, since the result is eventually
+        * outputted anyways without escaping and this allows us to verify
+        * stuff is safe even though the caller has taintedness cleared.
+        * @param-taint $errors exec_html
         * @return string HTML
         * @since 1.18
         */
index a679e45..e5e5cdd 100644 (file)
@@ -159,10 +159,8 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
                                'rows' => $this->mParams['rows'],
                                'columns' => $this->mParams['columns'],
                                'tooltips' => $this->mParams['tooltips'],
-                               'forcedOff' => isset( $this->mParams['force-options-off'] ) ?
-                                       $this->mParams['force-options-off'] : [],
-                               'forcedOn' => isset( $this->mParams['force-options-on'] ) ?
-                                       $this->mParams['force-options-on'] : [],
+                               'forcedOff' => $this->mParams['force-options-off'] ?? [],
+                               'forcedOn' => $this->mParams['force-options-on'] ?? [],
                                'values' => $value
                        ] + OOUI\Element::configFromHtmlAttributes( $attribs )
                );
index e49a846..e17d163 100644 (file)
@@ -1153,21 +1153,6 @@ abstract class DatabaseUpdater {
                }
        }
 
-       /**
-        * Updates the timestamps in the transcache table
-        * @return bool
-        */
-       protected function doUpdateTranscacheField() {
-               if ( $this->updateRowExists( 'convert transcache field' ) ) {
-                       $this->output( "...transcache tc_time already converted.\n" );
-
-                       return true;
-               }
-
-               return $this->applyPatch( 'patch-tc-timestamp.sql', false,
-                       "Converting tc_time from UNIX epoch to MediaWiki timestamp" );
-       }
-
        /**
         * Update CategoryLinks collation
         */
index 6ebf95e..0181ab2 100644 (file)
@@ -145,6 +145,7 @@ class MssqlUpdater extends DatabaseUpdater {
                        [ 'addIndex', 'page_props', 'PRIMARY', 'patch-page_props-pk.sql' ],
                        [ 'addIndex', 'site_identifiers', 'PRIMARY', 'patch-site_identifiers-pk.sql' ],
                        [ 'addIndex', 'recentchanges', 'rc_this_oldid', 'patch-recentchanges-rc_this_oldid-index.sql' ],
+                       [ 'dropTable', 'transcache' ],
                ];
        }
 
index 45f932a..1b0780b 100644 (file)
@@ -485,18 +485,32 @@ class MysqlInstaller extends DatabaseInstaller {
                /** @var Database $conn */
                $conn = $status->value;
                $dbName = $this->getVar( 'wgDBname' );
-               if ( !$conn->selectDB( $dbName ) ) {
+               if ( !$this->databaseExists( $dbName ) ) {
                        $conn->query(
                                "CREATE DATABASE " . $conn->addIdentifierQuotes( $dbName ) . "CHARACTER SET utf8",
                                __METHOD__
                        );
-                       $conn->selectDB( $dbName );
                }
+               $conn->selectDB( $dbName );
                $this->setupSchemaVars();
 
                return $status;
        }
 
+       /**
+        * Try to see if a given database exists
+        * @param string $dbName Database name to check
+        * @return bool
+        */
+       private function databaseExists( $dbName ) {
+               $encDatabase = $this->db->addQuotes( $dbName );
+
+               return $this->db->query(
+                       "SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $encDatabase",
+                       __METHOD__
+               )->numRows() > 0;
+       }
+
        /**
         * @return Status
         */
index 408f2fb..9469cf2 100644 (file)
@@ -84,7 +84,6 @@ class MysqlUpdater extends DatabaseUpdater {
                        [ 'doUserGroupsUpdate' ],
                        [ 'addField', 'site_stats', 'ss_total_pages', 'patch-ss_total_articles.sql' ],
                        [ 'addTable', 'user_newtalk', 'patch-usernewtalk.sql' ],
-                       [ 'addTable', 'transcache', 'patch-transcache.sql' ],
                        [ 'addField', 'interwiki', 'iw_trans', 'patch-interwiki-trans.sql' ],
 
                        // 1.6
@@ -172,7 +171,6 @@ class MysqlUpdater extends DatabaseUpdater {
                        [ 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ],
                        [ 'addIndex', 'change_tag', 'change_tag_rc_tag', 'patch-change_tag-indexes.sql' ],
                        [ 'addField', 'redirect', 'rd_interwiki', 'patch-rd_interwiki.sql' ],
-                       [ 'doUpdateTranscacheField' ],
                        [ 'doUpdateMimeMinorField' ],
 
                        // 1.17
@@ -319,7 +317,6 @@ class MysqlUpdater extends DatabaseUpdater {
                        [ 'renameIndex', 'querycache_info', 'qci_type', 'PRIMARY', false,
                                'patch-querycache_info-fix-pk.sql' ],
                        [ 'renameIndex', 'site_stats', 'ss_row_id', 'PRIMARY', false, 'patch-site_stats-fix-pk.sql' ],
-                       [ 'renameIndex', 'transcache', 'tc_url_idx', 'PRIMARY', false, 'patch-transcache-fix-pk.sql' ],
                        [ 'renameIndex', 'user_former_groups', 'ufg_user_group', 'PRIMARY', false,
                                'patch-user_former_groups-fix-pk.sql' ],
                        [ 'renameIndex', 'user_properties', 'user_properties_user_property', 'PRIMARY', false,
@@ -368,6 +365,7 @@ class MysqlUpdater extends DatabaseUpdater {
                        [ 'renameIndex', 'site_identifiers', 'site_ids_type', 'PRIMARY', false,
                                'patch-site_identifiers-fix-pk.sql' ],
                        [ 'addIndex', 'recentchanges', 'rc_this_oldid', 'patch-recentchanges-rc_this_oldid-index.sql' ],
+                       [ 'dropTable', 'transcache' ],
                ];
        }
 
index fbb7696..aa23d2c 100644 (file)
@@ -156,6 +156,7 @@ class OracleUpdater extends DatabaseUpdater {
                        [ 'addIndex', 'archive', 'ar_revid_uniq', 'patch-archive-ar_rev_id-unique.sql' ],
                        [ 'populateContentTables' ],
                        [ 'addIndex', 'recentchanges', 'rc_this_oldid', 'patch-recentchanges-rc_this_oldid-index.sql' ],
+                       [ 'dropTable', 'transcache' ],
 
                        // KEEP THIS AT THE BOTTOM!!
                        [ 'doRebuildDuplicateFunction' ],
index e8663fb..1be837a 100644 (file)
@@ -591,6 +591,7 @@ class PostgresUpdater extends DatabaseUpdater {
                        [ 'addIndex', 'protected_titles', 'protected_titles_pkey', 'patch-protected_titles-pk.sql' ],
                        [ 'addIndex', 'site_identifiers', 'site_identifiers_pkey', 'patch-site_identifiers-pk.sql' ],
                        [ 'addPgIndex', 'recentchanges', 'rc_this_oldid', '(rc_this_oldid)' ],
+                       [ 'dropTable', 'transcache' ],
                ];
        }
 
index 57bf389..b48ac9b 100644 (file)
@@ -56,7 +56,6 @@ class SqliteUpdater extends DatabaseUpdater {
                        [ 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ],
                        [ 'addIndex', 'change_tag', 'change_tag_rc_tag', 'patch-change_tag-indexes.sql' ],
                        [ 'addField', 'redirect', 'rd_interwiki', 'patch-rd_interwiki.sql' ],
-                       [ 'doUpdateTranscacheField' ],
                        [ 'sqliteSetupSearchindex' ],
 
                        // 1.17
@@ -184,7 +183,6 @@ class SqliteUpdater extends DatabaseUpdater {
                        [ 'renameIndex', 'querycache_info', 'qci_type', 'PRIMARY', false,
                                'patch-querycache_info-fix-pk.sql' ],
                        [ 'renameIndex', 'site_stats', 'ss_row_id', 'PRIMARY', false, 'patch-site_stats-fix-pk.sql' ],
-                       [ 'renameIndex', 'transcache', 'tc_url_idx', 'PRIMARY', false, 'patch-transcache-fix-pk.sql' ],
                        [ 'renameIndex', 'user_former_groups', 'ufg_user_group', 'PRIMARY', false,
                                'patch-user_former_groups-fix-pk.sql' ],
                        [ 'renameIndex', 'user_properties', 'user_properties_user_property', 'PRIMARY', false,
@@ -232,6 +230,7 @@ class SqliteUpdater extends DatabaseUpdater {
                        [ 'renameIndex', 'site_identifiers', 'site_ids_type', 'PRIMARY', false,
                                'patch-site_identifiers-fix-pk.sql' ],
                        [ 'addIndex', 'recentchanges', 'rc_this_oldid', 'patch-recentchanges-rc_this_oldid-index.sql' ],
+                       [ 'dropTable', 'transcache' ],
                ];
        }
 
index 6b2f33f..2e72e67 100644 (file)
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е олекотена система за бази от данни, която е много добре поддържана. ([http://www.php.net/manual/bg/pdo.installation.php Как се компилира PHP с поддръжка на SQLite], използва PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е комерсиална корпоративна база от данни. ([http://www.php.net/manual/en/oci8.installation.php Как се компилира PHP с поддръжка на OCI8])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] е комерсиална корпоративна база от данни за Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Как да се компилира PHP с поддръжка на SQLSRV])",
-       "config-header-mysql": "Ð\9dаÑ\81Ñ\82Ñ\80ойки Ð·Ð° MySQL",
+       "config-header-mysql": "Ð\9dаÑ\81Ñ\82Ñ\80ойки Ð½Ð° MariaDB/MySQL",
        "config-header-postgres": "Настройки за PostgreSQL",
        "config-header-sqlite": "Настройки за SQLite",
        "config-header-oracle": "Настройки за Oracle",
        "config-db-web-create": "Създаване на сметката, ако все още не съществува",
        "config-db-web-no-create-privs": "Посочената сметка за инсталацията не разполага с достатъчно права за създаване на нова сметка.\nНеобходимо е посочената сметка вече да съществува.",
        "config-mysql-engine": "Хранилище на данни:",
-       "config-mysql-innodb": "InnoDB",
+       "config-mysql-innodb": "InnoDB (препоръчително)",
        "config-mysql-myisam": "MyISAM",
        "config-mysql-myisam-dep": "<strong>Внимание:</strong> Избрана е MyISAM като система за складиране в MySQL, която не се препоръчва за използване с МедияУики, защото:\n* почти не поддържа паралелност заради заключване на таблиците\n* е по-податлива на повреди в сравнение с други системи\n* кодът на МедияУики не винаги поддържа MyISAM коректно\n\nАко инсталацията на MySQL поддържа InnoDB, силно е препоръчително да се използва тя.\nАко инсталацията на MySQL не поддържа InnoDB, вероятно е време за обновяване.",
        "config-mysql-only-myisam-dep": "<strong>Внимание:</strong> MyISAM e единственият наличен на тази машина тип на таблиците за MySQL и не е препоръчителен за употреба при МедияУики защото:\n* има слаба поддръжка на конкурентност на заявките, поради закючването на таблиците\n* е много по-податлив на грешки в базите от данни от другите типове таблици\n* кодът на МедияУики не винаги работи с MyISAM както трябва\n\nВашият MySQL не поддържа InnoDB, така че може би е дошло време за актуализиране.",
index 1d4d515..ae4ce21 100644 (file)
        "config-email-watchlist": "Włącz powiadomienie o zmianach stron obserwowanych",
        "config-email-watchlist-help": "Pozwól użytkownikom otrzymywać powiadomienia o zmianach na stronach obserwowanych, jeśli będą mieć włączoną tę funkcję w swoich preferencjach.",
        "config-email-auth": "Włącz uwierzytelnianie e‐mailem",
-       "config-email-auth-help": "Jeśli ta opcja jest włączona, użytkownicy będą musieli potwierdzić swoje adresy e-mail przy użyciu wysłanego do nich łącza, gdy będą je ustawiać lub zmieniać.\nTylko uwierzytelnione adresy e-mail mogą otrzymywać wiadomości od innych użytkowników lub mailowe powiadomienia o zmianach.\nUstawienie tej opcji jest'''zalecane''' na publicznych wiki ze względu na potencjalne nadużycia funkcji poczty e-mail.",
+       "config-email-auth-help": "Jeśli ta opcja jest włączona, użytkownicy będą musieli potwierdzić swoje adresy e-mail przy użyciu wysłanego do nich łącza, gdy będą je ustawiać lub zmieniać.\nTylko uwierzytelnione adresy e-mail mogą otrzymywać wiadomości od innych użytkowników lub mailowe powiadomienia o zmianach.\nUstawienie tej opcji jest <strong>zalecane</strong> na publicznych wiki ze względu na potencjalne nadużycia funkcji poczty e-mail.",
        "config-email-sender": "Zwrotny adres e‐mail",
-       "config-email-sender-help": "Wprowadź adres e-mail używany jako adres zwrotny wiadomości wychodzących.\nTo tam będą wysyłane szturchnięcia.\nWiele serwerów poczty wymaga, by co najmniej część nazwy domeny była prawidłowa.",
+       "config-email-sender-help": "Wprowadź adres e-mail używany jako adres zwrotny wiadomości wychodzących.\nTo tam będą wysyłane zwroty z serwerów pocztowych.\nWiele serwerów poczty wymaga, by co najmniej część nazwy domeny była prawidłowa.",
        "config-upload-settings": "Przesyłanie obrazków i plików",
        "config-upload-enable": "Włącz przesyłanie plików na serwer",
        "config-upload-help": "Przesyłanie plików potencjalnie wystawia serwer na zagrożenia.\nWięcej informacji na ten temat można znaleźć w [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security sekcji zabezpieczeń] podręcznika.\n\nAby włączyć przesyłanie plików, zmień właściwości podkatalogu <code>images</code> katalogu głównego MediaWiki tak, aby serwer sieci web mógł zapisywać do niego.\nNastępnie włącz tę opcję.",
index 3bdc761..e35e38f 100644 (file)
@@ -9,15 +9,19 @@
                        "Zoranzoki21",
                        "Acamicamacaraca",
                        "Obsuser",
-                       "BadDog"
+                       "BadDog",
+                       "Prevodim"
                ]
        },
        "config-desc": "Инсталација за Медијавики",
        "config-title": "Инсталација Медијавикија $1",
        "config-information": "Информација",
        "config-localsettings-upgrade": "Откривена је датотека <code>LocalSettings.php</code>.\nДа бисте надоградили инсталацију, унесите вредности од <code>$wgUpgradeKey</code> у оквиру испод.\nНаћи ћете га у <code>LocalSettings.php</code>.",
+       "config-localsettings-cli-upgrade": "Датотека <code>LocalSettings.php</code> се налази на Вашем систему.\nУколико желите да ажурирате ову инсталацију, молимо покрените <code>update.php</code>",
        "config-localsettings-key": "Кључ за уградњу:",
        "config-localsettings-badkey": "Наведени кључ за надоградњу је неисправан.",
+       "config-upgrade-key-missing": "Постојећа инсталација Медијавикија је пронађена.\nКако бисте ажурирали ову инсталацију, молимо ставите следећу линију кôда на крај ваше <code>LocalSettings.php</code> датотеке.\n\n$1",
+       "config-localsettings-incomplete": "Постојећи <code>LocalSettings.php</code> је изгледа некомплетан.\nПроменљива $1 није постављена.\nМолимо промените <code>LocalSettings.php</code> и поставите ову променљиву, потом кликните „{{int:Config-continue}}“.",
        "config-session-error": "Грешка при започињању сесије: $1",
        "config-session-expired": "Ваши подаци о сесији су истекли.\nСесије су подешене да трају $1.\nЊихов рок можете повећати постављањем <code>session.gc_maxlifetime</code> у php.ini.\nПоново покрените инсталацију.",
        "config-no-session": "Ваши подаци о сесији су изгубљени!\nПроверите Ваш php.ini и обезбедите да је <code>session.save_path</code> постављен на одговарајући директоријум.",
@@ -50,6 +54,9 @@
        "config-env-hhvm": "HHVM $1 је инсталиран.",
        "config-apc": "[https://secure.php.net/apc APC] је инсталиран",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] је инсталиран",
+       "config-diff3-bad": "GNU diff3 није пронађен.",
+       "config-git": "Пронађен Гит софтвер за контролу верзије кôда: <code>$1</code>",
+       "config-git-bad": "Гит софтвер за контролу верзије кôда није пронађен.",
        "config-db-type": "Тип базе података:",
        "config-db-host": "Хост базе података",
        "config-db-wiki-settings": "Идентификуј овај вики",
@@ -57,6 +64,7 @@
        "config-db-name-oracle": "Шема базе података:",
        "config-db-username": "Корисничко име базе података:",
        "config-db-password": "Лозинка базе података:",
+       "config-db-prefix": "Префикс табеле у бази података:",
        "config-db-port": "Порт базе података:",
        "config-db-schema": "Шема за Медијавики:",
        "config-type-mysql": "MariaDB, MySQL, или компактибилан",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-header-mysql": "MariaDB/MySQL подешавања",
+       "config-header-postgres": "Подешавања PostgreSQL-а",
+       "config-header-sqlite": "Подешавања SQLite-а",
+       "config-header-oracle": "Подешавања Oracle-а",
        "config-header-mssql": "Подешавања Microsoft SQL Server-а",
        "config-invalid-db-type": "Неважећи тип базе података.",
        "config-mssql-old": "Потребан је Microsoft SQL Server $1 или новији. Ви имате $2.",
+       "config-sqlite-readonly": "Датотека <code>$1</code> није записива.",
+       "config-regenerate": "Регенериши LocalSettings.php →",
        "config-mysql-innodb": "InnoDB (препоручено)",
        "config-mysql-myisam": "MyISAM",
        "config-mssql-auth": "Тип потврде идентитета:",
        "config-admin-password-mismatch": "Лозинке које сте унели се не поклапају.",
        "config-admin-email": "Имејл адреса:",
        "config-admin-error-bademail": "Унели сте неисправну имејл адресу.",
+       "config-optional-continue": "Постави ми још питања.",
        "config-optional-skip": "Досадно ми је, само инсталирај вики.",
        "config-profile-wiki": "Отворен вики",
        "config-profile-no-anon": "Неопходно је отворити налог",
        "config-install-step-done": "готово",
        "config-install-step-failed": "није успело",
        "config-install-extensions": "Обухвата екстензије",
+       "config-install-database": "Подешавам базу података",
        "config-install-schema": "Прављење шеме",
+       "config-install-pg-schema-not-exist": "Шема PostgreSQL не постоји.",
+       "config-install-user": "Правим корисника базе података",
+       "config-install-user-alreadyexists": "Корисник „$1” већ постоји",
        "config-install-tables": "Прављење табела",
        "config-install-stats": "Покрећем статистику",
        "config-install-keys": "Генеришем тајне кључеве",
        "config-nofile": "Не могу да пронађем датотеку „$1”. Није ли она била избрисана?",
        "config-skins-screenshots": "„$1” (снимци екрана: $2)",
        "config-skins-screenshot": "$1 ($2)",
+       "config-extensions-requires": "$1 (захтева $2)",
        "config-screenshot": "снимак екрана",
        "mainpagetext": "<strong>Медијавики је инсталиран.</strong>",
        "mainpagedocfooter": "Погледајте [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents кориснички водич] за коришћење програма.\n\n== Увод ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Помоћ у вези са подешавањима]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Често постављана питања]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Дописни списак о издањима Медијавикија]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Научите како да се борите против спама на својој вики]"
index 93d44e4..ada4d36 100644 (file)
@@ -19,7 +19,8 @@
                        "Elftrkn",
                        "Vito Genovese",
                        "Incelemeelemani",
-                       "Hedda"
+                       "Hedda",
+                       "By erdo can"
                ]
        },
        "config-desc": "MediaWiki yükleyicisi",
@@ -92,6 +93,7 @@
        "config-using-uri": "Sunucu URLsi olarak \"<nowiki>$1$2</nowiki>\" kullanılıyor.",
        "config-uploads-not-safe": "<strong>Uyarı:</strong> Yüklemeler için varsayılan dizininiz <code>$1</code>, rastgele komut dosyalarının yürütülmesine karşı savunmasızdır.\nMediaWiki, karşıya yüklenen tüm dosyaları güvenlik tehditlerine karşı denetlese de, yüklemeleri etkinleştirmeden önce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security bu güvenlik açığını kapatmanız] önemle tavsiye edilir.",
        "config-no-cli-uploads-check": "<strong>Uyarı:</strong> Yüklemeler için varsayılan dizininiz (<code>$1</code>), CLI yüklemesi sırasında rastgele kod yürütme güvenlik açığı açısından denetlenmez.",
+       "config-brokenlibxml": "Sisteminizde, \"buggy\" olan ve MediaWiki ve diğer web uygulamalarında gizli veri bozulmasına neden olabilecek PHP ve libxml2 sürümlerinin bir kombinasyonu vardır.\nLibxml2 2.7.3 veya sonraki bir sürüme yükseltin ([https://bugs.php.net/bug.php?id=45996 PHP ile dosyalanmış hata]).\nKurulum iptal edildi.",
        "config-db-type": "Veritabanı tipi:",
        "config-db-host": "Veritabanı sunucusu:",
        "config-db-host-help": "Veritabanı sunucunuz farklı bir sunucu üzerinde ise, ana bilgisayar adını veya IP adresini buraya girin.\n\nPaylaşılan ağ barındırma hizmeti kullanıyorsanız, barındırma sağlayıcınız size doğru bir ana bilgisayar adını kendi belgelerinde vermiştir.\n\nEğer MySQL kullanan bir Windows sunucusuna yükleme yapıyorsanız, sunucu adı olarak \"localhost\" kullanırsanız çalışmayabilir. Çalışmazsa, yerel IP adresi için \"127.0.0.1\" deneyin.\n\nPostgreSQL kullanıyorsanız, bu alanı bir Unix soketi ile bağlanmak için boş bırakın.",
        "config-extension-link": "Vikinizin [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions eklentileri] desteklediğini biliyor musunuz?\n\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category Eklentileri kategorilerine göre] inceleyebilir ya da tüm eklentilerin listesini görmek için [https://www.mediawiki.org/wiki/Extension_Matrix Eklenti Matrisine] bakabilirsiniz.",
        "config-skins-screenshots": "$1 (ekran görüntüleri: $2)",
        "config-screenshot": "ekran görüntüsü",
-       "mainpagetext": "'''MediaWiki başarı ile kuruldu.'''",
-       "mainpagedocfooter": "Viki yazılımının kullanımı hakkında bilgi almak için [https://meta.wikimedia.org/wiki/Help:Contents kullanıcı rehberine] bakınız.\n\n== Yeni Başlayanlar ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Yapılandırma ayarlarının listesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki SSS]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki e-posta listesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Kendi diliniz için MediaWiki yerelleştirmesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Kendi vikinizde spam ile nasıl savaşılacağını öğrennin]"
+       "mainpagetext": "<strong>MediaWiki başarı ile kuruldu.</strong>",
+       "mainpagedocfooter": "Viki yazılımının kullanımı hakkında bilgi almak için [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents kullanıcı rehberine] bakınız.\n\n== Yeni Başlayanlar ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Yapılandırma ayarlarının listesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki SSS]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki e-posta listesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Kendi diliniz için MediaWiki yerelleştirmesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Kendi vikinizde spam ile nasıl savaşılacağını öğrennin]"
 }
index 0a14192..8328abf 100644 (file)
@@ -47,6 +47,10 @@ class DeleteLinksJob extends Job {
 
                // Serialize links updates by page ID so they see each others' changes
                $scopedLock = LinksUpdate::acquirePageLock( wfGetDB( DB_MASTER ), $pageId, 'job' );
+               if ( $scopedLock === null ) {
+                       $this->setLastError( 'LinksUpdate already running for this page, try again later.' );
+                       return false;
+               }
 
                if ( WikiPage::newFromID( $pageId, WikiPage::READ_LATEST ) ) {
                        // The page was restored somehow or something went wrong
index 8854c65..aa8e121 100644 (file)
@@ -146,6 +146,11 @@ class RefreshLinksJob extends Job {
                $dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scopedLock = LinksUpdate::acquirePageLock( $dbw, $page->getId(), 'job' );
+               if ( $scopedLock === null ) {
+                       // Another job is already updating the page, likely for an older revision (T170596).
+                       $this->setLastError( 'LinksUpdate already running for this page, try again later.' );
+                       return false;
+               }
                // Get the latest ID *after* acquirePageLock() flushed the transaction.
                // This is used to detect edits/moves after loadPageData() but before the scope lock.
                // The works around the chicken/egg problem of determining the scope lock key.
index 1ab17a0..fbcb3bd 100644 (file)
@@ -271,7 +271,7 @@ class FormatJson {
                                        $lookAhead = ( $idx + 1 < $maxLen ) ? $str[$idx + 1] : '';
                                        $lookBehind = ( $idx - 1 >= 0 ) ? $str[$idx - 1] : '';
                                        if ( $inString ) {
-                                               continue;
+                                               break;
 
                                        } elseif ( !$inComment &&
                                                ( $lookAhead === '/' || $lookAhead === '*' )
index 304b99b..c060380 100644 (file)
@@ -96,4 +96,4 @@ class RiffExtractor {
        public static function extractUInt32( $string ) {
                return unpack( 'V', $string )[1];
        }
-};
+}
index cd1860f..1e0e1dc 100644 (file)
@@ -26,24 +26,47 @@ namespace Wikimedia;
 class StaticArrayWriter {
 
        /**
-        * @param string[] $data Array with string keys/values to export
+        * @param array $data Array with keys/values to export
         * @param string $header
         *
         * @return string PHP code
         */
        public function create( array $data, $header = 'Automatically generated' ) {
-               $format = "\t%s => %s,\n";
                $code = "<?php\n"
                        . "// " . implode( "\n// ", explode( "\n", $header ) ) . "\n"
                        . "return [\n";
                foreach ( $data as $key => $value ) {
-                       $code .= sprintf(
-                               $format,
-                               var_export( $key, true ),
-                               var_export( $value, true )
-                       );
+                       $code .= $this->encode( $key, $value, 1 );
                }
                $code .= "];\n";
                return $code;
        }
+
+       /**
+        * Recursively turn one k/v pair into properly-indented PHP
+        *
+        * @param string|int $key
+        * @param array|mixed $value
+        * @param int $indent Indentation level
+        *
+        * @return string
+        */
+       private function encode( $key, $value, $indent ) {
+               $tabs = str_repeat( "\t", $indent );
+               $line = $tabs .
+                       var_export( $key, true ) .
+                       ' => ';
+               if ( is_array( $value ) ) {
+                       $line .= "[\n";
+                       foreach ( $value as $key2 => $value2 ) {
+                               $line .= $this->encode( $key2, $value2, $indent + 1 );
+                       }
+                       $line .= "$tabs]";
+               } else {
+                       $line .= var_export( $value, true );
+               }
+
+               $line .= ",\n";
+               return $line;
+       }
 }
index 716641f..3af820b 100644 (file)
@@ -27,6 +27,8 @@ use Psr\Log\NullLogger;
 /**
  * Multi-datacenter aware caching interface
  *
+ * ### Using WANObjectCache
+ *
  * All operations go to the local datacenter cache, except for delete(),
  * touchCheckKey(), and resetCheckKey(), which broadcast to all datacenters.
  *
@@ -36,34 +38,63 @@ use Psr\Log\NullLogger;
  * The preferred way to do this logic is through getWithSetCallback().
  * When querying the store on cache miss, the closest DB replica
  * should be used. Try to avoid heavyweight DB master or quorum reads.
- * When the source data changes, a purge method should be called.
- * Since purges are expensive, they should be avoided. One can do so if:
- *   - a) The object cached is immutable; or
- *   - b) Validity is checked against the source after get(); or
- *   - c) Using a modest TTL is reasonably correct and performant
  *
+ * To ensure consumers of the cache see new values in a timely manner,
+ * you either need to follow either the validation strategy, or the
+ * purge strategy.
+ *
+ * The validation strategy refers to the natural avoidance of stale data
+ * by one of the following means:
+ *
+ *   - A) The cached value is immutable.
+ *        If the consumer has access to an identifier that uniquely describes a value,
+ *        cached value need not change. Instead, the key can change. This also allows
+ *        all servers to access their perceived current version. This is important
+ *        in context of multiple deployed versions of your application and/or cross-dc
+ *        database replication, to ensure deterministic values without oscillation.
+ *   - B) Validity is checked against the source after get().
+ *        This is the inverse of A. The unique identifier is embedded inside the value
+ *        and validated after on retreival. If outdated, the value is recomputed.
+ *   - C) The value is cached with a modest TTL (without validation).
+ *        If value recomputation is reasonably performant, and the value is allowed to
+ *        be stale, one should consider using TTL only – using the value's age as
+ *        method of validation.
+ *
+ * The purge strategy refers to the the approach whereby your application knows that
+ * source data has changed and can react by purging the relevant cache keys.
+ * As purges are expensive, this strategy should be avoided if possible.
  * The simplest purge method is delete().
  *
- * There are three supported ways to handle broadcasted operations:
- *   - a) Configure the 'purge' EventRelayer to point to a valid PubSub endpoint
- *         that has subscribed listeners on the cache servers applying the cache updates.
- *   - b) Ommit the 'purge' EventRelayer parameter and set up mcrouter as the underlying cache
+ * No matter which strategy you choose, callers must not rely on updates or purges
+ * being immediately visible to other servers. It should be treated similarly as
+ * one would a database replica.
+ *
+ * The need for immediate updates should be avoided. If needed, solutions must be
+ * sought outside WANObjectCache.
+ *
+ * ### Deploying WANObjectCache
+ *
+ * There are three supported ways to set up broadcasted operations:
+ *
+ *   - A) Configure the 'purge' EventRelayer to point to a valid PubSub endpoint
+ *        that has subscribed listeners on the cache servers applying the cache updates.
+ *   - B) Omit the 'purge' EventRelayer parameter and set up mcrouter as the underlying cache
  *        backend, using a memcached BagOStuff class for the 'cache' parameter. The 'region'
- *        and 'cluster' parameters must be provided and 'mcrouterAware' must be set to 'true'.
+ *        and 'cluster' parameters must be provided and 'mcrouterAware' must be set to `true`.
  *        Configure mcrouter as follows:
  *          - 1) Use Route Prefixing based on region (datacenter) and cache cluster.
- *                See https://github.com/facebook/mcrouter/wiki/Routing-Prefix and
- *                https://github.com/facebook/mcrouter/wiki/Multi-cluster-broadcast-setup
+ *               See https://github.com/facebook/mcrouter/wiki/Routing-Prefix and
+ *               https://github.com/facebook/mcrouter/wiki/Multi-cluster-broadcast-setup.
  *          - 2) To increase the consistency of delete() and touchCheckKey() during cache
- *                server membership changes, you can use the OperationSelectorRoute to
- *                configure 'set' and 'delete' operations to go to all servers in the cache
- *                cluster, instead of just one server determined by hashing.
- *                See https://github.com/facebook/mcrouter/wiki/List-of-Route-Handles
- *   - c) Ommit the 'purge' EventRelayer parameter and set up dynomite as cache middleware
- *         between the web servers and either memcached or redis. This will also broadcast all
- *         key setting operations, not just purges, which can be useful for cache warming.
- *         Writes are eventually consistent via the Dynamo replication model.
- *         See https://github.com/Netflix/dynomite
+ *               server membership changes, you can use the OperationSelectorRoute to
+ *               configure 'set' and 'delete' operations to go to all servers in the cache
+ *               cluster, instead of just one server determined by hashing.
+ *               See https://github.com/facebook/mcrouter/wiki/List-of-Route-Handles.
+ *   - C) Omit the 'purge' EventRelayer parameter and set up dynomite as cache middleware
+ *        between the web servers and either memcached or redis. This will broadcast all
+ *        key setting operations, not just purges, which can be useful for cache warming.
+ *        Writes are eventually consistent via the Dynamo replication model.
+ *        See https://github.com/Netflix/dynomite.
  *
  * Broadcasted operations like delete() and touchCheckKey() are done asynchronously
  * in all datacenters this way, though the local one should likely be near immediate.
index 45179cc..938e534 100644 (file)
@@ -78,9 +78,8 @@ class ChronologyProtector implements LoggerAwareInterface {
         */
        public function __construct( BagOStuff $store, array $client, $posIndex = null ) {
                $this->store = $store;
-               $this->clientId = isset( $client['clientId'] )
-                       ? $client['clientId']
-                       : md5( $client['ip'] . "\n" . $client['agent'] );
+               $this->clientId = $client['clientId'] ??
+                       md5( $client['ip'] . "\n" . $client['agent'] );
                $this->key = $store->makeGlobalKey( __CLASS__, $this->clientId, 'v2' );
                $this->waitForPosIndex = $posIndex;
 
index 4bdd8f6..b1353b7 100644 (file)
@@ -45,7 +45,7 @@ class DBQueryError extends DBExpectedError {
        public function __construct( IDatabase $db, $error, $errno, $sql, $fname, $message = null ) {
                if ( $message === null ) {
                        if ( $db instanceof Database && $db->wasConnectionError( $errno ) ) {
-                               $message = "A connection error occured. \n" .
+                               $message = "A connection error occurred. \n" .
                                         "Query: $sql\n" .
                                         "Function: $fname\n" .
                                         "Error: $errno $error\n";
index 2c1a782..60044ba 100644 (file)
@@ -56,7 +56,11 @@ class LBFactorySingle extends LBFactory {
         * @since 1.28
         */
        public static function newFromConnection( IDatabase $db, array $params = [] ) {
-               return new static( [ 'connection' => $db ] + $params );
+               return new static( array_merge(
+                       [ 'localDomain' => $db->getDomainID() ],
+                       $params,
+                       [ 'connection' => $db ]
+               ) );
        }
 
        /**
index fbc3be9..00b4130 100644 (file)
@@ -938,10 +938,6 @@ class LoadBalancer implements ILoadBalancer {
                        $server = $this->servers[$i];
                        $server['serverIndex'] = $i;
                        $server['autoCommitOnly'] = $autoCommit;
-                       if ( $this->localDomain->getDatabase() !== null ) {
-                               // Use the local domain table prefix if the local domain is specified
-                               $server['tablePrefix'] = $this->localDomain->getTablePrefix();
-                       }
                        $conn = $this->reallyOpenConnection( $server, $this->localDomain );
                        $host = $this->getServerName( $i );
                        if ( $conn->isOpen() ) {
@@ -1037,7 +1033,6 @@ class LoadBalancer implements ILoadBalancer {
                                $this->errorConnection = $conn;
                                $conn = false;
                        } else {
-                               $conn->tablePrefix( $prefix ); // as specified
                                // Note that if $domain is an empty string, getDomainID() might not match it
                                $this->conns[$connInUseKey][$i][$conn->getDomainID()] = $conn;
                                $this->connLogger->debug( __METHOD__ . ": opened new connection for $i/$domain" );
@@ -1081,20 +1076,20 @@ class LoadBalancer implements ILoadBalancer {
         * Returns a Database object whether or not the connection was successful.
         *
         * @param array $server
-        * @param DatabaseDomain $domainOverride Use an unspecified domain to not select any database
+        * @param DatabaseDomain $domain Domain the connection is for, possibly unspecified
         * @return Database
         * @throws DBAccessError
         * @throws InvalidArgumentException
         */
-       protected function reallyOpenConnection( array $server, DatabaseDomain $domainOverride ) {
+       protected function reallyOpenConnection( array $server, DatabaseDomain $domain ) {
                if ( $this->disabled ) {
                        throw new DBAccessError();
                }
 
-               // Handle $domainOverride being a specified or an unspecified domain
-               if ( $domainOverride->getDatabase() === null ) {
-                       // Normally, an RDBMS requires a DB name specified on connection and the $server
-                       // configuration array is assumed to already specify an appropriate DB name.
+               if ( $domain->getDatabase() === null ) {
+                       // The database domain does not specify a DB name and some database systems require a
+                       // valid DB specified on connection. The $server configuration array contains a default
+                       // DB name to use for connections in such cases.
                        if ( $server['type'] === 'mysql' ) {
                                // For MySQL, DATABASE and SCHEMA are synonyms, connections need not specify a DB,
                                // and the DB name in $server might not exist due to legacy reasons (the default
@@ -1102,10 +1097,16 @@ class LoadBalancer implements ILoadBalancer {
                                $server['dbname'] = null;
                        }
                } else {
-                       $server['dbname'] = $domainOverride->getDatabase();
-                       $server['schema'] = $domainOverride->getSchema();
+                       $server['dbname'] = $domain->getDatabase();
+               }
+
+               if ( $domain->getSchema() !== null ) {
+                       $server['schema'] = $domain->getSchema();
                }
 
+               // It is always possible to connect with any prefix, even the empty string
+               $server['tablePrefix'] = $domain->getTablePrefix();
+
                // Let the handle know what the cluster master is (e.g. "db1052")
                $masterName = $this->getServerName( $this->getWriterIndex() );
                $server['clusterMasterHost'] = $masterName;
index 1b72502..5c0af11 100644 (file)
@@ -54,7 +54,8 @@ class LoadBalancerSingle extends LoadBalancer {
                        ],
                        'trxProfiler' => $params['trxProfiler'] ?? null,
                        'srvCache' => $params['srvCache'] ?? null,
-                       'wanCache' => $params['wanCache'] ?? null
+                       'wanCache' => $params['wanCache'] ?? null,
+                       'localDomain' => $params['localDomain'] ?? $this->db->getDomainID()
                ] );
 
                if ( isset( $params['readOnlyReason'] ) ) {
@@ -69,7 +70,11 @@ class LoadBalancerSingle extends LoadBalancer {
         * @since 1.28
         */
        public static function newFromConnection( IDatabase $db, array $params = [] ) {
-               return new static( [ 'connection' => $db ] + $params );
+               return new static( array_merge(
+                       [ 'localDomain' => $db->getDomainID() ],
+                       $params,
+                       [ 'connection' => $db ]
+               ) );
        }
 
        protected function reallyOpenConnection( array $server, DatabaseDomain $domainOverride ) {
index 3a7b18e..e90334f 100644 (file)
@@ -33,23 +33,30 @@ use MediaWiki\MediaWikiServices;
  * moved to separate EditPage and HTMLFileCache classes.
  */
 class Article implements Page {
-       /** @var IContextSource The context this Article is executed in */
+       /**
+        * @var IContextSource|null The context this Article is executed in.
+        * If null, REquestContext::getMain() is used.
+        */
        protected $mContext;
 
        /** @var WikiPage The WikiPage object of this instance */
        protected $mPage;
 
-       /** @var ParserOptions ParserOptions object for $wgUser articles */
+       /**
+        * @var ParserOptions|null ParserOptions object for $wgUser articles.
+        * Initialized by getParserOptions by calling $this->mPage->makeParserOptions().
+        */
        public $mParserOptions;
 
        /**
-        * @var string Text of the revision we are working on
+        * @var string|null Text of the revision we are working on
         * @todo BC cruft
         */
        public $mContent;
 
        /**
-        * @var Content Content of the revision we are working on
+        * @var Content|null Content of the revision we are working on.
+        * Initialized by fetchContentObject().
         * @since 1.21
         */
        public $mContentObject;
@@ -60,7 +67,7 @@ class Article implements Page {
        /** @var int|null The oldid of the article that is to be shown, 0 for the current revision */
        public $mOldId;
 
-       /** @var Title Title from which we were redirected here */
+       /** @var Title|null Title from which we were redirected here, if any. */
        public $mRedirectedFrom = null;
 
        /** @var string|bool URL to redirect to or false if none */
@@ -69,10 +76,16 @@ class Article implements Page {
        /** @var int Revision ID of revision we are working on */
        public $mRevIdFetched = 0;
 
-       /** @var Revision Revision we are working on */
+       /**
+        * @var Revision|null Revision we are working on. Initialized by getOldIDFromRequest()
+        * or fetchContentObject().
+        */
        public $mRevision = null;
 
-       /** @var ParserOutput */
+       /**
+        * @var ParserOutput|null|false The ParserOutput generated for viewing the page,
+        * initialized by view(). If no ParserOutput could be generated, this is set to false.
+        */
        public $mParserOutput;
 
        /**
@@ -641,7 +654,7 @@ class Article implements Page {
                # Note that $this->mParserOutput is the *current*/oldid version output.
                $pOutput = ( $outputDone instanceof ParserOutput )
                        ? $outputDone // object fetched by hook
-                       : $this->mParserOutput;
+                       : $this->mParserOutput ?: null; // ParserOutput or null, avoid false
 
                # Adjust title for main page & pages with displaytitle
                if ( $pOutput ) {
index 147c9f3..b609d7b 100644 (file)
@@ -23,6 +23,7 @@
 use MediaWiki\Edit\PreparedEdit;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\RevisionRenderer;
 use MediaWiki\Storage\DerivedPageDataUpdater;
 use MediaWiki\Storage\PageUpdater;
 use MediaWiki\Storage\RevisionRecord;
@@ -223,6 +224,13 @@ class WikiPage implements Page, IDBAccessObject {
                return MediaWikiServices::getInstance()->getRevisionStore();
        }
 
+       /**
+        * @return RevisionRenderer
+        */
+       private function getRevisionRenderer() {
+               return MediaWikiServices::getInstance()->getRevisionRenderer();
+       }
+
        /**
         * @return ParserCache
         */
@@ -931,6 +939,7 @@ class WikiPage implements Page, IDBAccessObject {
                                // links.
                                $hasLinks = (bool)count( $editInfo->output->getLinks() );
                        } else {
+                               // NOTE: keep in sync with revisionRenderer::getLinkCount
                                $hasLinks = (bool)wfGetDB( DB_REPLICA )->selectField( 'pagelinks', 1,
                                        [ 'pl_from' => $this->getId() ], __METHOD__ );
                        }
@@ -1630,6 +1639,7 @@ class WikiPage implements Page, IDBAccessObject {
                $derivedDataUpdater = new DerivedPageDataUpdater(
                        $this, // NOTE: eventually, PageUpdater should not know about WikiPage
                        $this->getRevisionStore(),
+                       $this->getRevisionRenderer(),
                        $this->getParserCache(),
                        JobQueueGroup::singleton(),
                        MessageCache::singleton(),
@@ -1961,7 +1971,7 @@ class WikiPage implements Page, IDBAccessObject {
         * Purges pages that include this page if the text was changed here.
         * Every 100th edit, prune the recent changes table.
         *
-        * @deprecated since 1.32, use PageUpdater::doEditUpdates instead.
+        * @deprecated since 1.32, use PageUpdater::doUpdates instead.
         *
         * @param Revision $revision
         * @param User $user User object that did the revision
@@ -3152,6 +3162,9 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Image redirects
                RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $title );
+
+               // Purge cross-wiki cache entities referencing this page
+               self::purgeInterwikiCheckKey( $title );
        }
 
        /**
@@ -3190,14 +3203,41 @@ class WikiPage implements Page, IDBAccessObject {
                // Clear file cache for this page only
                HTMLFileCache::clearFileCache( $title );
 
+               // Purge ?action=info cache
                $revid = $revision ? $revision->getId() : null;
                DeferredUpdates::addCallableUpdate( function () use ( $title, $revid ) {
                        InfoAction::invalidateCache( $title, $revid );
                } );
+
+               // Purge cross-wiki cache entities referencing this page
+               self::purgeInterwikiCheckKey( $title );
        }
 
        /**#@-*/
 
+       /**
+        * Purge the check key for cross-wiki cache entries referencing this page
+        *
+        * @param Title $title
+        */
+       private static function purgeInterwikiCheckKey( Title $title ) {
+               global $wgEnableScaryTranscluding;
+
+               if ( !$wgEnableScaryTranscluding ) {
+                       return; // @todo: perhaps this wiki is only used as a *source* for content?
+               }
+
+               DeferredUpdates::addCallableUpdate( function () use ( $title ) {
+                       $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+                       $cache->resetCheckKey(
+                               // Do not include the namespace since there can be multiple aliases to it
+                               // due to different namespace text definitions on different wikis. This only
+                               // means that some cache invalidations happen that are not strictly needed.
+                               $cache->makeGlobalKey( 'interwiki-page', wfWikiID(), $title->getDBkey() )
+                       );
+               } );
+       }
+
        /**
         * Returns a list of categories this page is a member of.
         * Results will include hidden categories
index b00ec3a..7ce125d 100644 (file)
@@ -472,7 +472,7 @@ abstract class IndexPager extends ContextSource implements Pager {
                }
 
                if ( in_array( $type, [ 'asc', 'desc' ] ) ) {
-                       $attrs['title'] = wfMessage( $type == 'asc' ? 'sort-ascending' : 'sort-descending' )->text();
+                       $attrs['title'] = $this->msg( $type == 'asc' ? 'sort-ascending' : 'sort-descending' )->text();
                }
 
                if ( $type ) {
index 1f5308f..d44ac8c 100644 (file)
@@ -98,11 +98,6 @@ class CoreParserFunctions {
                        $args = array_slice( func_get_args(), 2 );
                        $message = wfMessage( $part1, $args )
                                ->inLanguage( $parser->getOptions()->getUserLangObj() );
-                       if ( !$message->exists() ) {
-                               // When message does not exists, the message name is surrounded by angle
-                               // and can result in a tag, therefore escape the angles
-                               return $message->escaped();
-                       }
                        return [ $message->plain(), 'noparse' => false ];
                } else {
                        return [ 'found' => false ];
index 6bee169..51c04ea 100644 (file)
@@ -425,12 +425,14 @@ class Parser {
         * Do not call this function recursively.
         *
         * @param string $text Text we want to parse
+        * @param-taint $text escapes_htmlnoent
         * @param Title $title
         * @param ParserOptions $options
         * @param bool $linestart
         * @param bool $clearState
         * @param int|null $revid Number to pass in {{REVISIONID}}
         * @return ParserOutput A ParserOutput
+        * @return-taint escaped
         */
        public function parse(
                $text, Title $title, ParserOptions $options,
@@ -517,7 +519,7 @@ class Parser {
                # with CSS (T37247)
                $class = $this->mOptions->getWrapOutputClass();
                if ( $class !== false && !$this->mOptions->getInterfaceMessage() ) {
-                       $text = Html::rawElement( 'div', [ 'class' => $class ], $text );
+                       $this->mOutput->addWrapperDivClass( $class );
                }
 
                $this->mOutput->setText( $text );
@@ -671,8 +673,10 @@ class Parser {
         * $text are not expanded
         *
         * @param string $text Text extension wants to have parsed
+        * @param-taint $text escapes_htmlnoent
         * @param bool|PPFrame $frame The frame to use for expanding any template variables
         * @return string UNSAFE half-parsed HTML
+        * @return-taint escaped
         */
        public function recursiveTagParse( $text, $frame = false ) {
                // Avoid PHP 7.1 warning from passing $this by reference
@@ -697,8 +701,10 @@ class Parser {
         * @since 1.25
         *
         * @param string $text Text extension wants to have parsed
+        * @param-taint $text escapes_htmlnoent
         * @param bool|PPFrame $frame The frame to use for expanding any template variables
         * @return string Fully parsed HTML
+        * @return-taint escaped
         */
        public function recursiveTagParseFully( $text, $frame = false ) {
                $text = $this->recursiveTagParse( $text, $frame );
@@ -1313,6 +1319,7 @@ class Parser {
         * @private
         *
         * @param string $text The text to parse
+        * @param-taint $text escapes_html
         * @param bool $isMain Whether this is being called from the main parse() function
         * @param PPFrame|bool $frame A pre-processor frame
         *
@@ -2692,9 +2699,19 @@ class Parser {
                                $this->mOutput->setFlag( 'vary-revision-id' );
                                wfDebug( __METHOD__ . ": {{REVISIONID}} used, setting vary-revision-id...\n" );
                                $value = $this->mRevisionId;
-                               if ( !$value && $this->mOptions->getSpeculativeRevIdCallback() ) {
-                                       $value = call_user_func( $this->mOptions->getSpeculativeRevIdCallback() );
-                                       $this->mOutput->setSpeculativeRevIdUsed( $value );
+
+                               if ( !$value ) {
+                                       $rev = $this->getRevisionObject();
+                                       if ( $rev ) {
+                                               $value = $rev->getId();
+                                       }
+                               }
+
+                               if ( !$value ) {
+                                       $value = $this->mOptions->getSpeculativeRevId();
+                                       if ( $value ) {
+                                               $this->mOutput->setSpeculativeRevIdUsed( $value );
+                                       }
                                }
                                break;
                        case 'revisionday':
@@ -3783,57 +3800,68 @@ class Parser {
         * Transclude an interwiki link.
         *
         * @param Title $title
-        * @param string $action
+        * @param string $action Usually one of (raw, render)
         *
         * @return string
         */
        public function interwikiTransclude( $title, $action ) {
-               global $wgEnableScaryTranscluding;
+               global $wgEnableScaryTranscluding, $wgTranscludeCacheExpiry;
 
                if ( !$wgEnableScaryTranscluding ) {
                        return wfMessage( 'scarytranscludedisabled' )->inContentLanguage()->text();
                }
 
                $url = $title->getFullURL( [ 'action' => $action ] );
-
-               if ( strlen( $url ) > 255 ) {
+               if ( strlen( $url ) > 1024 ) {
                        return wfMessage( 'scarytranscludetoolong' )->inContentLanguage()->text();
                }
-               return $this->fetchScaryTemplateMaybeFromCache( $url );
-       }
 
-       /**
-        * @param string $url
-        * @return mixed|string
-        */
-       public function fetchScaryTemplateMaybeFromCache( $url ) {
-               global $wgTranscludeCacheExpiry;
-               $dbr = wfGetDB( DB_REPLICA );
-               $tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry );
-               $obj = $dbr->selectRow( 'transcache', [ 'tc_time', 'tc_contents' ],
-                               [ 'tc_url' => $url, "tc_time >= " . $dbr->addQuotes( $tsCond ) ] );
-               if ( $obj ) {
-                       return $obj->tc_contents;
-               }
-
-               $req = MWHttpRequest::factory( $url, [], __METHOD__ );
-               $status = $req->execute(); // Status object
-               if ( $status->isOK() ) {
-                       $text = $req->getContent();
-               } elseif ( $req->getStatus() != 200 ) {
+               $wikiId = $title->getTransWikiID(); // remote wiki ID or false
+
+               $fname = __METHOD__;
+               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+
+               $data = $cache->getWithSetCallback(
+                       $cache->makeGlobalKey(
+                               'interwiki-transclude',
+                               ( $wikiId !== false ) ? $wikiId : 'external',
+                               sha1( $url )
+                       ),
+                       $wgTranscludeCacheExpiry,
+                       function ( $oldValue, &$ttl ) use ( $url, $fname, $cache ) {
+                               $req = MWHttpRequest::factory( $url, [], $fname );
+
+                               $status = $req->execute(); // Status object
+                               if ( !$status->isOK() ) {
+                                       $ttl = $cache::TTL_UNCACHEABLE;
+                               } elseif ( $req->getResponseHeader( 'X-Database-Lagged' ) !== null ) {
+                                       $ttl = min( $cache::TTL_LAGGED, $ttl );
+                               }
+
+                               return [
+                                       'text' => $status->isOK() ? $req->getContent() : null,
+                                       'code' => $req->getStatus()
+                               ];
+                       },
+                       [
+                               'checkKeys' => ( $wikiId !== false )
+                                       ? [ $cache->makeGlobalKey( 'interwiki-page', $wikiId, $title->getDBkey() ) ]
+                                       : [],
+                               'pcGroup' => 'interwiki-transclude:5',
+                               'pcTTL' => $cache::TTL_PROC_LONG
+                       ]
+               );
+
+               if ( is_string( $data['text'] ) ) {
+                       $text = $data['text'];
+               } elseif ( $data['code'] != 200 ) {
                        // Though we failed to fetch the content, this status is useless.
-                       return wfMessage( 'scarytranscludefailed-httpstatus' )
-                               ->params( $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
+                       $text = wfMessage( 'scarytranscludefailed-httpstatus' )
+                               ->params( $url, $data['code'] )->inContentLanguage()->text();
                } else {
-                       return wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text();
+                       $text = wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text();
                }
 
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->replace( 'transcache', [ 'tc_url' ], [
-                       'tc_url' => $url,
-                       'tc_time' => $dbw->timestamp( time() ),
-                       'tc_contents' => $text
-               ] );
                return $text;
        }
 
@@ -5739,10 +5767,9 @@ class Parser {
                if ( !is_null( $this->mRevisionObject ) ) {
                        return $this->mRevisionObject;
                }
-               if ( is_null( $this->mRevisionId ) ) {
-                       return null;
-               }
 
+               // NOTE: try to get the RevisionObject even if mRevisionId is null.
+               // This is useful when parsing revision that has not yet been saved.
                $rev = call_user_func(
                        $this->mOptions->getCurrentRevisionCallback(), $this->getTitle(), $this
                );
@@ -5750,7 +5777,7 @@ class Parser {
                # If the parse is for a new revision, then the callback should have
                # already been set to force the object and should match mRevisionId.
                # If not, try to fetch by mRevisionId for sanity.
-               if ( $rev && $rev->getId() != $this->mRevisionId ) {
+               if ( $this->mRevisionId && $rev && $rev->getId() != $this->mRevisionId ) {
                        $rev = Revision::newFromId( $this->mRevisionId );
                }
 
index 5e6081d..43c72b1 100644 (file)
@@ -301,6 +301,10 @@ class ParserCache {
                $cacheTime = null,
                $revId = null
        ) {
+               if ( !$parserOutput->hasText() ) {
+                       throw new InvalidArgumentException( 'Attempt to cache a ParserOutput with no text set!' );
+               }
+
                $expire = $parserOutput->getCacheExpiry();
                if ( $expire > 0 && !$this->mMemc instanceof EmptyBagOStuff ) {
                        $cacheTime = $cacheTime ?: wfTimestampNow();
index b30c116..a8da3ce 100644 (file)
@@ -61,6 +61,7 @@ class ParserOptions {
         */
        private static $lazyOptions = [
                'dateformat' => [ __CLASS__, 'initDateFormat' ],
+               'speculativeRevId' => [ __CLASS__, 'initSpeculativeRevId' ],
        ];
 
        /**
@@ -831,9 +832,38 @@ class ParserOptions {
                return $this->setOptionLegacy( 'templateCallback', $x );
        }
 
+       /**
+        * A guess for {{REVISIONID}}, calculated using the callback provided via
+        * setSpeculativeRevIdCallback(). For consistency, the value will be calculated upon the
+        * first call of this method, and re-used for subsequent calls.
+        *
+        * If no callback was defined via setSpeculativeRevIdCallback(), this method will return false.
+        *
+        * @since 1.32
+        * @return int|false
+        */
+       public function getSpeculativeRevId() {
+               return $this->getOption( 'speculativeRevId' );
+       }
+
+       /**
+        * Callback registered with ParserOptions::$lazyOptions, triggered by getSpeculativeRevId().
+        *
+        * @param ParserOptions $popt
+        * @return bool|false
+        */
+       private static function initSpeculativeRevId( ParserOptions $popt ) {
+               $cb = $popt->getOption( 'speculativeRevIdCallback' );
+               $id = $cb ? $cb() : null;
+
+               // returning null would result in this being re-called every access
+               return $id ?? false;
+       }
+
        /**
         * Callback to generate a guess for {{REVISIONID}}
         * @since 1.28
+        * @deprecated since 1.32, use getSpeculativeRevId() instead!
         * @return callable|null
         */
        public function getSpeculativeRevIdCallback() {
@@ -847,6 +877,7 @@ class ParserOptions {
         * @return callable|null Old value
         */
        public function setSpeculativeRevIdCallback( $x ) {
+               $this->setOption( 'speculativeRevId', null ); // reset
                return $this->setOptionLegacy( 'speculativeRevIdCallback', $x );
        }
 
@@ -1081,6 +1112,7 @@ class ParserOptions {
                                'currentRevisionCallback' => [ Parser::class, 'statelessFetchRevision' ],
                                'templateCallback' => [ Parser::class, 'statelessFetchTemplate' ],
                                'speculativeRevIdCallback' => null,
+                               'speculativeRevId' => null,
                        ];
 
                        Hooks::run( 'ParserOptionsRegister', [
index 182648a..48ba111 100644 (file)
@@ -31,9 +31,9 @@ class ParserOutput extends CacheTime {
        const SUPPORTS_UNWRAP_TRANSFORM = 1;
 
        /**
-        * @var string $mText The output text
+        * @var string|null $mText The output text
         */
-       public $mText;
+       public $mText = null;
 
        /**
         * @var array $mLanguageLinks List of the full text of language links,
@@ -212,6 +212,11 @@ class ParserOutput extends CacheTime {
        /** @var int|null Assumed rev ID for {{REVISIONID}} if no revision is set */
        private $mSpeculativeRevId;
 
+       /** string CSS classes to use for the wrapping div, stored in the array keys.
+        * If no class is given, no wrapper is added.
+        */
+       private $mWrapperDivClasses = [];
+
        /** @var int Upper bound of expiry based on parse duration */
        private $mMaxAdaptiveExpiry = INF;
 
@@ -227,6 +232,15 @@ class ParserOutput extends CacheTime {
        const SLOW_AR_TTL = 3600; // adaptive TTL for "slow" pages
        const MIN_AR_TTL = 15; // min adaptive TTL (for sanity, pool counter, and edit stashing)
 
+       /**
+        * @param string|null $text HTML. Use null to indicate that this ParserOutput contains only
+        *        meta-data, and the HTML output is undetermined, as opposed to empty. Passing null
+        *        here causes hasText() to return false.
+        * @param array $languageLinks
+        * @param array $categoryLinks
+        * @param bool $unused
+        * @param string $titletext
+        */
        public function __construct( $text = '', $languageLinks = [], $categoryLinks = [],
                $unused = false, $titletext = ''
        ) {
@@ -236,6 +250,20 @@ class ParserOutput extends CacheTime {
                $this->mTitleText = $titletext;
        }
 
+       /**
+        * Returns true if text was passed to the constructor, or set using setText(). Returns false
+        * if null was passed to the $text parameter of the constructor to indicate that this
+        * ParserOutput only contains meta-data, and the HTML output is undetermined.
+        *
+        * @since 1.32
+        *
+        * @return bool Whether this ParserOutput contains rendered text. If this returns false, the
+        *         ParserOutput contains meta-data only.
+        */
+       public function hasText() {
+               return ( $this->mText !== null );
+       }
+
        /**
         * Get the cacheable text with <mw:editsection> markers still in it. The
         * return value is suitable for writing back via setText() but is not valid
@@ -245,6 +273,10 @@ class ParserOutput extends CacheTime {
         * @since 1.27
         */
        public function getRawText() {
+               if ( $this->mText === null ) {
+                       throw new LogicException( 'This ParserOutput contains no text!' );
+               }
+
                return $this->mText;
        }
 
@@ -258,7 +290,12 @@ class ParserOutput extends CacheTime {
         *  - enableSectionEditLinks: (bool) Include section edit links, assuming
         *     section edit link tokens are present in the HTML. Default is true,
         *     but might be statefully overridden.
-        *  - unwrap: (bool) Remove a wrapping mw-parser-output div. Default is false.
+        *  - unwrap: (bool) Return text without a wrapper div. Default is false,
+        *    meaning a wrapper div will be added if getWrapperDivClass() returns
+        *    a non-empty string.
+        *  - wrapperDivClass: (string) Wrap the output in a div and apply the given
+        *    CSS class to that div. This overrides the output of getWrapperDivClass().
+        *    Setting this to an empty string has the same effect as 'unwrap' => true.
         *  - deduplicateStyles: (bool) When true, which is the default, `<style>`
         *    tags with the `data-mw-deduplicate` attribute set are deduplicated by
         *    value of the attribute: all but the first will be replaced by `<link
@@ -266,6 +303,7 @@ class ParserOutput extends CacheTime {
         *    the scheme-specific-part of the href is the (percent-encoded) value
         *    of the `data-mw-deduplicate` attribute.
         * @return string HTML
+        * @return-taint escaped
         */
        public function getText( $options = [] ) {
                $options += [
@@ -273,28 +311,14 @@ class ParserOutput extends CacheTime {
                        'enableSectionEditLinks' => true,
                        'unwrap' => false,
                        'deduplicateStyles' => true,
+                       'wrapperDivClass' => $this->getWrapperDivClass(),
                ];
-               $text = $this->mText;
+               $text = $this->getRawText();
 
                Hooks::runWithoutAbort( 'ParserOutputPostCacheTransform', [ $this, &$text, &$options ] );
 
-               if ( $options['unwrap'] !== false ) {
-                       $start = Html::openElement( 'div', [
-                               'class' => 'mw-parser-output'
-                       ] );
-                       $startLen = strlen( $start );
-                       $end = Html::closeElement( 'div' );
-                       $endPos = strrpos( $text, $end );
-                       $endLen = strlen( $end );
-
-                       if ( substr( $text, 0, $startLen ) === $start && $endPos !== false
-                               // if the closing div is followed by real content, bail out of unwrapping
-                               && preg_match( '/^(?>\s*<!--.*?-->)*\s*$/s', substr( $text, $endPos + $endLen ) )
-                       ) {
-                               $text = substr( $text, $startLen );
-                               $text = substr( $text, 0, $endPos - $startLen )
-                                       . substr( $text, $endPos - $startLen + $endLen );
-                       }
+               if ( $options['wrapperDivClass'] !== '' && !$options['unwrap'] ) {
+                       $text = Html::rawElement( 'div', [ 'class' => $options['wrapperDivClass'] ], $text );
                }
 
                if ( $options['enableSectionEditLinks'] ) {
@@ -362,9 +386,48 @@ class ParserOutput extends CacheTime {
                        );
                }
 
+               // Hydrate slot section header placeholders generated by RevisionRenderer.
+               $text = preg_replace_callback(
+                       '#<mw:slotheader>(.*?)</mw:slotheader>#',
+                       function ( $m ) {
+                               $role = htmlspecialchars_decode( $m[1] );
+                               // TODO: map to message, using the interface language. Set lang="xyz" accordingly.
+                               $headerText = $role;
+                               return $headerText;
+                       },
+                       $text
+               );
                return $text;
        }
 
+       /**
+        * Add a CSS class to use for the wrapping div. If no class is given, no wrapper is added.
+        *
+        * @param string $class
+        */
+       public function addWrapperDivClass( $class ) {
+               $this->mWrapperDivClasses[$class] = true;
+       }
+
+       /**
+        * Clears the CSS class to use for the wrapping div, effectively disabling the wrapper div
+        * until addWrapperDivClass() is called.
+        */
+       public function clearWrapperDivClass() {
+               $this->mWrapperDivClasses = [];
+       }
+
+       /**
+        * Returns the class (or classes) to be used with the wrapper div for this otuput.
+        * If there is no wrapper class given, no wrapper div should be added.
+        * The wrapper div is added automatically by getText().
+        *
+        * @return string
+        */
+       public function getWrapperDivClass() {
+               return implode( ' ', array_keys( $this->mWrapperDivClasses ) );
+       }
+
        /**
         * @param int $id
         * @since 1.28
@@ -445,6 +508,9 @@ class ParserOutput extends CacheTime {
                return $this->mExternalLinks;
        }
 
+       public function setNoGallery( $value ) {
+               $this->mNoGallery = (bool)$value;
+       }
        public function getNoGallery() {
                return $this->mNoGallery;
        }
@@ -1223,4 +1289,211 @@ class ParserOutput extends CacheTime {
                        [ 'mParseStartTime' ]
                );
        }
+
+       /**
+        * Merges internal metadata such as flags, accessed options, and profiling info
+        * from $source into this ParserOutput. This should be used whenever the state of $source
+        * has any impact on the state of this ParserOutput.
+        *
+        * @param ParserOutput $source
+        */
+       public function mergeInternalMetaDataFrom( ParserOutput $source ) {
+               $this->mOutputHooks = self::mergeList( $this->mOutputHooks, $source->getOutputHooks() );
+               $this->mWarnings = self::mergeMap( $this->mWarnings, $source->mWarnings ); // don't use getter
+               $this->mTimestamp = $this->useMaxValue( $this->mTimestamp, $source->getTimestamp() );
+
+               if ( $this->mSpeculativeRevId && $source->mSpeculativeRevId
+                       && $this->mSpeculativeRevId !== $source->mSpeculativeRevId
+               ) {
+                       wfLogWarning(
+                               'Inconsistent speculative revision ID encountered while merging parser output!'
+                       );
+               }
+
+               $this->mSpeculativeRevId = $this->useMaxValue(
+                       $this->mSpeculativeRevId,
+                       $source->getSpeculativeRevIdUsed()
+               );
+               $this->mParseStartTime = $this->useEachMinValue(
+                       $this->mParseStartTime,
+                       $source->mParseStartTime
+               );
+
+               $this->mFlags = self::mergeMap( $this->mFlags, $source->mFlags );
+               $this->mAccessedOptions = self::mergeMap( $this->mAccessedOptions, $source->mAccessedOptions );
+
+               // TODO: maintain per-slot limit reports!
+               if ( empty( $this->mLimitReportData ) ) {
+                       $this->mLimitReportData = $source->mLimitReportData;
+               }
+               if ( empty( $this->mLimitReportJSData ) ) {
+                       $this->mLimitReportJSData = $source->mLimitReportJSData;
+               }
+       }
+
+       /**
+        * Merges HTML metadata such as head items, JS config vars, and HTTP cache control info
+        * from $source into this ParserOutput. This should be used whenever the HTML in $source
+        * has been somehow mered into the HTML of this ParserOutput.
+        *
+        * @param ParserOutput $source
+        */
+       public function mergeHtmlMetaDataFrom( ParserOutput $source ) {
+               // HTML and HTTP
+               $this->mHeadItems = self::mergeMixedList( $this->mHeadItems, $source->getHeadItems() );
+               $this->mModules = self::mergeList( $this->mModules, $source->getModules() );
+               $this->mModuleScripts = self::mergeList( $this->mModuleScripts, $source->getModuleScripts() );
+               $this->mModuleStyles = self::mergeList( $this->mModuleStyles, $source->getModuleStyles() );
+               $this->mJsConfigVars = self::mergeMap( $this->mJsConfigVars, $source->getJsConfigVars() );
+               $this->mMaxAdaptiveExpiry = min( $this->mMaxAdaptiveExpiry, $source->mMaxAdaptiveExpiry );
+
+               // "noindex" always wins!
+               if ( $this->mIndexPolicy === 'noindex' || $source->mIndexPolicy === 'noindex' ) {
+                       $this->mIndexPolicy = 'noindex';
+               } elseif ( $this->mIndexPolicy !== 'index' ) {
+                       $this->mIndexPolicy = $source->mIndexPolicy;
+               }
+
+               // Skin control
+               $this->mNewSection = $this->mNewSection || $source->getNewSection();
+               $this->mHideNewSection = $this->mHideNewSection || $source->getHideNewSection();
+               $this->mNoGallery = $this->mNoGallery || $source->getNoGallery();
+               $this->mEnableOOUI = $this->mEnableOOUI || $source->getEnableOOUI();
+               $this->mPreventClickjacking = $this->mPreventClickjacking || $source->preventClickjacking();
+
+               // TODO: we'll have to be smarter about this!
+               $this->mSections = array_merge( $this->mSections, $source->getSections() );
+               $this->mTOCHTML = $this->mTOCHTML . $source->mTOCHTML;
+
+               // XXX: we don't want to concatenate title text, so first write wins.
+               // We should use the first *modified* title text, but we don't have the original to check.
+               if ( $this->mTitleText === null || $this->mTitleText === '' ) {
+                       $this->mTitleText = $source->mTitleText;
+               }
+
+               // class names are stored in array keys
+               $this->mWrapperDivClasses = self::mergeMap(
+                       $this->mWrapperDivClasses,
+                       $source->mWrapperDivClasses
+               );
+
+               // NOTE: last write wins, same as within one ParserOutput
+               $this->mIndicators = self::mergeMap( $this->mIndicators, $source->getIndicators() );
+
+               // NOTE: include extension data in "tracking meta data" as well as "html meta data"!
+               // TODO: add a $mergeStrategy parameter to setExtensionData to allow different
+               // kinds of extension data to be merged in different ways.
+               $this->mExtensionData = self::mergeMap(
+                       $this->mExtensionData,
+                       $source->mExtensionData
+               );
+       }
+
+       /**
+        * Merges dependency tracking metadata such as backlinks, images used, and extension data
+        * from $source into this ParserOutput. This allows dependency tracking to be done for the
+        * combined output of multiple content slots.
+        *
+        * @param ParserOutput $source
+        */
+       public function mergeTrackingMetaDataFrom( ParserOutput $source ) {
+               $this->mLanguageLinks = self::mergeList( $this->mLanguageLinks, $source->getLanguageLinks() );
+               $this->mCategories = self::mergeMap( $this->mCategories, $source->getCategories() );
+               $this->mLinks = self::merge2D( $this->mLinks, $source->getLinks() );
+               $this->mTemplates = self::merge2D( $this->mTemplates, $source->getTemplates() );
+               $this->mTemplateIds = self::merge2D( $this->mTemplateIds, $source->getTemplateIds() );
+               $this->mImages = self::mergeMap( $this->mImages, $source->getImages() );
+               $this->mFileSearchOptions = self::mergeMap(
+                       $this->mFileSearchOptions,
+                       $source->getFileSearchOptions()
+               );
+               $this->mExternalLinks = self::mergeMap( $this->mExternalLinks, $source->getExternalLinks() );
+               $this->mInterwikiLinks = self::merge2D(
+                       $this->mInterwikiLinks,
+                       $source->getInterwikiLinks()
+               );
+
+               // TODO: add a $mergeStrategy parameter to setProperty to allow different
+               // kinds of properties to be merged in different ways.
+               $this->mProperties = self::mergeMap( $this->mProperties, $source->getProperties() );
+
+               // NOTE: include extension data in "tracking meta data" as well as "html meta data"!
+               // TODO: add a $mergeStrategy parameter to setExtensionData to allow different
+               // kinds of extension data to be merged in different ways.
+               $this->mExtensionData = self::mergeMap(
+                       $this->mExtensionData,
+                       $source->mExtensionData
+               );
+       }
+
+       private static function mergeMixedList( array $a, array $b ) {
+               return array_unique( array_merge( $a, $b ), SORT_REGULAR );
+       }
+
+       private static function mergeList( array $a, array $b ) {
+               return array_values( array_unique( array_merge( $a, $b ), SORT_REGULAR ) );
+       }
+
+       private static function mergeMap( array $a, array $b ) {
+               return array_replace( $a, $b );
+       }
+
+       private static function merge2D( array $a, array $b ) {
+               $values = [];
+               $keys = array_merge( array_keys( $a ), array_keys( $b ) );
+
+               foreach ( $keys as $k ) {
+                       if ( empty( $a[$k] ) ) {
+                               $values[$k] = $b[$k];
+                       } elseif ( empty( $b[$k] ) ) {
+                               $values[$k] = $a[$k];
+                       } elseif ( is_array( $a[$k] ) && is_array( $b[$k] ) ) {
+                               $values[$k] = array_replace( $a[$k], $b[$k] );
+                       } else {
+                               $values[$k] = $b[$k];
+                       }
+               }
+
+               return $values;
+       }
+
+       private static function useEachMinValue( array $a, array $b ) {
+               $values = [];
+               $keys = array_merge( array_keys( $a ), array_keys( $b ) );
+
+               foreach ( $keys as $k ) {
+                       if ( is_array( $a[$k] ?? null ) && is_array( $b[$k] ?? null ) ) {
+                               $values[$k] = self::useEachMinValue( $a[$k], $b[$k] );
+                       } else {
+                               $values[$k] = self::useMinValue( $a[$k] ?? null, $b[$k] ?? null );
+                       }
+               }
+
+               return $values;
+       }
+
+       private static function useMinValue( $a, $b ) {
+               if ( $a === null ) {
+                       return $b;
+               }
+
+               if ( $b === null ) {
+                       return $a;
+               }
+
+               return min( $a, $b );
+       }
+
+       private static function useMaxValue( $a, $b ) {
+               if ( $a === null ) {
+                       return $b;
+               }
+
+               if ( $b === null ) {
+                       return $a;
+               }
+
+               return max( $a, $b );
+       }
+
 }
index bf61779..eb56e13 100644 (file)
@@ -45,6 +45,7 @@ class ExtensionProcessor implements Processor {
                'MediaHandlers',
                'PasswordPolicy',
                'RateLimits',
+               'RawHtmlMessages',
                'RecentChangesFlags',
                'RemoveCredentialsBlacklist',
                'RemoveGroups',
index 59853b4..1569e08 100644 (file)
@@ -183,23 +183,19 @@ class VersionChecker {
                                'missing' => $dependencyName,
                        ];
                }
+               if ( $constraint === '*' ) {
+                       // short-circuit since any version is OK.
+                       return false;
+               }
                // Check if the dependency has specified a version
                if ( !isset( $this->loaded[$dependencyName]['version'] ) ) {
-                       // If we depend upon any version, and none is set, that's fine.
-                       if ( $constraint === '*' ) {
-                               wfDebug( "{$dependencyName} does not expose its version, but {$checkedExt}"
-                                       . " mentions it with constraint '*'. Assume it's ok so." );
-                               return false;
-                       } else {
-                               // Otherwise, mark it as incompatible.
-                               $msg = "{$dependencyName} does not expose its version, but {$checkedExt}"
-                                       . " requires: {$constraint}.";
-                               return [
-                                       'msg' => $msg,
-                                       'type' => "incompatible-$type",
-                                       'incompatible' => $checkedExt,
-                               ];
-                       }
+                       $msg = "{$dependencyName} does not expose its version, but {$checkedExt}"
+                               . " requires: {$constraint}.";
+                       return [
+                               'msg' => $msg,
+                               'type' => "incompatible-$type",
+                               'incompatible' => $checkedExt,
+                       ];
                } else {
                        // Try to get a constraint for the dependency version
                        try {
index 98bae24..fc0ca1d 100644 (file)
@@ -135,7 +135,7 @@ class ResourceLoader implements LoggerAwareInterface {
                        $module = $this->getModule( $row->md_module );
                        if ( $module ) {
                                $module->setFileDependencies( $context, ResourceLoaderModule::expandRelativePaths(
-                                       FormatJson::decode( $row->md_deps, true )
+                                       json_decode( $row->md_deps, true )
                                ) );
                                $modulesWithDeps[] = $row->md_module;
                        }
@@ -1163,9 +1163,9 @@ MESSAGE;
                                $out = $this->ensureNewline( $out ) . $stateScript;
                        }
                } else {
-                       if ( count( $states ) ) {
-                               $this->errors[] = 'Problematic modules: ' .
-                                       FormatJson::encode( $states, self::inDebugMode() );
+                       if ( $states ) {
+                               // Keep default escaping of slashes (e.g. "</script>") for ResourceLoaderClientHtml.
+                               $this->errors[] = 'Problematic modules: ' . json_encode( $states, JSON_PRETTY_PRINT );
                        }
                }
 
index 3bf309d..a507ad3 100644 (file)
@@ -416,7 +416,7 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
 
                        if ( !is_null( $deps ) ) {
                                $this->fileDeps[$vary] = self::expandRelativePaths(
-                                       (array)FormatJson::decode( $deps, true )
+                                       (array)json_decode( $deps, true )
                                );
                        } else {
                                $this->fileDeps[$vary] = [];
@@ -476,7 +476,9 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                                        return; // T124649; avoid write slams
                                }
 
-                               $deps = FormatJson::encode( $localPaths );
+                               // No needless escaping as this isn't HTML output.
+                               // Only stored in the database and parsed in PHP.
+                               $deps = json_encode( $localPaths, JSON_UNESCAPED_SLASHES );
                                $dbw = wfGetDB( DB_MASTER );
                                $dbw->upsert( 'module_deps',
                                        [
@@ -687,79 +689,77 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
                $statStart = microtime( true );
 
-               // Only include properties that are relevant to this context (e.g. only=scripts)
-               // and that are non-empty (e.g. don't include "templates" for modules without
-               // templates). This helps prevent invalidating cache for all modules when new
-               // optional properties are introduced.
+               // This MUST build both scripts and styles, regardless of whether $context->getOnly()
+               // is 'scripts' or 'styles' because the result is used by getVersionHash which
+               // must be consistent regardles of the 'only' filter on the current request.
+               // Also, when introducing new module content resources (e.g. templates, headers),
+               // these should only be included in the array when they are non-empty so that
+               // existing modules not using them do not get their cache invalidated.
                $content = [];
 
                // Scripts
-               if ( $context->shouldIncludeScripts() ) {
-                       // If we are in debug mode, we'll want to return an array of URLs if possible
-                       // However, we can't do this if the module doesn't support it
-                       // We also can't do this if there is an only= parameter, because we have to give
-                       // the module a way to return a load.php URL without causing an infinite loop
-                       if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
-                               $scripts = $this->getScriptURLsForDebug( $context );
-                       } else {
-                               $scripts = $this->getScript( $context );
-                               // Make the script safe to concatenate by making sure there is at least one
-                               // trailing new line at the end of the content. Previously, this looked for
-                               // a semi-colon instead, but that breaks concatenation if the semicolon
-                               // is inside a comment like "// foo();". Instead, simply use a
-                               // line break as separator which matches JavaScript native logic for implicitly
-                               // ending statements even if a semi-colon is missing.
-                               // Bugs: T29054, T162719.
-                               if ( is_string( $scripts )
-                                       && strlen( $scripts )
-                                       && substr( $scripts, -1 ) !== "\n"
-                               ) {
-                                       $scripts .= "\n";
-                               }
+               // If we are in debug mode, we'll want to return an array of URLs if possible
+               // However, we can't do this if the module doesn't support it.
+               // We also can't do this if there is an only= parameter, because we have to give
+               // the module a way to return a load.php URL without causing an infinite loop
+               if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
+                       $scripts = $this->getScriptURLsForDebug( $context );
+               } else {
+                       $scripts = $this->getScript( $context );
+                       // Make the script safe to concatenate by making sure there is at least one
+                       // trailing new line at the end of the content. Previously, this looked for
+                       // a semi-colon instead, but that breaks concatenation if the semicolon
+                       // is inside a comment like "// foo();". Instead, simply use a
+                       // line break as separator which matches JavaScript native logic for implicitly
+                       // ending statements even if a semi-colon is missing.
+                       // Bugs: T29054, T162719.
+                       if ( is_string( $scripts )
+                               && strlen( $scripts )
+                               && substr( $scripts, -1 ) !== "\n"
+                       ) {
+                               $scripts .= "\n";
                        }
-                       $content['scripts'] = $scripts;
                }
+               $content['scripts'] = $scripts;
 
                // Styles
-               if ( $context->shouldIncludeStyles() ) {
-                       $styles = [];
-                       // Don't create empty stylesheets like [ '' => '' ] for modules
-                       // that don't *have* any stylesheets (T40024).
-                       $stylePairs = $this->getStyles( $context );
-                       if ( count( $stylePairs ) ) {
-                               // If we are in debug mode without &only= set, we'll want to return an array of URLs
-                               // See comment near shouldIncludeScripts() for more details
-                               if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
-                                       $styles = [
-                                               'url' => $this->getStyleURLsForDebug( $context )
-                                       ];
-                               } else {
-                                       // Minify CSS before embedding in mw.loader.implement call
-                                       // (unless in debug mode)
-                                       if ( !$context->getDebug() ) {
-                                               foreach ( $stylePairs as $media => $style ) {
-                                                       // Can be either a string or an array of strings.
-                                                       if ( is_array( $style ) ) {
-                                                               $stylePairs[$media] = [];
-                                                               foreach ( $style as $cssText ) {
-                                                                       if ( is_string( $cssText ) ) {
-                                                                               $stylePairs[$media][] =
-                                                                                       ResourceLoader::filter( 'minify-css', $cssText );
-                                                                       }
+               $styles = [];
+               // Don't create empty stylesheets like [ '' => '' ] for modules
+               // that don't *have* any stylesheets (T40024).
+               $stylePairs = $this->getStyles( $context );
+               if ( count( $stylePairs ) ) {
+                       // If we are in debug mode without &only= set, we'll want to return an array of URLs
+                       // See comment near shouldIncludeScripts() for more details
+                       if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
+                               $styles = [
+                                       'url' => $this->getStyleURLsForDebug( $context )
+                               ];
+                       } else {
+                               // Minify CSS before embedding in mw.loader.implement call
+                               // (unless in debug mode)
+                               if ( !$context->getDebug() ) {
+                                       foreach ( $stylePairs as $media => $style ) {
+                                               // Can be either a string or an array of strings.
+                                               if ( is_array( $style ) ) {
+                                                       $stylePairs[$media] = [];
+                                                       foreach ( $style as $cssText ) {
+                                                               if ( is_string( $cssText ) ) {
+                                                                       $stylePairs[$media][] =
+                                                                               ResourceLoader::filter( 'minify-css', $cssText );
                                                                }
-                                                       } elseif ( is_string( $style ) ) {
-                                                               $stylePairs[$media] = ResourceLoader::filter( 'minify-css', $style );
                                                        }
+                                               } elseif ( is_string( $style ) ) {
+                                                       $stylePairs[$media] = ResourceLoader::filter( 'minify-css', $style );
                                                }
                                        }
-                                       // Wrap styles into @media groups as needed and flatten into a numerical array
-                                       $styles = [
-                                               'css' => $rl->makeCombinedStyles( $stylePairs )
-                                       ];
                                }
+                               // Wrap styles into @media groups as needed and flatten into a numerical array
+                               $styles = [
+                                       'css' => $rl->makeCombinedStyles( $stylePairs )
+                               ];
                        }
-                       $content['styles'] = $styles;
                }
+               $content['styles'] = $styles;
 
                // Messages
                $blob = $this->getMessageBlob( $context );
@@ -803,22 +803,12 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         * @return string Hash (should use ResourceLoader::makeHash)
         */
        public function getVersionHash( ResourceLoaderContext $context ) {
-               // The startup module produces a manifest with versions representing the entire module.
-               // Typically, the request for the startup module itself has only=scripts. That must apply
-               // only to the startup module content, and not to the module version computed here.
-               $context = new DerivativeResourceLoaderContext( $context );
-               $context->setModules( [] );
-               // Version hash must cover all resources, regardless of startup request itself.
-               $context->setOnly( null );
-               // Compute version hash based on content, not debug urls.
-               $context->setDebug( false );
-
                // Cache this somewhat expensive operation. Especially because some classes
                // (e.g. startup module) iterate more than once over all modules to get versions.
                $contextHash = $context->getHash();
                if ( !array_key_exists( $contextHash, $this->versionHash ) ) {
                        if ( $this->enableModuleContentVersion() ) {
-                               // Detect changes directly
+                               // Detect changes directly by hashing the module contents.
                                $str = json_encode( $this->getModuleContent( $context ) );
                        } else {
                                // Infer changes based on definition and other metrics
index de25d32..2455596 100644 (file)
@@ -76,6 +76,89 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
                return $styles;
        }
 
+       /**
+        * @param ResourceLoaderContext $context
+        * @return array
+        */
+       public function getPreloadLinks( ResourceLoaderContext $context ) {
+               return $this->getLogoPreloadlinks();
+       }
+
+       /**
+        * Helper method for getPreloadLinks()
+        * @return array
+        */
+       private function getLogoPreloadlinks() {
+               $logo = $this->getLogoData( $this->getConfig() );
+
+               $tags = [];
+               $logosPerDppx = [];
+               $logos = [];
+
+               $preloadLinks = [];
+
+               if ( !is_array( $logo ) ) {
+                       // No media queries required if we only have one variant
+                       $preloadLinks[ $logo ] = [ 'as' => 'image' ];
+                       return $preloadLinks;
+               }
+
+               if ( isset( $logo['svg'] ) ) {
+                       // No media queries required if we only have a 1x and svg variant
+                       // because all preload-capable browsers support SVGs
+                       $preloadLinks [ $logo['svg'] ] = [ 'as' => 'image' ];
+                       return $preloadLinks;
+               }
+
+               foreach ( $logo as $dppx => $src ) {
+                       // Keys are in this format: "1.5x"
+                       $dppx = substr( $dppx, 0, -1 );
+                       $logosPerDppx[$dppx] = $src;
+               }
+
+               // Because PHP can't have floats as array keys
+               uksort( $logosPerDppx, function ( $a , $b ) {
+                       $a = floatval( $a );
+                       $b = floatval( $b );
+                       // Sort from smallest to largest (e.g. 1x, 1.5x, 2x)
+                       return $a <=> $b;
+               } );
+
+               foreach ( $logosPerDppx as $dppx => $src ) {
+                       $logos[] = [ 'dppx' => $dppx, 'src' => $src ];
+               }
+
+               $logosCount = count( $logos );
+               // Logic must match ResourceLoaderSkinModule:
+               // - 1x applies to resolution < 1.5dppx
+               // - 1.5x applies to resolution >= 1.5dppx && < 2dppx
+               // - 2x applies to resolution >= 2dppx
+               // Note that min-resolution and max-resolution are both inclusive.
+               for ( $i = 0; $i < $logosCount; $i++ ) {
+                       if ( $i === 0 ) {
+                               // Smallest dppx
+                               // min-resolution is ">=" (larger than or equal to)
+                               // "not min-resolution" is essentially "<"
+                               $media_query = 'not all and (min-resolution: ' . $logos[ 1 ]['dppx'] . 'dppx)';
+                       } elseif ( $i !== $logosCount - 1 ) {
+                               // In between
+                               // Media query expressions can only apply "not" to the entire expression
+                               // (e.g. can't express ">= 1.5 and not >= 2).
+                               // Workaround: Use <= 1.9999 in place of < 2.
+                               $upper_bound = floatval( $logos[ $i + 1 ]['dppx'] ) - 0.000001;
+                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] .
+                                       'dppx) and (max-resolution: ' . $upper_bound . 'dppx)';
+                       } else {
+                               // Largest dppx
+                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] . 'dppx)';
+                       }
+
+                       $preloadLinks[ $logos[$i]['src'] ] = [ 'as' => 'image', 'media' => $media_query ];
+               }
+
+               return $preloadLinks;
+       }
+
        /**
         * Ensure all media keys use array values.
         *
@@ -93,25 +176,14 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
        }
 
        /**
-        * Non-static proxy to ::getLogo (for overloading in sub classes or tests).
-        *
-        * @codeCoverageIgnore
         * @since 1.31
-        * @param Config $conf
-        * @return string|array
-        */
-       protected function getLogoData( Config $conf ) {
-               return static::getLogo( $conf );
-       }
-
-       /**
         * @param Config $conf
         * @return string|array Single url if no variants are defined,
         *  or an array of logo urls keyed by dppx in form "<float>x".
         *  Key "1x" is always defined. Key "svg" may also be defined,
         *  in which case variants other than "1x" are omitted.
         */
-       public static function getLogo( Config $conf ) {
+       protected function getLogoData( Config $conf ) {
                $logo = $conf->get( 'Logo' );
                $logoHD = $conf->get( 'LogoHD' );
 
index 2457fe8..18cc4d5 100644 (file)
@@ -388,31 +388,50 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                if ( $context->getDebug() ) {
                        $mwLoaderCode .= file_get_contents( "$IP/resources/src/startup/mediawiki.log.js" );
                }
+               if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
+                       $mwLoaderCode .= file_get_contents( "$IP/resources/src/startup/profiler.js" );
+               }
 
-               $mapToJson = function ( $value ) {
-                       $value = FormatJson::encode( $value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK );
-                       // Fix indentation
-                       $value = str_replace( "\n", "\n\t", $value );
-                       return $value;
-               };
+               // Keep output as small as possible by disabling needless escapes that PHP uses by default.
+               // This is not HTML output, only used in a JS response.
+               $jsonFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+               if ( ResourceLoader::inDebugMode() ) {
+                       $jsonFlags |= JSON_PRETTY_PRINT;
+               }
 
                // Perform replacements for mediawiki.js
-               $mwLoaderCode = strtr( $mwLoaderCode, [
-                       '$VARS.baseModules' => $mapToJson( $this->getBaseModules() ),
-               ] );
-
-               // Perform replacements for startup.js
-               $pairs = array_map( $mapToJson, [
-                       '$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
-                       '$VARS.configuration' => $this->getConfigSettings( $context ),
-               ] );
-               // Raw JavaScript code (not for JSON)
-               $pairs['$CODE.registrations();'] = str_replace(
-                       "\n",
-                       "\n\t",
-                       trim( $this->getModuleRegistrations( $context ) )
-               );
-               $pairs['$CODE.defineLoader();'] = $mwLoaderCode;
+               $mwLoaderPairs = [
+                       '$VARS.baseModules' => json_encode( $this->getBaseModules(), $jsonFlags ),
+               ];
+               $profilerStubs = [
+                       '$CODE.profileExecuteStart();' => 'mw.loader.profiler.onExecuteStart( module );',
+                       '$CODE.profileExecuteEnd();' => 'mw.loader.profiler.onExecuteEnd( module );',
+                       '$CODE.profileScriptStart();' => 'mw.loader.profiler.onScriptStart( module );',
+                       '$CODE.profileScriptEnd();' => 'mw.loader.profiler.onScriptEnd( module );',
+               ];
+               if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
+                       // When profiling is enabled, insert the calls.
+                       $mwLoaderPairs += $profilerStubs;
+               } else {
+                       // When disabled (by default), insert nothing.
+                       $mwLoaderPairs += array_fill_keys( array_keys( $profilerStubs ), '' );
+               }
+               $mwLoaderCode = strtr( $mwLoaderCode, $mwLoaderPairs );
+
+               // Perform string replacements for startup.js
+               $pairs = [
+                       '$VARS.wgLegacyJavaScriptGlobals' => json_encode(
+                               $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
+                               $jsonFlags
+                       ),
+                       '$VARS.configuration' => json_encode(
+                               $this->getConfigSettings( $context ),
+                               $jsonFlags
+                       ),
+                       // Raw JavaScript code (not JSON)
+                       '$CODE.registrations();' => trim( $this->getModuleRegistrations( $context ) ),
+                       '$CODE.defineLoader();' => $mwLoaderCode,
+               ];
                $startupCode = strtr( $startupCode, $pairs );
 
                return $startupCode;
@@ -434,13 +453,15 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
        public function getDefinitionSummary( ResourceLoaderContext $context ) {
                global $IP;
                $summary = parent::getDefinitionSummary( $context );
-               $summary[] = [
-                       // Detect changes to variables exposed in mw.config (T30899).
+               $startup = [
+                       // getScript() exposes these variables to mw.config (T30899).
                        'vars' => $this->getConfigSettings( $context ),
-                       // Changes how getScript() creates mw.Map for mw.config
+                       // getScript() uses this to decide how configure mw.Map for mw.config.
                        'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
-                       // Detect changes to the module registrations
+                       // Detect changes to the module registrations output by getScript().
                        'moduleHashes' => $this->getAllModuleHashes( $context ),
+                       // Detect changes to base modules listed by getScript().
+                       'baseModules' => $this->getBaseModules(),
 
                        'fileHashes' => [
                                $this->safeFileHash( "$IP/resources/src/startup/startup.js" ),
@@ -448,6 +469,13 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                                $this->safeFileHash( "$IP/resources/src/startup/mediawiki.requestIdleCallback.js" ),
                        ],
                ];
+               if ( $context->getDebug() ) {
+                       $startup['fileHashes'][] = $this->safeFileHash( "$IP/resources/src/startup/mediawiki.log.js" );
+               }
+               if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
+                       $startup['fileHashes'][] = $this->safeFileHash( "$IP/resources/src/startup/profiling.js" );
+               }
+               $summary[] = $startup;
                return $summary;
        }
 
index 679acc6..11f2d13 100644 (file)
  * Item class for a archive table row
  */
 class RevDelArchiveItem extends RevDelRevisionItem {
-       public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-               $this->revision = Revision::newFromArchiveRow( $row,
-                       [ 'page' => $this->list->title->getArticleID() ] );
+       protected static function initRevision( $list, $row ) {
+               return Revision::newFromArchiveRow( $row,
+                       [ 'page' => $list->title->getArticleID() ] );
        }
 
        public function getIdField() {
index d36fac9..00e40a0 100644 (file)
@@ -29,11 +29,14 @@ class RevDelArchivedFileItem extends RevDelFileItem {
        protected $lockFile;
 
        public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-               $this->file = ArchivedFile::newFromRow( $row );
+               parent::__construct( $list, $row );
                $this->lockFile = RepoGroup::singleton()->getLocalRepo()->newFile( $row->fa_name );
        }
 
+       protected static function initFile( $list, $row ) {
+               return ArchivedFile::newFromRow( $row );
+       }
+
        public function getIdField() {
                return 'fa_id';
        }
index d839fcf..fd214e1 100644 (file)
  * used via RevDelRevisionList.
  */
 class RevDelArchivedRevisionItem extends RevDelArchiveItem {
-       public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-
-               $this->revision = Revision::newFromArchiveRow( $row,
-                       [ 'page' => $this->list->title->getArticleID() ] );
-       }
-
        public function getIdField() {
                return 'ar_rev_id';
        }
index 0ca84d7..c7941b7 100644 (file)
@@ -30,7 +30,18 @@ class RevDelFileItem extends RevDelItem {
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
-               $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
+               $this->file = static::initFile( $list, $row );
+       }
+
+       /**
+        * Create file object from $row sourced from $list
+        *
+        * @param RevDelFileList $list
+        * @param mixed $row
+        * @return mixed
+        */
+       protected static function initFile( $list, $row ) {
+               return RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
        }
 
        public function getIdField() {
index 7b5d130..2cfa2ab 100644 (file)
@@ -28,7 +28,18 @@ class RevDelRevisionItem extends RevDelItem {
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
-               $this->revision = new Revision( $row );
+               $this->revision = static::initRevision( $list, $row );
+       }
+
+       /**
+        * Create revision object from $row sourced from $list
+        *
+        * @param RevisionListBase $list
+        * @param mixed $row
+        * @return Revision
+        */
+       protected static function initRevision( $list, $row ) {
+               return new Revision( $row );
        }
 
        public function getIdField() {
index 14d5c4b..2f1a5c2 100644 (file)
@@ -127,7 +127,7 @@ class SearchResultSet implements Countable, IteratorAggregate {
        /**
         * Some search modes will run an alternative query that it thinks gives
         * a better result than the provided search. Returns true if this has
-        * occured.
+        * occurred.
         *
         * @return bool
         */
index c603f2f..2f5e0c8 100644 (file)
@@ -503,6 +503,10 @@ abstract class Skin extends ContextSource {
 
        /**
         * Whether the logo should be preloaded with an HTTP link header or not
+        *
+        * @deprecated since 1.32 Redundant. It now happens automatically based on whether
+        *  the skin loads a stylesheet based on ResourceLoaderSkinModule, which all
+        *  skins that use wgLogo in CSS do, and other's would not.
         * @since 1.29
         * @return bool
         */
@@ -533,7 +537,7 @@ abstract class Skin extends ContextSource {
                        $t = $embed . implode( "{$pop}{$embed}", $allCats['normal'] ) . $pop;
 
                        $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped();
-                       $linkPage = wfMessage( 'pagecategorieslink' )->inContentLanguage()->text();
+                       $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
                        $title = Title::newFromText( $linkPage );
                        $link = $title ? Linker::link( $title, $msg ) : $msg;
                        $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
@@ -1331,7 +1335,7 @@ abstract class Skin extends ContextSource {
         * @param string $message
         */
        public function addToSidebar( &$bar, $message ) {
-               $this->addToSidebarPlain( $bar, wfMessage( $message )->inContentLanguage()->plain() );
+               $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
        }
 
        /**
@@ -1621,13 +1625,13 @@ abstract class Skin extends ContextSource {
 
                $attribs = [];
                if ( !is_null( $tooltip ) ) {
-                       $attribs['title'] = wfMessage( 'editsectionhint' )->rawParams( $tooltip )
+                       $attribs['title'] = $this->msg( 'editsectionhint' )->rawParams( $tooltip )
                                ->inLanguage( $lang )->text();
                }
 
                $links = [
                        'editsection' => [
-                               'text' => wfMessage( 'editsection' )->inLanguage( $lang )->escaped(),
+                               'text' => $this->msg( 'editsection' )->inLanguage( $lang )->escaped(),
                                'targetTitle' => $nt,
                                'attribs' => $attribs,
                                'query' => [ 'action' => 'edit', 'section' => $section ],
@@ -1652,7 +1656,7 @@ abstract class Skin extends ContextSource {
 
                $result .= implode(
                        '<span class="mw-editsection-divider">'
-                               . wfMessage( 'pipe-separator' )->inLanguage( $lang )->escaped()
+                               . $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
                                . '</span>',
                        $linksHtml
                );
index b44d409..564220c 100644 (file)
@@ -1055,13 +1055,13 @@ class SkinTemplate extends Skin {
                                        }
                                } else {
                                        // article doesn't exist or is deleted
-                                       if ( $user->isAllowed( 'deletedhistory' ) ) {
+                                       if ( $title->quickUserCan( 'deletedhistory', $user ) ) {
                                                $n = $title->isDeleted();
                                                if ( $n ) {
                                                        $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
                                                        // If the user can't undelete but can view deleted
                                                        // history show them a "View .. deleted" tab instead.
-                                                       $msgKey = $user->isAllowed( 'undelete' ) ? 'undelete' : 'viewdeleted';
+                                                       $msgKey = $title->quickUserCan( 'undelete', $user ) ? 'undelete' : 'viewdeleted';
                                                        $content_navigation['actions']['undelete'] = [
                                                                'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
                                                                'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
index ff44bda..088b060 100644 (file)
@@ -43,18 +43,31 @@ class AncientPagesPage extends QueryPage {
        }
 
        public function getQueryInfo() {
+               $tables = [ 'page', 'revision' ];
+               $conds = [
+                       'page_namespace' => MWNamespace::getContentNamespaces(),
+                       'page_is_redirect' => 0
+               ];
+               $joinConds = [
+                       'revision' => [
+                               'INNER JOIN', [
+                                       'page_latest = rev_id'
+                               ]
+                       ],
+               ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'AncientPagesQuery', [ &$tables, &$conds, &$joinConds ] );
+
                return [
-                       'tables' => [ 'page', 'revision' ],
+                       'tables' => $tables,
                        'fields' => [
                                'namespace' => 'page_namespace',
                                'title' => 'page_title',
                                'value' => 'rev_timestamp'
                        ],
-                       'conds' => [
-                               'page_namespace' => MWNamespace::getContentNamespaces(),
-                               'page_is_redirect' => 0,
-                               'page_latest=rev_id'
-                       ]
+                       'conds' => $conds,
+                       'join_conds' => $joinConds
                ];
        }
 
index 970a2e2..1d0ff21 100644 (file)
@@ -157,9 +157,9 @@ class SpecialChangeCredentials extends AuthManagerSpecialPage {
 
                $form->addPreText(
                        Html::openElement( 'dl' )
-                       . Html::element( 'dt', [], wfMessage( 'credentialsform-provider' )->text() )
+                       . Html::element( 'dt', [], $this->msg( 'credentialsform-provider' )->text() )
                        . Html::element( 'dd', [], $info['provider'] )
-                       . Html::element( 'dt', [], wfMessage( 'credentialsform-account' )->text() )
+                       . Html::element( 'dt', [], $this->msg( 'credentialsform-account' )->text() )
                        . Html::element( 'dd', [], $info['account'] )
                        . Html::closeElement( 'dl' )
                );
index f5e2b86..63b64ea 100644 (file)
@@ -706,7 +706,7 @@ class SpecialContributions extends IncludableSpecialPage {
                $dateRangeSelection = Html::rawElement(
                        'div',
                        [],
-                       Xml::label( wfMessage( 'date-range-from' )->text(), 'mw-date-start' ) . ' ' .
+                       Xml::label( $this->msg( 'date-range-from' )->text(), 'mw-date-start' ) . ' ' .
                        new DateInputWidget( [
                                'infusable' => true,
                                'id' => 'mw-date-start',
@@ -714,7 +714,7 @@ class SpecialContributions extends IncludableSpecialPage {
                                'value' => $this->opts['start'],
                                'longDisplayFormat' => true,
                        ] ) . '<br>' .
-                       Xml::label( wfMessage( 'date-range-to' )->text(), 'mw-date-end' ) . ' ' .
+                       Xml::label( $this->msg( 'date-range-to' )->text(), 'mw-date-end' ) . ' ' .
                        new DateInputWidget( [
                                'infusable' => true,
                                'id' => 'mw-date-end',
index 975d64e..3f87712 100644 (file)
@@ -61,7 +61,9 @@ class DeletedContributionsPage extends SpecialPage {
                $opts->validateIntBounds( 'limit', 0, $this->getConfig()->get( 'QueryPageDefaultLimit' ) );
 
                if ( $par !== null ) {
-                       $opts->setValue( 'target', $par );
+                       // Beautify the username
+                       $par = User::getCanonicalName( $par, false );
+                       $opts->setValue( 'target', (string)$par );
                }
 
                $ns = $opts->getValue( 'namespace' );
index 9248a40..7de44d8 100644 (file)
@@ -438,7 +438,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                         * SPF and bounce problems with some mailers (see below).
                         */
                        $mailFrom = new MailAddress( $config->get( 'PasswordSender' ),
-                               wfMessage( 'emailsender' )->inContentLanguage()->text() );
+                               $context->msg( 'emailsender' )->inContentLanguage()->text() );
                        $replyTo = $from;
                } else {
                        /**
@@ -482,7 +482,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                                if ( $config->get( 'UserEmailUseReplyTo' ) ) {
                                        $mailFrom = new MailAddress(
                                                $config->get( 'PasswordSender' ),
-                                               wfMessage( 'emailsender' )->inContentLanguage()->text()
+                                               $context->msg( 'emailsender' )->inContentLanguage()->text()
                                        );
                                        $replyTo = $ccFrom;
                                } else {
index ac10c2f..be79cae 100644 (file)
@@ -437,7 +437,7 @@ class SpecialExport extends SpecialPage {
                $pages = [];
 
                foreach ( $res as $row ) {
-                       $pages[] = Title::makeName( $row->page_title, $row->page_namespace );
+                       $pages[] = Title::makeName( $row->page_namespace, $row->page_title );
                }
 
                return $pages;
@@ -462,7 +462,7 @@ class SpecialExport extends SpecialPage {
                $pages = [];
 
                foreach ( $res as $row ) {
-                       $pages[] = Title::makeName( $row->page_title, $row->page_namespace );
+                       $pages[] = Title::makeName( $row->page_namespace, $row->page_title );
                }
 
                return $pages;
index da10b90..d4ef936 100644 (file)
@@ -42,8 +42,8 @@ class SpecialLinkAccounts extends AuthManagerSpecialPage {
                if ( !$this->isActionAllowed( $this->authAction ) ) {
                        if ( $this->authAction === AuthManager::ACTION_LINK ) {
                                // looks like no linking provider is installed or willing to take this user
-                               $titleMessage = wfMessage( 'cannotlink-no-provider-title' );
-                               $errorMessage = wfMessage( 'cannotlink-no-provider' );
+                               $titleMessage = $this->msg( 'cannotlink-no-provider-title' );
+                               $errorMessage = $this->msg( 'cannotlink-no-provider' );
                                throw new ErrorPageError( $titleMessage, $errorMessage );
                        } else {
                                // user probably back-button-navigated into an auth session that no longer exists
index 0490cbb..08b33c1 100644 (file)
@@ -130,7 +130,7 @@ class SpecialPreferences extends SpecialPage {
                                                'role' => 'presentation',
                                                'class' => ( $key === 'personal' ) ? 'selected' : null
                                        ],
-                                       Html::rawElement( 'a',
+                                       Html::element( 'a',
                                                [
                                                        'id' => 'preftab-' . $key,
                                                        'role' => 'tab',
index b159fff..9564d53 100644 (file)
@@ -56,7 +56,7 @@ class SpecialUnlinkAccounts extends AuthManagerSpecialPage {
                }
 
                $status = StatusValue::newGood();
-               $status->warning( wfMessage( 'unlinkaccounts-success' ) );
+               $status->warning( $this->msg( 'unlinkaccounts-success' ) );
                $this->loadAuth( $subPage, null, true ); // update requests so the unlinked one doesn't show up
 
                // Reset sessions - if the user unlinked an account because it was compromised,
index c832f2d..f9d6b5f 100644 (file)
@@ -116,7 +116,7 @@ class SpecialUpload extends SpecialPage {
                $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
 
                $commentDefault = '';
-               $commentMsg = wfMessage( 'upload-default-description' )->inContentLanguage();
+               $commentMsg = $this->msg( 'upload-default-description' )->inContentLanguage();
                if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
                        $commentDefault = $commentMsg->plain();
                }
@@ -401,12 +401,12 @@ class SpecialUpload extends SpecialPage {
                        } elseif ( $warning == 'no-change' ) {
                                $file = $args;
                                $filename = $file->getTitle()->getPrefixedText();
-                               $msg = "\t<li>" . wfMessage( 'fileexists-no-change', $filename )->parse() . "</li>\n";
+                               $msg = "\t<li>" . $this->msg( 'fileexists-no-change', $filename )->parse() . "</li>\n";
                        } elseif ( $warning == 'duplicate-version' ) {
                                $file = $args[0];
                                $count = count( $args );
                                $filename = $file->getTitle()->getPrefixedText();
-                               $message = wfMessage( 'fileexists-duplicate-version' )
+                               $message = $this->msg( 'fileexists-duplicate-version' )
                                        ->params( $filename )
                                        ->numParams( $count );
                                $msg = "\t<li>" . $message->parse() . "</li>\n";
@@ -415,14 +415,14 @@ class SpecialUpload extends SpecialPage {
                                $ltitle = SpecialPage::getTitleFor( 'Log' );
                                $llink = $linkRenderer->makeKnownLink(
                                        $ltitle,
-                                       wfMessage( 'deletionlog' )->text(),
+                                       $this->msg( 'deletionlog' )->text(),
                                        [],
                                        [
                                                'type' => 'delete',
                                                'page' => Title::makeTitle( NS_FILE, $args )->getPrefixedText(),
                                        ]
                                );
-                               $msg = "\t<li>" . wfMessage( 'filewasdeleted' )->rawParams( $llink )->parse() . "</li>\n";
+                               $msg = "\t<li>" . $this->msg( 'filewasdeleted' )->rawParams( $llink )->parse() . "</li>\n";
                        } elseif ( $warning == 'duplicate' ) {
                                $msg = $this->getDupeWarning( $args );
                        } elseif ( $warning == 'duplicate-archive' ) {
index c8b1578..a00b031 100644 (file)
@@ -130,7 +130,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
 
                if ( $type !== 'file' && $type !== 'thumb' ) {
                        throw new UploadStashBadPathException(
-                               wfMessage( 'uploadstash-bad-path-unknown-type', $type )
+                               $this->msg( 'uploadstash-bad-path-unknown-type', $type )
                        );
                }
                $fileName = strtok( '/' );
@@ -140,7 +140,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                        $srcNamePos = strrpos( $thumbPart, $fileName );
                        if ( $srcNamePos === false || $srcNamePos < 1 ) {
                                throw new UploadStashBadPathException(
-                                       wfMessage( 'uploadstash-bad-path-unrecognized-thumb-name' )
+                                       $this->msg( 'uploadstash-bad-path-unrecognized-thumb-name' )
                                );
                        }
                        $paramString = substr( $thumbPart, 0, $srcNamePos - 1 );
@@ -152,7 +152,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                                return [ 'file' => $file, 'type' => $type, 'params' => $params ];
                        } else {
                                throw new UploadStashBadPathException(
-                                       wfMessage( 'uploadstash-bad-path-no-handler', $file->getMimeType(), $file->getPath() )
+                                       $this->msg( 'uploadstash-bad-path-no-handler', $file->getMimeType(), $file->getPath() )
                                );
                        }
                }
@@ -200,14 +200,14 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                $thumbnailImage = $file->transform( $params, $flags );
                if ( !$thumbnailImage ) {
                        throw new UploadStashFileNotFoundException(
-                               wfMessage( 'uploadstash-file-not-found-no-thumb' )
+                               $this->msg( 'uploadstash-file-not-found-no-thumb' )
                        );
                }
 
                // we should have just generated it locally
                if ( !$thumbnailImage->getStoragePath() ) {
                        throw new UploadStashFileNotFoundException(
-                               wfMessage( 'uploadstash-file-not-found-no-local-path' )
+                               $this->msg( 'uploadstash-file-not-found-no-local-path' )
                        );
                }
 
@@ -217,7 +217,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                        $this->stash->repo, $thumbnailImage->getStoragePath(), false );
                if ( !$thumbFile ) {
                        throw new UploadStashFileNotFoundException(
-                               wfMessage( 'uploadstash-file-not-found-no-object' )
+                               $this->msg( 'uploadstash-file-not-found-no-object' )
                        );
                }
 
@@ -273,7 +273,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                if ( !$status->isOK() ) {
                        $errors = $status->getErrorsArray();
                        throw new UploadStashFileNotFoundException(
-                               wfMessage(
+                               $this->msg(
                                        'uploadstash-file-not-found-no-remote-thumb',
                                        print_r( $errors, 1 ),
                                        $scalerThumbUrl
@@ -283,7 +283,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                $contentType = $req->getResponseHeader( "content-type" );
                if ( !$contentType ) {
                        throw new UploadStashFileNotFoundException(
-                               wfMessage( 'uploadstash-file-not-found-missing-content-type' )
+                               $this->msg( 'uploadstash-file-not-found-missing-content-type' )
                        );
                }
 
@@ -302,7 +302,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
        private function outputLocalFile( File $file ) {
                if ( $file->getSize() > self::MAX_SERVE_BYTES ) {
                        throw new SpecialUploadStashTooLargeException(
-                               wfMessage( 'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
+                               $this->msg( 'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
                        );
                }
 
@@ -324,7 +324,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                $size = strlen( $content );
                if ( $size > self::MAX_SERVE_BYTES ) {
                        throw new SpecialUploadStashTooLargeException(
-                               wfMessage( 'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
+                               $this->msg( 'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
                        );
                }
                // Cancel output buffering and gzipping if set
index 5f07073..78b0335 100644 (file)
@@ -26,8 +26,8 @@ class EditWatchlistNormalHTMLForm extends OOUIHTMLForm {
                $namespace = substr( $namespace, 2 );
 
                return $namespace == NS_MAIN
-                       ? $this->msg( 'blanknamespace' )->escaped()
-                       : htmlspecialchars( $this->getContext()->getLanguage()->getFormattedNsText( $namespace ) );
+                       ? $this->msg( 'blanknamespace' )->text()
+                       : $this->getContext()->getLanguage()->getFormattedNsText( $namespace );
        }
 
        public function displaySection(
index 3d7148d..889ec1a 100644 (file)
@@ -449,7 +449,7 @@ class ImageListPager extends TablePager {
                                        if ( $thumb ) {
                                                return $thumb->toHtml( [ 'desc-link' => true ] );
                                        } else {
-                                               return wfMessage( 'thumbnail_error', '' )->escaped();
+                                               return $this->msg( 'thumbnail_error', '' )->escaped();
                                        }
                                } else {
                                        return htmlspecialchars( $value );
index 7783f31..510b352 100644 (file)
@@ -45,26 +45,18 @@ class CheckMatrixWidget extends \OOUI\Widget {
 
                parent::__construct( $config );
 
-               $this->name = isset( $config['name'] ) ?
-                       $config[ 'name' ] : null;
-               $this->id = isset( $config['id'] ) ?
-                       $config['id'] : null;
+               $this->name = $config['name'] ?? null;
+               $this->id = $config['id'] ?? null;
 
                // Properties
-               $this->rows = isset( $config['rows'] ) ?
-                       $config['rows'] : [];
-               $this->columns = isset( $config['columns'] ) ?
-                       $config['columns'] : [];
-               $this->tooltips = isset( $config['tooltips'] ) ?
-                       $config['tooltips'] : [];
+               $this->rows = $config['rows'] ?? [];
+               $this->columns = $config['columns'] ?? [];
+               $this->tooltips = $config['tooltips'] ?? [];
 
-               $this->values = isset( $config['values'] ) ?
-                       $config['values'] : [];
+               $this->values = $config['values'] ?? [];
 
-               $this->forcedOn = isset( $config['forcedOn'] ) ?
-                       $config['forcedOn'] : [];
-               $this->forcedOff = isset( $config['forcedOff'] ) ?
-                       $config['forcedOff'] : [];
+               $this->forcedOn = $config['forcedOn'] ?? [];
+               $this->forcedOff = $config['forcedOff'] ?? [];
 
                // Build the table
                $table = new \OOUI\Tag( 'table' );
@@ -180,8 +172,7 @@ class CheckMatrixWidget extends \OOUI\Widget {
         * @return string Tooltip. Null if none is available.
         */
        private function getTooltip( $label ) {
-               return isset( $this->tooltips[ $label ] ) ?
-                       $this->tooltips[ $label ] : null;
+               return $this->tooltips[ $label ] ?? null;
        }
 
        protected function getJavaScriptClassName() {
index eab09a1..85daa14 100644 (file)
@@ -4194,8 +4194,13 @@ class Language {
        /**
         * convert text to different variants of a language.
         *
-        * @param string $text
-        * @return string
+        * @warning Glossary state is maintained between calls. This means
+        *  if you pass unescaped text to this method it can cause an XSS
+        *  in later calls to this method, even if the later calls have properly
+        *  escaped the input. Never feed this method user controlled text that
+        *  is not properly escaped!
+        * @param string $text Content that has been already escaped for use in HTML
+        * @return string HTML
         */
        public function convert( $text ) {
                return $this->mConverter->convert( $text );
index c098518..e51dca9 100644 (file)
@@ -642,8 +642,12 @@ class LanguageConverter {
         * -{flags|code1:text1;code2:text2;...}-  or
         * -{text}- in which case no conversion should take place for text
         *
-        * @param string $text Text to be converted
-        * @return string Converted text
+        * @warning Glossary state is maintained between calls. Never feed this
+        *   method input that hasn't properly been escaped as it may result in
+        *   an XSS in subsequent calls, even if those subsequent calls properly
+        *   escape things.
+        * @param string $text Text to be converted, already html escaped.
+        * @return string Converted text (html)
         */
        public function convert( $text ) {
                $variant = $this->getPreferredVariant();
@@ -653,9 +657,11 @@ class LanguageConverter {
        /**
         * Same as convert() except a extra parameter to custom variant.
         *
-        * @param string $text Text to be converted
+        * @param string $text Text to be converted, already html escaped
+        * @param-taint $text exec_html
         * @param string $variant The target variant code
         * @return string Converted text
+        * @return-taint escaped
         */
        public function convertTo( $text, $variant ) {
                global $wgDisableLangConversion;
@@ -773,7 +779,7 @@ class LanguageConverter {
                                                        $warningDone = true;
                                                }
                                                $startPos += 2;
-                                               continue;
+                                               break;
                                        }
                                        // Recursively parse another rule
                                        $inner .= $this->recursiveConvertRule( $text, $variant, $startPos, $depth + 1 );
index a5b0188..4a648f9 100644 (file)
@@ -202,7 +202,7 @@ class Names {
                'ht' => 'Kreyòl ayisyen', # Haitian Creole French
                'hu' => 'magyar', # Hungarian
                'hu-formal' => "magyar (formal)\u{200E}", # Hungarian formal address
-               'hy' => 'Õ\80Õ¡ÕµÕ¥Ö\80Õ¥Õ¶', # Armenian
+               'hy' => 'Õ°Õ¡ÕµÕ¥Ö\80Õ¥Õ¶', # Armenian, T202611
                'hyw' => 'արեւմտահայերէն', # Western Armenian, T201276
                'hz' => 'Otsiherero', # Herero
                'ia' => 'interlingua', # Interlingua (IALA)
index 5cdcfaf..4ec37c5 100644 (file)
@@ -75,8 +75,8 @@
        "thu": "Ham",
        "fri": "Jum",
        "sat": "Sab",
-       "january": "Buleuën Sa",
-       "february": "Buleuën Duwa",
+       "january": "Buleuen Sa",
+       "february": "Buleuen Duwa",
        "march": "Buleuën Lhèë",
        "april": "Buleuën Peuët",
        "may_long": "Buleuën Limöng",
@@ -86,7 +86,7 @@
        "september": "Buleuën Sikureuëng",
        "october": "Buleuën Siplôh",
        "november": "Buleuën Siblaih",
-       "december": "Buleuën Duwa Blaih",
+       "december": "Buleuen Duwa Blaih",
        "january-gen": "Buleuën Sa",
        "february-gen": "Buleuën Duwa",
        "march-gen": "Buleuën Lhèë",
        "mypage": "Laman",
        "mytalk": "Marit",
        "anontalk": "Marit",
-       "navigation": "Keumudoë",
+       "navigation": "Keumudoe",
        "and": "&#32;ngön",
        "faq": "Teunanyöng Umom",
        "actions": "Buët",
        "protect_change": "ubah",
        "unprotect": "Gantoë neulindông",
        "newpage": "Laman barô",
-       "talkpagelinktext": "Marit",
+       "talkpagelinktext": "marit",
        "specialpage": "Laman kusuih",
        "personaltools": "Peukakaih droë",
        "talk": "Marit",
        "redirectedfrom": "(Geupupinah nibak $1)",
        "redirectpagesub": "Laman peuninah",
        "redirectto": "Peupinah u:",
-       "lastmodifiedat": "Mieng nyoe seuneulheueh geuandam bak $1, poh $2.",
+       "lastmodifiedat": "Laman nyoe seuneulheueh geuandam bak $1, poh $2.",
        "viewcount": "Laman nyoë ka geusaweuë {{PLURAL:$1|sigo|$sigo}}.<br />",
        "protectedpage": "Laman teupeulindông",
        "jumpto": "Grôp u:",
        "disclaimerpage": "Project:Beunantah umom",
        "edithelp": "Bantu andam",
        "helppage-top-gethelp": "Beunantu",
-       "mainpage": "Ôn Keuë",
+       "mainpage": "Ôn Keue",
        "mainpage-description": "Ôn Keuë",
        "policy-url": "Project:Neuatô",
        "portal": "Meusapat",
        "viewsourceold": "Eu nè",
        "editlink": "andam",
        "viewsourcelink": "eu nè",
-       "editsectionhint": "Andam bideuëng: $1",
+       "editsectionhint": "Andam bideueng: $1",
        "toc": "Asoë",
        "showtoc": "peuleumah",
        "hidetoc": "peusom",
        "site-atom-feed": "Umpeuën Atôm $1",
        "page-rss-feed": "Umpeuën RSS \"$1\"",
        "page-atom-feed": "Umpeuën Atom \"$1\"",
-       "red-link-title": "$1 (miëng hana)",
+       "red-link-title": "$1 (laman hana)",
        "sort-descending": "Peuurôt tren",
        "sort-ascending": "Peuurôt ék",
        "nstab-main": "Miëng",
        "nstab-template": "Seunaleuëk",
        "nstab-help": "Beunantu",
        "nstab-category": "Kawan",
-       "mainpage-nstab": "Ôn keuë",
+       "mainpage-nstab": "Ôn keue",
        "nosuchaction": "Hana buët nyan",
        "nosuchactiontext": "Buët nyang geulakèë lé URL nyan hana sah. Droeneuh kadang salah neukeutik URL, atawa neuseutöt saboh neuhubông nyang hana beutôi. Hai nyoë kadang jeuët keu lageuëm saboh bug bak alat leumiëk nyang geungui lé {{SITENAME}}.",
        "nosuchspecialpage": "Hana laman kusuih lagèë nyan",
        "ns-specialprotected": "Laman khusuih bèk neuandam",
        "titleprotected": "Nan nyoe ka geupeulindông nibak neuandam lé [[User:$1|$1]].\nDalèhjih nakeuh <em>$2</em>.",
        "invalidtitle-knownnamespace": "Nan nyang hana sah ngön ruweueng nan \"$2\" ngön \"$3\"",
-       "exception-nologin": "Hana tamöng lom",
+       "exception-nologin": "Goh lom tamong log",
        "exception-nologin-text": "Droëneuh suwah [[Special:Userlogin|neutamöng]] mangat jeuët neupeuhah laman nyoë",
-       "virus-unknownscanner": "Antivirus hana meuturi:",
+       "virus-unknownscanner": "Antivirus hana geuturi:",
        "logouttext": "'''Droeneuh ka neutubiet log.'''\n\nBeuneuteupue meunyoe na padum-padum laman nyang deuh lagèe na neutamöng log, sampoe ka lheuh neupeugléh ''cache''.",
        "cannotlogoutnow-title": "H`an jeuet teubiet log jinoe",
        "welcomeuser": "Seulamat trôk teuka, $1 !",
        "nextn": "{{PLURAL:$1|$1}} lheuëh nyan",
        "prevn-title": "$1 {{PLURAL:$1|hasé|hasé}} sigohlomjih",
        "nextn-title": "$1 {{PLURAL:$1|hasé}} lheuëh nyan",
-       "shown-title": "Peuleumah $1 {{PLURAL:$1|hasé}} tiep mieng",
+       "shown-title": "Peudeuih $1 {{PLURAL:$1|hasé}} tiep laman",
        "viewprevnext": "Eu ($1 {{int:pipe-separator}} $2)($3)",
        "searchmenu-exists": "'''Na laman ngön nan \"[[:$1]]\" bak wiki nyoe.'''",
        "searchmenu-new": "<strong>Peugöt laman \"[[:$1]]\" bak wiki nyoë!</strong> {{PLURAL:$2|0=|Eu cit laman nyang geurumpok nibak meunita droëneuh.|Eu cit hasé mita nyang geurumpok.}}",
        "newpageletter": "B",
        "boteditletter": "b",
        "number_of_watching_users_pageview": "[$1 kalön {{PLURAL:$1|ureuëng ngui}}]",
-       "rc-change-size-new": "$1 {{PLURAL:$1|bita}} lheuëh neuubah",
+       "rc-change-size-new": "$1 {{PLURAL:$1|bita}} lheueh neuubah",
        "newsectionsummary": "/* $1 */ bideung barô",
        "rc-enhanced-expand": "Peuleumah rincian",
        "rc-enhanced-hide": "Peusom rincian",
        "filehist-filesize": "Rayek beureukah",
        "filehist-comment": "Seuneu'ôt",
        "imagelinks": "Seuneungui beureukaih",
-       "linkstoimage": "{{PLURAL:$1|miëng}} di yup nyoë mupawôt u beureukaih nyoë:",
-       "nolinkstoimage": "Hana laman nyang na meupawôt u beureukaih nyoë.",
+       "linkstoimage": "{{PLURAL:$1|laman}} di yup nyoe mupawôt u beureukaih nyoe:",
+       "nolinkstoimage": "Hana laman nyang na meupawôt u beureukaih nyoe.",
        "sharedupload": "Beureukah nyoë dari $1 ngön kadang geunguy lé buët-buët la’én.",
        "sharedupload-desc-here": "Beureukaih nyoe nejih nibak $1 ngon kadang geunguy le proyek-proyek la'en.\nTeuneurang bak [$2 on teuneurangjih] geupeuleumah di yup nyoe.",
        "filepage-nofile": "Hana beureukaih ngön nan nyoe",
        "randomredirect": "Peuninah saban sakri",
        "statistics": "Keunira",
        "doubleredirects": "Peuninah ganda",
+       "double-redirect-fixer": "Ngön pupaih peuninah",
        "brokenredirects": "Peuninah reulöh",
        "withoutinterwiki": "Laman tan na hubông bahsa",
        "fewestrevisions": "Teunuléh ngön neu’ubah paléng dit",
        "emailccsubject": "Salén peusan droeneuh keu $1: $2",
        "emailsent": "Surat-e meukirém",
        "emailsenttext": "Surat-e droeneuh ka meukirém.",
+       "usermessage-editor": "Peukakaih peutrôk peusan",
        "watchlist": "Dapeuta keunalön",
        "mywatchlist": "Keunalön",
        "watchlistfor2": "Keu $1 $2",
        "tooltip-invert": "Neuceuë kutak nyoë keu neupeusom neuubah miëng lam ruweuëng nan nyang neupiléh (ngön ruweuëng nan teukaw`èt meunyö neuceuë)",
        "namespace_association": "Ruweuëng nan meuhubông",
        "tooltip-namespace_association": "Neuceuë kutak nyoë keu neupeurôh ruweuëng nan marit atawa bhaih nyang teukaw`èt ngön ruweuëng nan teupiléh",
-       "blanknamespace": "(Keuë)",
+       "blanknamespace": "(Keue)",
        "contributions": "Beuneuri {{GENDER:$1|ureuëng ngui}}",
        "contributions-title": "Beuneuri ureuëng ngui keu $1",
        "mycontris": "Beuneuri",
        "tooltip-pt-logout": "Teubiët",
        "tooltip-pt-createaccount": "Droëneuh geupadan keu neupeugöt saboh akun ngön neutamöng; bah pih nyan hana wajéb",
        "tooltip-ca-talk": "Marit miëng asoë",
-       "tooltip-ca-edit": "Andam miëng nyoë",
+       "tooltip-ca-edit": "Andam laman nyoe",
        "tooltip-ca-addsection": "Puphôn beunagi barô",
        "tooltip-ca-viewsource": "Laman nyoë geulindông.\nDroëneuh jeuët neu’eu nèjih mantöng.",
        "tooltip-ca-history": "Geunantoë awai nibak miëng nyoë",
        "tooltip-ca-watch": "Tamah miëng nyoë u dapeuta kalön droëneuh",
        "tooltip-ca-unwatch": "Sampôh laman nyoë nibak dapeuta kalön droëneuh",
        "tooltip-search": "Mita {{SITENAME}}",
-       "tooltip-search-go": "Mita saboh miëng ngon nan nyang peureuséh lagèë nyoë meunyo na",
+       "tooltip-search-go": "Mita saboh laman ngon nan nyang peureuséh lagèë nyoë meunyo na",
        "tooltip-search-fulltext": "Mita miëng nyang na asoë lagèë nyoë",
        "tooltip-p-logo": "Saweuë ôn keuë",
        "tooltip-n-mainpage": "Saweuë ôn keuë",
        "tooltip-t-contributions": "Dapeuta beuneuri {{GENDER:$1|ureuëng ngui nyoë}}",
        "tooltip-t-emailuser": "Peu-ét surat elektronik keu {{GENDER:$1|ureueng ngui nyoe}}",
        "tooltip-t-upload": "Peutamong beureukaih",
-       "tooltip-t-specialpages": "Dapeuta ban dum miëng kusuih",
+       "tooltip-t-specialpages": "Dapeuta ban dum laman kusuih",
        "tooltip-t-print": "Seunalén rakam miëng nyoë",
        "tooltip-t-permalink": "Peunawôt teutap keu geunantoë miëng nyoë",
        "tooltip-ca-nstab-main": "Eu miëng asoë",
        "tooltip-diff": "Peuleumah neuubah nyang ka Droëneuh peugöt",
        "tooltip-compareselectedversions": "Ngiëng bida nibak duwa geunantoë laman nyang teupiléh",
        "tooltip-watch": "Tamah laman nyoë u dapeuta kalön droëneuh",
-       "tooltip-rollback": "Peuriwang neu’andam-neu’andam bak laman nyoë u nyang tuléh keuneulheuëh lam sigo teugön",
+       "tooltip-rollback": "\"Rollback\" jipeugisa keulayi neuandam ureueng tuléh seuneulheueh u laman nyoe ngön sigo teugön",
        "tooltip-undo": "Peuriwang geunantoë nyoë ngön peuhah plôk neu’andam ngön cara eu dilèë. Choë jeuët geupeutamah bak plôk ehtisa.",
        "tooltip-summary": "Pasoë éhtisa paneuk",
        "interlanguage-link-title": "$1 – $2",
        "simpleantispam-label": "Paréksa anti-spam.\n<strong>BÈK</strong> neupasoë!",
        "pageinfo-title": "Keutrangan keu \"$1\"",
        "pageinfo-header-basic": "Keutrangan peuneuphôn",
+       "pageinfo-header-edits": "Riwayat andam",
        "pageinfo-header-restrictions": "Lindông mieng",
        "pageinfo-display-title": "Judul tampilan",
        "pageinfo-default-sort": "Gunci urôt baku",
        "pageinfo-redirects-name": "Jumeulah peuninah u mieng nyoe",
        "pageinfo-firstuser": "Ureueng peugot mieng",
        "pageinfo-firsttime": "Uroe buleuen pumeugot mieng",
+       "pageinfo-lastuser": "Ureueng andam seuneulheueh",
+       "pageinfo-lasttime": "Uroe andam seuneulheueh",
        "pageinfo-edits": "Jumeulah neuandam ban dum",
+       "pageinfo-authors": "Jumeulah ban dum ureueng teumuléh nyang mubida",
        "pageinfo-recent-edits": "Jumeulah neuandam ban-ban nyoe (lam $1 nyoe)",
        "pageinfo-toolboxlink": "Keutrangan miëng",
        "pageinfo-contentpage-yes": "Nyo",
        "redirect-revision": "Pubeutoi mieng",
        "redirect-file": "Nan beureukaih",
        "fileduplicatesearch-submit": "Mita",
-       "specialpages": "Miëng kusuih",
+       "specialpages": "Laman kusuih",
        "specialpages-note-restricted": "* Laman kusuih biasa.\n* <span class=\"mw-specialpagerestricted\">Laman kusuih geutheun.</span>",
        "specialpages-group-maintenance": "Beuneuri thèë plara",
        "specialpages-group-other": "La'én-la'én",
index 65562a1..27dd646 100644 (file)
        "accountcreatedtext": "أنشئ حساب مستخدم ل[[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|نقاش]]).",
        "createaccount-title": "إنشاء حساب في {{SITENAME}}",
        "createaccount-text": "شخص ما أنشأ حسابا لعنوان بريدك الإلكتروني في {{SITENAME}} ($4) بالاسم \"$2\"، كلمة السر \"$3\".\nينبغي عليك تسجيل الدخول وتغيير كلمة السر الخاصة بك الآن.\n\nيمكنك تجاهل هذه الرسالة، لو تم إنشاء هذا الحساب بالخطأ.",
-       "login-throttled": "لقد قمت بمحاولات دخول كثيرة جدا مؤخرا.\nمن فضلك انتظر $1 قبل المحاولة مرة أخرى.",
+       "login-throttled": "لقد قمت مؤخرًا بمحاولات دخول كثيرة جدًا.\nمن فضلك انتظر $1 قبل المحاولة مرة أخرى.",
        "login-abort-generic": "فشل دخولك - تم إجهاضه",
        "login-migrated-generic": "تم تهجير حسابك، ولم يعد اسم المستخدم الخاص بك موجوداً على هذه الويكي",
        "loginlanguagelabel": "اللغة: $1",
index aaea4c7..b1977cf 100644 (file)
        "confirm-unwatch-top": "¿Desaniciar esta páxina de la to llista de vixilancia?",
        "confirm-rollback-button": "Aceutar",
        "confirm-rollback-top": "¿Revertir les ediciones a esta páxina?",
+       "confirm-mcrundo-title": "Desfacer un cambéu",
+       "mcrundofailed": "Falló desfacer",
+       "mcrundo-missingparam": "Faltan parámetros riquíos na solicitú.",
+       "mcrundo-changed": "La páxina cambió desque visti les diferencies. Revisa'l cambiu nuevu.",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← páxina anterior",
        "imgmultipagenext": "páxina siguiente →",
index 2913aa2..473c55c 100644 (file)
@@ -10,7 +10,8 @@
                        "Urhixidur",
                        "아라",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "ShimunUfesoj"
                ]
        },
        "tog-underline": "Linyahan an kilyawan:",
        "nstab-template": "Templato",
        "nstab-help": "Pahina kan tabang",
        "nstab-category": "Kategorya",
+       "mainpage-nstab": "Panginot na Pahina",
        "nosuchaction": "Mayong siring na aksyon",
        "nosuchactiontext": "An aksyon na pinanungdan kan kilyawan sarong imbalido.\nBaka napasala ka sa pagsurat kan kilyawan, o nagsunod nin salang kilyawan.\nIni minapanungod man nin sarong kubol (bug) sa ginagamit na software kan {{SITENAME}}.",
        "nosuchspecialpage": "Mayong siring na espesyal na páhina",
        "newarticle": "(Bàgo)",
        "newarticletext": "Ika nakapagsunod sa sarong sugpon pasiring sa sarong pahina na bako pang eksistido. Tanganing makapagmukna nin pahina, magpoon sa pagpindot sa laog nin kahon sa ibaba (hilngon an [$1 pahina nin katabangan] para sa kadugangan na impormasyon).\nKun ika napasalang nakadigde, i-klik an  '''ibalik''' na pindutan kan saimong kilyawan.",
        "anontalkpagetext": "----''Ini iyo an pahina kan orolayan para an sarong dae bistadong paragamit na dae pa nakapagmukna nin panindog, o dae pa nakapaggamit kaini.\nKaya kami kaipong gumamit nin numerikal na IP address sa pagbisto saiya.\nAn arog kaining IP address puwedeng maikapagheras sa nagkapirang mga paragamit.\nKun ika sarong dae pa bistadong paragamit asin mati mo na igwang irelebanteng sambit na pinanungod saimo, tabi paki [[Special:CreateAccount|mukna nin panindog]] or [[Special:UserLogin|maglaog ka]] tanganing malikayan an pagkaribong sa pag-iriba kan iba pang mga paragamit.''",
-       "noarticletext": "Mayo tabi sa presente nin teksto sa pahinang ini.\nIka mapuwedeng [[Special:Search/{{PAGENAME}}|maghanap para sa titulo kan pahinang ini]] sa iba pang mga pahina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa magkasurundong mga talaan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} liwaton ining pahina]</span>.",
+       "noarticletext": "Mayo tabi sa presente nin teksto sa pahinang ini.\nIka puwedeng [[Special:Search/{{PAGENAME}}|maghanap para sa titulo kan pahinang ini]] sa iba pang mga pahina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa magkasurundong mga talaan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} liwaton ining pahina]</span>.",
        "noarticletext-nopermission": "Mayong sa presente nin teksto an pahinang ini.\nIka mapuwedeng [[Special:Search/{{PAGENAME}}|hanapa para kaining titulo kan pahina]] sa iba pang mga pahina,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa magkasurundong mga talaan]</span>.",
        "missing-revision": "An rebisyon #$1 kan pahina pinagngaranan na \"{{FULLPAGENAME}}\" bakong eksistido.\n\nIni pirmihan na pinagkakausa sa paagi nin pagsusunod nin luwas na petsang historiya nin kasugpunan pasiring sa sarong pahinang pinagpura na.\nAn mga detalye matatagboan sa [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} pinagpura na talaan].",
        "userpage-userdoesnotexist": "Paragamit na panindog \"$1\" bako tabing rehistrado.\nPaki-tsek kun ika magustong magmukna/magliwat kaining pahina.",
        "currentrev": "Ppagpakarhay sa ngunyan",
        "currentrev-asof": "Pinakahuring pagpakarhay kan $1",
        "revisionasof": "Pagpakarhay poon kan $1",
-       "revision-info": "Rebisyon poon kan $1 ni $2",
+       "revision-info": "Rebisyon poon kan {{GENDER:$6|$2}}$7",
        "previousrevision": "← Dating pagpakarhay",
        "nextrevision": "Bagong pagpakarhay →",
        "currentrevisionlink": "Sa ngunyan na rebisyon",
        "showhideselectedversions": "Ihayag/itago mga piniling pagbabago",
        "editundo": "sulíton",
        "diff-empty": "(Mayong kalaenan)",
+       "diff-multi-sameuser": "({{PLURAL:$1|Sarong intermediate na pagbabago|$1 mga intermediate na pagbabago}} kan parehas na paragamit na dae pigpapahiling)",
        "diff-multi-manyusers": "({{PLURAL:$1|Sarong intermediate na pagbabago|$1 mga intermediate na mga pagbabago}} na sobra sa $2 {{PLURAL:$2|paragamit|mga paragamit}} dae pinaghahayag)",
        "difference-missing-revision": "{{PLURAL:$2|sarong rebisyon|$2 mga rebisyon}} kaining diperensiya ($1) {{PLURAL:$2|na iyo an|kaidto na iyo an}} dae nanagboan.\n\nIni pirmihan na pinagkakausa sa paagi nin pagsusunod nin luwas sa petsang diff na kasugponan pasiring sa sarong pahina na pinagpura na.\nAn mga detalye mapuwedeng matatagboan sa [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} talaan kan pinagpuraan].",
        "searchresults": "Resulta kan paghahánap",
        "shown-title": "Ipahiling $1  {{PLURAL:$1|resulta|mga resulta}} sa kada pahina",
        "viewprevnext": "Tanawon ($1{{int:pipe-separator}}$2)($3)",
        "searchmenu-exists": "'''Igwa nin sarong pahina na pinagngaranan na \"[[:$1]]\" sa wiking ini.'''",
-       "searchmenu-new": "'''Muknaon an pahina \"[[:$1]]\" sa wiking ini!'''",
+       "searchmenu-new": "'''Muknaon an pahina \"[[:$1]]\" sa wiking ini!''' {PLURAL:$2|0=|Hilingon man an pahina na nadugangan sa saimong paghahanap.|Hilingon man an mga resulta kan paghahanap na nadugangan.}}",
        "searchprofile-articles": "Mga pahina nin laog",
        "searchprofile-images": "Multimidya",
        "searchprofile-everything": "Gabós na bagay",
        "searchrelated": "kauyon",
        "searchall": "gabós",
        "showingresults": "Pigpapahiling sa babâ sagkod sa {{PLURAL:$1|'''1''' resulta|'''$1''' mga resulta}} poon sa #'''$2'''.",
+       "search-showingresults": "{{PLURAL:$4|Resulta <strong>$1</strong> kan <strong>$3</strong>|mga Resulta <strong>$1 – $2</strong> kan <strong>$3</strong>}}",
        "search-nonefound": "Mayo nin mga resulta na panampok sa kahaputan.",
        "powersearch-legend": "Adbansiyadong paghahanap",
        "powersearch-ns": "Maghanap sa mga espasyong-ngaran:",
        "apisandbox-request-time": "Hagad oras:$1",
        "booksources": "Mga Ginikanan kan libro",
        "booksources-search-legend": "Maghanap para sa mga ginikanang libro",
+       "booksources-search": "Hanápon",
        "booksources-text": "Mahihiling sa babâ an lista kan mga takod sa ibang ''site'' na nagbenbenta nin mga bâgo asin nagamit nang libro, asin pwede ser na igwa pang mga ibang impormasyon manonongod sa mga librong pighahanap mo:",
        "booksources-invalid-isbn": "An pinagtaong ISBN dae minaluwas na balido; paki-tsek tabi nin mga sala sa pagkopya gikan sa orihinal na piggikanan.",
        "specialloguserlabel": "Paragibo:",
        "contributions": "{{GENDER:$1|Paragamit}} na mga kaambagan",
        "contributions-title": "Mga kontribusyon kan paragamit para sa $1",
        "mycontris": "Mga Kaarambagan",
+       "anoncontribs": "Mga Kaarambagan",
        "contribsub2": "Para ki {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Mayong mga pagbabago na nahanap na kapadis sa ining mga criteria.",
        "uctop": "(sa ngunyan)",
        "whatlinkshere-next": "{{PLURAL:$1|masunod|masunod na $1}}",
        "whatlinkshere-links": "← mga kasugpunan",
        "whatlinkshere-hideredirs": "$1 mga panukdong otro",
-       "whatlinkshere-hidetrans": "$1 kabaling-binalyuhan",
-       "whatlinkshere-hidelinks": "$1 mga kasugpon",
+       "whatlinkshere-hidetrans": "$1 mga pinagkabalihan",
+       "whatlinkshere-hidelinks": "$1 mga kasugpunan",
        "whatlinkshere-hideimages": "$1 mga kasugpon nin mga sagunson",
        "whatlinkshere-filters": "Mga saraan",
        "autoblockid": "Awtomatikong-kabarahan #$1",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|rebisyon|mga rebisyon}} gikan sa $2",
        "javascripttest": "Testing sa JavaScript",
        "javascripttest-qunit-intro": "Hilngon [$1 dokumentasyon sa pagtesting] sa mediawiki.org.",
-       "tooltip-pt-userpage": "An saimong paragamit na pahina",
+       "tooltip-pt-userpage": "{{GENDER:|An saimong paragamit }} na pahina",
        "tooltip-pt-anonuserpage": "An páhina nin páragamit para sa ip na pighihira mo bilang",
-       "tooltip-pt-mytalk": "An saimong pahina sa olayan",
+       "tooltip-pt-mytalk": "{{GENDER:|An saimong}} pahina nin urulayan",
        "tooltip-pt-anontalk": "Mga olay manonongod sa mga hira halî sa ip na ini",
-       "tooltip-pt-preferences": "Saimong mga kamuyahan",
+       "tooltip-pt-preferences": "{{GENDER:|Saimong}} mga kamuyahan",
        "tooltip-pt-watchlist": "Sarong listahan kan mga pahina na saimong inaantabayanan para sa mga kaliwatan",
-       "tooltip-pt-mycontris": "Sarong listahan kan saimong mga kontribusyon",
+       "tooltip-pt-mycontris": "Sarong listahan kan {{GENDER:|saimong}} mga kontribusyon",
        "tooltip-pt-login": "Ika inaagyat na maglaog; alagad, bako tabi ining piriritan",
        "tooltip-pt-logout": "Magluwas",
        "tooltip-pt-createaccount": "Inaalok ika na maggibo nin account asin maglaog; alagad dai man ini kinakaipohan.",
        "tooltip-t-recentchangeslinked": "Dae pa sana nahahaloy na mga kaliwatan sa mga pahina na nakasugpon gikan kaining pahina",
        "tooltip-feed-rss": "Hungit na RSS sa pahinang ini",
        "tooltip-feed-atom": "Hungit Atomo para kaining pahina",
-       "tooltip-t-contributions": "Sarong listahan kan mga paraambag kaining paragamit",
+       "tooltip-t-contributions": "Sarong listahan kan mga paraambag kan {{GENDER:$1|paragamit na ini}}",
        "tooltip-t-emailuser": "Magpadara nin sarong e-surat sa paragamit na ini",
        "tooltip-t-upload": "Ikarga an mga sagunson",
        "tooltip-t-specialpages": "Sarong listahan kan gabos na mga espesyal na pahina",
        "logentry-rights-rights": "$1 {{GENDER:$2|pinagliwat}} kan pangrupong pagkamiyembro para sa $3 gikan sa $4 pasiring sa $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|nagliwat}} kan pangrupong pagkamiyembro para sa $3",
        "logentry-rights-autopromote": "$1 awtomatikong {{GENDER:$2|pinagpalangkaw}} gikan sa $4 pasiring sa $5",
+       "logentry-upload-upload": "$1 {{GENDER:$2|pig-upload}} $3",
        "rightsnone": "(mayô)",
        "feedback-adding": "Idugang an balik-simbag sa pahina...",
        "feedback-bugcheck": "Marhay! I-tsek sana baya na ini bakong saro sa mga [$1 bistadong kuto].",
index 0c51bfe..f860934 100644 (file)
        "customcssprotected": "Вы ня маеце правоў на рэдагаваньне гэтай CSS-старонкі, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
        "customjsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
        "customjsprotected": "Вы ня маеце правоў на рэдагаваньне гэтай старонкі JavaScript, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
-       "sitecssprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай CSS-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў",
-       "sitejsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў",
+       "sitecssprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай CSS-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў.",
+       "sitejsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў.",
        "sitejsprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JavaScript-старонкі, бо гэта можа паўплываць на ўсіх наведнікаў",
        "mycustomcssprotected": "Вы ня маеце дазволу рэдагаваць гэтую CSS-старонку.",
        "mycustomjsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі.",
        "upload-form-label-not-own-work-message-generic-foreign": "Калі вы ня можаце загрузіць гэты файл паводле правілаў агульнага сховішча, калі ласка, закрыйце гэты дыялёг і паспрабуйце іншы мэтад.",
        "upload-form-label-not-own-work-local-generic-foreign": "Вы можаце паспрабаваць скарыстацца [[Special:Upload|старонкай загрузкі {{GRAMMAR:родны|{{SITENAME}}}}]], калі гэты файл можна туды загрузіць згодна з правіламі.",
        "backend-fail-stream": "Немагчыма накіраваць файл $1.",
-       "backend-fail-backup": "Немагчыма зрабіць рэзэрвовую копію файла $1.",
+       "backend-fail-backup": "Немагчыма зрабіць рэзэрвовую копію файлу «$1».",
        "backend-fail-notexists": "Файл $1 не існуе.",
        "backend-fail-hashes": "Немагчыма атрымаць хэшы файлаў для параўнаньня.",
-       "backend-fail-notsame": "Ð\9dеÑ\96дÑ\8dнÑ\82Ñ\8bÑ\84Ñ\96каванÑ\8b Ñ\84айл Ñ\83жо Ñ\96Ñ\81нÑ\83е $1.",
-       "backend-fail-invalidpath": "$1 не зьяўляецца слушным шляхам да сховішча.",
-       "backend-fail-delete": "Немагчыма выдаліць файл $1.",
-       "backend-fail-describe": "Не атрымалася зьмяніць мэтазьвесткі для файла «$1».",
-       "backend-fail-alreadyexists": "Файл $1 ужо існуе.",
-       "backend-fail-store": "Немагчыма захаваць файл $1 у $2.",
+       "backend-fail-notsame": "Ужо Ñ\96Ñ\81нÑ\83е Ð½ÐµÑ\96дÑ\8dнÑ\82Ñ\8bÑ\87нÑ\8b Ñ\84айл Â«$1».",
+       "backend-fail-invalidpath": "«$1» не зьяўляецца слушным шляхам да сховішча.",
+       "backend-fail-delete": "Немагчыма выдаліць файл «$1».",
+       "backend-fail-describe": "Не атрымалася зьмяніць мэтазьвесткі для файлу «$1».",
+       "backend-fail-alreadyexists": "Файл «$1» ужо існуе.",
+       "backend-fail-store": "Немагчыма захаваць файл «$1» у «$2».",
        "backend-fail-copy": "Немагчыма скапіяваць файл $1 у $2.",
        "backend-fail-move": "Немагчыма перанесьці файл $1 у $2.",
        "backend-fail-opentemp": "Немагчыма адкрыць часовы файл.",
        "confirm-unwatch-top": "Выдаліць гэтую старонку з Вашага сьпісу назіраньня?",
        "confirm-rollback-button": "Так",
        "confirm-rollback-top": "Адкаціць праўкі на гэтай старонцы?",
+       "confirm-mcrundo-title": "Адмяніць зьмену",
+       "mcrundofailed": "Адмена не атрымалася",
+       "mcrundo-missingparam": "Адсутнічаюць абавязковыя парамэтры для запыту.",
+       "mcrundo-changed": "Гэтая старонка была зьмененая з моманту, калі вы праглядалі зьмены. Калі ласка, праглядзіце новую зьмену.",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← папярэдняя старонка",
        "imgmultipagenext": "наступная старонка →",
index bd5ac50..dd4bd76 100644 (file)
@@ -34,7 +34,8 @@
                        "Andrus",
                        "Da voli",
                        "OlegCinema",
-                       "Gorgich"
+                       "Gorgich",
+                       "Vlad5250"
                ]
        },
        "tog-underline": "Падкрэсліваць спасылкі:",
        "right-bot": "Лічыцца аўтаматычным працэсам",
        "right-nominornewtalk": "Не паведамляць пра новыя паведамленні ў адказ на дробныя праўкі размоўных старонак",
        "right-apihighlimits": "Карыстацца вышэйшымі лімітамі ў API-зваротах",
-       "right-writeapi": "Карыстацца праграмным інтэрфейсам запісу (write API)",
+       "right-writeapi": "Карыстацца праграмным інтэрфейсам запісу (''write API'')",
        "right-delete": "Выдаляць старонкі",
        "right-bigdelete": "Выдаляць старонкі з вялікімі гісторыямі",
        "right-deletelogentry": "Выдаляць і аднаўляць асобныя запісы журналаў",
index 3e02cea..498662d 100644 (file)
        "cascadeprotected": "Тази страница е защитена против редактиране, защото е включена в {{PLURAL:$1|следната страница, която от своя страна има|следните страници, които от своя страна имат}} „каскадна“ защита:\n$2",
        "namespaceprotected": "Нямате права за редактиране на страници в именно пространство <strong>$1</strong>.",
        "customcssprotected": "Нямате права за редактиране на тази CSS страница, защото тя съдържа чужди потребителски настройки.",
+       "customjsonprotected": "Нямате права за редактиране на тази JSON страница, защото тя съдържа чужди потребителски настройки.",
        "customjsprotected": "Нямате права за редактиране на тази JavaScript страница, тъй като съдържа чужди потребителски настройки.",
        "mycustomcssprotected": "Нямате права за редактиране на тази CSS страница.",
+       "mycustomjsonprotected": "Нямате права за редактиране на тази JSON страница.",
        "mycustomjsprotected": "Нямате права за редактиране на тази JavaScript страница.",
        "myprivateinfoprotected": "Нямате права да редактирате личната си информация.",
        "mypreferencesprotected": "Нямате права да редактирате настройките си.",
        "ns-specialprotected": "Специалните страници не могат да бъдат редактирани.",
        "titleprotected": "Тази страница е била защитена срещу създаване от [[User:$1|$1]].\nПосочената причина е <em>$2</em>.",
        "filereadonlyerror": "Файлът „$1“ не може да бъде променен, тъй като файловото хранилище „$2“ е в режим само за четене.\n\nСистемният администратор, който го е заключил, е посочил следната причина: „$3“.",
+       "invalidtitle": "Невалидно заглавие",
        "invalidtitle-knownnamespace": "Невалидно заглавие с именно пространство „$2“ и текст „$3“",
        "invalidtitle-unknownnamespace": "Невалидно заглавие с неразпознато именно пространство номер $1 и текст „$2“",
        "exception-nologin": "Не сте влезли в системата",
        "right-override-export-depth": "Изнасяне на страници, включително свързаните с тях в дълбочина до пето ниво",
        "right-sendemail": "Изпращане на е-писма до другите потребители",
        "right-managechangetags": "Създаване и (де)активиране на [[Special:Tags|етикети]]",
+       "right-applychangetags": "Задаване на [[Special:Tags|етикети]] заедно с направените промени",
+       "right-changetags": "Добавяне и премахване на произволни [[Special:Tags|етикети]] в индивидуални редакции и записи в дневници",
+       "right-deletechangetags": "Изтриване на [[Special:Tags|етикети]] от базата на данни",
        "grant-group-page-interaction": "Взаимодействие със страници",
        "grant-group-file-interaction": "Взаимодействие с медийни файлове",
        "grant-group-watchlist-interaction": "Взаимодействие с вашия списък за наблюдение",
        "action-editcontentmodel": "редактиране на модела на съдържанието на страница",
        "action-managechangetags": "създаване и (де)активиране на етикети",
        "action-applychangetags": "прилагане на етикетите заедно с промените ви",
+       "action-changetags": "добавяне и премахване на произволни етикети в индивидуални редакции и записи в дневниците",
        "action-deletechangetags": "изтриване на етикети от базата от данни",
        "action-purge": "почисти кеша на тази страница",
        "nchanges": "$1 {{PLURAL:$1|промяна|промени}}",
        "rcfilters-group-results-by-page": "Групиране на резултатите по страница",
        "rcfilters-activefilters": "Активни филтри",
        "rcfilters-activefilters-hide": "Скриване",
+       "rcfilters-activefilters-show": "Показване",
        "rcfilters-advancedfilters": "Разширени филтри",
        "rcfilters-limit-title": "Резултати за показване",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|промяна|промени}}, $2",
index 2e7eb73..7115f8a 100644 (file)
        "feed-atom": "অ্যাটম",
        "red-link-title": "$1 (পাতার অস্তিত্ব নেই)",
        "sort-descending": "উল্টো বর্ণক্রমে সাজান",
-       "sort-ascending": "বরà§\8dণানুক্রমে সাজান",
+       "sort-ascending": "à¦\8aরà§\8dদà§\8dধানুক্রমে সাজান",
        "nstab-main": "পাতা",
        "nstab-user": "ব্যবহারকারীর পাতা",
        "nstab-media": "মিডিয়া পাতা",
        "ns-specialprotected": "বিশেষ পাতাসমূহ সম্পাদনা করা যাবে না।",
        "titleprotected": "[[User:$1|$1]] কর্তৃক এই শিরোনামটি সৃষ্টি করা থেকে সুরক্ষিত করা হয়েছে। কারণ: <em>$2</em>।",
        "filereadonlyerror": "\"$1\" ফাইলটিকে পরিবর্তন করা সম্ভব হচ্ছে না কারণ \"$2\" ফাইল সংগ্রহশালাটি শুধুমাত্র-পঠন মোডে আছে।\n\nসিস্টেম প্রশাসক যিনি ফাইলটি অবরুদ্ধ করেছেন তিনি এই ব্যাখ্যা দিয়েছেন: \"$3\"।",
+       "invalidtitle": "ভুল শিরোনাম",
        "invalidtitle-knownnamespace": "অবৈধ শিরোনাম, যেখানে নামস্থান \"$2\" এবং লেখা হয়েছে \"$3\"",
        "invalidtitle-unknownnamespace": "অবৈধ শিরোনাম, যেখানে ব্যবহৃত হয়েছে অপরিচিত নামস্থান সংখ্যা $1 এবং লেখা হয়েছে \"$2\"",
        "exception-nologin": "প্রবেশ করেন নি",
        "diff-paragraph-moved-toold": "অনুচ্ছেদ স্থানান্তর করা হয়েছে। পুরনো অবস্থানে যাওয়ার জন্য ক্লিক করুন।",
        "difference-missing-revision": "এই পার্থক্যের ($1) অন্তর্গত {{PLURAL:$2|একটি সংশোধিত সংস্করণ|$2টি সংশোধিত সংস্করণ}} খুঁজে পাওয়া যাচ্ছে না।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাস পাতার লিংক খোলার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} পাতা অবলুপ্তি লগে] বিস্তারিত তথ্য জানা যাবে।",
        "searchresults": "অনুসন্ধানের ফলাফল",
-       "search-filter-title-prefix": "শুধুমাত্র \"$1\" শিরোনাম দিয়ে শুরু হওয়া পাতাগুলি খোঁজা হচ্ছে",
+       "search-filter-title-prefix": "শুধুমাত্র \"$1\" শিরোনাম দিয়ে শুরু হওয়া পাতাগুলিতে খোঁজা হচ্ছে",
        "search-filter-title-prefix-reset": "সব পাতা অনুসন্ধান করুন",
        "searchresults-title": "\"$1\" অনুসন্ধানের ফলাফল",
        "titlematches": "নিবন্ধের শিরোনাম মিলেছে",
        "filestatus": "কপিরাইট অবস্থা:",
        "filesource": "উৎস:",
        "ignorewarning": "সতর্কীকরণ উপেক্ষা করেই ফাইল সংরক্ষণ করুন",
-       "ignorewarnings": "সমসà§\8dত à¦¸à¦¤à¦°à§\8dà¦\95à§\80à¦\95রণ à¦\89পà§\87à¦\95à§\8dষা à¦\95রা à¦¹à§\8bà¦\95",
+       "ignorewarnings": "সমসà§\8dত à¦¸à¦¤à¦°à§\8dà¦\95à§\80à¦\95রণ à¦\89পà§\87à¦\95à§\8dষা à¦\95রà§\81ন",
        "minlength1": "ফাইলের নাম কমপক্ষে এক বর্ণের হতে হবে।",
        "illegalfilename": "\"$1\" ফাইলনামটিতে এমন কিছু ক্যারেক্টার আছে যেগুলি পাতার শিরোনামে ব্যবহার করা অবৈধ। অনুগ্রহ করে ফাইলটি নতুন করে নামকরণ করুন এবং তারপর আপলোড করার চেষ্টা করুন।",
        "filename-toolong": "ফাইলের নাম ২৪০ বাইটের বড় হওয়া যাবে না।",
        "filehist-filesize": "ফাইলের আকার",
        "filehist-comment": "মন্তব্য",
        "imagelinks": "ফাইলের ব্যবহার",
-       "linkstoimage": "নিà¦\9aà§\87র {{PLURAL:$1|à¦\9fি à¦ªà¦¾à¦¤à¦¾|$1à¦\9fি à¦ªà¦¾à¦¤à¦¾}} à¦¥à§\87à¦\95à§\87 à¦\8fà¦\87 à¦«à¦¾à¦\87লà§\87 à¦¸à¦\82যà§\8bà¦\97 à¦\86à¦\9bে:",
+       "linkstoimage": "নিমà§\8dনলিà¦\96িত {{PLURAL:$1|পাতাà¦\9fি|$1à¦\9fি à¦ªà¦¾à¦¤à¦¾}} à¦\8fà¦\87 à¦«à¦¾à¦\87ল à¦¬à§\8dযবহার à¦\95রে:",
        "linkstoimage-more": "এই ফাইলের সাথে $1টির বেশি {{PLURAL:$1|পাতার লিংক}} রয়েছে।\nনিচের তালিকায় ফাইলের সাথে যুক্ত {{PLURAL:$1|প্রথম পাতাটির লিংক|প্রথম $1টি পাতার লিংক}} দেখানো হচ্চে।\nএছাড়া একটি [[Special:WhatLinksHere/$2|পূর্ণাঙ্গ তালিকাও]] রয়েছে।",
        "nolinkstoimage": "এই ফাইলে সংযোগ করে এমন কোন পাতা নেই।",
        "morelinkstoimage": "এই ফাইলের [[Special:WhatLinksHere/$1|আরও লিঙ্ক]] দেখাও।",
        "ipbexpiry": "যখন মেয়াদোত্তীর্ণ হবে:",
        "ipbreason": "কারণ:",
        "ipbreason-dropdown": "*বাধা দানের সাধারণ কারণগুলি\n** মিথ্যা তথ্য যোগ করা\n** পাতা থেকে বিষয়বস্তু মুছে ফেলা\n** অবাঞ্ছিত বহিঃস্থ কোন সাইটের প্রতি সংযোগ বারংবার যোগ করা\n** পাতাগুলিতে অর্থহীন বিষয়বস্তু যোগ করা\n** ভীতি উদ্রেককারী আচরণ/হয়রানি\n** একাধিক অ্যাকাউন্টের অপব্যবহার\n** ব্যবহারকারী নাম অগ্রহণযোগ্য",
-       "ipb-hardblock": "à¦\8fà¦\87 à¦\86à¦\87পি à¦ à¦¿à¦\95ানা à¦¥à§\87à¦\95à§\87 à¦²à¦\97-à¦\87নà¦\95à§\83ত à¦¬à§\8dযবহারà¦\95ারà§\80দà§\87রà¦\95à§\87 à¦¸à¦®à§\8dপাদনায় à¦¬à¦¾à¦§à¦¾ à¦¦à¦¾à¦\93",
+       "ipb-hardblock": "পà§\8dরবà§\87শà¦\95à§\83ত à¦¬à§\8dযবহারà¦\95ারà§\80দà§\87রà¦\95à§\87 à¦\8fà¦\87 à¦\86à¦\87পি à¦ à¦¿à¦\95ানা à¦¥à§\87à¦\95à§\87 à¦¸à¦®à§\8dপাদনায় à¦¬à¦¾à¦§à¦¾ à¦¦à¦¿à¦¨",
        "ipbcreateaccount": "অ্যাকাউন্ট সৃষ্টিতে বাধা দেওয়া হোক",
        "ipbemailban": "ব্যবহারকারীকে ই-মেইল পাঠাতে বাধা দেওয়া হোক",
        "ipbenableautoblock": "এই ব্যবহারকারীর ব্যবহার করা সর্বশেষ আইপি ঠিকানা, এবং পরবর্তী যেসব আইপি ঠিকানা থেকে সম্পাদনার চেষ্টা করা হবে, সেগুলিকেও স্বয়ংক্রিয়ভাবে বাধা দেয়া হোক",
index 822a79f..fe0bbef 100644 (file)
        "cascadeprotected": "Uređivanje ove stranice zabranjeno je jer se koristi u {{PLURAL:$1|sljedećoj stranici, koja je zaštićena|sljedećim stranicama, koje su zaštićene}} prenosivom zaštitom:\n$2",
        "namespaceprotected": "Vi nemate dozvulu da mijenjate stranicu '''$1'''.",
        "customcssprotected": "Nemate dozvolu za mijenjanje ove CSS stranice jer sadrži osobne postavke nekog drugog korisnika.",
+       "customjsonprotected": "Nemate dozvolu za mijenjanje ove JSON stranice jer sadrži lične postavke drugog korisnika.",
        "customjsprotected": "Nemate dozvolu za mijenjanje ove JavaScript stranice jer sadrži osobne postavke nekog drugog korisnika.",
        "mycustomcssprotected": "Nemate dozvolu da uređujete ovu CSS stranicu.",
+       "mycustomjsonprotected": "Nemate dozvolu da uređujete ovu JSON stranicu.",
        "mycustomjsprotected": "Nemate dozvolu da uređujete ovu stranicu sa JavaScriptom.",
        "myprivateinfoprotected": "Nemate dozvolu da uređujete svoje privatne informacije.",
        "mypreferencesprotected": "Nemate dozvolu da uređujete svoje postavke.",
index e9577e1..9e1b9b4 100644 (file)
@@ -60,7 +60,8 @@
                        "Abella",
                        "Pierpao",
                        "Amire80",
-                       "Leptictidium"
+                       "Leptictidium",
+                       "Townie"
                ]
        },
        "tog-underline": "Subratlla els enllaços:",
        "grouppage-bureaucrat": "{{ns:project}}:Buròcrates",
        "grouppage-suppress": "{{ns:project}}:Supressors de Flow",
        "right-read": "Llegir pàgines",
-       "right-edit": "Modifica les pàgines",
+       "right-edit": "Modificar les pàgines",
        "right-createpage": "Crear pàgines (que no són de discussió)",
        "right-createtalk": "Crear pàgines de discussió",
        "right-createaccount": "Crear nous comptes",
        "uploadstash-bad-path-invalid": "El camí no és vàlid.",
        "uploadstash-bad-path-unknown-type": "El tipus «$1» és desconegut.",
        "uploadstash-bad-path-unrecognized-thumb-name": "Nom de miniatura no reconegut.",
+       "uploadstash-file-not-found-no-thumb": "No s'ha pogut obtenir una miniatura.",
        "uploadstash-file-not-found-not-exists": "No es pot trobar el camí, o bé no és un fitxer pla.",
        "uploadstash-file-too-large": "No es pot servir un fitxer més gran de $1 bytes.",
+       "uploadstash-not-logged-in": "Cap usuari ha iniciat una sessió. Els fitxers han de pertànyer als usuaris.",
+       "uploadstash-wrong-owner": "Aquest fitxer ($1) no pertany a l'usuari actual.",
        "uploadstash-no-extension": "L’extensió és nul·la.",
        "uploadstash-zero-length": "El fitxer té mida zero.",
        "invalid-chunk-offset": "El desplaçament del fragment no és vàlid",
        "http-timed-out": "La petició HTTP ha expirat.",
        "http-curl-error": "Error en recuperar l'URL: $1",
        "http-bad-status": "Hi ha hagut un problema durant la petició HTTP: $1 $2",
+       "http-internal-error": "Error intern HTTP.",
        "upload-curl-error6": "No s'ha pogut accedir a l'URL",
        "upload-curl-error6-text": "No s'ha pogut accedir a l'URL que s'ha proporcionat. Torneu a comprovar que sigui correcte i que el lloc estigui funcionant.",
        "upload-curl-error28": "S'ha excedit el temps d'espera de la càrrega",
        "filehist-filesize": "Mida del fitxer",
        "filehist-comment": "Comentari",
        "imagelinks": "Ús del fitxer",
-       "linkstoimage": "{{PLURAL:$1|La pàgina següent enllaça|Les $1 pàgines següents enllacen}} a aquest fitxer:",
+       "linkstoimage": "{{PLURAL:$1|La pàgina següent utilitza|Les $1 pàgines següents utilitzen}} aquest fitxer:",
        "linkstoimage-more": "Hi ha més de $1 {{PLURAL:$1|pàgina que enllaça|pàgines que enllacen}} a aquest fitxer.\nLa següent llista només mostra {{PLURAL:$1|la primera d'aquestes pàgines|les primeres $1 d'aquestes pàgines}}.\nPodeu consultar la [[Special:WhatLinksHere/$2|llista completa]].",
        "nolinkstoimage": "No hi ha pàgines que enllacin a aquesta imatge.",
        "morelinkstoimage": "Visualitza [[Special:WhatLinksHere/$1|més enllaços]] que porten al fitxer.",
        "namespace_association": "Espai de noms associat",
        "tooltip-namespace_association": "Marqueu aquesta casella per incloure l'espai de noms de discussió o de no discussió associat a l'espai de noms seleccionat",
        "blanknamespace": "(Principal)",
-       "contributions": "Contribucions de {{GENDER:$1|lusuari|la usuària}}",
+       "contributions": "Contribucions de {{GENDER:$1|l'usuari|la usuària}}",
        "contributions-title": "Contribucions de l'usuari $1",
        "mycontris": "Contribucions",
        "anoncontribs": "Contribucions",
        "sp-contributions-newbies-title": "Contribucions dels comptes d'usuari més nous",
        "sp-contributions-blocklog": "Registre de blocatges",
        "sp-contributions-suppresslog": "contribucions suprimides de {{GENDER:$1|l'usuari|la usuària}}",
-       "sp-contributions-deleted": "Contribucions de {{GENDER:$1|lusuari|la usuària}} esborrades",
+       "sp-contributions-deleted": "Contribucions de {{GENDER:$1|l'usuari|la usuària}} esborrades",
        "sp-contributions-uploads": "càrregues",
        "sp-contributions-logs": "registres",
        "sp-contributions-talk": "discussió",
        "confirm-unwatch-top": "Voleu treure aquesta pàgina de la llista de seguiment?",
        "confirm-rollback-button": "D'acord",
        "confirm-rollback-top": "Voleu revertir les modificacions a la pàgina?",
+       "confirm-mcrundo-title": "Desfés un canvi",
        "colon-separator": ":&#32;",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← pàgina anterior",
        "watchlistedit-clear-titles": "Títols:",
        "watchlistedit-clear-submit": "Neteja la llista de seguiment (això és permanent!)",
        "watchlistedit-clear-done": "S'ha netejat la vostra llista de seguiment.",
+       "watchlistedit-clear-jobqueue": "S'està netejant la vostra llista de seguiment. Això pot trigar una estona!",
        "watchlistedit-clear-removed": "{{PLURAL:$1|S'ha suprimit 1 títol|S'han suprimit $1 títols}}:",
        "watchlistedit-too-many": "Hi ha massa pàgines per mostrar-les aquí.",
        "watchlisttools-clear": "Neteja la llista de seguiment",
        "tag-mw-blank": "Buidament",
        "tag-mw-blank-description": "Modificacions que blanquegen una pàgina",
        "tag-mw-replace": "Substitució",
+       "tag-mw-replace-description": "Modificacions que eliminen més del 90% del contingut d'una pàgina",
        "tag-mw-undo": "Desfés",
        "tags-title": "Etiquetes",
        "tags-intro": "Aquesta pàgina llista les etiquetes amb què el programari pot marcar una modificació, i el seu significat.",
index 4f58d19..3e55964 100644 (file)
        "newpassword": "新密碼:",
        "retypenew": "確認密碼:",
        "resetpass_submit": "設置密碼再登錄",
+       "botpasswords-label-update": "Gĕng-sĭng",
        "resetpass_forbidden": "密碼改𣍐來",
        "resetpass-no-info": "汝著登錄乍會使直接看茲蜀頁。",
        "resetpass-submit-loggedin": "修改密碼",
        "newuserlogpage": "Kŭi dióng-hô nĭk-cé",
        "action-edit": "修改茲蜀頁",
        "recentchanges": "Cī-bŏng gì gāi-biéng",
-       "recentchanges-summary": "敆維基茲頁跟蹤般其改變。",
+       "recentchanges-summary": "敆維基茲頁跟蹤般其改變。",
        "recentchanges-label-newpage": "Cī siŏh bĭk siŭ-gāi cháung-gióng lāu sĭng hiĕk",
        "recentchanges-label-minor": "Cuòi sê siŏh bĭk guó-éu siŭ-gāi",
        "recentchanges-label-bot": "Cuòi sê gĭ-ké-nè̤ng siŭ-gāi gì",
+       "recentchanges-label-plusminus": "Cī-bĭh hiĕk-miêng gāi-biéng gì ôi-nguòng-cū duâi-nâung",
+       "rcfilters-legend-heading": "<strong>Gāng-siā liĕk-biēu:</strong>",
+       "rcfilters-other-review-tools": "Gì-tă gì giēng-că gĕ̤ng-gê̤ṳ",
+       "rcfilters-activefilters": "Gēng-chók-lì gì biĕng-cĭk",
+       "rcfilters-activefilters-hide": "Káung-kī",
+       "rcfilters-limit-and-date-label": "$1 huòi {{PLURAL:$1|siŭ-gāi}}, $2",
+       "rcfilters-quickfilters": "Bō̤-còng gì guó-lê̤ṳ-ké",
+       "rcfilters-search-placeholder": "Gēng biĕk-gì biĕng-cĭk (dĭk-ciék káng chái-dăng hĕ̤k-chiā că guó-lê̤ṳ-ké gì miàng)",
+       "rcfilters-filterlist-feedbacklink": "Gōng nāng-gă tiăng nṳ̄ giéng-gáe̤k ciā guó-lê̤ṳ-ké ciông-gì",
+       "rcfilters-filter-editsbyself-label": "Nṳ̄ gì siŭ-gāi",
+       "rcfilters-filter-editsbyother-label": "Biĕk-nè̤ng gì siŭ-gāi",
        "rcfilters-filter-humans-label": "Ìng-lôi (n̂g-sê gĭ-ké-nè̤ng)",
+       "rcfilters-filter-pageedits-label": "Hiĕk-miêng biĕng-cĭk",
+       "rcfilters-liveupdates-button": "Sĭk-sì gĕng-sĭng",
        "rclistfrom": "Hiēng-sê téng $3 $2 gáu dāng gì sĭng gāi-biéng",
        "rcshowhideminor": "$1 guó-éu siŭ-gāi",
        "rcshowhidebots": "$1 gĭ-ké-nè̤ng",
        "recentchangeslinked-feed": "相關其改變",
        "recentchangeslinked-toolbox": "Sŏng-guăng gì gāi-biéng",
        "recentchangeslinked-page": "頁面名:",
+       "recentchangeslinked-to": "Hiēng-sê liêng-ciék gáu cī-dêng hiĕk-miêng gì gāi-biéng",
        "upload": "Siông-diòng ùng-giông",
        "uploadbtn": "上傳文件",
        "reuploaddesc": "取消上傳,轉去上傳頁面",
index f95f33a..c6142e4 100644 (file)
        "botpasswords-label-appid": "Ботан цӀе:",
        "botpasswords-label-create": "Кхолла",
        "botpasswords-label-update": "Карлаяккха",
-       "botpasswords-label-cancel": "Юхаяккха",
+       "botpasswords-label-cancel": "Юхаяккхар",
        "botpasswords-label-delete": "ДӀаяккхар",
        "botpasswords-label-resetpassword": "Пароль кхоссар",
        "botpasswords-label-grants": "Лелош йолу шоралаш:",
        "rcfilters-savedqueries-remove": "ДӀаяккха",
        "rcfilters-savedqueries-new-name-label": "ЦӀе",
        "rcfilters-savedqueries-apply-label": "Ӏалашде нисъяр",
-       "rcfilters-savedqueries-cancel-label": "ЦаоÑ\8cÑ\88Ñ\83",
+       "rcfilters-savedqueries-cancel-label": "ЮÑ\85аÑ\8fккÑ\85аÑ\80",
        "rcfilters-savedqueries-add-new-title": "Ӏалашде литтар нисъяр",
        "rcfilters-restore-default-filters": "Литтарш Ӏадйитаран кепе меттахӀоттае",
        "rcfilters-clear-all-filters": "Ерриге литтарш цӀанъян",
        "tag-mw-changed-redirect-target": "хийцаран бахьна ду дӀасахьажорг",
        "tag-mw-blank": "цӀанъяр",
        "tag-mw-rollback": "Юхаяккха",
-       "tag-mw-undo": "Ñ\86аоÑ\8cÑ\88Ñ\83",
+       "tag-mw-undo": "Ñ\8eÑ\85аÑ\8fккÑ\85аÑ\80",
        "tags-title": "Билгалонаш",
        "tags-intro": "ХӀокху агӀона чохь гойтуш бу билгалонийн могӀам царца программин латторо билгал доху нисдарш, кхин билгалонийн маьӀна а.",
        "tags-tag": "Билгалона цӀе",
        "feedback-adding": "АгӀона хетарг тӀетохар...",
        "feedback-back": "ЮхагӀо",
        "feedback-bugornote": "Хьайн техникин халонах лаьцна яздан хӀума делахь, дехар до, [$1 хаам бе тхоьга].\nДацахь хьан йиш ю хӀокху атта кепаца «[$3 $2]» агӀонг коммент тӀетоха хьан декъашхочун цӀарца, кхин лелош йолу браузер билгал еш.",
-       "feedback-cancel": "ЦаоÑ\8cÑ\88Ñ\83",
+       "feedback-cancel": "ЮÑ\85аÑ\8fккÑ\85аÑ\80",
        "feedback-close": "Кийчча ю",
        "feedback-message": "Хаам:",
        "feedback-subject": "Тема:",
index 8e2621e..901629c 100644 (file)
        "rcfilters-view-tags": "دەستکارییە تاگکراوەکان",
        "rcfilters-view-tags-help-icon-tooltip": "زیاتر بزانە لەسەر دەستکارییە تاگکراوەکان",
        "rcfilters-liveupdates-button": "نوێکردنەوەی زیندوو",
+       "rcfilters-watchlist-edit-watchlist-button": "دەستکاریکردنی پێڕستی پەڕە چاودێریکراوەکانت",
+       "rcfilters-watchlist-showupdated": "ئەو پەڕانەی دەستکاریکراون و لەکاتی دەستکاریکردنەکەوە سەردانت نەکردوونەتەوە بە <strong>تۆخ</strong> دەردەکەون، بە نیشانی پڕکراوەوە.",
        "rcnotefrom": "ژێرەوە {{PLURAL:$5|گۆڕانکارییەکەیە|گۆڕانکارییەکانە}} لە <strong>$3، $4</strong>ەوە (ھەتا <strong>$1</strong> نیشان دراوە).",
        "rclistfromreset": "گەڕاندنەوەی ھەڵبژاردەی بەروار",
        "rclistfrom": "گۆڕانکارییە نوێکان نیشان بدە بە دەستپێکردن لە $3 $2",
index 207ced9..44c1b55 100644 (file)
        "customcssprotected": "Nemáte povoleno editovat tuto stránku s CSS, protože obsahuje osobní nastavení jiného uživatele.",
        "customjsonprotected": "Nemáte povoleno editovat tuto stránku s JSONem, protože obsahuje osobní nastavení jiného uživatele.",
        "customjsprotected": "Nemáte povoleno editovat tuto stránku s JavaScriptem, protože obsahuje osobní nastavení jiného uživatele.",
-       "sitecssprotected": "Nemáte oprávnění editovat tuto stránku s CSS, protože to může mít dopad na všechny návštěvníky",
-       "sitejsonprotected": "Nemáte oprávnění editovat tuto stránku s JSONem, protože to může mít dopad na všechny návštěvníky",
-       "sitejsprotected": "Nemáte oprávnění editovat tuto stránku s JavaScriptem, protože to může mít dopad na všechny návštěvníky",
+       "sitecssprotected": "Nemáte oprávnění editovat tuto stránku s CSS, protože to může mít dopad na všechny návštěvníky.",
+       "sitejsonprotected": "Nemáte oprávnění editovat tuto stránku s JSONem, protože to může mít dopad na všechny návštěvníky.",
+       "sitejsprotected": "Nemáte oprávnění editovat tuto stránku s JavaScriptem, protože to může mít dopad na všechny návštěvníky.",
        "mycustomcssprotected": "Nemáte oprávnění editovat tuto stránku s CSS.",
        "mycustomjsonprotected": "Nemáte oprávnění editovat tuto stránku s JSONem.",
        "mycustomjsprotected": "Nemáte oprávnění editovat tuto stránku s JavaScriptem.",
        "import-mapping-namespace": "Importovat do jmenného prostoru:",
        "import-mapping-subpage": "Importovat jako podstránky následující stránky:",
        "import-upload-filename": "Jméno souboru:",
+       "import-upload-username-prefix": "Interwiki prefix:",
        "import-assign-known-users": "Přiřazovat editace lokálním uživatelům, pokud zde existuje uživatel s daným jménem",
        "import-comment": "Zdůvodnění:",
        "importtext": "Prosím exportujte soubor ze zdrojové wiki pomocí [[Special:Export|exportního nástroje]].\nUložte jej na svůj disk a nahrajte ho sem.",
        "edit-error-long": "Chyby:\n\n$1",
        "revid": "revize $1",
        "pageid": "Stránka s ID $1",
-       "interfaceadmin-info": "$1\n\nOprávnění editovat celoprojektové soubory s CSS/JS/JSON bylo nedávno odděleno od práva <code>editinterface</code>. Pokud nerozumíte tomu, proč vidíte tuto chybu, podívejte se na [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "Oprávnění editovat celoprojektové soubory s CSS/JS/JSON bylo nedávno omezeno na členy skupiny [[{{int:grouppage-interface-admin}}|{{int:group-interface-admin}}]]. Pro více informací viz [[m:Creation of separate user group for editing sitewide CSS/JS]].",
        "rawhtml-notallowed": "Značky &lt;html&gt; nelze používat mimo běžné stránky.",
        "gotointerwiki": "Opustit {{GRAMMAR:4sg|{{SITENAME}}}}",
        "gotointerwiki-invalid": "Zadaný název je neplatný.",
        "pagedata-not-acceptable": "Nenalezen odpovídající formát. Podporované MIME typy: $1",
        "pagedata-bad-title": "Neplatný název: $1.",
        "unregistered-user-config": "Z bezpečnostních důvodů nelze načítat uživatelské podstránky s JavaScriptem, CSS nebo JSONem u neregistrovaných uživatelů.",
+       "passwordpolicies": "Zásady pro heslo",
        "passwordpolicies-group": "Skupina",
        "passwordpolicies-policy-minimalpasswordlength": "Heslo musí být alespoň {{PLURAL:$1|$1 znak|$1 znaky|$1 znaků}} dlouhé",
        "passwordpolicies-policy-minimumpasswordlengthtologin": "Pro přihlášení je vyžadováno alespoň {{PLURAL:$1|$1 znak|$1 znaky|$1 znaků}} dlouhé heslo",
index 6e5cfb8..66a0816 100644 (file)
        "ns-specialprotected": "Ni ellir golygu tudalennau arbennig.",
        "titleprotected": "Diogelwyd y teitl hwn rhag ei greu gan [[User:$1|$1]].\nRhoddwyd y rheswm hwn - <em>$2</em>.",
        "filereadonlyerror": "Nid oes modd newid y ffeil \"$1\" gan fod ffeil \"$2\" yn y modd 'darllen-yn-unig'.\n\nY rheswm a roddwyd gan y gweinyddwr a roddodd y ffeil dan glo yw \"''$3''\".",
+       "invalidtitle": "Teitl annilys",
        "invalidtitle-knownnamespace": "Teitl annilys o'r enw \"$3\" yn y parth \"$2\"",
        "invalidtitle-unknownnamespace": "Teitl annilys ag iddi'r rhif parth anhysbys $1 a'r enw \"$2\"",
        "exception-nologin": "Nid ydych wedi mewngofnodi",
        "wrongpasswordempty": "Roedd y cyfrinair yn wag. Rhowch gynnig arall arni.",
        "passwordtooshort": "Mae'n rhaid fod gan gyfrinair o leia $1 {{PLURAL:$1|nod}}.",
        "passwordtoolong": "Ni chaiff cyfrinair fod yn hirach na {{PLURAL:$1|1 llythyren|$1 llythyren}}.",
-       "passwordtoopopular": "Chewch chi ddim defnyddio cyfreinair rhy syml, rhy gyffredin. Dewisiwch un unigryw!",
+       "passwordtoopopular": "Chewch chi ddim defnyddio cyfrineiriau cyffredin. Dewisiwch un unigryw a gwahanol!",
        "password-name-match": "Rhaid i'ch cyfrinair a'ch enw defnyddiwr fod yn wahanol i'w gilydd.",
        "password-login-forbidden": "Gwaharddwyd defnyddio'r enw defnyddiwr a'r cyfrinair hwn.",
        "mailmypassword": "Ailosoder y cyfrinair",
        "passwordremindertitle": "Hysbysu cyfrinair dros dro newydd ar gyfer {{SITENAME}}",
-       "passwordremindertext": "Mae rhywun (chi mwy na thebyg, o'r cyfeiriad IP $1) wedi gofyn i ni anfon cyfrinair newydd atoch ar gyfer {{SITENAME}} ($4).\nMae cyfrinair dros dro, sef \"$3\", wedi ei greu ar gyfer y defnyddiwr \"$2\". Os mai dyma oedd y bwriad, yna dylech fewngofnodi a'i newid cyn gynted â phosib. Daw'ch cyfrinair dros dro i ben ymhen {{PLURAL:$5||diwrnod|deuddydd|tridiau|$5 diwrnod|$5 diwrnod}}.\n\nOs mai rhywun arall a holodd am y cyfrinair, ynteu eich bod wedi cofio'r hen gyfrinair, ac nac ydych am newid y cyfrinair, rhydd i chi anwybyddu'r neges hon a pharhau i ddefnyddio'r cyfrinair gwreiddiol.",
+       "passwordremindertext": "Mae rhywun (chi mwy na thebyg, o'r cyfeiriad IP $1) wedi gofyn i ni anfon cyfrinair newydd atoch ar gyfer {{SITENAME}} ($4).\nMae cyfrinair dros dro, sef \"$3\", wedi ei greu ar gyfer y defnyddiwr \"$2\". Os mai dyma oedd y bwriad, yna dylech fewngofnodi a'i newid cyn gynted â phosib. Daw'ch cyfrinair dros dro i ben ymhen {{PLURAL:$5||diwrnod}}.\n\nOs mai rhywun arall a holodd am y cyfrinair, ynteu eich bod wedi cofio'r hen gyfrinair, ac nac ydych am newid y cyfrinair, rhydd i chi anwybyddu'r neges hon a pharhau i ddefnyddio'r cyfrinair gwreiddiol.",
        "noemail": "Does dim cyfeiriad e-bost yng nghofnodion y defnyddiwr '$1'.",
        "noemailcreate": "Mae'n rhaid i chi gynnig cyfeiriad e-bost dilys",
        "passwordsent": "Mae cyfrinair newydd wedi'i ddanfon at gyfeiriad e-bost cofrestredig \"$1\". Mewngofnodwch eto ar ôl i chi dderbyn y cyfrinair, os gwelwch yn dda.",
        "page_last": "olaf",
        "histlegend": "Cymharu dau fersiwn: marciwch y cylchoedd ar y ddau fersiwn i'w cymharu, yna pwyswch ar 'return' neu'r botwm 'Cymharer y fersiynau dewisedig'.<br />\nEglurhad: '''({{int:cur}})''' = gwahaniaethau rhyngddo a'r fersiwn cyfredol,\n'''({{int:last}})''' = gwahaniaethau rhyngddo a'r fersiwn cynt, '''({{int:minoreditletter}})''' = golygiad bychan",
        "history-fieldset-title": "Chwilio drwy'r hanes",
-       "history-show-deleted": "Yr ddalen a adolygwyd yn unig a ddilëwyd",
+       "history-show-deleted": "Dangos y rhai a ddilëwyd yn unig",
        "histfirst": "cynharaf",
        "histlast": "diweddaraf",
        "historysize": "({{PLURAL:$1|$1 beit|$1 beit|$1 feit|$1 beit|$1 beit|$1 beit}})",
        "sp-contributions-blocked-notice-anon": "Mae'r cyfeiriad IP hwn wedi'i rwystro ar hyn o bryd.\nMae'r cofnod diweddaraf yn y lòg blocio i'w weld isod:",
        "sp-contributions-search": "Chwilio am gyfraniadau",
        "sp-contributions-username": "Cyfeiriad IP neu enw defnyddiwr:",
-       "sp-contributions-toponly": "Dangos golygiadau sy'n olygiadau diweddaraf yn unig",
-       "sp-contributions-newonly": "Dangos y golygiadau hynny sy'n dechrau tudalen yn unig",
+       "sp-contributions-toponly": "Dangos y golygiadau diweddaraf yn unig",
+       "sp-contributions-newonly": "Dangos dalennau newydd yn unig",
        "sp-contributions-hideminor": "Cuddio golygiadau bach",
        "sp-contributions-submit": "Chwilier",
        "whatlinkshere": "Beth sy'n cysylltu yma",
index 21cc02a..7c698d3 100644 (file)
@@ -69,7 +69,8 @@
                        "Kenn.jensen",
                        "Saederup92",
                        "Fitoschido",
-                       "Jorn Ari"
+                       "Jorn Ari",
+                       "Fnielsen"
                ]
        },
        "tog-underline": "Understreg henvisninger:",
        "right-editcontentmodel": "Redigere indholdsmodellen for en side",
        "right-editinterface": "Ændre brugergrænsefladens tekster",
        "right-editusercss": "Ændre andre brugeres CSS filer",
+       "right-edituserjson": "Redigér andre brugeres JSON-filter",
        "right-edituserjs": "Ændre andre brugeres JS filer",
        "right-editsitecss": "Rediger CSS for hele siden",
        "right-editsitejson": "Rediger JSON for hele siden",
        "right-editsitejs": "Rediger JavaScript for hele siden",
        "right-editmyusercss": "Redigere dine egne CSS-filer",
+       "right-editmyuserjson": "Redigér dine egne bruger-JSON-filer",
        "right-editmyuserjs": "Redigere dine egne JavaScript-filer",
        "right-viewmywatchlist": "Se din egen overvågningsliste",
        "right-editmywatchlist": "Redigere din egen overvågningsliste. Bemærk nogle handlinger tilføjer sider selv uden denne rettelse.",
        "rcfilters-advancedfilters": "Avancerede filtre",
        "rcfilters-limit-title": "Antal resultater som skal vises",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|ændring|ændringer}}, $2",
+       "rcfilters-date-popup-title": "Tidsperiode at søge i",
        "rcfilters-days-title": "De sidste dage",
        "rcfilters-hours-title": "De sidste timer",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|dag|dage}}",
        "rcfilters-highlighted-filters-list": "Fremhævede: $1",
        "rcfilters-quickfilters": "Gemte filtre",
        "rcfilters-quickfilters-placeholder-title": "Ingen filtre gemt endnu",
+       "rcfilters-quickfilters-placeholder-description": "For at gemme filterindstillingerne og genbruge dem senere, klik på bogmærkeikonet i området Aktive Filtre herunder.",
        "rcfilters-savedqueries-defaultlabel": "Gemte filtre",
        "rcfilters-savedqueries-rename": "Omdøb",
        "rcfilters-savedqueries-setdefault": "Vælg som grundindstilling",
        "protectedtitles-submit": "Vis sidetitler",
        "listusers": "Brugerliste",
        "listusers-editsonly": "Vis kun brugere med redigeringer",
+       "listusers-temporarygroupsonly": "Vis kun brugere i midlertidige brugergrupper",
        "listusers-creationsort": "Sorter efter oprettelsesdato",
        "listusers-desc": "Sortér i faldende rækkefølge",
        "usereditcount": "{{PLURAL:$1|én redigering|$1 redigeringer}}",
        "apihelp": "API-hjælp",
        "apihelp-no-such-module": "Modul \"$1\" ikke fundet.",
        "apisandbox": "API-sandkassen",
+       "apisandbox-jsonly": "JavaScript kræves for at bruge API-sandkassen.",
        "apisandbox-api-disabled": "API er deaktiveret på dette websted.",
        "apisandbox-intro": "Brug denne side til at eksperimentere med '''MediaWiki web service API'''.\nVi henviser til [https://www.mediawiki.org/wiki/API:Main_page dokumentationen af API] for yderligere oplysninger om brug af API.  Eksempel: [https://www.mediawiki.org/wiki/API#A_simple_example få indholdet af en forside]. Vælg en handling at se flere eksempler.\n\nBemærk, at selv om dette er en sandkasse, vil handlinger du udfører på denne side redigere wikien.",
        "apisandbox-submit": "Lav forespørgsel",
index 89eb5d7..96b50ec 100644 (file)
        "confirm-unwatch-top": "Diese Seite von der persönlichen Beobachtungsliste entfernen?",
        "confirm-rollback-button": "Okay",
        "confirm-rollback-top": "Bearbeitungen an dieser Seite zurücksetzen?",
+       "confirm-mcrundo-title": "Eine Änderung rückgängig machen",
+       "mcrundofailed": "Rückgängigmachung fehlgeschlagen",
+       "mcrundo-missingparam": "Erforderliche Parameter fehlen bei der Anfrage.",
+       "mcrundo-changed": "Die Seite wurde verändert, seit du dir den Versionsunterschied ansiehst. Bitte überprüfe die neue Änderung.",
        "ellipsis": "…",
        "percent": "$1&#160;%",
        "quotation-marks": "„$1“",
        "edit-error-long": "Fehler:\n\n$1",
        "revid": "Version $1",
        "pageid": "Seitenkennung $1",
-       "interfaceadmin-info": "$1\n\nBerechtigungen für das Bearbeiten von wikiweiten CSS/JS/JSON-Dateien wurden kürzlich von dem Recht <code>editinterface</code> getrennt. Falls du nicht verstehst, warum du diesen Fehler erhältst, siehe bitte [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nBerechtigungen für das Bearbeiten von wikiweiten CSS/JS/JSON-Dateien wurden kürzlich vom Recht <code>editinterface</code> getrennt. Falls du nicht verstehst, warum du diesen Fehler erhältst, siehe [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "&lt;html&gt;-Tags können nicht außerhalb von normalen Seiten verwendet werden.",
        "gotointerwiki": "{{SITENAME}} verlassen",
        "gotointerwiki-invalid": "Der angegebene Titel ist ungültig.",
index 0cff6d9..29651e9 100644 (file)
        "cascadeprotected": "Za toś ten bok jo se wobźěłowanje znjemóžniło, dokulaž jo zawězany do {{PLURAL:$1|slědujucego boka|slědujuceju bokowu|slědujucych bokow}}, {{PLURAL:$1|kótaryž jo|kótarejž stej|kótarež su}} pśez kaskadowu opciju {{PLURAL:$1|šćitany|šćitanej|šćitane}}: $2",
        "namespaceprotected": "Njejsy wopšawnjony, boki w rumje: '''$1''' wobźěłaś.",
        "customcssprotected": "Njamaš pšawo, aby toś ten CSS-bok wobźěłał, dokulaž wopśimujo  wósobinske nastajenja drugego wužywarja.",
+       "customjsonprotected": "Njamaš pšawo, aby toś ten JSON-bok wobźěłał, dokulaž wopśimujo  wósobinske nastajenja drugego wužywarja.",
        "customjsprotected": "Njamaš pšawo, aby toś ten JavaScriptowy bok wobźěłał, dokulaž wopśimujo  wósobinske nastajenja drugego wužywarja.",
        "mycustomcssprotected": "Njamaš pšawo toś ten CSS-bok wobźěłaś.",
+       "mycustomjsonprotected": "Njamaš pšawo toś ten JSON-bok wobźěłaś.",
        "mycustomjsprotected": "Njamaš pšawo toś ten JavaScript-bok wobźěłaś.",
        "myprivateinfoprotected": "Njamaš pšawo swóje priwatne informacije wobźěłaś.",
        "mypreferencesprotected": "Njamaš pšawo swóje nastajenja wobźěłaś.",
index 20bb78a..c66aa07 100644 (file)
        "search-nonefound-thiswiki": "Δεν υπάρχουν αποτελέσματα που να ικανοποιούν το ερώτημα σε αυτόν τον ιστότοπο.",
        "powersearch-legend": "Αναλυτική αναζήτηση",
        "powersearch-ns": "Αναζήτηση στους ονοματοχώρους:",
-       "powersearch-togglelabel": "Î\88λεγÏ\87οÏ\82:",
+       "powersearch-togglelabel": "Î\95Ï\80ιλογή:",
        "powersearch-toggleall": "Όλοι",
        "powersearch-togglenone": "Κανένας",
        "powersearch-remember": "Διατήρηση επιλογής για μελλοντικές αναζητήσεις",
index 47747b6..18dc51a 100644 (file)
        "customcssprotected": "You do not have permission to edit this CSS page because it contains another user's personal settings.",
        "customjsonprotected": "You do not have permission to edit this JSON page because it contains another user's personal settings.",
        "customjsprotected": "You do not have permission to edit this JavaScript page because it contains another user's personal settings.",
-       "sitecssprotected": "You do not have permission to edit this CSS page because it may affect all visitors",
-       "sitejsonprotected": "You do not have permission to edit this JSON page because it may affect all visitors",
-       "sitejsprotected": "You do not have permission to edit this JavaScript page because it may affect all visitors",
+       "sitecssprotected": "You do not have permission to edit this CSS page because it may affect all visitors.",
+       "sitejsonprotected": "You do not have permission to edit this JSON page because it may affect all visitors.",
+       "sitejsprotected": "You do not have permission to edit this JavaScript page because it may affect all visitors.",
        "mycustomcssprotected": "You do not have permission to edit this CSS page.",
        "mycustomjsonprotected": "You do not have permission to edit this JSON page.",
        "mycustomjsprotected": "You do not have permission to edit this JavaScript page.",
        "searchdisabled": "{{SITENAME}} search is disabled.\nYou can search via Google in the meantime.\nNote that their indexes of {{SITENAME}} content may be out of date.",
        "googlesearch": "<form method=\"get\" action=\"//www.google.com/search\" id=\"googlesearch\">\n\t<input type=\"hidden\" name=\"domains\" value=\"{{SERVER}}\" />\n\t<input type=\"hidden\" name=\"num\" value=\"50\" />\n\t<input type=\"hidden\" name=\"ie\" value=\"$2\" />\n\t<input type=\"hidden\" name=\"oe\" value=\"$2\" />\n\n\t<input type=\"text\" name=\"q\" size=\"31\" maxlength=\"255\" value=\"$1\" />\n\t<input type=\"submit\" name=\"btnG\" value=\"$3\" />\n  <div>\n\t<input type=\"radio\" name=\"sitesearch\" id=\"gwiki\" value=\"{{SERVER}}\" checked=\"checked\" /><label for=\"gwiki\">{{SITENAME}}</label>\n\t<input type=\"radio\" name=\"sitesearch\" id=\"gWWW\" value=\"\" /><label for=\"gWWW\">WWW</label>\n  </div>\n</form>",
        "search-error": "An error has occurred while searching: $1",
-       "search-warning": "A warning has occured while searching: $1",
+       "search-warning": "A warning has occurred while searching: $1",
        "opensearch-desc": "{{SITENAME}} ({{CONTENTLANGUAGE}})",
        "preferences": "Preferences",
        "preferences-summary": "",
        "confirm-unwatch-top": "Remove this page from your watchlist?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Revert edits to this page?",
+       "confirm-mcrundo-title": "Undo a change",
+       "mcrundofailed": "Undo failed",
+       "mcrundo-missingparam": "Missing required parameters on request.",
+       "mcrundo-changed": "The page has been changed since you viewed the diff. Please review the new change.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
index 2fd9783..be27028 100644 (file)
                        "Tiberius1701",
                        "Astroemi",
                        "Jelou",
-                       "Ktranz"
+                       "Ktranz",
+                       "AVIADOR71"
                ]
        },
        "tog-underline": "Subrayar los enlaces:",
        "tog-showtoolbar": "Mostrar la barra de edición",
        "tog-editondblclick": "Editar páginas al hacer doble clic",
        "tog-editsectiononrightclick": "Permitir las modificaciones de sección al hacer clic derecho en sus títulos",
-       "tog-watchcreations": "Añadir las páginas que cree y los archivos que suba a mi lista de seguimento",
-       "tog-watchdefault": "Añadir las páginas y archivos que edite a mi lista de seguimiento",
+       "tog-watchcreations": "Añadir a mi lista de seguimiento las páginas que cree y los archivos que suba",
+       "tog-watchdefault": "Añadir a mi lista de seguimiento las páginas y archivos que edite",
        "tog-watchmoves": "Añadir las páginas y archivos que mueva a mi lista de seguimiento",
        "tog-watchdeletion": "Añadir las páginas y archivos que borre a mi lista de seguimiento",
-       "tog-watchuploads": "Añadir los archivos nuevos que suba a mi lista de seguimiento",
-       "tog-watchrollback": "Añadir las páginas donde haya realizado una reversión a mi lista de seguimiento",
+       "tog-watchuploads": "Añadir a mi lista de seguimiento los archivos nuevos que suba",
+       "tog-watchrollback": "Añadir a mi lista de seguimiento las páginas donde haya realizado una reversión",
        "tog-minordefault": "Marcar todas las ediciones como menores de manera predeterminada",
        "tog-previewontop": "Mostrar previsualización antes del cuadro de edición",
        "tog-previewonfirst": "Mostrar previsualización en la primera edición",
        "confirm-unwatch-top": "¿Quitar esta página de tu lista de seguimiento?",
        "confirm-rollback-button": "Aceptar",
        "confirm-rollback-top": "¿Revertir las ediciones a esta página?",
+       "confirm-mcrundo-title": "Deshacer un cambio",
+       "mcrundofailed": "Error al deshacer",
+       "mcrundo-missingparam": "Faltan parámetros requeridos en la solicitud.",
+       "mcrundo-changed": "La página ha sido cambiada desde que viste el diff. Por favor revisa el nuevo cambio.",
        "comma-separator": ",&#32;",
        "ellipsis": "…",
        "percent": "$1 %",
index a67c238..7131875 100644 (file)
        "filehist-filesize": "Faili suurus",
        "filehist-comment": "Kommentaar",
        "imagelinks": "Failikasutus",
-       "linkstoimage": "Sellele failile {{PLURAL:$1|viitab järgmine lehekülg|viitavad järgmised $1 leheküljed}}:",
-       "linkstoimage-more": "Sellele failile viitab enam kui {{PLURAL:$1|üks lehekülg|$1 lehekülge}}.\nJärgmises loendis on näidatud ainult {{PLURAL:$1|esimene viitav lehekülg|esimesed $1 viitavat lehekülge}}.\n[[Special:WhatLinksHere/$2|Kogu loetelu]] on saadaval.",
-       "nolinkstoimage": "Sellele failile ei viita ükski lehekülg.",
+       "linkstoimage": "Seda faili {{PLURAL:$1|kasutab järgmine lehekülg|kasutavad järgmised $1 lehekülge}}:",
+       "linkstoimage-more": "Seda faili kasutab enam kui {{PLURAL:$1|üks lehekülg|$1 lehekülge}}.\nJärgmises loendis on näidatud ainult {{PLURAL:$1|esimene lehekülg|esimesed $1 lehekülge}}, mis faili {{PLURAL:$1|kasutab|kasutavad}}.\n[[Special:WhatLinksHere/$2|Kogu loetelu]] on saadaval.",
+       "nolinkstoimage": "Seda faili ei kasuta ükski lehekülg.",
        "morelinkstoimage": "Vaata [[Special:WhatLinksHere/$1|veel linke]], mis sellele failile viitavad.",
        "linkstoimage-redirect": "$1 (failiümbersuunamine) $2",
        "duplicatesoffile": "{{PLURAL:$1|Järgmine fail|Järgmised $1 faili}} on selle faili {{PLURAL:$1|duplikaat|duplikaadid}} ([[Special:FileDuplicateSearch/$2|üksikasjad]]):",
        "cachedspecial-refresh-now": "Vaata uusimat versiooni.",
        "categories": "Kategooriad",
        "categories-submit": "Näita",
-       "categoriespagetext": "Vikis on {{PLURAL:$1|järgmine kategooria|järgmised kategooriad}}.\nSiin ei näidata [[Special:UnusedCategories|kasutamata kategooriaid]].\nVaata ka [[Special:WantedCategories|puuduvaid kategooriaid]].",
+       "categoriespagetext": "Vikis on {{PLURAL:$1|järgmine kategooria. See|järgmised kategooriad. Need}} ei pruugi olla kasutusel.\nVaata ka [[Special:WantedCategories|puuduvaid kategooriaid]].",
        "categoriesfrom": "Näita kategooriaid alates:",
        "deletedcontributions": "Kustutatud kaastöö",
        "deletedcontributions-title": "Kasutaja kustutatud kaastöö",
index a7aaabe..609f692 100644 (file)
        "ns-specialprotected": "صفحه‌های ویژه غیر قابل ویرایش هستند.",
        "titleprotected": "این عنوان توسط [[User:$1|$1]] در برابر ایجاد محافظت شده‌است.\nدلیل ارائه‌شده این است: <em>$2</em>.",
        "filereadonlyerror": "تغییر پروندهٔ «$1» ممکن نیست چون مخزن پروندهٔ «$2» در حالت فقط خواندنی قرار دارد.\n\nمدیری که آن را قفل کرده چنین توضیحی را ذکر کرده:  «$3».",
+       "invalidtitle": "عنوان نامعتبر",
        "invalidtitle-knownnamespace": "عنوان نامعتبر با فضای نام «$2» و متن «$3»",
        "invalidtitle-unknownnamespace": "عنوان نامعتبر با فضای نام ناشناختهٔ شمارهٔ $1 و متن «$2»",
        "exception-nologin": "به سامانه وارد نشده‌اید",
        "converter-manual-rule-error": "خطا در قوانین مبدل دستی زبان",
        "undo-success": "این ویرایش را می‌توان خنثی کرد.\nلطفاً تفاوت زیر را بررسی کنید تا تأیید کنید که این چیزی است که می‌خواهید انجام دهید، سپس تغییرات زیر را ذخیره کنید تا خنثی‌سازی ویرایش را به پایان ببرید.",
        "undo-failure": "به علت تعارض با ویرایش‌های میانی، این ویرایش را نمی‌توان خنثی کرد.",
+       "undo-main-slot-only": "ویرایش را نمی‌توان انجام داد زیرا شامل محتویات خارج از شیار اصلی است.",
        "undo-norev": "این ویرایش را نمی‌توان خنثی کرد چون وجود ندارد یا حذف شده‌است.",
        "undo-nochange": "به نظر می‌رسد ویرایش از پیش خنثی‌سازی شده است.",
        "undo-summary": "خنثی‌سازی ویرایش $1 توسط [[Special:Contributions/$2|$2]] ([[User talk:$2|بحث]])",
        "diff-paragraph-moved-toold": "پاراگراف جابه‌جا شده بود. کلیک کنید تا به جای قدیمش بروید.",
        "difference-missing-revision": "{{PLURAL:$2|یک ویرایش|$2 ویرایش}}  از تفاوت نسخه‌ها ($1) {{PLURAL:$2|یافت|یافت}}  نشد.\n\nاین اتفاق معمولاً در اثر دنبال کردن پیوند تفاوتی به یک صفحهٔ حذف‌شده پیش می‌آید.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
        "searchresults": "نتایج جستجو",
+       "search-filter-title-prefix": "فقط در صفحاتی که عنوانش با «$1» شروع می‌شود",
        "search-filter-title-prefix-reset": "جستجوی همه صفحات",
        "searchresults-title": "نتایج جستجو برای «$1»",
        "titlematches": "تطبیق عنوان مقاله",
        "prefs-watchlist-edits": "تعداد ویرایش‌های نشان‌داده‌شده در فهرست پی‌گیری‌ها:",
        "prefs-watchlist-edits-max": "حداکثر تعداد: ۱۰۰۰",
        "prefs-watchlist-token": "رمز فهرست پی‌گیری:",
+       "prefs-watchlist-managetokens": "مدیریت بلیط‌ها",
        "prefs-misc": "متفرقه",
        "prefs-resetpass": "تغییر گذرواژه",
        "prefs-changeemail": "تغییر یا حذف نشانی ایمیل",
        "recentchangescount": "تعداد نمایش پیش‌فرض ویرایش‌ها در تغییرات اخیر، تاریخچه صفحه و سیاهه‌ها:",
        "prefs-help-recentchangescount": "حداکثر تعداد: ۱۰۰۰",
        "prefs-help-watchlist-token2": "این کلید رمز خوراک وب فهرست پی‌گیری‌های شماست.\nهرکس آن را بداند می‌تواند فهرست پی‌گیری‌هایتان را بخواند، بنابراین آن را به اشتراک نگذارید. اگر لازم باشد [[Special:ResetTokens|می‌توانید کلیدی نو ایجاد کنید]].",
+       "prefs-help-tokenmanagement": "برای حسابتان که به خوراک وب‌سایت فهرست پیگیری‌تان دسترسی دارد کلید محرمانه را می‌توانید ببینید و بازنشانی کنید. کلید قادر به خواندن فهرست پیگیری‌های شما خواهد بود، پس آن را به اشتراک نگذارید.",
        "savedprefs": "ترجیحات شما ذخیره شد.",
        "savedrights": "گروه‌های کاربری {{GENDER:$1|$1}} ذخیره شده‌است.",
        "timezonelegend": "منطقهٔ زمانی:",
        "group-autoconfirmed-member": "{{GENDER:$1|کاربر تأییدشده}}",
        "group-bot-member": "ربات",
        "group-sysop-member": "{{GENDER:$1|مدیر}}",
-       "group-interface-admin-member": "مدیر رابط کاربری",
+       "group-interface-admin-member": "{{GENDER:$1|مدیر رابط کاربری}}",
        "group-bureaucrat-member": "{{GENDER:$1|دیوان‌سالار}}",
        "group-suppress-member": "{{GENDER:$1|فرونشاننده}}",
        "grouppage-user": "{{ns:project}}:کاربران",
        "grouppage-autoconfirmed": "{{ns:project}}:کاربران تأییدشده",
        "grouppage-bot": "{{ns:project}}:ربات‌ها",
        "grouppage-sysop": "{{ns:project}}:مدیران",
+       "grouppage-interface-admin": "{{ns:project}}:مدیران رابط کاربری",
        "grouppage-bureaucrat": "{{ns:project}}:دیوان‌سالاران",
        "grouppage-suppress": "{{ns:project}}:فرونشانی",
        "right-read": "خواندن صفحه",
        "right-editcontentmodel": "ویرایش مدل محتوای یک صفحه",
        "right-editinterface": "ویرایش واسط کاربری",
        "right-editusercss": "ویرایش صفحه‌های CSS دیگر کاربرها",
+       "right-edituserjson": "ویرایش پرونده‌های JSON دیگر کاربرها",
        "right-edituserjs": "ویرایش صفحه‌های JS دیگر کاربرها",
+       "right-editsitecss": "ویرایش گسترده CSS وب‌گاه",
+       "right-editsitejson": "ویرایش گسترده JSON وب‌گاه",
+       "right-editsitejs": "ویرایش گسترده JavaScript وب‌گاه",
        "right-editmyusercss": "پرونده‌های سی‌اس‌اس کاربری خود را ویرایش کنید",
+       "right-editmyuserjson": "پرونده‌های JSON کاربری خود را ویرایش کنید",
        "right-editmyuserjs": "پرونده‌های جاوااسکریپت کاربری خود را ویرایش کنید",
        "right-viewmywatchlist": "فهرست پیگیری‌های خود را ببینید",
        "right-editmywatchlist": "فهرست پیگیری‌های خود را ویرایش کنید. توجه داشته باشید برخی از اقدامات حتی بدون این دسترسی هم صفحات را اضافه می‌کنند.",
        "grant-createaccount": "ایجاد حساب‌های کاربری",
        "grant-createeditmovepage": "ایجاد، ویرایش و انتقال صفحات",
        "grant-delete": "حذف صفحات، نسخه‌های ویرایش و سیاهه ورودی",
-       "grant-editinterface": "ویرایش CSS کاربر/جاوااسکریپت/JSON  و فضای نام مدیاویکی",
+       "grant-editinterface": "ویرایش صفحه‌های جی‌سان کاربری یا سراسری و فضای نام مدیاویکی",
        "grant-editmycssjs": "ویرایش  CSS /جاوااسکریپت/JSON  کاربری",
        "grant-editmyoptions": "اولویت‌های کاربری را ویرایش کنید",
        "grant-editmywatchlist": "ویرایش فهرست پی‌گیری‌هایتان",
+       "grant-editsiteconfig": "ویرایش گسترده CSS/JS کاربر",
        "grant-editpage": "ویرایش صفحات موجود",
        "grant-editprotected": "ویرایش صفحه محافظت شده",
        "grant-highvolume": "ویرایش با حجم بالا",
        "rcfilters-activefilters": "پالایه‌های فعال",
        "rcfilters-activefilters-hide": "نهفتن",
        "rcfilters-activefilters-show": "نمایش",
+       "rcfilters-activefilters-hide-tooltip": "پنهان کردن محیط پالایه فعال",
+       "rcfilters-activefilters-show-tooltip": "نمایش محیط پالایه فعال",
        "rcfilters-advancedfilters": "پالایه‌‌های پیشرفته",
        "rcfilters-limit-title": "تعداد تغییرات برای نمایش",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|تغییر|تغییر}}, $2",
        "rcfilters-filter-humans-label": "انسان (ربات نه)",
        "rcfilters-filter-humans-description": "ویرایش توسط انسان.",
        "rcfilters-filtergroup-reviewstatus": "وضعیت بازبینی",
+       "rcfilters-filter-reviewstatus-unpatrolled-description": "ویرایش‌های غیردستی یا خودکار به عنوان گشت‌خورده.",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "گشت‌نخورده",
+       "rcfilters-filter-reviewstatus-manual-description": "ویرایش‌های دستی به عنوان گشت‌خورده.",
        "rcfilters-filter-reviewstatus-manual-label": "به طور دستی گشت خورد",
+       "rcfilters-filter-reviewstatus-auto-description": "ویرایش‌های کاربران باتجربه که ویرایشش به عنوان گشت‌خورده برچسب خورده‌است.",
+       "rcfilters-filter-reviewstatus-auto-label": "گشت خودکار",
        "rcfilters-filtergroup-significance": "اهمیت",
        "rcfilters-filter-minor-label": "ویرایش‌های جزئی",
        "rcfilters-filter-minor-description": "ویرایش‌هایی که به عنوان جزئی برچسب خورده‌اند.",
        "rcfilters-watchlist-showupdated": "تغییرات صفحاتی که شما بازدید نکردید از زمانی که تغییرات رخ داده به صورت <strong>پررنگ</strong>، با نشانگر توپر.",
        "rcfilters-preference-label": "مخفی کردن نسخه بهبود یافته تغییرات اخیر",
        "rcfilters-preference-help": "تغییرات رابط کاربری که در سال ۲۰۱۷ اضافه شده است را بر می‌گرداند.",
+       "rcfilters-watchlist-preference-label": "نمایش نسخهٔ بهبودیافتهٔ فهرست پیگیری",
+       "rcfilters-watchlist-preference-help": "واگردان در سال ۲۰۱۷ دوباره طراحی شد و تمام ابزارها اضافه و از آن زمان به بعد اضافه شدند.",
        "rcfilters-filter-showlinkedfrom-label": "نمایش تغییرات صفحاتی که پیوند شده‌اند",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>صفحات پیوند به</strong> صفحهٔ انتخاب شده",
        "rcfilters-filter-showlinkedto-label": "نمایش تغییرات در صفحاتی که در ون این صفحه پیوند شده‌اند",
        "uploadstash-zero-length": "اندازهٔ پرونده صفر است.",
        "invalid-chunk-offset": "جابجایی نامعتبر قطعه",
        "img-auth-accessdenied": "منع دسترسی",
-       "img-auth-nopathinfo": "PATH_INFO موجود نیست.\nسرور شما برای ردکردن این مقدار تنظیم نشده‌است.\nممکن است مبتنی بر سی‌جی‌آی باشد و از img_auth پشتیبانی نکند.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
+       "img-auth-nopathinfo": "مسیر اطلاعات موجود نیست.\nسرورتان برای ردکردن متغییرهای REQUEST_URI و/یا PATH_INFO باید تنظیم شود.\nاگر مبتنی قصد فعال‌کردن wgUsePathInfo دارد.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
        "img-auth-notindir": "مسیر درخواست شده در شاخهٔ بارگذاری تنظیم‌شده قرار ندارد.",
        "img-auth-badtitle": "امکان ایجاد یک عنوان مجاز از «$1» وجود ندارد.",
        "img-auth-nologinnWL": "شما به سامانه وارد نشده‌اید و «$1» در فهرست سفید قرار ندارد.",
        "http-timed-out": "مهلت درخواست اچ‌تی‌تی‌پی به سر رسید.",
        "http-curl-error": "خطا در آوردن نشانی اینترنتی: $1",
        "http-bad-status": "در حین درخواست اچ‌تی‌تی‌پی خطایی رخ داد: $1 $2",
+       "http-internal-error": "خطای درونی HTTP",
        "upload-curl-error6": "دسترسی به نشانی اینترنتی ممکن نشد",
        "upload-curl-error6-text": "نشانی اینترنتی داده شده قابل دسترسی نیست.\nلطفاً درستی آن و اینکه تارنما برقرار است را بررسی کنید.",
        "upload-curl-error28": "مهلت بارگذاری به سر رسید",
        "filehist-filesize": "اندازهٔ پرونده",
        "filehist-comment": "توضیح",
        "imagelinks": "کاربرد پرونده",
-       "linkstoimage": "{{PLURAL:$1|صفحهٔ|صفحه‌های}} زیر به این تصویر پیوند {{PLURAL:$1|دارد|دارند}}:",
-       "linkstoimage-more": "بÛ\8cØ´ Ø§Ø² $1 ØµÙ\81Ø­Ù\87 Ø¨Ù\87 Ø§Û\8cÙ\86 Ù¾Ø±Ù\88Ù\86دÙ\87 Ù¾Û\8cÙ\88Ù\86د {{PLURAL:$1|دارد|دارÙ\86د}}.\nÙ\81Ù\87رست Ø²Û\8cر ØªÙ\86Ù\87ا {{PLURAL:$1|اÙ\88Ù\84Û\8cÙ\86 Ù¾Û\8cÙ\88Ù\86د|اÙ\88Ù\84Û\8cÙ\86 $1 Ù¾Û\8cÙ\88Ù\86د}} Ø¨Ù\87 این صفحه را نشان می‌دهد.\n[[Special:WhatLinksHere/$2|فهرست کامل]] نیز موجود است.",
+       "linkstoimage": "{{PLURAL:$1|صفحهٔ|صفحه‌های}} زیر به این تصویر پیوند دارد:",
+       "linkstoimage-more": "بÛ\8cØ´ Ø§Ø² $1 ØµÙ\81Ø­Ù\87 Ø§Ø² Ø§Û\8cÙ\86 Ù¾Ø±Ù\88Ù\86دÙ\87 Ø§Ø³ØªÙ\81ادÙ\87 {{PLURAL:$1|Ù\85Û\8câ\80\8cÚ©Ù\86د|Ù\85Û\8câ\80\8cÚ©Ù\86Ù\86د}}.\nÙ\81Ù\87رست Ø²Û\8cر ØªÙ\86Ù\87ا {{PLURAL:$1|اÙ\88Ù\84Û\8cÙ\86 Ø§Ø³ØªÙ\81ادÙ\87|اÙ\88Ù\84Û\8cÙ\86 $1 Ø§Ø³ØªÙ\81ادÙ\87}} Ø§Ø² این صفحه را نشان می‌دهد.\n[[Special:WhatLinksHere/$2|فهرست کامل]] نیز موجود است.",
        "nolinkstoimage": "این پرونده در هیچ صفحه‌ای به کار نرفته‌است.",
        "morelinkstoimage": "[[Special:WhatLinksHere/$1|پیوندهای دیگر]] به این پرونده را ببینید.",
        "linkstoimage-redirect": "$1 (تغییرمسیر پرونده) $2",
        "protectedtitles-submit": "نمایش عناوین",
        "listusers": "فهرست کاربران",
        "listusers-editsonly": "فقط کاربرانی که ویرایش دارند را نشان بده",
+       "listusers-temporarygroupsonly": "نمایش کاربرانی که به صورت موقت در گروه کاربران هستند",
        "listusers-creationsort": "مرتب کردن بر اساس تاریخ ایجاد",
        "listusers-desc": "ترتیب نزولی",
        "usereditcount": "$1 {{PLURAL:$1|ویرایش|ویرایش}}",
        "apisandbox-dynamic-parameters-add-label": "افزودن پارامتر:",
        "apisandbox-dynamic-parameters-add-placeholder": "نام پارامتر",
        "apisandbox-dynamic-error-exists": "پارامتری به نام \"$1\"هم اکنون وجود دارد.",
+       "apisandbox-templated-parameter-reason": "این [[Special:ApiHelp/main#main/templatedparams|پارامتر الگو]] بر پایهٔ {{PLURAL:$1|مقدار|مقدار}} $2 پیشنهاد می‌شود.",
        "apisandbox-deprecated-parameters": "پارامتر های نامناسب",
        "apisandbox-fetch-token": "پرکردن خودکار توکن",
        "apisandbox-add-multi": "افزودن",
        "speciallogtitlelabel": "هدف (عنوان یا {{ns:user}}:نام کاربر برای کاربر):",
        "log": "سیاهه‌ها",
        "logeventslist-submit": "نمایش",
+       "logeventslist-more-filters": "نمایش سیاهه‌های بیشتر:",
        "logeventslist-patrol-log": "سیاههٔ گشت",
        "logeventslist-tag-log": "سیاهه برچسب",
        "all-logs-page": "تمام سیاهه‌های عمومی",
        "cachedspecial-refresh-now": "مشاهده آخرین.",
        "categories": "رده‌ها",
        "categories-submit": "نمایش",
-       "categoriespagetext": "{{PLURAL:$1|ردهٔ|رده‌های}} زیر دارای صفحات یا پرونده‌هایی {{PLURAL:$1|است|هستند}}.\n[[Special:UnusedCategories|رده‌های استفاده‌نشده]] در اینجا نمایش داده نشده‌اند.\nهمچنین [[Special:WantedCategories|رده‌های مورد نیاز]] را ببینید.",
+       "categoriespagetext": "{{PLURAL:$1|ردهٔ|رده‌های}} زیر دارای صفحات یا پرونده‌هایی است.\nرده‌های استفاده‌نشده در اینجا نمایش داده نشده‌اند.\nهمچنین [[Special:WantedCategories|رده‌های مورد نیاز]] را ببینید.",
        "categoriesfrom": "نمایش رده‌ها با شروع از:",
        "deletedcontributions": "مشارکت‌های حذف‌شده",
        "deletedcontributions-title": "مشارکت‌های حذف‌شده",
        "activeusers-noresult": "کاربری پیدا نشد.",
        "activeusers-submit": "نمایش کاربران فعال",
        "listgrouprights": "اختیارات گروه‌های کاربری",
-       "listgrouprights-summary": "فهرست زیر شامل گروه‌های کاربری تعریف شده در این ویکی و اختیارات داده شده به آن‌ها است.\nاطلاعات بیشتر در مورد هر یک از اختیارات را در [[{{MediaWiki:Listgrouprights-helppage}}]] بیابید.",
+       "listgrouprights-summary": "فهرست زیر شامل گروه‌های کاربری تعریف شده در این ویکی و اختیارات داده شده به آن‌ها است.\nاطلاعات بیشتر در مورد هر کدام از آنها را در [[{{MediaWiki:Listgrouprights-helppage}}|اختیارات گروه‌های کاربری]] بیابید.",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">اختیارات داده‌شده</span>\n* <span class=\"listgrouprights-revoked\">اختیارات گرفته‌شده</span>",
        "listgrouprights-group": "گروه",
        "listgrouprights-rights": "دسترسی‌ها",
        "dellogpage": "سیاههٔ حذف",
        "dellogpagetext": "فهرست زیر فهرستی از آخرین حذف‌هاست.\nهمهٔ زمان‌های نشان‌داده‌شده زمان کارساز (وقت گرینویچ) است.",
        "deletionlog": "سیاههٔ حذف",
+       "log-name-create": "سیاههٔ ایجاد صفحه",
+       "log-description-create": "در زیر فهرست صفحاتی که اخیراً ایجاد شده‌اند قرار دارد.",
+       "logentry-create-create": "$1 صفحهٔ $3 را {{GENDER:$2|ساخته}}",
        "reverted": "به نسخهٔ قدیمی‌تر واگردانده شد",
        "deletecomment": "دلیل:",
        "deleteotherreason": "دلیل دیگر/اضافی:",
        "protect-othertime": "زمانی دیگر:",
        "protect-othertime-op": "زمانی دیگر",
        "protect-existing-expiry": "زمان انقضای موجود: $2، $3",
-       "protect-existing-expiry-infinity": "زÙ\85اÙ\86 Ø§Ù\86Ù\82ضاÛ\8c Ù\85Ù\88جÙ\88د: Ø¨Û\8câ\80\8cÙ\86Ù\87اÛ\8cت",
+       "protect-existing-expiry-infinity": "زÙ\85اÙ\86 Ø§Ù\86Ù\82ضاÛ\8c Ù\85Ù\88جÙ\88د: Ø¨Û\8câ\80\8cپاÛ\8cاÙ\86",
        "protect-otherreason": "دلیل دیگر/اضافی:",
        "protect-otherreason-op": "دلیل دیگر",
        "protect-dropdown": "*دلایل متداول محافظت\n** خرابکاری گسترده\n** هرزنگاری گسترده\n** جنگ ویرایشی غیر سازنده\n** صفحهٔ پر بازدید",
        "uctop": "(نسخهٔ کنونی)",
        "month": "در این ماه (و پیش از آن):",
        "year": "در این سال (و پیش از آن):",
+       "date": "از تاریخ (و زودتر):",
        "sp-contributions-newbies": "فقط مشارکت‌های تازه‌کاران نمایش داده شود",
        "sp-contributions-newbies-sub": "برای تازه‌کاران",
        "sp-contributions-newbies-title": "مشارکت‌های کاربری برای حساب‌های تازه‌کار",
        "interlanguage-link-title": "$1–$2",
        "interlanguage-link-title-nonlang": "$1 – $2",
        "common.css": "/* دستورات این بخش همهٔ کاربران را تحت تاثیر قرار می‌دهند. */",
+       "common.json": "/*همهٔ JSONهای اینجا برای همهٔ کاربران در همهٔ صفحات بارگذاری می‌شوند.*/",
        "anonymous": "{{PLURAL:$1|کاربر|کاربران}} گمنام {{SITENAME}}",
        "siteuser": "$1، کاربر {{SITENAME}}",
        "anonuser": "$1 کاربر ناشناس {{SITENAME}}",
        "unlinkaccounts-success": "پیوند کاربری بدون پیوند شد.",
        "authenticationdatachange-ignored": "به تغيير اطلاعات احراز هويت پرداخته نشد. آیا ممکن است که هيچ مهيا کننده‌ای برای اين کار تنظيم نشده باشد؟",
        "userjsispublic": "لطفاً توجه کنید: زیرصفحه‌های جاوااسکریپت نباید حاوی اطلاعات محرمانه باشند چون توسط دیگران قابل مشاهده هستند.",
+       "userjsonispublic": "لطفا توجه داشته باشید: صفحات JSON نباید شامل اطلاعاتی که دیگر کاربران نباید ببینند، باشد.",
        "usercssispublic": "لطفاً توجه کنید: زیرصفحه‌های سی‌اس‌اس نباید حاوی اطلاعات محرمانه باشند چون توسط دیگران قابل مشاهده هستند.",
        "restrictionsfield-badip": "نشانی یا بازهٔ آی‌پی نامعتبر: $1",
        "restrictionsfield-label": "بازه‌های آی‌پی مجاز:",
        "edit-error-long": "خطاها:\n\n$1",
        "revid": "نسخهٔ $1",
        "pageid": "شناسهٔ صفحهٔ $1",
+       "interfaceadmin-info": "\n$1\n\nدسترسی‌ها برای ویرایش فایل‌های CSS/JS/JSON که اخیراً از دسترسی <code>editinterface</code> جدا شده‌اند. اگر نمی دانید که چرا این خطا رخ داده‌است [[mw:MediaWiki_1.32/interface-admin]] را مطالعه کنید.",
        "rawhtml-notallowed": "برچسب‌های &lt;html&gt; را نمی‌توان خارج از صفحه‌های معمولی استفاده کرد.",
        "gotointerwiki": "در حال ترک {{SITENAME}}",
        "gotointerwiki-invalid": "عنوان مشخص شده نامجاز است.",
        "pagedata-text": "این صفحه یک رابط داده به صفحات است. لطفا نام صفحه را در آدرس به شکل زیرصفحه وارد کنید.\n* مذاکره محتوا با استفاده از هدر Accept ممکن است. این به این معنی است که داده‌ّای صفحه در قالبی که ترجیح دهید باز خواهد شد.",
        "pagedata-not-acceptable": "هیچ قالب تطبیقی یافت نشد. انواع MIME پشتیبانی شده: $1",
        "pagedata-bad-title": "عنوان نامعتبر: «$1».",
+       "unregistered-user-config": "برای موارد امنیتی صفحات JavaScript، CSS و JSON برای کاربران ثبت‌نام نکرده دیده نمی‌شوند.",
        "passwordpolicies": "سیاست‌های گذرواژه",
+       "passwordpolicies-summary": "این فهرست سیاست‌های موثر بر گذرواژه‌ها برای گروه‌های کاربری تعریف شده در این ویکی‌ست.",
        "passwordpolicies-group": "گروه",
-       "passwordpolicies-policies": "سیاست‌ها"
+       "passwordpolicies-policies": "سیاست‌ها",
+       "passwordpolicies-policy-minimalpasswordlength": "گذرواژه باید حداقل $1 {{PLURAL:$1|نویسه|نویسه}} طول داشته باشد",
+       "passwordpolicies-policy-minimumpasswordlengthtologin": "گذرواژه باید حداقل $1 {{PLURAL:$1|نویسه|نویسه}} طول داشته باشد تا بتواند به سامانه وارد شود",
+       "passwordpolicies-policy-passwordcannotmatchusername": "گذرواژه نمی تواند مانند نام کاربری باشد",
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "گذرواژه نمی‌تواند مشابه گذرواژه‌های فهرست شده در فهرست سیاه باشد",
+       "passwordpolicies-policy-maximalpasswordlength": "گذرواژه باید کمتر از $1 {{PLURAL:$1|نویسه|نویسه}} طول داشته باشد",
+       "passwordpolicies-policy-passwordcannotbepopular": "گذرواژه نمی‌تواند {{PLURAL:$1|گذرواژه پراستفاده باشد|در فهرست $1 گذرواژه‌های پراستفاده باشد}}",
+       "easydeflate-invaliddeflate": "محتوی تهیه‌شده به صورت درست خالی نشده‌است"
 }
index c55acd3..f676f3d 100644 (file)
        "filehist-filesize": "Tiedostokoko",
        "filehist-comment": "Kommentti",
        "imagelinks": "Tiedoston käyttö",
-       "linkstoimage": "{{PLURAL:$1|Seuraavalta sivulta|$1 sivulla}} on linkki tähän tiedostoon:",
-       "linkstoimage-more": "Enemmän kuin $1 {{PLURAL:$1|sivu|sivua}} linkittää tähän tiedostoon.\nSeuraava lista näyttää {{PLURAL:$1|ensimmäisen linkittävän sivun|$1 ensimmäistä linkittävää sivua}} tähän tiedostoon.\n[[Special:WhatLinksHere/$2|Koko lista]] on saatavilla.",
-       "nolinkstoimage": "Tähän tiedostoon ei ole linkkejä miltään sivulta.",
+       "linkstoimage": "{{PLURAL:$1|Seuraava sivu käyttää|Seuraavat $1 sivua käyttävät}} tätä tiedostoa:",
+       "linkstoimage-more": "Enemmän kuin $1 {{PLURAL:$1|sivu linkittää|sivua linkittävät}} tähän tiedostoon.\nSeuraava lista näyttää {{PLURAL:$1|ensimmäisen sivun, joka käyttää|$1 ensimmäistä sivua, jotka käyttävät}} vain tätä tiedostoa.\n[[Special:WhatLinksHere/$2|Koko lista]] on saatavilla.",
+       "nolinkstoimage": "Tätä tiedostoa ei käytetä millään sivulla.",
        "morelinkstoimage": "Näytä [[Special:WhatLinksHere/$1|lisää linkkejä]] tähän tiedostoon.",
        "linkstoimage-redirect": "$1 (tiedosto-ohjaus) $2",
        "duplicatesoffile": "{{PLURAL:$1|Seuraava tiedosto on tämän tiedoston kaksoiskappale|Seuraavat $1 tiedostoa ovat tämän tiedoston kaksoiskappaleita}} ([[Special:FileDuplicateSearch/$2|lisätietoja]]):",
        "uctop": "(uusin)",
        "month": "Alkaen kuukaudesta (ja aiemmin):",
        "year": "Vuosi",
-       "date": "Alkaen päivämäärästä (tai sitä aikaisemmasta):",
+       "date": "Alkaen päivämäärästä (ja sitä aiemmat):",
        "sp-contributions-newbies": "Näytä uusien tulokkaiden muutokset",
        "sp-contributions-newbies-sub": "Uusien käyttäjien muokkaukset",
        "sp-contributions-newbies-title": "Uusien käyttäjien muokkaukset",
        "confirm-unwatch-top": "Poistetaanko tämä sivu tarkkailulistaltasi?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Palauta tämän sivun muokkaukset?",
+       "confirm-mcrundo-title": "Kumoa muutos",
+       "mcrundofailed": "Kumoaminen epäonnistui",
+       "mcrundo-missingparam": "Tarvittavat parametrit puuttuvat pyynnöstä.",
+       "mcrundo-changed": "Sivu on muuttunut siitä lähtien, kun katsoit tätä muokkausta. Arvioi uusi muokkaus.",
        "percent": "$1&#160;%",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← edellinen sivu",
        "mw-widgets-titleinput-description-new-page": "sivua ei ole olemassa vielä",
        "mw-widgets-titleinput-description-redirect": "ohjaus kohteeseen $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Lisää luokka...",
-       "mw-widgets-usersmultiselect-placeholder": "Lisää enemmän...",
+       "mw-widgets-usersmultiselect-placeholder": "Lisää useampia...",
        "date-range-from": "Aloituspäivä:",
        "date-range-to": "Päättymispäivä:",
        "sessionmanager-tie": "Monentyyppisiä kirjautumispyyntöjä ei voi yhdistää: $1.",
        "pagedata-bad-title": "Virheellinen otsikko: $1.",
        "unregistered-user-config": "Turvallisuussyistä JavaScript-, CSS- ja JSON-käyttäjäalasivuja ei voi ladata rekisteröimättömiltä käyttäjiltä.",
        "passwordpolicies": "Salasanakäytännöt",
-       "passwordpolicies-summary": "Tämä on luettelo käytössä olevista salasanakäytännöistä tämän wikin käyttäjäryhmille.",
+       "passwordpolicies-summary": "Tämä on luettelo voimassa olevista salasanakäytännöistä tämän wikin käyttäjäryhmille.",
        "passwordpolicies-group": "Ryhmä",
        "passwordpolicies-policies": "Käytännöt",
-       "passwordpolicies-policy-minimalpasswordlength": "Salasanan on oltava ainakin $1 {{PLURAL:$1|merkki|merkkiä}} pitkä",
+       "passwordpolicies-policy-minimalpasswordlength": "Salasanan tulee olla vähintään {{PLURAL:$1|yhden merkin|$1 merkin}} pituinen",
        "passwordpolicies-policy-minimumpasswordlengthtologin": "Salasanassa on oltava vähintään $1 {{PLURAL:$1|merkki|merkkiä}} pystyäksesi kirjautumaan",
-       "passwordpolicies-policy-passwordcannotmatchusername": "Salasana ei voi olla sama kuin käyttäjänimi",
-       "passwordpolicies-policy-passwordcannotmatchblacklist": "Salasana ei voi vastata mustalla listalla olevia salasanoja",
-       "passwordpolicies-policy-maximalpasswordlength": "Salasanan on oltava vähemmän kuin $1 {{PLURAL:$1|merkki|merkkiä}} pitkä",
-       "passwordpolicies-policy-passwordcannotbepopular": "Salasana ei voi olla {{PLURAL:$1|suosittu salasana|$1 suositun salasanan listalla}}"
+       "passwordpolicies-policy-passwordcannotmatchusername": "Salasana ei saa olla sama kuin käyttäjänimi",
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "Salasana ei saa olla mustalla listalla",
+       "passwordpolicies-policy-maximalpasswordlength": "Salasanan tulee olla lyhyempi kuin $1 {{PLURAL:$1|merkki|merkkiä}}",
+       "passwordpolicies-policy-passwordcannotbepopular": "Salasana ei saa olla {{PLURAL:$1|suosittu salasana|$1 suosituimman salasanan listalla}}"
 }
index abfc0e4..0724ba6 100644 (file)
        "customcssprotected": "Vous n’avez pas la permission de modifier cette feuille de style CSS, car elle contient les paramètres personnels d’un autre utilisateur.",
        "customjsonprotected": "Vous n’avez pas le droit de modifier cette page JSON parce qu’elle contient les paramètres personnels d’un autre utilisateur.",
        "customjsprotected": "Vous n’avez pas la permission de modifier cette page de JavaScript, car elle contient les paramètres personnels d’un autre utilisateur.",
-       "sitecssprotected": "Vous n’avez pas le droit de modifier cette page CSS parce que cela peut affecter tous les visiteurs",
-       "sitejsonprotected": "Vous n’avez pas le droit de modifier cette page JSON parce que cela peut affecter tous les visiteurs",
-       "sitejsprotected": "Vous n’avez pas le droit de modifier cette page JavaScript parce que cela peut affecter tous les visiteurs",
+       "sitecssprotected": "Vous n’avez pas le droit de modifier cette page CSS parce que cela peut affecter tous les visiteurs.",
+       "sitejsonprotected": "Vous n’avez pas le droit de modifier cette page JSON parce que cela peut affecter tous les visiteurs.",
+       "sitejsprotected": "Vous n’avez pas le droit de modifier cette page JavaScript parce que cela peut affecter tous les visiteurs.",
        "mycustomcssprotected": "Vous n’avez pas le droit de modifier cette page CSS.",
        "mycustomjsonprotected": "Vous n’avez pas le droit de modifier cette page JSON.",
        "mycustomjsprotected": "Vous n’avez pas le droit de modifier cette page JavaScript.",
        "group-autoconfirmed": "Utilisateurs autoconfirmés",
        "group-bot": "Robots",
        "group-sysop": "Administrateurs",
-       "group-interface-admin": "Administrateurs d'interfaces",
+       "group-interface-admin": "Administrateurs d'interface",
        "group-bureaucrat": "Bureaucrates",
        "group-suppress": "Limitateurs",
        "group-all": "(tous)",
        "confirm-unwatch-top": "Supprimer cette page de votre liste de suivi ?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Révoquer les modifications de cette page ?",
+       "confirm-mcrundo-title": "Annuler une modification",
+       "mcrundofailed": "L’annulation a échoué",
+       "mcrundo-missingparam": "Paramètres obligatoires absents dans la requête.",
+       "mcrundo-changed": "La page a été modifiée depuis que vous avez affiché le diff. Veuillez revoir la nouvelle modification.",
        "semicolon-separator": "&nbsp;;&#32;",
        "colon-separator": "&nbsp;:&#32;",
        "percent": "$1&#160;%",
index 79e62fe..c7025f7 100644 (file)
        "feb": "feb",
        "mar": "mrt",
        "apr": "apr",
-       "may": "maa",
+       "may": "mai",
        "jun": "jun",
        "jul": "jul",
        "aug": "aug",
        "otherlanguages": "In oare talen",
        "redirectedfrom": "(Trochwiisd fan \"$1\")",
        "redirectpagesub": "Trochferwiis-side",
-       "lastmodifiedat": "Lêste kear bewurke op $2, $1.",
+       "lastmodifiedat": "Dizze side is it lêst bewurke op $1 om $2.",
        "viewcount": "Disse side is {{PLURAL:$1|ienris|$1 kear}} iepenslein.",
        "protectedpage": "Skoattele side",
        "jumpto": "Gean nei:",
        "laggedslavemode": "<strong>Warskôging:</strong> Mûglik binne resinte bewurkings noch net trochfierd.",
        "readonly": "Databank is 'Net-skriuwe'.",
        "enterlockreason": "Skriuw wêrom de databank 'net-skriuwe' makke is, en hoenear't men wêr nei alle gedachten wer skriuwe kin.",
-       "readonlytext": "De {{SITENAME}} databank is ôfsletten foar nije siden en oare wizigings,\nnei alle gedachten is it foar ûnderhâld, en kinne jo der letter gewoan wer brûk fan meitsje.\nDe behearder hat dizze útlis jûn:\n<p>$1</p>",
+       "readonlytext": "De databank is op it stuit skoattele foar nije ynbring en oare wizigings, faaks foar gewoan databankûnderhâld, wêrnei't dat wer normaal wurkje sil.\n\nDe systeembehearder dy't it skoattele joech dizze taljochting: $1",
        "missing-article": "Yn de database is gjin ynhâld oantroffen foar de side \"$1\" dy't der wol wêze moatte soe ($2).\n\nDat kin foarkomme as Jo in ferâldere ferwizing nei it ferskil tusken twa ferzjes fan in side folgje of in ferzje opfreegje dy't wiske is.\n\nAs dat net sa is, hawwe Jo faaks in fout yn 'e software fûn.\nMeitsje dêr melding fan by in [[Special:ListUsers/sysop|systeembehearder]] fan {{SITENAME}} en neam dêrby de URL fan dizze side.",
        "missingarticle-rev": "(ferzjenûmer: $1)",
        "missingarticle-diff": "(Feroaring: $1, $2)",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "noname": "Jo moatte in meidognamme opjaan.",
        "loginsuccesstitle": "Oanmelden slagge.",
-       "loginsuccess": "<strong>Jo binne no oanmelden op de {{SITENAME}} as: \"$1.\"</strong>",
+       "loginsuccess": "<strong>Jo binne no oanmeld op {{SITENAME}} as \"$1\".</strong>",
        "nosuchuser": "Der is gjin meidogger \"$1\".\nKontrolearje de stavering, of [[Special:CreateAccount|meitsje in nije meidogger oan]].",
        "nosuchusershort": "Der is gjin meidogger mei de namme \"$1\". It is goed skreaun?",
        "nouserspecified": "Jo moatte in brûkersnamme opjaan.",
        "passwordtooshort": "Wachtwurden moatte op syn minst {{PLURAL:$1|1 teken|$1 tekens}} lang wêze.",
        "password-name-match": "Jo wachtwurd mei net itselde wêze as jo meidoggersnamme.",
        "mailmypassword": "E-mail my in nij wachtwurd.",
-       "passwordremindertitle": "Nij wachtwurd foar de {{SITENAME}}",
+       "passwordremindertitle": "Nij tydlik wachtwurd foar {{SITENAME}}",
        "passwordremindertext": "Immen (nei alle gedachten jo, fan ynternetadres $1) had in nij wachtwurd\nfoar {{SITENAME}} ($4) oanfrege. Der is in tydlik wachtwurd foar meidogger\n\"$2\"  makke en ynstelt as \"$3\". As dat jo bedoeling wie, melde jo jo dan\nno oan en kies in nij wachtwurd. Dyn tydlik wachtwurd komt yn {{PLURAL:$5|ien dei|$5 dagen}} te ferfallen.\nDer is in tydlik wachtwurd oanmakke foar brûker \"$2\": \"$3\".\n\nAs immen oars as jo dit fersyk dien hat of at it wachtwurd jo tuskentiidsk wer yn 't sin kommen is en\njo it net langer feroarje wolle, dan kinne jo dit berjocht ferjitte en\nfierdergean mei it brûken fan jo âlde wachtwurd.",
        "noemail": "Der is gjin e-postadres foar meidogger \"$1\".",
        "passwordsent": "In nij wachtwurd is tastjoerd oan it e-postadres foar \"$1\". Jo kinne jo wer oanmelde as jo it wachtwurd ûntfongen hawwe.",
        "summary-preview": "Gearfetting sa at dy brûkt wurdt:",
        "subject-preview": "Neisjen ûnderwerp/kop:",
        "blockedtitle": "Meidogger is útsletten troch",
-       "blockedtext": "<strong>Jo meidochnamme of ynternet-adres is útsletten.</strong>\n\nDe útsluting is útfierd troch $1.\nAs reden is opjûn <em>$2</em>.\n\n* Begjin útsluting: $8\n* Ein útsluting: $6\n* Bedoeld út te sluten: $7\n\nAs jo wolle, kinne jo kontakt opnimme mei $1 of in oare [[{{MediaWiki:Grouppage-sysop}}|behearder]] en besprekke de útsluting.\nJo kinne de funksje 'Skriuw dizze meidogger' net brûke, of it moast wêze dat jo in jildich e-mailadres opjûn hawwe by jo [[Special:Preferences|ynstellings]] en net útsletten binne dat te brûken.\nJo hjoeddeisk ynternet-adres is $3, en it útslútnûmer is #$5.\nNim alle boppesteande gegevens op yn jo reäksjes.\n\n(Om't in ynternet-adres faak mar foar ien sesje tawiisd wurdt, kin it wêze dat it om in oar giet, dy't deselde tagongkedizer hat as jo hawwe. As it jo net oanbelanget, besykje dan earst of it noch sa is as jo in skoftke gjin ynternet-ferbining hân hawwe. As it in probleem bliuwt, skriuw dan in behearder. Sorry, foar it ûngemak.)",
-       "autoblockedtext": "Jo IP-adres is automatysk útsletten om't brûkt is troch in oare brûker, dy't útsletten is troch $1.\nDe opjûne reden is:\n\n:''$2''\n\n* Begjin útsluting : $8\n* Ein útsluting : $6\n* Bedoeld út te sluten: $7\n\nJo kinne kontakt opnimme mei $1 of in oare [[{{MediaWiki:Grouppage-sysop}}|behearder]] om de útsluting te besprekken.\nJo kinne gjin gebrûk meitsje fan 'e funksje 'Skriuw meidogger', of jo moatte in jildich e-postadres opjûn hawwe yn jo [[Special:Preferences|foarkarren]] en it gebrûk fan dy funksje moat net útsletten wêze.\nJo tsjintwurdich e-postadres is $3 en it útsletnûmer is #$5. Neam beide gegevens as jo earne op dizze útsluting reagearje.",
+       "blockedtext": "<strong>Jo meidochnamme of ynternet-adres is útsletten.</strong>\n\nDe útsluting is útfierd troch $1.\nAs reden is opjûn <em>$2</em>.\n\n* Begjin útsluting: $8\n* Ein útsluting: $6\n* Bedoeld út te sluten: $7\n\nAs jo wolle, kinne jo kontakt opnimme mei $1 of in oare [[{{MediaWiki:Grouppage-sysop}}|behearder]] en besprekke de útsluting.\nJo kinne de funksje \"{{int:emailuser}}\" net brûke, of it moast wêze dat jo in jildich e-mailadres opjûn hawwe by jo [[Special:Preferences|ynstellings]] en net útsletten binne dat te brûken.\nJo hjoeddeisk ynternet-adres is $3, en it útslútnûmer is #$5.\nNim alle boppesteande gegevens op yn jo reäksjes.\n\n(Om't in ynternet-adres faak mar foar ien sesje tawiisd wurdt, kin it wêze dat it om in oar giet, dy't deselde tagongkedizer hat as jo hawwe. As it jo net oanbelanget, besykje dan earst of it noch sa is as jo in skoftke gjin ynternet-ferbining hân hawwe. As it in probleem bliuwt, skriuw dan in behearder. Sorry, foar it ûngemak.)",
+       "autoblockedtext": "Jo ynternet-adres is automatysk útsletten, om't it brûkt is troch in oare meidogger dy't útsletten is troch $1.\nAs reden is opjûn:\n\n:<em>$2</em>\n\n* Begjin útsluting: $8\n* Ein útsluting: $6\n* Bedoeld út te sluten: $7\n\nAs jo wolle, meie jo kontakt opnimme mei $1 of ien fan 'e oare [[{{MediaWiki:Grouppage-sysop}}|behearders]] en besprekke de útsluting.\n\nTink derom dat jo de funksje \"{{int:emailuser}}\" net brûke kinne, of it moast wêze dat jo in jildich e-mailadres fêstlein hawwe yn jo [[Special:Preferences|ynstellings]] en net útsletten binne dat te brûken.\n\nJo hjoeddeisk ynternet-adres is $3, en it útslútnûmer is #$5.\nNim alle boppesteande gegevens op yn jo reäksjes.",
+       "systemblockedtext": "Jo meidochnamme of ynternet-adres is automatysk útsletten troch MediaWiki.\nAs reden is opjûn:\n\n:<em>$2</em>\n\n* Begjin útsluting: $8\n* Ein útsluting: $6\n* Bedoeld út te sluten: $7\n\nJo hjoeddeisk ynternet-adres is $3.\nNim alle boppesteande gegevens op yn jo reäksjes.",
        "blockednoreason": "gjin reden opjûn",
        "whitelistedittext": "Jo moatte $1 om siden te bewurkjen.",
        "confirmedittext": "Jo moatte jo e-mailadres befêstichje foar't jo siden feroarje kinne.\nFier in e-mailadres yn by jo [[Special:Preferences|foarkarren]] en befêstichje it.",
        "searchall": "alle",
        "showingresults": "{{PLURAL:$1|<strong>1</strong> resultaat|<strong>$1</strong> resultaten}} fan #<strong>$2</strong> ôf.",
        "search-showingresults": "{{PLURAL:$4|Resultaat <strong>$1</strong> fan <strong>$3</strong>|Resultaten <strong>$1 - $2</strong> fan <strong>$3</strong>}}",
-       "search-nonefound": "Der binne gjin resultaten foar Jo sykopdracht.",
+       "search-nonefound": "Der binne gjin resultaten foar jo sykopdracht.",
        "powersearch-legend": "Sykje",
-       "powersearch-ns": "Sykje op nammeromten:",
+       "powersearch-ns": "Sykje yn nammeromten:",
        "powersearch-togglelabel": "Oantikje:",
        "powersearch-toggleall": "Alle",
        "powersearch-togglenone": "Gjin",
+       "powersearch-remember": "Seleksje ûnthâlde foar sykopdrachten yn 'e takomst",
        "search-external": "Utwindich sykje",
        "searchdisabled": "<p>Op it stuit stiet it trochsykjen fan tekst út omdat dizze funksje tefolle kompjûterkapasiteit ferget. As we nije apparatuer krije, en dy is ûnderweis, dan wurdt dizze funksje wer aktyf. Oant salang kinne jo sykje fia Google:</p>",
        "preferences": "Foarkarren",
        "timezoneregion-europe": "Jeropa",
        "timezoneregion-indian": "Yndyske Oseaan",
        "timezoneregion-pacific": "Stille Oseaan",
-       "allowemail": "Lit my ek e-mail fan oare meidoggers ûntfange",
+       "allowemail": "Stean oare meidoggers ta my te e-mailen",
        "prefs-searchoptions": "Sykje",
        "prefs-namespaces": "Nammeromten",
        "default": "standert",
        "enhancedrc-history": "skiednis",
        "recentchanges": "Koartlyn feroare",
        "recentchanges-legend": "Opsjes foar resinte feroarings",
-       "recentchanges-summary": "De lêste feroarings fan de {{SITENAME}}.",
+       "recentchanges-summary": "Folgje de lêste feroarings oan 'e wiki op dizze side.",
        "recentchanges-feed-description": "Mei dizze feed kinne jo de nijste feroarings yn dizze wiki besjen.",
        "recentchanges-label-newpage": "Mei dizze wiziging is in nije side makke",
        "recentchanges-label-minor": "Dit is in tekstwiziging",
-       "recentchanges-label-bot": "Dizze wiziging is troch in robot makke",
+       "recentchanges-label-bot": "Dizze bewurking is troch in bot útfierd",
        "recentchanges-label-unpatrolled": "Dizze wiziging is noch net neisjûn",
        "recentchanges-label-plusminus": "De sidegrutte is mei dit oantal bytes wizige",
        "recentchanges-legend-heading": "<strong>Leginda:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (sjoch ek de [[Special:NewPages|list mei nije siden]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(sjoch ek de [[Special:NewPages|list mei nije siden]])",
+       "rcfilters-legend-heading": "<strong>List fan ôfkoartings:</strong>",
        "rcnotefrom": "Dit binne de feroarings sûnt <b>$2</b> (maksimaal <b>$1</b>).",
        "rclistfrom": "Jou nije feroarings, begjinnende mei $3 $2",
        "rcshowhideminor": "$1 tekstwizigings",
        "usereditcount": "$1 {{PLURAL:$1|bewurking|bewurkings}}",
        "newpages": "Nije siden",
        "newpages-username": "Brûkersnamme:",
-       "ancientpages": "Alde siden",
+       "ancientpages": "Aldste siden",
        "move": "Omneame",
        "movethispage": "Dizze side omneame",
        "unusedimagestext": "<p>Tink derom dat oare websiden fan oare parten fan it meartalige projekt mooglik in keppeling nei it URL fan it ôfbyld makke hawwe. Sokke ôfbylden wurde wol brûkt, mar steane dochs op dizze list.",
        "allpagesfrom": "Begjin list by",
        "allpagesto": "Siden besjen oant:",
        "allarticles": "Alle siden",
-       "allinnamespace": "Alle siden (yn de $1-nammeromte)",
+       "allinnamespace": "Alle siden (yn nammeromte $1)",
        "allpagessubmit": "Los!",
        "allpagesprefix": "Siden sjen litte dy't begjinne mei:",
        "allpagesbadtitle": "De opjûne sidenamme is ûnjildich of hat in yntertaal- of ynterwikifoarheaksel.\nMûglik befettet de namme karakters dy't net brûkt wurde meie yn sidenammen.",
        "trackingcategories-name": "Berjochtnamme",
        "mailnologin": "Gjin adres beskikber",
        "mailnologintext": "Jo moatte [[Special:UserLogin|oanmelden]] wêze, en in jildich e-postadres [[Special:Preferences|ynsteld]] hawwe, om oan oare meidoggers e-post stjoere te kinnen.",
-       "emailuser": "E-mail meidogger",
+       "emailuser": "E-mail dizze meidogger",
        "emailuser-title-notarget": "E-mail nei meidogger",
        "emailpagetext": "Fia dit berjocht kinne jo in e-mail oan dizze brûker ferstjoere.\nIt e-mailadres dat jo opjûn hawwe by [[Special:Preferences|jo foarkarren]] wurdt as ôfstjoerder  brûkt.\nDe ûntfanger kin dus daliks nei jo reagearje.",
        "defemailsubject": "E-mail fan {{SITENAME}}-brûker \"$1\"",
        "undelete-show-file-submit": "Ja",
        "namespace": "Nammeromte:",
        "invert": "Seleksje útsein",
-       "blanknamespace": "(Ensyklopedy)",
+       "blanknamespace": "(Haad)",
        "contributions": "{{GENDER:$1|Meidogger}}-bydragen",
        "contributions-title": "Bydragen fan $1",
        "mycontris": "Bydragen",
        "change-blocklink": "blokkade feroarje",
        "contribslink": "bydragen",
        "emaillink": "e-mail stjoere:",
-       "autoblocker": "Jo wiene útsletten om't jo ynternet-adres oerienkomt mei dat fan \"[[User:$1|$1]]\". Foar it útsluten fan dy meidogger waard dizze reden jûn: \"$2\".",
+       "autoblocker": "Automatysk útsletten om't jo ynternet-adres okkerdeis brûkt is troch \"[[User:$1|$1]]\".\nAs reden foar de útsluting fan $1 is opjûn \"$2\"",
        "blocklogpage": "Utslútloch",
        "blocklogentry": "\"[[$1]]\" útsletten foar $2 $3",
        "blocklogtext": "Dit is in loch fan it útsluten en talitten fan meidoggers. Fansels útsletten IP-adressen binne net opnaam. Sjoch de [[Special:BlockList|útslútlist]] foar de no jildende útslutings.",
        "lockbtn": "Meitsje de database 'Net-skriuwe'",
        "unlockbtn": "Meitsje de databank skriuwber",
        "locknoconfirm": "Jo hawwe jo hanneling net befêstige.",
-       "lockdbsuccesssub": "Databank is 'Net-skriuwe'",
-       "unlockdbsuccesssub": "Database is skriuwber",
-       "lockdbsuccesstext": "De {{SITENAME}} databank is 'Net-skriuwe' makke.\n<br />Tink derom en meitsje de databank skriuwber as jo ûnderhâld ree is.",
-       "unlockdbsuccesstext": "De {{SITENAME}} databank is skriuwber makke.",
+       "lockdbsuccesssub": "De databank is skoattele",
+       "unlockdbsuccesssub": "De databank is ûntskoattele",
+       "lockdbsuccesstext": "De databank is skoattele.<br />\nTink derom en [[Special:UnlockDB|ûntskoattelje]] as jo ûnderhâld ree is.",
+       "unlockdbsuccesstext": "De databank is ûntskoattele.",
        "lockedbyandtime": "(troch {{GENDER:$1|$1}} op $2 om $3)",
        "move-page": "\"$1\" omneame",
        "move-page-legend": "Side omneame",
        "tooltip-feed-rss": "RSS-feed foar dizze side",
        "tooltip-feed-atom": "Atom-feed foar dizze side",
        "tooltip-t-contributions": "Bydragen fan dizze brûker",
-       "tooltip-t-emailuser": "Stjoer in e-mail nei dizze brûker",
+       "tooltip-t-emailuser": "Stjoer in e-mail nei {{GENDER:$1|dizze meidogger}}",
        "tooltip-t-upload": "Triemmen oplade",
        "tooltip-t-specialpages": "List fan alle spesjale siden",
        "tooltip-ca-nstab-user": "Brûkersside sjen litte",
index 261420e..716bd42 100644 (file)
@@ -4,7 +4,7 @@
                        "LeGuyanaisPure"
                ]
        },
-       "tog-underline": "Soulignman di lyen :",
+       "tog-underline": "Soulignman dé lyannaj :",
        "tog-hideminor": "Maské modifikasyon minò andan modifikasyon résant",
        "tog-hidepatrolled": "Maské modifikasyon ki rouli andan modifikasyon résant",
        "tog-newpageshidepatrolled": "Maské paj ki rouli andan lis dé nouvèl paj",
@@ -30,7 +30,7 @@
        "tog-enotifrevealaddr": "Afiché mo adrès élèktronik andan kouryé di notifikasyon",
        "tog-shownumberswatching": "Afiché nonm-an di itilizatò an kour",
        "tog-oldsig": "Zòt signatir atchwèl :",
-       "tog-fancysig": "Trété signatir-a kou di wikitèks (san lyen otomatik)",
+       "tog-fancysig": "Trété signatir-a kou di wikitègs (san lyannaj otonmantik)",
        "tog-uselivepreview": "Afiché apèrsou san roucharjé paj-a",
        "tog-forceeditsummary": "Avèrti mo lòské mo pa èspésifyé di rézimen di modifikasyon",
        "tog-watchlisthideown": "Maské mo pròp modifikasyon annan lis di swivi",
        "listingcontinuesabbrev": "(swit)",
        "index-category": "Paj endèksé",
        "noindex-category": "Paj ki pa endèksé",
-       "broken-file-category": "Paj ké dé lyen di fiché brizé",
+       "broken-file-category": "Paj ké lyannaj di fiché brizé",
        "categoryviewer-pagedlinks": "($1) ($2)",
        "category-header-numerals": "$1–$2",
        "about": "Apropo",
        "tagline": "Di {{SITENAME}}",
        "help": "Lèd",
        "search": "Sasé",
-       "search-ignored-headings": " #<!-- pa modifyé sa lign --><pre>\n# Tit dé sèksyon ki ké fika ignoré pa sasé-a.\n# Chanjman-yan ki éfèktchwé isi ka pran léfè lò ki paj-a ké tit-a sa endèksé.\n# Zòt pouvé fòrsé réyendèksasyon di paj-a an éfèktchwan roun modifikasyon vid.\n# Sentaks-a sa swivant-a :\n#   * Tousa ki ka swiv roun « # » jouk finisman-an di lign-an sa roun koumantèr.\n#   * Tout lign ki pa-vid sa tit ègzak-a pou ignoré, kas konprann osi.\nRéférans\nLyen ègstèrn\nWè osi\n #</pre><!-- pa modifyé sa lign -->",
+       "search-ignored-headings": " #<!-- pa modifyé sa lign --><pre>\n# Tit dé sègsyon ki ké fika ignoré pa sasé-a.\n# Chanjman-yan ki éfègtchwé isi ka pran léfè lò ki paj-a ké tit-a sa endègsé.\n# Zòt pouvé fòrsé réyendègsasyon di paj-a an éfègtchwan roun modifikasyon vid.\n# Sentags-a sa swivant-a :\n#   * Tousa ki ka swiv roun « # » jouk finisman-an di lign-an sa roun koumantèr.\n#   * Tout lign ki pa-vid sa tit ègzak-a pou ignoré, kas konprann osi.\nRéférans\nLyannaj ègstèrn\nWè osi\n #</pre><!-- pa modifyé sa lign -->",
        "searchbutton": "Sasé",
        "go": "Konsilté",
        "searcharticle": "Kontinwé",
        "history_small": "listorik",
        "updatedmarker": "modifyé dipi mo dannyé vizit",
        "printableversion": "Vèrsyon enprimab",
-       "permalink": "Lyen pèrmanan",
+       "permalink": "Lyannaj pèrmannan",
        "print": "Enprimé",
        "view": "Lir",
        "view-foreign": "Wè asou $1",
        "viewtalkpage": "Wè paj di diskisyon",
        "otherlanguages": "Annan rounòt langaj",
        "redirectedfrom": "(Roudirijé dipi $1)",
-       "redirectpagesub": "Paj di roudirèksyon",
+       "redirectpagesub": "Paj di roudirègsyon",
        "redirectto": "Roudirijé bò'd :",
        "lastmodifiedat": "Dannyé modifikasyon di sa paj té fè $1 à $2.",
-       "viewcount": "Sa paj {{PLURAL:$1|0=pa té janmè konsilté|1=té konsilté roun sèl fwè|té konsilté $1 fwè}}.",
+       "viewcount": "Sa paj {{PLURAL:$1|0=pa té janmen konsilté|1=té konsilté roun sèl fwè|té konsilté $1 fwè}}.",
        "protectedpage": "Paj protéjé",
        "jumpto": "Alé à",
        "jumptonavigation": "navigasyon",
        "nstab-category": "Katégori",
        "mainpage-nstab": "Paj prensipal",
        "nosuchaction": "Aksyon enkonèt",
-       "nosuchactiontext": "Aksyon-an èspésifyé annan URL-a sa envalid.\nZòt pitèt mal antré URL-a oben swivi roun lyen éroné.\nLi pouvé égalman endiké oun anomali andan logisyèl itilizé pa {{SITENAME}}.",
+       "nosuchactiontext": "Agsyon-an ki èspésifyé annan URL-a sa envalid.\nZòt pitèt mal antré URL-a oben swivi roun lyannaj éronnen.\nLi pouvé égalman endiké oun annonmanli annan logisyèl-a ki itilizé pa {{SITENAME}}.",
        "nosuchspecialpage": "Paj èspésyal inègzistant",
        "nospecialpagetext": "<strong>Zòt doumandé oun paj èspésyal ki pa ka ègzisté.</strong>\n\nOun lis dé paj èspésyal valid ka trouvé so kò asou [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Érò",
        "readonly": "Baz di data vérouyé",
        "enterlockreason": "Endiké rézon-an di vérouyaj ensi ki roun èstimasyon di so douré",
        "readonlytext": "Ajou ké mizajou di baz di data sa atchwèlman bloké, probabman pou pèrmèt mentnans di baz-a, aprè sa, tout bagaj ké rantré annan lòrd.\n\nAdministratò sistenm-an ki vérouyé baz di data fourni èsplikasyon-an ki ka swiv :<br /> $1",
-       "missing-article": "Baz-a di data pa trouvé tèks-a di roun paj ki li té divèt trouvé, ki entitilé « $1 » $2.\n\nJénéralman, sala ka sirvini an swivan roun lyen bò'd roun diff périmé oben bò'd listorik di roun paj souprimé.\n\nSi a pa sa ki la, zòt pitèt trouvé roun annonmali annan progranm-an.\nSouplé, signalé li à roun [[Special:ListUsers/sysop|administratò]] é pa bliyé di endiké li URL-a di paj-a.",
+       "missing-article": "Baz-a di data pa trouvé tègs-a di roun paj ki li té divèt trouvé, ki entitilé « $1 » $2.\n\nJénéralman, sala ka sirvini an swivan roun lyannaj bò'd roun dif ki périmen oben bò'd listorik-a di roun paj ki souprimen.\n\nSi a pa sa ki la, zòt pitèt trouvé roun annonmanli annan progranm-an.\nSouplé, signalé li à roun [[Special:ListUsers/sysop|administratò]] é pa bliyé di endiké li URL-a di paj-a.",
        "missingarticle-rev": "(niméro di vèrsyon : $1)",
        "missingarticle-diff": "(diff : $1, $2)",
        "readonly_lag": "Baz-a di data té otonmatikman vérouyé pannan ki sèrvò-ya ségondèr ka réyaligné yé kò asou sèrvò prensipal-a",
        "badtitletext": "Tit di paj doumandé pa valid, vid, oben mal fòrmé si a roun tit entèr-lanng oben entèr-projè.\nI ka kontni pitèt oun oben plizyò karaktèr ki pa pouvé fika itilizé annan tit-ya.",
        "title-invalid-empty": "Tit di paj doumandé sa vid oben ka kontni sèlman non-an di roun lèspas di non.",
        "title-invalid-utf8": "Tit di paj doumandé ka kontni roun sékans UTF-8 envalid.",
-       "title-invalid-interwiki": "Paj sib ka kontni roun lyen interwiki ki nou pa pouvé itilizé annan tit-ya.",
+       "title-invalid-interwiki": "Paj siblé-a ka kontni roun lyannaj entèrwiki ki pa pouvé fika itilizé annan tit-ya.",
        "title-invalid-talk-namespace": "Tit di paj doumandé ka fè référans à roun paj di diskisyon ki pa pouvé ègzisté.",
        "title-invalid-characters": "Tit di paj doumandé ka kontni dé karaktèr ki pa valid : « $1 ».",
        "title-invalid-relative": "Tit ka kontni oun chimen roulatif. Tit-ya ki ka référansé dé paj roulativ (./, ../) pa valid pas li sa souvan itilizé pa navigatò di itilizatò-a.",
        "perfcached": "Data-ya ki ka swiv sa an kach é pa pouvé fika mizajou. Oun magsimonm di {{PLURAL:$1|1=roun rézilta|$1 rézilta}} sa disponib annan kach-a.",
        "perfcachedts": "Data-ya ki ka swiv sa an kach é té mizajou pou dannyè fwè-a $1-a. Oun magsimonm di {{PLURAL:$4|1=roun rézilta sa disponib|$4 rézilta sa disponib}} annan kach-a.",
        "querypage-no-updates": "Mizajou-ya pou sa paj sa atchwèlman dézagtivé.\nData-ya ki anba pa ké fika mizajou.",
-       "viewsource": "Wè tèks sours",
+       "viewsource": "Wè tègs sours-a",
        "viewsource-title": "Wè sours-a di $1",
        "actionthrottled": "Aksyon limité",
        "actionthrottledtext": "Pou briga kont abi-ya, itilizasyon-an di sa aksyon sa limité à roun sèrten nonm di fwè annan roun laps di tan asé kourt é zòt dépasé sa limit.\nSouplé, éséyé òkò annan tchèk minout.",
        "protectedpagetext": "Sa paj té protéjé pou anpéché so modifikasyon oben dé ròt aksyon.",
        "viewsourcetext": "Zòt pouvé wè é kopyé kontni-a di sa paj.",
        "viewyourtext": "Zòt pouvé wè ké kopyé kontni-a di <strong>zòt modifikasyon</strong> à sa paj.",
-       "protectedinterface": "Sa paj ka fourni tèks d'entèrfas pou lojisyèl-a asou sa wiki é sa protéjé pou évité abi-ya.\nPou ajouté oben modifyé dé anmòrfwézaj asou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di réjyonalizasyon di MediaWiki.",
-       "editinginterface": "<strong>Panga :</strong> zòt ka modifiyé oun paj itilizé pou kréyé tèks-a di lojisyèl.\nChanjman-yan asou sa paj ké répèrkité asou aparans di entèrfas itilizatò pou ròt itilizatò-ya di sa wiki.",
+       "protectedinterface": "Sa paj ka fourni tègs di lentèrfas pou lojisyèl-a asou sa wiki é sa protéjé pou évité abi-ya.\nPou ajouté oben modifyé dé anmòrfwézaj asou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di réjyonnalizasyon di MediaWiki.",
+       "editinginterface": "<strong>Panga :</strong> zòt ka modifiyé oun paj ki itilizé pou kréyé tègs-a di lentèrfas-a di lojisyèl.\nChanjman-yan asou sa paj ké répèrkité yé kò asou laparans-a di lentèrfas itilizatò-a pou ròt itilizatò-ya di sa wiki.",
        "translateinterface": "Pou ajouté oben modifyé dé anmòrfwézaj pou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di lokalizasyon lengwistik di MediaWiki.",
        "cascadeprotected": "Sa paj protéjé kont modifikasyon-yan pas li sa transkliz pa {{PLURAL:$1|paj-a ki ka swiv, ki té protéjé|paj-ya ki ka swiv, ki té protéjé}} ké lòpsyon « protèksyon an kaskad » aktivé :\n$2",
        "namespaceprotected": "Zòt pa gen pèrmisyon-an di modifyé paj-ya di lèspas di non « <strong>$1</strong> ».",
        "userlogin-yourname": "Non di itilizatò",
        "userlogin-yourname-ph": "Antré zòt non di itilizatò",
        "createacct-another-username-ph": "Antré non-an di itilizatò",
-       "yourpassword": "Mo di pas :",
-       "userlogin-yourpassword": "Mo di pas",
+       "yourpassword": "Modipas :",
+       "userlogin-yourpassword": "Modipas",
        "userlogin-yourpassword-ph": "Antré zòt mo di pas",
        "createacct-yourpassword-ph": "Antré oun mo di pas",
-       "yourpasswordagain": "Konfirmé mo di pas :",
-       "createacct-yourpasswordagain": "Konfirmé mo di pas",
+       "yourpasswordagain": "Konfirmen modipas-a :",
+       "createacct-yourpasswordagain": "Konfirmen modipas-a",
        "createacct-yourpasswordagain-ph": "Antré òkò menm mo di pas",
        "userlogin-remembermypassword": "Gardé mo sésyon aktiv",
        "userlogin-signwithsecure": "Itilizé roun konnègsyon sékirizé",
        "loginerror": "Lérò di konnègsyon",
        "createacct-error": "Érò lò kréyasyon-an di kont",
        "createaccounterror": "Enposib di kréyé kont-a : $1",
-       "nocookiesnew": "Kont itilizatò fin kréyé, mé zòt pa konnègté.\n{{SITENAME}} ka itilizé dé témwen (''cookies'') pou konsèrvé konnègsyon-an mé zòt dézagtivé yé.\nSouplé, agtivé yé é rikonnègté zòt kò ké menm non é menm modipas.",
+       "nocookiesnew": "Kont itilizatò-a kréyé, mé zòt pa konnègté.\n{{SITENAME}} ka itilizé dé témwen (''cookies'') pou konsèrvé konnègsyon-an mé zòt dézagtivé yé.\nSouplé, agtivé yé é rikonnègté zòt kò ké menm non é menm modipas.",
        "nocookieslogin": "{{SITENAME}} itilizé dé témwen (''cookies'') pou konsèrvé konnègsyon-an mé zòt dézagtivé yé.\nSouplé, agtivé yé é rikonnègté zòt kò.",
        "nocookiesfornew": "Kont itilizatò pa té kréyé, pas nou pa té pouvé idantifyé so lorijin.\nVérifyé ki zòt aktivé témwen-yan (''cookies''), roucharjé paj-a é éséyé òkò.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
-       "createacct-loginerror": "Kont-a byen fin kréyé mé zòt pa pouvé konnègté zòt kò otonmatikman.\nSouplé, [[Special:UserLogin|konnègté zòt kò manniyèlman]].",
+       "createacct-loginerror": "Kont-a byen  kréyé mé zòt pa pouvé konnègté zòt kò otonmatikman.\nSouplé, [[Special:UserLogin|konnègté zòt kò manniyèlman]].",
        "noname": "Zòt pa sézi roun non d'itilizatò valid.",
        "loginsuccesstitle": "Konnègté",
        "loginsuccess": "<strong>Zòt sa atchwèlman konnègté à {{SITENAME}} antan ki « $1 ».</strong>",
        "passwordtoopopular": "Mo di pas ki tròp kouran pa pouvé fika itilizé. Souplé, chwézi roun mo di pas pli difisil à douviné.",
        "password-name-match": "Zòt mo di pas divèt fika diféran di zòt non d'itilizatò.",
        "password-login-forbidden": "Itilizasyon-an di sa non d'itilizatò oben di sa mo di pas té entèrdit.",
-       "mailmypassword": "Réyinisyalizé mo di pas",
+       "mailmypassword": "Réyinisyalizé modipas-a",
        "passwordremindertitle": "Nouvèl mo di pas tanporèr pou {{SITENAME}}",
-       "passwordremindertext": "Tchèk moun (dipi adrès IP-a $1) doumandé roun modipas nòv pou {{SITENAME}} ($4). Oun modipas tanporèr pou itilizatò-a\n« $2 » fin kréyé é sa « $3 ». Si sala té zòt entansyon,\nzòt divèt konnègté zòt kò é chwézi roun modipas nòv.\nZòt modipas tanporèr ké èspiré annan $5 jou{{PLURAL:}}.\n\nSi zòt pa lotò di sa doumann, oben si zòt ka souvni zòt kò atchwèlman di zòt modipas é zòt pli ka swété an chanjé, zòt pouvé ignoré sa mésaj é kontinwé di itilizé zòt ansyen modipas.",
+       "passwordremindertext": "Tchèk moun (dipi adrès IP-a $1) doumandé roun modipas nòv pou {{SITENAME}} ($4). Oun modipas tanporèr pou itilizatò-a\n« $2 »  kréyé é sa « $3 ». Si sala té zòt entansyon,\nzòt divèt konnègté zòt kò é chwézi roun modipas nòv.\nZòt modipas tanporèr ké èspiré annan $5 jou{{PLURAL:}}.\n\nSi zòt pa lotò di sa doumann, oben si zòt ka souvni zòt kò atchwèlman di zòt modipas é zòt pli ka swété an chanjé, zòt pouvé ignoré sa mésaj é kontinwé di itilizé zòt ansyen modipas.",
        "noemail": "Pyès adrès di kouryé té anréjistré pou itilizat{{GENDER:$1|ò|ris}}-a « $1 ».",
        "noemailcreate": "Zòt divèt fourni roun adrès di kouryé valid",
        "passwordsent": "Roun nouvèl mo di pas té voyé kot adrès-a di kouryé di itilizat{{GENDER:$1|ò|ris}} « $1 ».\nSouplé, roukonèkté zòt kò aprè ki zòt rousouvri li.",
        "resetpass_announce": "Pou tèrminé zòt enskripsyon, zòt divèt fourni roun mo di pas nòv.",
        "resetpass_text": "<!-- Ajouté tègs-a isi -->",
        "resetpass_header": "Chanjé mo di pas di kont",
-       "oldpassword": "Ansyen mo di pas :",
-       "newpassword": "Mo di pas nòv :",
+       "oldpassword": "Ansyen modipas :",
+       "newpassword": "Nouvèl modipas :",
        "retypenew": "Konfirmé mo di pas nòv :",
        "resetpass_submit": "Chanjé modipas-a é konnègté so kò.",
-       "changepassword-success": "Zòt mo di pas té modifyé !",
+       "changepassword-success": "Zòt modipas modifyé !",
        "changepassword-throttled": "Zòt fè tròp di tantativ di konnègsyon résaman. \nSouplé, antann $1 anvan di réyéséyé.",
        "botpasswords": "Mo di pas di robo",
        "botpasswords-summary": "<em>Modipas-ya di robo</em> ka pèrmèt di agsédé à roun kont itilizatò vya API-a san itilizé idantifyan-yan di konnègsyon prensipal. Drwè itilizatò disponib lò to konnègté ké roun modipas robo pouvé fika rédjwi.\n\nSi zòt pa ka wè poukisa zòt ké lé fè sa, a ki zòt pa benzwen di fè sa. Pésonn divèt janmen doumandé zòt di an jénéré roun é di bay li.",
        "resettokens-watchlist-token": "Jéton pou flux (Atom/RSS) web di [[Special:Watchlist|modifikasyon di paj di zòt lis di swivi]]",
        "resettokens-done": "Jéton réyinisyalizé.",
        "resettokens-resetbutton": "Réyinisyalizé jéton-yan ki sékèksyoné",
-       "bold_sample": "Tèks gra",
-       "bold_tip": "Tèks gra",
-       "italic_sample": "Tèks italik",
-       "italic_tip": "Tèks italik",
-       "link_sample": "Tit di lyen",
-       "link_tip": "Lyen entèrn",
-       "extlink_sample": "http://www.example.com/ tit di lyen",
-       "extlink_tip": "Lyen èkstèrn (pa bliyé préfiks http://)",
-       "headline_sample": "Tèks di tit",
+       "bold_sample": "Tègs gra",
+       "bold_tip": "Tègs gra",
+       "italic_sample": "Tègs italik",
+       "italic_tip": "Tègs italik",
+       "link_sample": "Tit di lyannaj",
+       "link_tip": "Lyannaj entèrn",
+       "extlink_sample": "http://www.example.com/ tit di lyannaj",
+       "extlink_tip": "Lyannaj ègstèrn (pa bliyé préfigs-a http://)",
+       "headline_sample": "Tègs di tit",
        "headline_tip": "Soutit nivo 2",
-       "nowiki_sample": "Antré tèks ki pa formaté isi",
+       "nowiki_sample": "Antré tègs-a ki pa fòrmanté isi",
        "nowiki_tip": "Ignoré sentaks wiki-a",
        "image_tip": "Fiché enséré",
-       "media_tip": "Lyen bò'd roun fiché médja",
+       "media_tip": "Lyannaj bò'd roun fiché médja",
        "sig_tip": "Zòt signatir ké dat",
        "hr_tip": "Lign orizontal (pa an abizé)",
        "summary": "Rézimen :",
        "anoneditwarning": "<strong>Panga :</strong> zòt pa konnègté. Zòt adrès IP ké vizib pa tout moun si zòt ka fè dé modifikasyon. Si zòt <strong>[$1 ka konnègté zòt kò]</strong> oben <strong>[$2 kréyé roun kont]</strong>, zòt modifikasyon ké fika atribiyé à zòt pròp non di itilizatò é zòt ké gen ròt avantaj.",
        "blockedtext": "<strong>Zòt kont itilizatò oben zòt adrès IP bloké.</strong>\n\nBlokaj té éfèktchwé pa $1.\nRézon-an ki évoké ka swiv : <em>$2</em>.\n\n* Koumansman di blokaj : $8\n* Èspirasyon di blokaj : $6\n* Kont bloké : $7.\n\nZòt pouvé kontakté $1 oben rounòt [[{{MediaWiki:Grouppage-sysop}}|administratò]] pou an diskité.\nZòt pa pouvé itilizé fonksyon-an « {{int:emailuser}} » rounso si oun adrès di kouryé valid sa èspésifyé andan zòt [[Special:Preferences|préférans]] é rounso si sa fonksyonalité pa bloké.\nZòt adrès IP atchwèl sa $3 é zòt idantifyan di blokaj sa $5.\nSouplé, enkli tout détay-ya lasou'l annan chakin dé rékèt ki zòt ké fè.",
        "loginreqlink": "konnègté so kò",
-       "newarticletext": "Zòt té ka swiv roun lyen bò'd roun paj ki pa ka ègzisté òkò. \nAfen di kréyé sa paj, antré zòt tèks annan bwèt ki aprè (zòt pouvé konsilté [$1 paj di lèd-a] pou plis d'enfòrmasyon).\nSi zòt vini{{GENDER:|}} isi pa éròr, kliké asou bouton <strong>Routour</strong> di zòt navigatò.",
+       "newarticletext": "Zòt té ka swiv roun lyannaj bò'd roun paj ki pa ka ègzisté òkò. \nAfen di kréyé sa paj, antré zòt tègs annan bwèt-a ki apré (zòt pouvé konsilté [$1 paj di lèd-a] pou plis di lenfòrmasyon).\nSi zòt vini{{GENDER:|}} isi pa lérò, kliké asou bouton-an <strong>Routour</strong> di zòt navigatò.",
        "anontalkpagetext": "----\n<em>Zòt asou paj di diskisyon di roun itilizatò annonnim ki pa òkò kréyé di kont oben ki pa ka an itilizé</em>.\nPou sa rézon, nou divèt itilizé so adrès IP pou idantifyé li.\nOun adrès IP pouvé fika patajé pa plizyò itilizatò.\nSi zòt roun itiliza{{GENDER:|ò}} annonnim é si zòt ka kontasté ki dé koumantèr ki pa ka konsèrné zòt sa adrèsé pou zòt, zòt pouvé [[Special:CreateAccount|kréyé roun kont]] oben [[Special:UserLogin|konnègté zòt kò]] atò di évité tout konfizyon fitir ké ròt kontribitò annonnim.",
-       "noarticletext": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan opérasyon ki lyannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
-       "noarticletext-nopermission": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] andan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal asosyé]</span>, mè zòt pa gen pèrmisyon di kréyé sa paj.",
+       "noarticletext": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan lopérasyon-yan ki lyannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
+       "noarticletext-nopermission": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] annan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal-ya ki asosyé]</span>, mé zòt pa gen pèrmisyon-an di kréyé sa paj.",
        "userpage-userdoesnotexist-view": "Kont itilizatò-a « $1 » pa anréjistré.",
        "clearyourcache": "<strong>Nòt :</strong> aprè zòt anréjistré zòt modifikasyon, zòt divèt fòrsé richarjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentni touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> oben <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentni touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé data d'èsplorasyon-yan → Zimaj ké fiché an kach</em>.",
        "previewnote": "<strong>Raplé-zòt ki a jis roun prévizwalizasyon.</strong>\nZòt modifikasyon pa òkò anréjistré !",
        "searchprofile-advanced-tooltip": "Sasé annan lèspas di non pèrsonalizé",
        "search-result-size": "$1 ({{PLURAL:$2|1 mo|$2}})",
        "search-result-category-size": "$1 manm{{PLURAL:$1|}} ($2 soukatégori{{PLURAL:$2|}}, $3 fiché{{PLURAL:$3|}})",
-       "search-redirect": "(Roudirèksyon dipi $1)",
+       "search-redirect": "(Roudirègsyon dipi $1)",
        "search-section": "(sèksyon $1)",
        "search-file-match": "(ka korèsponn o kontni di fiché)",
        "search-suggest": "Éséyé ké sa òrtograf : $1",
        "recentchanges-feed-description": "Swivé dannyé modifikasyon-yan di wiki andan sa flux.",
        "recentchanges-label-newpage": "Sa modifikasyon té kréyé roun nouvèl paj",
        "recentchanges-label-minor": "Sa modifikasyon sa minò.",
-       "recentchanges-label-bot": "Sa modifikasyon té éfèktchwé pa roun robo.",
+       "recentchanges-label-bot": "Sa modifikasyon té fika éfègtchwé pa roun robo.",
        "recentchanges-label-unpatrolled": "Sa modifikasyon pa té òkò réli.",
        "recentchanges-label-plusminus": "Tay di paj-a chanjé di sa nonm d'oktè.",
        "recentchanges-legend-heading": "<strong>Léjann :</strong>",
        "recentchangeslinked-title": "Swivi dé paj asosyé à « $1 »",
        "recentchangeslinked-summary": "Antré roun non di paj pou wè modifikasyon-yan ki fè résaman asou dé paj ki lyannen dipi oben bò'd sa paj (pou wè manm-yan di oun katégori, antré {{ns:category}}:Non di katégori). Modifikasyon-yan dé paj di [[Special:Watchlist|zòt lis di swivi]] sa <strong>an gra</strong>.",
        "recentchangeslinked-page": "Non di paj :",
-       "recentchangeslinked-to": "Afiché modifikasyon-yan dé paj ki ka konpòrté roun lyen bò'd paj-a ki bay plito ki lenvèrs-a",
+       "recentchangeslinked-to": "Afiché modifikasyon-yan dé paj ki ka konpòrté roun lyannaj bò'd paj-a ki bay plito ki lenvèrs-a",
        "upload": "Enpòrté roun fiché",
        "uploadlogpage": "Journal di enpo di fiché",
        "filedesc": "Dèskripsyon",
        "linkstoimage": "{{PLURAL:$1|Paj swivant ka itilizé}} sa fiché :",
        "linkstoimage-more": "Plis {{PLURAL:$1|di roun paj ka itilizé|di $1 paj ka itilizé}} sa fiché.\nLis swivant ka afiché sèlman {{PLURAL:$1|pronmyé paj-a ki ka itilizé|$1 pronmyé paj-ya ki ka itilizé}} sa fiché.\nOun [[Special:WhatLinksHere/$2|lis konplèt]] sa disponib.",
        "nolinkstoimage": "Pyès paj pa ka itilizé sa fiché.",
-       "linkstoimage-redirect": "$1 (roudirèksyon di fiché) $2",
+       "linkstoimage-redirect": "$1 (roudirègsyon di fiché) $2",
        "sharedupload-desc-here": "Sa fiché ka provini di $1. Li pouvé fika itilizé pa ròt projè.\nSo dèskripsyon asou so [$2 paj di dèskripsyon] sa afiché anba.",
        "filepage-nofile": "Pyès fiché di sa non ka ègzisté.",
        "upload-disallowed-here": "Zòt pa pouvé ranplasé sa fiché.",
        "randompage": "Paj an azò",
        "statistics": "Èstatistik",
-       "double-redirect-fixer": "Korèktò di roudirèksyon",
+       "double-redirect-fixer": "Korègtò di roudirègsyon",
        "nbytes": "$1 {{PLURAL:$1|òktè}}",
        "nmembers": "$1 manm{{PLURAL:$1|}}",
        "prefixindex": "Tout paj ki ka koumansé pa...",
        "allpages": "Tout paj-ya",
        "allarticles": "Tout paj-ya",
        "allpagessubmit": "Listé",
-       "allpages-hide-redirects": "Maské roudirèksyon-yan",
+       "allpages-hide-redirects": "Maské roudirègsyon-yan",
        "categories": "Lis dé katégori",
        "listgrouprights-members": "(lis dé manm)",
        "emailuser": "Voyé li roun kouryé",
        "whatlinkshere": "Paj ki lyannen",
        "whatlinkshere-title": "Paj ki ka pwenté bò'd « $1 »",
        "whatlinkshere-page": "Paj :",
-       "linkshere": "Paj-ya ki anba ka kontni roun lyen bò'd <strong>$2</strong> :",
-       "nolinkshere": "Pyès paj ka kontni dé lyen bò'd <strong>$2</strong>.",
-       "isredirect": "paj di roudirèksyon",
+       "linkshere": "Paj-ya ki anba ka kontni roun lyannaj bò'd <strong>$2</strong> :",
+       "nolinkshere": "Pyès paj ka kontni lyannaj bò'd <strong>$2</strong>.",
+       "isredirect": "paj di roudirègsyon",
        "istemplate": "enklizyon",
-       "isimage": "Lyen bò'd fiché-a",
+       "isimage": "lyannaj bò'd fiché-a",
        "whatlinkshere-prev": "{{PLURAL:$1|présédant|$1 présédant}}",
        "whatlinkshere-next": "{{PLURAL:$1|swivant|$1 swivant}}",
-       "whatlinkshere-links": "lyen",
-       "whatlinkshere-hideredirs": "$1 roudirèksyon-yan",
+       "whatlinkshere-links": "← lyannaj",
+       "whatlinkshere-hideredirs": "$1 roudirègsyon-yan",
        "whatlinkshere-hidetrans": "$1 enklizyon-yan",
-       "whatlinkshere-hidelinks": "$1 lyen-yan",
-       "whatlinkshere-hideimages": "$1 lyen-yan bò'd fiché-a",
+       "whatlinkshere-hidelinks": "$1 lyannaj-ya",
+       "whatlinkshere-hideimages": "$1 lyannaj-ya bò'd fiché-a",
        "whatlinkshere-filters": "Filt",
        "ipboptions": "2 lò:2 hours,1 jou:1 day,3 jou:3 days,1 simenn:1 week,2 simenn:2 weeks,1 mwa:1 month,3 mwa:3 months,6 mwa:6 months,1 lan:1 year,endéfiniman:infinite",
        "infiniteblock": "enfini",
        "block-log-flags-nocreate": "kréyasyon di kont entèrdit",
        "proxyblocker": "Blokò di mandatèr",
        "movelogpage": "Journal dé rounonmaj",
-       "export": "Èkspòrté dé paj",
+       "export": "Ègspòrté dé paj",
        "thumbnail-more": "Agrandir",
        "importlogpage": "Journal dé enpòrtasyon",
        "tooltip-pt-userpage": "Zòt paj di {{GENDER:|itilizatò|itilizatris}}",
        "tooltip-ca-unwatch": "Routiré sa paj di zòt lis di swivi",
        "tooltip-search": "Sasé annan {{SITENAME}}",
        "tooltip-search-go": "Aksédé à roun paj di menm non si li ka ègzisté",
-       "tooltip-search-fulltext": "Sasé paj-ya ka konpòrté sa tèks.",
+       "tooltip-search-fulltext": "Sasé paj-ya ka konpòrté sa tègs.",
        "tooltip-p-logo": "Vizité paj prensipal-a",
        "tooltip-n-mainpage": "Vizité paj prensipal-a di sit",
        "tooltip-n-mainpage-description": "Paj prensipal jénéral",
        "tooltip-minoredit": "Marké sala kou modifikasyon minò",
        "tooltip-save": "Anréjistré zòt modifikasyon",
        "tooltip-preview": "Mési di prévizwalizé zòt modifikasyon anvan di pibliyé yé.",
-       "tooltip-diff": "Afiché modifikasyon-yan ki zòt apòrté andan tèks-a.",
+       "tooltip-diff": "Afiché modifikasyon-yan ki zòt apòrté annan tègs-a",
        "tooltip-compareselectedversions": "Afiché diférans-ya ant dé vèrsyon-yan sélèksyoné di sa paj",
        "tooltip-watch": "Ajouté sa paj annan zòt lis di swivi",
        "tooltip-rollback": "« Révoké » ka annilé an roun klik modifikasyon(-an oben -yan) di sa paj ki réyalizé pa so dannyé kontribitò",
        "pageinfo-robot-noindex": "Pa otorizé",
        "pageinfo-watchers": "Nonm di kontribitò ki gen paj andan yé lis di swivi",
        "pageinfo-few-watchers": "Mwens di $1 {{PLURAL:$1|obsèrvatò}}",
-       "pageinfo-redirects-name": "Nonm di roudirèksyon bò'd sa paj",
+       "pageinfo-redirects-name": "Nonm di roudirègsyon bò'd sa paj",
        "pageinfo-subpages-name": "Nonm di soupaj di sa paj",
-       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|roudirèksyon}}; $3 {{PLURAL:$3|pa-roudirèksyon}})",
+       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|roudirègsyon}}; $3 {{PLURAL:$3|pa-roudirègsyon}})",
        "pageinfo-firstuser": "Kréyatò di paj-a",
        "pageinfo-firsttime": "Dat di kréyasyon di paj-a",
        "pageinfo-lastuser": "Dannyé kontribitò",
        "logentry-delete-revision": "$1 {{GENDER:$2|modifyé}} vizibilité {{PLURAL:$5|di oun révizyon|di $5 révizyon}} asou paj $3 : $4",
        "revdelete-content-hid": "kontni maské",
        "logentry-move-move": "$1 déplasé paj-a $3 bò'd $4",
-       "logentry-move-move-noredirect": "$1 {{GENDER:$2|déplasé}} paj-a $3 bò'd $4 san lésé di roudirèksyon",
-       "logentry-move-move_redir": "$1 {{GENDER:$2|déplasé}} paj-a $3 bò'd $4 asou roun roudirèksyon",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|déplasé}} paj-a $3 bò'd $4 san lésé di roudirègsyon",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|déplasé}} paj-a $3 bò'd $4 asou roun roudirègsyon",
        "logentry-patrol-patrol-auto": "$1 {{GENDER:$2|té otomatikman marké}} révizyon $4 di paj $3 kou rouli",
        "logentry-newusers-create": "Kont di itilizat{{GENDER:$4|ò|ris}} $1 té kréyé",
-       "logentry-newusers-autocreate": "Kont $1 {{GENDER:$2|té kréyé}} otomatikman",
-       "logentry-upload-upload": "$1 {{GENDER:$2|té télévèrsé}} $3",
+       "logentry-newusers-autocreate": "Kont $1 {{GENDER:$2|té kréyé}} otonmantikman",
+       "logentry-upload-upload": "$1 {{GENDER:$2|télévèrsé}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|télévèrsé}} oun nouvèl vèrsyon di $3",
        "searchsuggest-search": "Sasé annan {{SITENAME}}",
        "duration-days": "$1 jou{{PLURAL:$1|}}",
index 89892eb..ceec1fe 100644 (file)
@@ -39,8 +39,8 @@
        "tog-oldsig": "Pali lo ulu'umu masatiya",
        "tog-fancysig": "Popopasiya pali lo'ulu'u odelo tuladuwiki (diyalu tuwawu wumbuta otomatis)",
        "tog-uselivepreview": "Popobilohe pratayang wawu ja detohe ulangi halaman",
-       "tog-forceeditsummary": "Popo'eelawa wa'u wonu dosi momoli'o diipo otuwa",
-       "tog-watchlisthideown": "Wantoa u biloli'u'u to daputari lo he'awasiyalo",
+       "tog-forceeditsummary": "Popo'ēlawa wa'u wonu dosi momoli'o dīpo otuwa",
+       "tog-watchlisthideown": "Wanto'a u biloli'u'u to daputari lo he'awasiyalo",
        "tog-watchlisthidebots": "Wanto'a u biloli'o bot to daputari lo he'awasiyalo",
        "tog-watchlisthideminor": "Wanto'a u loboli'a ngo'idi to daputari lo he'awasiyalo",
        "tog-watchlisthideliu": "Wanto'a u biloli'o ta ohu'uwo tilumuwoto log to daputari he awasiyalo",
@@ -48,9 +48,9 @@
        "tog-watchlisthideanons": "Wanto'a u bilo;i'o ta ohu'uwo anonim monto daputari he awasiyalo",
        "tog-watchlisthidepatrolled": "Wanto'a u biloli'o patroli monto daputari he'awasiyalo",
        "tog-watchlisthidecategorization": "Wanto'a dalala lo halaman",
-       "tog-ccmeonemails": "Lawoli wa'u wami lo surel u yilawou to tawu",
+       "tog-ccmeonemails": "Lawoli wa'u wami lo surel u yilawo'u to tawu",
        "tog-diffonly": "Ja popobilohe tuwango halaman u hihihede",
-       "tog-showhiddencats": "Popobilehe dalala u hewanto'a",
+       "tog-showhiddencats": "Popobilohe dalala u hewanto'a",
        "tog-norollbackdiff": "Japopobilohe hihedeliyo to'u yilapato pilopohuwalingo",
        "tog-useeditwarning": "Popo'eelawa wa'u wonu molola halaman heboli'olo wonu dipo tilahu",
        "tog-prefershttps": "Layito momake koneksi amani wonu tumuwoto log",
        "article": "Tuwango halaman",
        "newwindow": "hu'owa to tutulowa bohu",
        "cancel": "Batali",
-       "moredotdotdot": "Uweewo",
-       "morenotlisted": "Daputari boti kira-kira diipo ganapu",
+       "moredotdotdot": "Uwēwo",
+       "morenotlisted": "Daputari botiya kira-kira dīpo ganapu",
        "mypage": "Halaman",
        "mytalk": "Lo'iya",
        "anontalk": "Lo'iya",
        "namespaces": "Huwali lo tanggulo",
        "variants": "Varian",
        "navigation-heading": "Menu navigasi",
-       "errorpagetitle": "Lotaalawa",
+       "errorpagetitle": "Tilala",
        "returnto": "Mohuwalingo ode $1",
        "tagline": "Lonto {{SITENAME}}",
        "help": "Wubodu",
        "searchbutton": "Lolohe",
        "go": "Ntali",
        "searcharticle": "Ntali",
-       "history": "Riwayati lo halaman",
-       "history_short": "Riwayati",
-       "history_small": "riwayati",
+       "history": "Riwāyati lo halaman",
+       "history_short": "Riwāyati",
+       "history_small": "riwāyati",
        "updatedmarker": "biloli'o to'u bililohe pulitiyo",
        "printableversion": "Persi cetak",
-       "permalink": "Wumbuta kakali",
-       "print": "Cetaki",
+       "permalink": "Wūmbuta kakali",
+       "print": "Cetakiya",
        "view": "Bilohi",
        "view-foreign": "Bilohi to $1",
        "edit": "Boli'o",
        "personaltools": "Pilaakasi lo hihilawo",
        "talk": "Lo'iya",
        "views": "Bibilohu",
-       "toolbox": "Pilaakasi",
-       "tool-link-userrights": "Boli'a lembo'a {{GENDER:$1|ta ohu'uwo}}",
-       "tool-link-userrights-readonly": "Bilohi lembo'a {{GENDER:$1|ta ohu'uwo}}",
+       "toolbox": "Pilākasi",
+       "tool-link-userrights": "Boli'a lēmbo'a {{GENDER:$1|ta ohu'uwo}}",
+       "tool-link-userrights-readonly": "Bilohi lēmbo'a {{GENDER:$1|ta ohu'uwo}}",
        "tool-link-emailuser": "Lawoli surel ode {{GENDER:$1|ta ohu'uwo}}",
        "imagepage": "Bilohi halaman berkas",
        "mediawikipage": "Bilohi halaman tahuli",
        "viewhelppage": "Bilohi halaman wubodu",
        "categorypage": "Bilohi dalala lo halaman",
        "viewtalkpage": "Bilohi u lo'iya",
-       "otherlanguages": "To bahasa uweewo",
+       "otherlanguages": "To bahasa uwēwo",
        "redirectedfrom": "Pilobale lonto $1",
        "redirectpagesub": "Halaman pilobaleya",
        "redirectto": "Mobale ode",
        "pool-servererror": "Ta hemorekeni pool botiye diya'a: $1",
        "poolcounter-usage-error": "Tilala lopohuna:$1",
        "aboutsite": "Tomimbihu {{SITENAME}}",
-       "aboutpage": "Proyek:Tomimbihu",
+       "aboutpage": "Project:Tomimbihu",
        "copyright": "Tuwanga botiya sadi-sadia odelo to tibawa $1",
        "copyrightpage": "{{ns:project}}:Haku lohutu",
-       "currentevents": "U yilowali baharu",
-       "currentevents-url": "Project:U yilowali baharu",
-       "disclaimers": "Momaahu",
-       "disclaimerpage": "Project:Momaahu umum",
+       "currentevents": "U yilowali bahāru",
+       "currentevents-url": "Project:U yilowali bahāru",
+       "disclaimers": "Momāhu",
+       "disclaimerpage": "Project:Momāhu umum",
        "edithelp": "Wubodu momoli'o",
        "helppage-top-gethelp": "Wubodu",
        "mainpage": "Halaman Bungaliyo",
        "mainpage-description": "Halaman bungaliyo",
        "policy-url": "Project:Tinepo",
-       "portal": "Buubu'a leembo'a",
-       "portal-url": "Project:Buubu'a lembo'a",
+       "portal": "Būbu'a lēmbo'a",
+       "portal-url": "Project:Būbu'a lēmbo'a",
        "privacy": "Tinepo privasi",
        "privacypage": "Project:Tinepo privasi",
        "badaccess": "Tilala haku momu'o",
        "thisisdeleted": "Bilohi meyalo pohuwalinga $1",
        "viewdeleted": "Bilohi $1",
        "restorelink": "{{PLURAL:$1|tuwawu biloli'o ma yiluluto}}",
-       "feedlinks": "Paalo",
-       "feed-invalid": "Hihile tayadu paalo dila banari.",
-       "feed-unavailable": "Paalo sindikasi diyaluwo",
-       "site-rss-feed": "Paalo $1 RSS",
-       "site-atom-feed": "Paalo $1 Atom",
-       "page-rss-feed": "Paalo $1 RSS",
-       "page-atom-feed": "Paalo $1 Atom",
-       "red-link-title": "$1 (halaman dipoluwo)",
+       "feedlinks": "Pālo",
+       "feed-invalid": "Hihile tayadu pālo ja banari.",
+       "feed-unavailable": "Pālo sindikasi diyāluwo",
+       "site-rss-feed": "Pālo $1 RSS",
+       "site-atom-feed": "Pālo $1 Atom",
+       "page-rss-feed": "Pālo $1 RSS",
+       "page-atom-feed": "Pālo $1 Atom",
+       "red-link-title": "$1 (halaman dipōluwo)",
        "sort-descending": "Boluti ode tibawa",
-       "sort-ascending": "Boluti ode yitaato",
+       "sort-ascending": "Boluti ode yitāto",
        "nstab-main": "Halaman",
        "nstab-user": "Halaman lo ta ohu'uwo",
        "nstab-media": "Halaman media",
        "nosuchactiontext": "Huhutu u hepohile lo URL ja valid.\nYi'o lotalawa lopotuwoto lo URL, meyalo lodudu'a wumbuta u ja banari.\nUtiye olo kira-kira tuwotiyo woluwo bug to pilaakasi u hepomake {{SITENAME}}",
        "nosuchspecialpage": "Diya'a halaman istimewa boyito",
        "nospecialpagetext": "<strong>Yi'o hemohile halaman istimewa u ja sah.</strong>\n\nDaputari halaman istimewa mowali bilehela to [[Special:SpecialPages|{{int:specialpages}}]]",
-       "error": "Tilala aba",
+       "error": "Tilala",
        "databaseerror": "Tilala tuwango data",
        "databaseerror-text": "Ma tilala tuwawu basis kueri.\nUtiya kira-kira tuwotiyo woluwo bug to pilaakasi moluluhi'o.",
        "databaseerror-textcl": "Tilala tuwawu basis kueri.",
        "databaseerror-query": "Kueri $1",
        "databaseerror-function": "Huna: $1",
-       "databaseerror-error": "Tilala aba: $1",
+       "databaseerror-error": "Tilala: $1",
        "transaction-duration-limit-exceeded": "Untuk mencegah penundaan replikasi yang tinggi, pengiriman ini dibatalkan karena durasi tulis ($1) melebihi batas $2 {{PLURAL:$2|detik|detik}}.\nJika Anda ingin mengganti banyak butir sekaligus, cobalah melakukan dalam operasi yang lebih kecil.",
        "laggedslavemode": "<strong>Warning:</strong> Halaman kira ja o tuwango u lobohuwa.",
        "readonly": "Basis data unti-unti",
        "directoryreadonlyerror": "Direktori \"$1\" bo pobaca.",
        "directorynotreadableerror": "Direktori \"$1\" jamowali pobaca.",
        "filenotfound": "Jamotapu tuwango \"$1\"",
-       "unexpected": "Nilai ja o'aata: \"$1\"=\"$2\".",
+       "unexpected": "Nilai ja o'āta: \"$1\"=\"$2\".",
        "formerror": "Tilala: Ja mowali molawo formulir",
        "badarticleerror": "Huhutu boti ja mowali pohutuwola to halaman boti.",
        "cannotdelete": "Halaman meyalo berkas \"$1\" jamowali lulutolo.\nKira-kira ma yiluluto tawu weewo.",
        "cannotdelete-title": "Ja mowali moluluta halaman \"$1\"",
        "delete-hook-aborted": "Moluluto bilatali lo kokayito.\nDiyaalu kataraangani.",
        "no-null-revision": "Ja mowali mohutu revisi noolo bohu lo halaman \"$1\"",
-       "badtitle": "Judul moleeto",
+       "badtitle": "Judul molēto",
        "badtitletext": "Judul halaman pilohile ja sah, ja otuwa, meyalo judul wolota lo bahasa meyalo wolota lo wiki u tilala lo humbuto.\nUtiye kira otuwa tuwawu meyalo limbata watade u ja mowali pomake to judul.",
        "title-invalid-empty": "Judul halaman pilohile ja otuwa meyalo bo otuwa tuwawu huwali lo tanggulo.",
        "title-invalid-utf8": "Judul halaman pilohile otuwa ayita UTF-8 u ja sah.",
        "ns-specialprotected": "Halaman spesial ja mowali ubaalo.",
        "titleprotected": "Judul botiya daha-daya monto ta mohutu oleh [[User:$1|$1]].\nAlasani u yilohiliyo de'uwito <em>$2</em>.",
        "invalidtitle-knownnamespace": "Judul u ja sah wolo huwali tanggulo \"$2\" wawu teks \"$3\"",
-       "exception-nologin": "Diipo tilumuwoto log",
+       "exception-nologin": "Dīpo tilumuwoto log",
        "exception-nologin-text": "Toduwolo tumuwoto log alihu mowali mokalaja to halaman botiye meyalo huhutu botiye.",
        "exception-nologin-text-manual": "Toduwoolo $1 tumuwoto alihu mowali mohutu halaman meyalo uweewo.",
        "virus-badscanner": "Tilala konfigurasi: pemindai virus ja iloonuhe: ''$1''",
        "virus-unknownscanner": "antivirus ja'otaawa",
        "cannotlogoutnow-title": "Ja mowali lumuwalo masatiya",
        "cannotlogoutnow-text": "Lumuwalo log ja mowali to'u mopohuna $1.",
-       "welcomeuser": "Toduwoolo, $1!",
+       "welcomeuser": "Toduwōlo, $1!",
        "welcomecreation-msg": "Akun olemu ma pilohutu. Ja lipata mongaturu konfigurasi [[Special:Preferences|preferensi {{SITENAME}}]] olemu.",
-       "yourname": "Ta ohu'uwo tanggulo",
-       "userlogin-yourname": "Ta ohu'uwo tanggulo",
-       "userlogin-yourname-ph": "Tuwota ta ohu'uwo lo tanggulo",
-       "createacct-another-username-ph": "Tuwota ta ohu'uwo lo tanggulo",
+       "yourname": "Tanggulo ta ohu'uwo",
+       "userlogin-yourname": "Tanggulo ta ohu'uwo",
+       "userlogin-yourname-ph": "Tuwota tanggulo ta ohu'uwo",
+       "createacct-another-username-ph": "Tuwota tanggulo ta ohu'uwo",
        "yourpassword": "Tahe u'unti",
        "userlogin-yourpassword": "Tahe u'unti",
        "userlogin-yourpassword-ph": "Tuwota tahe u'unti",
        "createacct-yourpassword-ph": "Tuwota tahe u'unti",
        "yourpasswordagain": "Ulangiya tahe u'unti",
        "createacct-yourpasswordagain": "Konfirmasi tahe u'unti",
-       "createacct-yourpasswordagain-ph": "Tuwota pooli tahe u'unti",
+       "createacct-yourpasswordagain-ph": "Tuwota pōli tahe u'unti",
        "userlogin-remembermypassword": "Hulima'o wa'u tuwo-tuwoto",
-       "userlogin-signwithsecure": "Popohunawa server aamani",
+       "userlogin-signwithsecure": "Popohunawa server āmani",
        "cannotloginnow-title": "Ja mowali tumuwoto log sa'ati botiya",
        "cannotloginnow-text": "Tumuwoto log ja mowali to'umopohuna $1.",
        "yourdomainname": "Domain Ulemu:",
        "nav-login-createaccount": "Tumuwoto log / mohutu akun",
        "logout": "Lumuwalo log",
        "userlogout": "Lumuwalo log",
-       "notloggedin": "Diipo tilumuwoto log",
-       "userlogin-noaccount": "Diipo o akun",
+       "notloggedin": "Dīpo tilumuwoto log",
+       "userlogin-noaccount": "Dīpo o akun",
        "userlogin-joinproject": "Motiwayito {{SITENAME}}",
        "createaccount": "Mohutu akun",
        "userlogin-resetpassword-link": "Ilolipata tahe u'unti?",
        "userlogin-helplink2": "Wubodu tumuwoto log",
        "userlogin-loggedin": "Yi'o ma tilumuwoto odelo {{GENDER:$1|$1}}\nPopohunawa formulir formulir to tibawa botiye odelo pengguna uweewo.",
        "userlogin-reauth": "Yi'o musti tumuwota pooli u mopopatato yi'o odelo {{GENDER:$1|$1}}",
-       "userlogin-createanother": "Mohutu akun uweewo",
-       "createacct-emailrequired": "Alaamati surel",
+       "userlogin-createanother": "Mohutu akun uwēwo",
+       "createacct-emailrequired": "Alamat tuladu email",
        "createacct-emailoptional": "Alamat tuladu email (paralu tuwangalo)",
        "createacct-email-ph": "Tuwanga alamat tuladu email",
        "createacct-another-email-ph": "Tuwanga alamat tuladu email",
        "badretype": "Tahe u'unti pilopotuwoto tilala.",
        "usernameinprogress": "Mohutu akun wolo tanggula botiye donggo na'o-na'o. Wulatipo ngope'e.",
        "userexists": "Ta ohu'uwo lo tanggulo pilopotuwoto ma pilomake lo tawu. Toduwolo molulawota tanggula uweewo.",
-       "loginerror": "Lotaalawa tilumuwato log",
-       "createacct-error": "Lotaalawa lohutu akun",
+       "loginerror": "Tilala tumuwato log",
+       "createacct-error": "Tilala lohutu akun",
        "createaccounterror": "Diya mowali mohutu akun: $1",
        "nocookiesnew": "Akun pengguna ma pilohutu, dabo Yi'o diipo tilumuwoto. {{SITENAME}} popohunawa kuki log pengguna.\nToduwolo mopo'aktif wawu tumuwota pooli wolo tanggulu ta ohu'uwo wawu tahe u'unti.",
        "noname": "Tanggulo ta ohu'uwo u pilopotuwotumu ja sah.",
        "blocked-mailpassword": "Alamat IP olemu ma diblokir monto u momoli'o. Modaha u mopotalawa, Yi'o diipo mowali mopobohu lo tahe u'unti moli alamat IP botiye.",
        "eauthentsent": "Tuladu elektronik u pokonfirmasi ma yilawo ode alamat lo tuladu. To'udiipo tuladu elektronik uweewo lawololo ode akun botiye, Yi'o musti modudu'a potunu to delomo tuladu boyito, u mokonformasi tutu liyo tutu alamat boyito banari ulemu.",
        "throttled-mailpassword": "Tahe u'unti bohu ma yilawo to delomo {{PLURAL:$1|$1 jam}}botiye.\nModaha ta mopotalawa, bo tuwawu tahe u'unti u lawololo timi'idu {{PLURAL:$1|jam|$1 jam}}.",
-       "mailerror": "Tilala lo lawo tuladu elektronik:$1",
+       "mailerror": "Tilala lolawo tuladu elektronik:$1",
        "emailauthenticated": "Alamat tuladu elektronikmu ma dikonfirmasi to $3, $2.",
        "emailnotauthenticated": "Alamat tuldu elektronikmu diipo dikonformasi.\nWonu diipo dikonfirmasi, Yi'o dila ta mololimo tulade elektronik monto fitur botiya.",
        "noemailprefs": "Yi'o musti mopomasu alamat surel to preferensimu alihu mowali mopohuna lo fitur-fitur botiye.",
        "botpasswords-label-update": "Mopobohu",
        "botpasswords-label-cancel": "Bataliya",
        "botpasswords-label-delete": "Luluta",
-       "passwordreset": "Ubawa tahe u'unti",
+       "passwordreset": "Boli'a tahe u'unti",
        "bold_sample": "Teks botiye ma cetakiyolo mohulodu",
        "bold_tip": "Teks mohulodu",
        "italic_sample": "Teks botiye ma cetakiyolo yinti-yintili",
        "yourdiff": "Hihede",
        "templatesused": "{{PLURAL:$1|Template}} pilopohuna to halaman botiye:",
        "templatesusedpreview": "{{PLURAL:$1|Template|Templates}} pilomake to'u mopobilohu.",
-       "template-protected": "(he dahalo)",
+       "template-protected": "(hedahalo)",
        "template-semiprotected": "(dahalo-ngowa)",
        "hiddencategories": "Halaman botiye woluwo anggota {{PLURAL:$1|1 kategori wanto-wanto'o $1}}:",
        "permissionserrors": "Tilala haku momu'o",
        "permissionserrorstext-withaction": "Yi'o ja haku akses $2, sababu {{PLURAL:$1|alasani}} botiya:",
        "recreate-moveddeleted-warn": "<Strong>Mopo'ota: Yi'o lohutu ulangi hlaman u ma yiluluto.</strong>\n\nPopotimbangiyapo huhutumu botiye delo mowali poturusiyolo.\nBotiya log piloluluta wawu piloheyiya halaman botiye.",
        "moveddeleted-notice": "Halaman botiye ma yiluluto.\nLog piloluluta, pilodahawa wawu piloheyiya halaman botiye woluwo to tibawa pohutu referensi.",
-       "postedit-confirmation-saved": "Biloli'umu ma tilahu.",
-       "edit-already-exists": "Ja mowali mohutu halaman bohu. Ma woluwo.",
+       "postedit-confirmation-saved": "Biloli'umu mā tilahu.",
+       "edit-already-exists": "Ja mowali mohutu halaman bohu. Mā woluwo.",
        "content-model-wikitext": "tuladu wiki",
        "undo-failure": "U biloli'a botiya ja mowali pohuwalingo sababu lodulehe ta lomoli'o.",
        "viewpagelogs": "Bilohi log lo halaman botiye",
        "nextrevision": "Biloli'o lapatiyoma'o →",
        "currentrevisionlink": "Biloli'o pulitiyo",
        "cur": "mst",
-       "last": "diipo",
+       "last": "dīpo",
        "histlegend": "Tulawota diff: Tuwoti kasi lo radio loboli'a u mopobandingiyo wawu woduta enter meyalo tombol to tibawa.<br />\nLegenda: <strong>({{int:cur}})</strong> = hihede wolo biloli'a pulitiyo, <strong>({{int:last}})</strong> = hihede wolo u biloli'a muloolo, <strong>{{int:minoreditletter}}</strong> = bilili'o ngo'idi.",
        "history-fieldset-title": "Lolohe u biloli'o",
        "histfirst": "mohihewo da'a",
        "mergelog": "Log mopohimbunguwo",
        "history-title": "Riwayati lo'u loboli'a lonto \"$1\"",
        "difference-title": "$1 hihede revisi",
-       "lineno": "Baarisi $1:",
+       "lineno": "Bārisi $1:",
        "compareselectedversions": "Popotadenga u tilulawoto",
        "editundo": "pohuwalinga",
        "diff-empty": "(Diya'a hihedeliyo)",
        "diff-multi-sameuser": "({{PLURAL:$1|$1 revisi wolota}} pilohutu lo tawu ngota ja pilopobilohu)",
        "diff-multi-otherusers": "({{PLURAL:$1|Tuwawu lopo'opiyohu wolota|$1 lopo'opiyohu wolota}} pilohutu {{PLURAL:$2|ngota ta ohu'uwo uweewo|$2 ta ohu'uwo}} ja pilopobilohu)",
        "searchresults": "U yilotapu",
-       "searchresults-title": "U yilotapu lololohe \"$1\"",
-       "prevn": "{{PLURAL:$1|$1}} to'udiipo",
+       "searchresults-title": "U yilotapu yilolohu \"$1\"",
+       "prevn": "{{PLURAL:$1|$1}} to'udīpo",
        "nextn": "{{PLURAL:$1|$1}} lapatiyoma'o",
-       "prevn-title": "To'u diipo $1 {{PLURAL:$1|hasili}}",
+       "prevn-title": "To'u dīpo $1 {{PLURAL:$1|hasili}}",
        "nextn-title": "$1 {{PLURAL:$1|hasili}}lapatiyoma'o",
-       "shown-title": "Popobilohe $1 {{PLURAL:$1|haasili}} per halaman",
+       "shown-title": "Popobilohe $1 {{PLURAL:$1|hāsili}} per halaman",
        "viewprevnext": "Bilohi ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "<strong>Woluwo halaman otanggula \"[[:$1]]\" to wiki botiye.</strong> {{PLURAL:$2|0=|Bilohi olo u yilotapu uweewo.}}",
        "searchmenu-new": "<strong>Mohutu halaman \"[[:$1]]\" to wiki botiya!</strong> {{PLURAL:$2|0=Bilohi halaman u yilotapu yilolohumu.|Bilohi hasili u yilotapu to'u yilolohu}}",
        "imgfile": "berkas",
        "listfiles": "Daputari berkas",
        "file-anchor-link": "Berkas",
-       "filehist": "Riwaayati lo berkas",
+       "filehist": "Riwāyati lo berkas",
        "filehist-help": "Klik to tanggal/wakutu momilohe berkas to saa'ati botiye.",
        "filehist-revert": "bataliya",
        "filehist-current": "baharu",
index c379bd3..fc7756e 100644 (file)
        "confirm-unwatch-top": "להסיר את הדף הזה מרשימת המעקב שלך?",
        "confirm-rollback-button": "אישור",
        "confirm-rollback-top": "לשחזר את העריכות בדף זה?",
+       "confirm-mcrundo-title": "ביטול שינוי",
+       "mcrundofailed": "הביטול נכשל",
+       "mcrundo-missingparam": "חסרים פרמטרים נדרשים בבקשה.",
+       "mcrundo-changed": "הדף שונה מאז הצפייה האחרונה שלך בהבדלים בין הגרסאות. נא לבדוק את השינוי החדש.",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "→ לדף הקודם",
        "imgmultipagenext": "לדף הבא ←",
index 4c31ab0..5bdbad1 100644 (file)
        "cascadeprotected": "Ova je stranica zaključana za uređivanja jer je uključena u {{PLURAL:$1|sljedeću stranicu|sljedeće stranice}}, koje su zaštićene \"prenosivom zaštitom\":\n$2",
        "namespaceprotected": "Ne možete uređivati stranice u imenskom prostoru '''$1'''.",
        "customcssprotected": "Ne možete uređivati ovu CSS stranicu zato što ona sadrži osobne postavke drugog suradnika.",
+       "customjsonprotected": "Ne možete uređivati ovu JSON stranicu zato što ona sadrži osobne postavke drugog suradnika.",
        "customjsprotected": "Ne možete uređivati ovu JavaScript stranicu zato što ona sadrži osobne postavke drugog suradnika.",
        "mycustomcssprotected": "Nemate ovlasti za uređivanje ove CSS stranice.",
+       "mycustomjsonprotected": "Nemate ovlasti za uređivanje ove JSON stranice.",
        "mycustomjsprotected": "Nemate ovlasti za uređivanje ove JavaScript stranice.",
        "myprivateinfoprotected": "Nemate ovlasti za uređivanje Vaših osobnih informacija.",
        "mypreferencesprotected": "Nemate ovlasti za uređivanje Vaših postavki.",
index f979761..b5b1137 100644 (file)
@@ -15,7 +15,8 @@
                        "Mikławš",
                        "Macofe",
                        "Matma Rex",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Vlad5250"
                ]
        },
        "tog-underline": "Wotkazy podšmórnić:",
        "cascadeprotected": "Tuta strona je za wobdźěłowanje zawrjena, dokelž je w {{PLURAL:$1|slědowacej stronje|slědowacymaj stronomaj|slědowacych stronach}} zapřijata, {{PLURAL:$1|kotraž je|kotrejž stej|kotrež su}} přez kaskadowu opciju {{PLURAL:$1|škitana|škitanej|škitane}}:\n$2",
        "namespaceprotected": "Nimaš dowolnosć, zo by stronu w mjenowym rumje '''$1''' wobdźěłał.",
        "customcssprotected": "Nimaš prawo, zo by tutu CSS-stronu wobdźěłał, dokelž wosobinske nastajenja druheho wužiwarja wobsahuje.",
+       "customjsonprotected": "Nimaš prawo, zo by tutu JSON-stronu wobdźěłał, dokelž wosobinske nastajenja druheho wužiwarja wobsahuje.",
        "customjsprotected": "Nimaš prawo, zo by tutu JavaScript-stronu wobdźěłał, dokelž wosobinske nastajenja druheho wužiwarja wobsahuje.",
        "mycustomcssprotected": "Nimaš prawo tutu CSS-stronu wobdźěłać.",
+       "mycustomjsonprotected": "Nimaš prawo tutu JSON-stronu wobdźěłać.",
        "mycustomjsprotected": "Nimaš prawo tutu JavaScript-stronu wobdźěłać.",
        "myprivateinfoprotected": "Nimaš prawo swoje priwatne informacije wobdźěłać.",
        "mypreferencesprotected": "Nimaš prawo swoje nastajenja wobdźěłać.",
index d252c7d..3e79a2e 100644 (file)
        "confirm-unwatch-top": "El szeretnéd távolítani a lapot a figyelőlistádról?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Visszavonod a változtatásokat?",
+       "confirm-mcrundo-title": "Egy változtatás visszavonva",
+       "mcrundofailed": "A visszavonás nem sikerült",
        "ellipsis": "…",
        "quotation-marks": "„$1”",
        "imgmultipageprev": "← előző oldal",
index 7602df5..d6c6350 100644 (file)
        "recentchanges-label-minor": "Սա չնչին խմբագրում է",
        "recentchanges-label-bot": "Այս խմբագրումը կատարվել է բոտի կողմից",
        "recentchanges-label-unpatrolled": "Այս խմբագրումը դեռ չի պարեկվել",
-       "recentchanges-label-plusminus": "Էջի չափսը փոփոխվեց այսքան բայթով",
+       "recentchanges-label-plusminus": "Էջի չափսը փոփոխվել է այսքան բայթով",
        "recentchanges-legend-heading": "<strong>Լեգենդ՝</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (տես նաև՝  [[Special:NewPages|նոր էջերի ցանկ]])",
        "recentchanges-submit": "Ցույց տալ",
        "rcfilters-view-tags": "Պիտակված խմբագրումներ",
        "rcfilters-liveupdates-button": "Կենդանի թարմացումներ",
        "rcnotefrom": "Ստորև բերված են փոփոխությունները սկսած՝ '''$2''' (մինչև՝ '''$1''')։",
-       "rclistfrom": "Ցույց տալ նոր փոփոխությունները սկսած $3 $2",
+       "rclistfrom": "Ցույց տալ նոր փոփոխությունները՝ սկսած $3 $2",
        "rcshowhideminor": "$1 չնչին խմբագրումները",
        "rcshowhideminor-show": "Ցուցադրել",
        "rcshowhideminor-hide": "Թաքցնել",
        "ipbother": "Այլ ժամկետ.",
        "ipboptions": "2 ժամ:2 hours,1 օր:1 day,3 օր:3 days,1 շաբաթ:1 week,2 շաբաթ:2 weeks,1 ամիս:1 month,3 ամիս:3 months,6 ամիս:6 months,1 տարի:1 year,անժամկետ:infinite",
        "ipbhidename": "Թաքցնել մասնակցի անունը արգելափակման տեղեկամատյանից, գործող արգելափակումների ցանկից և մասնակիցների ցանկից։",
-       "ipbwatchuser": "Ավելացնել հսկացանկում մասնակցի էջն ու քննարկման էջն",
+       "ipbwatchuser": "Հսկացանկում ավելացնել մասնակցի էջն ու քննարկման էջը",
        "ipb-disableusertalk": "Արգելել մասնակցին խմբագրել իր քննարկման էջն արգելափակման ընթացքում",
        "badipaddress": "Սխալ IP-հասցե",
        "blockipsuccesssub": "Արգելափակումը կատարված է",
index a5c4009..066ca61 100644 (file)
@@ -10,6 +10,7 @@
        },
        "underline-always": "Միշտ",
        "underline-never": "Երբեք",
+       "editfont-serif": "Սերիֆ տառատեսակ",
        "sunday": "Կիրակի",
        "monday": "Երկուշաբթի",
        "tuesday": "Երեքշաբթի",
        "october-date": "$1 Հոկտեմբեր",
        "november-date": "$1 Նոյեմբեր",
        "december-date": "$1 Դեկտեմբեր",
+       "period-am": "Նախ Կէսօր",
+       "period-pm": "Կէսօրէն Յետոյ",
        "pagecategories": "{{PLURAL:$1|Ստորոգութիւն|Ստորոգութիւններ}}",
        "category_header": "«$1» ստորոգութեան մէջ էջեր",
        "subcategories": "Ենթաստորոգութիւններ",
        "category-media-header": "\"$1\" ստորոգութեան հաղորդամիջոց",
        "category-empty": "<em>Այս ստորոգութիւնը ներկայիս դատարկ է։<em>",
        "hidden-categories": "{{PLURAL:$1|Թաքուն ստորոգութիւն|Թաքուն ստորոգութիւններ}}",
+       "hidden-category-category": "Թաքցուած ստորոգութիւններ",
        "category-subcat-count": "{{PLURAL:$2|Այս ստորոգութիւնը ունի միայն հետեւեալ ենթաստորոգութիւնը։|Այս ստորոգութիւնը ունի հետեւեալ {{PLURAL:$1|ենթաստորոգութիւն|ենթաստորոգութիւններ}}ը՝ ընդհանուր $2էն։}}",
+       "category-subcat-count-limited": "Այս ստորոգութիւնը ունի հետեւեալ {{PLURAL:$1|ենթաստորոգութիւն|$1 ենթաստորոգութիւններ}}։",
        "category-article-count": "{{PLURAL:$2|Այս ստորոգութիւնը կը պարունակէ միայն հետեւեալ էջը։|Ստորեւ այս ստորոգութեան ընդհանուր $2էն {{PLURAL:$1|էջը|$1 էջերը}}։}}",
+       "category-article-count-limited": "Այս ստորոգութիւնի մէջ կը գտնուին հետեւեալ {{PLURAL:$1|էջը|$1 էջերը}}։",
        "category-file-count": "{{PLURAL:$2|Այս ստորոգութիւնը կը պարունակէ միայն հետեւեալ էջը։|Ստորեւ այս ստորոգութեան ընդհանուր $2-էն {{PLURAL:$1|էջը|$1 էջերը}}։}}",
+       "category-file-count-limited": "Այս ստորոգութիւնի մէջ կը գտնուին հետեւեալ  {{PLURAL:$1|նիշքը|$1 նիշքերը}}։",
        "listingcontinuesabbrev": "շար.",
+       "index-category": "Չցուցակագրուած էջեր",
        "noindex-category": "Չցուցակագրուած էջեր",
        "broken-file-category": "Հասցէազուրկ նիշքի յղումներով էջեր",
        "about": "Նախագիծին մասին",
+       "article": "Բովանդակութեան էջեր",
        "newwindow": "(Նոր պատուհանի մէջ կը բացուի)",
        "cancel": "Չեղարկել",
+       "moredotdotdot": "Աւելի...",
+       "morenotlisted": "Այս ցանկը կարելի է անկատար ըլլալ։",
        "mypage": "Էջ",
        "mytalk": "Քննարկում",
        "anontalk": "Քննարկել",
        "navigation": "Նաւարկութիւն",
        "and": "&#32;եւ",
+       "faq": "ՅՀՀ",
+       "actions": "Գործողութիւններ",
        "namespaces": "Անուանատարածքներ",
        "variants": "Տարբերակներ",
        "navigation-heading": "Նաւարկութեան ցուցակ",
+       "errorpagetitle": "Սխալ",
        "returnto": "Վերադարնալ դէպի $1։",
        "tagline": "{{SITENAME}}էն",
        "help": "Օգնութիւն",
        "search": "Որոնել",
        "searchbutton": "Որոնել",
+       "go": "‎Յառաջանալ",
        "searcharticle": "‎Յառաջանալ",
        "history": "Էջի պատմութիւն",
        "history_short": "Պատմութիւն",
        "tool-link-emailuser": "Ղրկել ասիկա էլ-նամակով {{GENDER:$1|գործածողին}}",
        "imagepage": "Դիտել նիշքի էջը",
        "mediawikipage": "Դիտել հաղորդագրութեան էջը",
+       "templatepage": "Դիտել կաղապարի էջը",
        "viewhelppage": "Դիտել օգնութեան էջը",
+       "categorypage": "Տեսնել ստորոգութեան էջը",
        "viewtalkpage": "Դիտել քննարկումը",
        "otherlanguages": "Այլ լեզուներով",
        "redirectedfrom": "(Վերայղուած է $1-էն)",
        "redirectpagesub": "վերայղման էջ",
        "redirectto": "Վերայղել դէպի՝",
        "lastmodifiedat": "Այս էջը վերջին անգամ խմբագրուած է $1 թուականի ժամը $2ին:",
+       "viewcount": "Այս էջը բացուած է {{PLURAL:$1|մէկ անգամ|$1 անգամ}}։",
        "protectedpage": "Պաշտպանուած էջ",
        "jumpto": "Ցատկել դէպի",
        "jumptonavigation": "նաւարկութիւն",
        "portal-url": "Project:Համայնքային դարպաս",
        "privacy": "Սեփական տուեալներու պահպանման քաղաքականութիւն",
        "privacypage": "Project:Սեփական տուեալներու պահպանման քաղաքականութիւն",
+       "badaccess": "Արտօնութեան սխալ",
+       "badaccess-group0": "Արտունութիւն չունիք այս գործողութիւնը կատարել:",
+       "badaccess-groups": "Տուեալ գործողութիւնը միայն $1 {{PLURAL:$2|խումբի|խումբերի}} մասնակիցները կ՛րնան կատարել։",
        "ok": "Լաւ",
        "retrievedfrom": "Վերցուած է «$1» էջէն",
        "youhavenewmessages": "{{PLURAL:$3|Դուք ունիք}} $1 ($2)։",
        "createacct-benefit-body1": "{{PLURAL:$1|խմբագրում}}",
        "createacct-benefit-body2": "$1 {{PLURAL:$1|էջ}}",
        "createacct-benefit-body3": "վերջին {{PLURAL:$1|մասնակից}}",
+       "loginsuccesstitle": "Բարեյաջող մուտք",
+       "loginsuccess": "'''Դուք մուտք գործեցիք {{SITENAME}}, իբր \"$1\"։'''",
+       "nouserspecified": "Հարկաւոր է նշել մասնակցին անունը։",
+       "login-userblocked": "Այս մասնակիցը արգելափակուած է: Մուտքը արգելուած է:",
+       "wrongpassword": "Սխալ մասնակիցի անուն կամ գաղտնաբար։ Հաճեցէք նորէն փորձել։",
+       "wrongpasswordempty": "Գաղտնաբար մը չը նշեցիք։ Հաճեցէք նորէն փորձել։",
+       "passwordtooshort": "Ամէնայ նուազագոյն գաղտնաբարը {{PLURAL:$1|1 նշանագիր |$1 նշանագիր}} նշանագիր կրնա՛յ ըլլալ:",
+       "passwordtoolong": "Ամենամեծ գաղտնաբարը {{PLURAL:$1|1 նշանագիր |$1 նշանագիր}} նշանագիր կրնա՛յ ըլլալ:",
+       "passwordtoopopular": "Դիւրուն գաղտնաբարներ չէք կրնալ գործածել:  Հաճեցէք աւելի ուժեղ գաղտնաբար մը:",
+       "password-name-match": "Ձեր գաղտնաբարը ձեր մասնակցի անունէն տարբեր պէտք է ելլայ։",
+       "password-login-forbidden": "Այս մասնակիցի անունը եւ գաղտաբարի օգտագործումը արգիլուած է:",
+       "mailmypassword": "Վերականգնել գաղտնաբառը",
+       "passwordremindertitle": "Նոր ժամանակաւոր գաղտնաբառ {{grammar:genitive|{{SITENAME}}}} համար",
+       "accountcreated": "Հաշիւը ստեղծուեցաւ:",
        "loginlanguagelabel": "Լեզու՝ $1",
        "pt-login": "Մուտք գործել",
        "pt-login-button": "Մուտք գործել",
+       "pt-login-continue-button": "Շարունակել մուտք գործել։",
        "pt-createaccount": "Հաշիւ ստեղծել",
        "pt-userlogout": "Դուրս գալ",
+       "php-mail-error-unknown": "Անյայտ սխալ PHP-ի mail() կախարկութեան մէջ:",
+       "changepassword": "Գաղտնաբառը փոխել",
+       "newpassword": "Նոր գաղտնաբառը.",
+       "retypenew": "Նորէն մուտքագրէք գաղտնաբառը",
+       "changepassword-success": "Ձեր գաղտնաբառը փոխուեցաւ։",
+       "botpasswords-label-create": "Ստեղծել",
+       "botpasswords-label-cancel": "Չեղարկել",
+       "botpasswords-label-delete": "Ջնջել",
+       "botpasswords-label-resetpassword": "Վերականգնել գաղտնաբառը",
+       "resetpass-submit-cancel": "Չեղարկել",
+       "resetpass-temp-password": "Ժամանակաւոր գաղտնաբառ.",
        "passwordreset": "Վերականգնել անցաբառը",
+       "passwordreset-domain": "Համակարգիչի պետութիւն.",
+       "passwordreset-email": "Էլ-նամակաի հասցէն.",
+       "passwordreset-emailtitle": "{{SITENAME}} հաշիւի մանրամասները",
        "bold_sample": "Շեշտուած տառերով գրութիւն",
        "bold_tip": "Շեշտուած տառերով գրութիւն",
        "italic_sample": "Շեղատառ գրութիւն",
        "sig_tip": "Ձեր ստորագրութիւնը ժամակնիքով",
        "hr_tip": "Հորիզոնական գիծ (գործածել խնայողաբար)",
        "summary": "Ամփոփում՝",
+       "subject": "Նիւթ.",
        "minoredit": "Ասիկա մանր խմբագրում է",
        "watchthis": "Հսկել այս էջը",
        "savearticle": "Էջը պահել",
+       "savechanges": "Պահպանել փոփոխութիւնները",
+       "publishpage": "Ստեղծել էջը",
+       "publishchanges": "Հրատարակել փոփոխութիւնները",
+       "savearticle-start": "Էջը պահել...",
+       "savechanges-start": "Պահպանել փոփոխութիւնները...",
+       "publishpage-start": "Ստեղծել էջը...",
        "preview": "Կանխաստուգել",
        "showpreview": "Կանխաստուգել",
        "showdiff": "Ցուցնել փոփոխութիւնները",
        "anoneditwarning": "<strong>Զգուշացում։</strong> Մուտք գործած չէք համակարգ։ Որեւէ խմբագրումի պարագային ձեր IP հասցէն տեսանելի կը դառնայ բոլորին։ Եթե <strong>[$1 մուտք գործէք]</strong> կամ <strong>[$2 ստեղծէք մասնակցային հաշիւ]</strong>, ձեր կատարած խմբագրումները կը կապուին ձեր մասնակցային անունին հետ, ինչպէս նաեւ կ՚ունենաք այլ առաւելութիւններ։",
-       "blockedtext": "<strong>Ձեր մասնակցային անոիւնը կամ IP հասցէն արգելակուած է։</strong>\n\nԱրգելակումը կատարուած է $1ի կողմէ.\nՊարտճառը՝ <em>$2</em>.\n\n* Արգելակման սկիբժ՝ $8\n* Արգելակման աւարտ՝ $6\n* արգելակուած առարկայ՝ $7\n\nԿրնաք կապուիլ $1ի կամ այլ անդատներու հետ [[{{MediaWiki:Grouppage-sysop}}|վարիչ]] արգելակման մասին զրուցելու համար.\nՉէք կրնար օգտագործել \"{{int:emailuser}}\" հնարաւորութիւնը բացի եթէ նշած էք իմակի վաւերական հասցէ մը ձեր [[Special:Նախասիրութիւններ|մասնակիցի նախասիրութիւններուն մէջ]] եւ արգելակուած չէ վեր անոր օգտագործումը.\nՁեր ընթացիկ IP հասցէն է $3, եւ արգելակման ինքնութեան համարն է #$5.\nԿը շնդրենք որ այս մանրամասնութիւնները նշէք ձեր բոլոր թղթակցութիւններուն մէջ։",
+       "blockedtext": "<strong>Ձեր մասնակցային անոիւնը կամ IP հասցէն արգելակուած է։</strong>\n\nԱրգելակումը կատարուած է $1ի կողմէ.\nՊարտճառը՝ <em>$2</em>.\n\n* Արգելակման սկիբժ՝ $8\n* Արգելակման աւարտ՝ $6\n* արգելակուած առարկայ՝ $7\n\nԿրնաք կապուիլ $1ի կամ այլ անդատներու հետ [[{{MediaWiki:Grouppage-sysop}}|վարիչ]] արգելակման մասին զրուցելու համար.\nՉէք կրնար օգտագործել \"{{int:emailuser}}\" հնարաւորութիւնը բացի եթէ նշած էք իմակի վաւերական հասցէ մը ձեր [[Special:Preferences|account preferences]] եւ արգելակուած չէ վեր անոր օգտագործումը.\nՁեր ընթացիկ IP հասցէն է $3, եւ արգելակման ինքնութեան համարն է #$5.\nԿը շնդրենք որ այս մանրամասնութիւնները նշէք ձեր բոլոր թղթակցութիւններուն մէջ։",
        "loginreqlink": "մուտք գործել",
        "newarticletext": "Դուք յղուած էք տակաւին գոյութիւն չունեցող էջի մը։\nԷջը ստեղծելու համար, մեքենագրեցէք ներքեւի տուփիկին մէջ (յաւելեալ տեղեկութեանց համար տե՛ս [$1 օգնութեան ցուցմունքներու էջը])։\nԵթէ սխալմամբ հոս հասած էք, սեղմել դիտարկիչի <strong>ետ</strong> կոճակը։",
        "anontalkpagetext": "<em> Այս էջը առայժմ հաշիւ չստեղծած, կամ հաշիւ չօգտագործող, անանուն մասնակիցներու քննարկման էջն է։</em>\nՈւրեմն որպէս ինքնութիւն ստիպուած ենք օգտագործել անոնց IP հասցէն։\nԱյսպիսի IP հասցէ կրնան ունենալ մէկէ աւելի մասնակիցներ։\nԵթէ դուք անանուն մասնակից էք եւ կը խորհիք որ անկապ դիտողութիւններու թիրախ դարձած էք, կը խնդրուի [[Special:CreateAccount|Հաշիւ ստեղծել]] կամ [[Special:UserLogin|մուտք գործել]] խուսափելու համար ապագային այլ անդանուն մասնակիցներու հետ շփոթուելու հնարաւորութենէն։",
        "editing": "Կը խմբագրուի՝ $1 էջը",
        "creating": "«$1» էջի ստեղծում",
        "editingsection": "$1 բաժինի խմբագրում",
+       "yourdiff": "Տարբերութիւններ",
        "templatesused": "Այս էջին մէջ օգտագործուած {{PLURAL:$1|կաղապարը|կաղապարները}}.",
        "templatesusedpreview": "{{PLURAL:$1|Կաղապար}} օգտագործուած այս կանխաստուգումին մէջ՝",
        "template-protected": "(պահպանուած)",
        "permissionserrorstext-withaction": "Արտօնութիւն չունիք $2 հետեւեալ {{PLURAL:$1|պատճառով|պատճառներով}}.",
        "recreate-moveddeleted-warn": "<strong>Զգուշացում. Նախապէս ջնջուած էջ մը պիտի վերստեղծուի։<strong>\n\nԿը խնդրուի մտածել այս էջի խմբագրման նպատակայարմարութեան մասին։ \nՁեր դիւրութեան համար ներքեւ կը գտնէք այս էջի ջնջումին և տեղափոխումին տեղեկատետրերը։",
        "moveddeleted-notice": "Այս էջը ջնջուած է։\nԷջին ջնջումի, պահպանումի եւ փոխադրումի տեղեկատետրը տրամադրելի է ներքեւ որպէս տեղեկութիւն։",
+       "edit-conflict": "Խմբագրման ընհարում։",
        "content-model-wikitext": "ուիքիթէքսթ",
+       "content-model-text": "պարզ բնաբան",
+       "content-model-javascript": "ՃաւաՍքրիփթ",
+       "content-json-empty-object": "Պարապ առարկայ",
+       "content-json-empty-array": "Պարապ շարք",
        "undo-failure": "Խմբագրումը կարելի չեղաւ ետ ընել միջանկեալ խմբագրումներու հետ ընդհարումի պատճառով։",
        "viewpagelogs": "Տեսնել այս էջին տեղեկատետրերը",
        "currentrev-asof": "Ընթացիկ տարբերակը $1ի դրութեամբ",
        "nextrevision": "Յաջորդ տարբերակ→",
        "currentrevisionlink": "Վերջին տարբերակ",
        "cur": "ընթ.",
+       "next": "յաջորդ",
        "last": "նախ.",
+       "page_first": "առաջին",
+       "page_last": "վերջին",
        "histlegend": "Տարբերութիւններու համեմատում. դրէ՛ք նշման կէտեր այն տարբերակներու կողքին, որոնք կ՚ուզէք համեմատել եւ սեղմեցէ՛ք ներքեւ գտնուող կոճակը։<br />\nԾանօթ.՝ <strong>({{int:cur}})</strong> = ընթացիկ տարբերակի հետ համեմատած տարբերութիւններ,\n<strong>({{int:last}})</strong> = նախորդ տարբերակի հետ համեմատած տարբերութիւններ,<br />'''չ''' = չնչին խմբագրում",
        "history-fieldset-title": "Որոնել տարբերակներ",
        "histfirst": "հնագոյն",
        "history-feed-description": "Ուիքիի այս էջին վերանայումներու ցուցակը",
        "history-feed-item-nocomment": "$1՝ $2",
        "rev-delundel": "ցուցնել/թաքցնել",
+       "rev-showdeleted": "Ցուցադրել",
+       "revdelete-show-file-submit": "Այո",
+       "revdelete-log": "Պատճառ.",
+       "revdelete-reasonotherlist": "Ուրիշ պատճառ.",
+       "mergehistory-reason": "Պատճառ.",
        "mergelog": "Ձուլման տեղեկատետր",
        "history-title": "«$1»ի վերանայումներու ցուցակ",
        "difference-title": "«$1»ի խմբագրումներու միջեւ տարբերութիւն",
        "searchresults-title": "«$1»-ի որոնման արդիւնքները",
        "prevn": "նախորդ {{PLURAL:$1|$1}}",
        "nextn": "յաջորդ {{PLURAL:$1|$1}}",
+       "prev-page": "նախորդ էջ",
+       "next-page": "յաջորդ էջ",
        "prevn-title": "Նախորդ $1 {{PLURAL:$1|արդիւնքը|արդիւնքները}}",
        "nextn-title": "Յաջորդ $1 {{PLURAL:$1|արդիւնքը|արդիւնքները}}",
        "shown-title": "Իւրաքանչիւր էջի վրայ ցոյց տալ $1 {{PLURAL:$1|արդիւնք|արդիւնքներ}}",
        "search-result-category-size": "{{PLURAL:$1|1 անդամ|$1 անդամներ}} ({{PLURAL:$2|1 ենթաստորոգութիւն|$2 ենթաստորոգութիւններ}}, {{PLURAL:$3|1 նիշք|$3 նիշքեր}})",
        "search-redirect": "(Վերայղուած է $1-էն)",
        "search-section": "(բաժին $1)",
+       "search-category": "(ստորոգութիւն $1)",
        "search-file-match": "(համապատասխան է նիշքի բովանդակութեան)",
        "search-suggest": "$1 Նկատի ունի՞ք",
+       "search-interwiki-more": "(աւելի)",
+       "search-interwiki-more-results": "աւելի շատ արդիւնքներ",
+       "search-relatedarticle": "Հարակից",
+       "searchrelated": "հարակից",
        "searchall": "բոլոր",
        "search-showingresults": "{{PLURAL:$4|<strong>$1</strong> արդիւնք <strong>$3</strong>-էն|<strong>$1 - $2</strong> արդիւնքներ <strong>$3</strong>-էն}}",
        "search-nonefound": "Որոնումին համապատասխանող արդիւնքներ չգտնուեցան",
        "mypreferences": "Նախընտրութիւններ",
+       "skin-preview": "Նախադիտել",
+       "stub-threshold-sample-link": "օրինակ",
+       "timezoneregion-africa": "Ափրիկէ",
+       "timezoneregion-america": "Ամերիկա",
+       "timezoneregion-antarctica": "Անթարքթիքա",
+       "timezoneregion-arctic": "Արքթիքա",
+       "timezoneregion-asia": "Ասիա",
+       "timezoneregion-australia": "Աւստրալիա",
+       "timezoneregion-europe": "Եւրոպա",
+       "timezoneregion-indian": "Հնդկական Ովկիանոս",
+       "timezoneregion-pacific": "Խաղաղ Ովկիանոս",
+       "youremail": "Էլեկտրական Նամակ",
+       "email": "Էլեկտրական Նամակ",
+       "group": "Խումբ.",
        "group-bot": "Մեքենայիկներ",
        "group-sysop": "Վարիչներ",
        "grouppage-bot": "{{ns:project}}:Մեքենայիկներ",
        "recentchangeslinked-feed": "Առնչուած փոփոխութիւններ",
        "recentchangeslinked-toolbox": "Առնչուող փոփոխութիւններ",
        "recentchangeslinked-title": "«$1» էջին առնչուած փոփոխութիւնները",
-       "recentchangeslinked-summary": "Նշել Էջի թիւը տեսնելու համար այդ էջին կամ էջէն յղուող փոփոխութիւնները։ (Ստորոգութեան մը անդամները տեսնելու համար, նշել {{ns:category}}:Ստորագութեան անունը))։\n[[Special:Հսկողութեան ցանկ|ձեր հսկողութեան ցանկ]]ի էջին վրայ գտնուող փոփոխութիւնները <strong>շեշտուած տառերով են</strong>։",
+       "recentchangeslinked-summary": "Նշել Էջի թիւը տեսնելու համար այդ էջին կամ էջէն յղուող փոփոխութիւնները։ (Ստորոգութեան մը անդամները տեսնելու համար, նշել {{ns:category}}:Ստորագութեան անունը)։\n [[Special:Watchlist|your Watchlist]] էջին վրայ գտնուող փոփոխութիւնները <strong>շեշտուած տառերով են</strong>։",
        "recentchangeslinked-page": "Էջին անունը՝",
        "recentchangeslinked-to": "Փոխարէնը ցոյց տալ տուեալ էջին առնչուած էջերուն մէջ կատարուած փոփոխութիւնները։",
        "upload": "Վերբեռնել նիշք",
        "watchlisttools-raw": "Խմբագրել հում հսկողութեան ցանկը",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|քննարկում]])",
        "redirect": "Վերայղում նիշքի, մասնակիցի, էջի, տարբերակի կամ տեղեկատետրի ինքնութեան համարէն",
-       "redirect-summary": "Այս յատուկ էջը կը վերայղուի նիշքի մը (տրուած ըլլալով նիշքին անունը), էջի մը (տրուած ըլլալով վերանայման կամ էջի ինքնութեան համարը), մասնակիցի էջի մը. տրուած ըլլալով մասնակիցի մը թուային ինքնութեան համարը), եւ կամ տեղեկատետրի մը մէջ տողի մը, (տրուած ըլլալով տեղեկատետրի ինքնութեան համարը)։ Գործածութիւն՝  [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
+       "redirect-summary": "Այս յատուկ էջը կը վերայղուի նիշքի մը (տրուած ըլլալով նիշքին անունը), էջի մը (տրուած ըլլալով վերանայման կամ էջի ինքնութեան համարը), մասնակիցի էջի մը. (տրուած ըլլալով մասնակիցի մը թուային ինքնութեան համարը), եւ կամ տեղեկատետրի մը մէջ տողի մը, (տրուած ըլլալով տեղեկատետրի ինքնութեան համարը)։ Գործածութիւն՝  [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Յառաջ",
        "redirect-lookup": "Որոնում՝",
        "redirect-value": "Արժէք՝",
index 65fe679..4d678ac 100644 (file)
        "customcssprotected": "Tu non ha le permission de modificar iste pagina de CSS perque illo contine le configuration personal de un altere usator.",
        "customjsonprotected": "Tu non ha le permission de modificar iste pagina JSON perque illo contine le configuration personal de un altere usator.",
        "customjsprotected": "Tu non ha le permission de modificar iste pagina de JavaScript perque illo contine le configuration personal de un altere usator.",
-       "sitecssprotected": "Tu non ha le permission de modificar iste pagina CSS perque isto pote affectar tote le visitantes",
-       "sitejsonprotected": "Tu non ha le permission de modificar iste pagina JSON perque isto pote affectar tote le visitantes",
-       "sitejsprotected": "Tu non ha le permission de modificar iste pagina JavaScript perque isto pote affectar tote le visitantes",
+       "sitecssprotected": "Tu non ha le permission de modificar iste pagina CSS perque isto pote affectar tote le visitantes.",
+       "sitejsonprotected": "Tu non ha le permission de modificar iste pagina JSON perque isto pote affectar tote le visitantes.",
+       "sitejsprotected": "Tu non ha le permission de modificar iste pagina JavaScript perque isto pote affectar tote le visitantes.",
        "mycustomcssprotected": "Tu non ha le permission de modificar iste pagina de CSS.",
        "mycustomjsonprotected": "Tu non ha le permission de modificar iste pagina JSON.",
        "mycustomjsprotected": "Tu non ha le permission de modificar iste pagina de JavaScript.",
        "confirm-unwatch-top": "Remover iste pagina de tu observatorio?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter le modificationes a iste pagina?",
+       "confirm-mcrundo-title": "Disfacer un modification",
+       "mcrundofailed": "Disfaction fallite",
+       "mcrundo-missingparam": "Manca parametros obligatori in le requesta.",
+       "mcrundo-changed": "Le pagina ha essite modificate post que tu examinava le differentias. Per favor revide le nove modification.",
        "quotation-marks": "“$1”",
        "imgmultipageprev": "← precedente pagina",
        "imgmultipagenext": "sequente pagina →",
        "edit-error-long": "Errores:\n\n$1",
        "revid": "version $1",
        "pageid": "ID de pagina $1",
-       "interfaceadmin-info": "$1\n\nLe permissiones pro modificar le files CSS/JS/JSON global del sito ha recentemente essite separate ab le derecto <code>editinterface</code>. Si tu non comprende proque tu incontra iste error, vide [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "Le permissiones pro modificar le files CSS/JS/JSON global del sito ha recentemente essite limitate al membros del gruppo [[{{int:grouppage-interface-admin}}|{{int:group-interface-admin}}]]. Vide [[m:Creation of separate user group for editing sitewide CSS/JS]] pro plus information.",
        "rawhtml-notallowed": "Etiquettas &lt;html&gt; non pote esser usate foras de paginas normal.",
        "gotointerwiki": "Quitar {{SITENAME}}",
        "gotointerwiki-invalid": "Le titulo specificate non es valide.",
index 7a3e68d..f7e8441 100644 (file)
        "customcssprotected": "Non si dispone dei permessi necessari alla modifica di questa pagina CSS, in quanto contiene le impostazioni personali di un altro utente.",
        "customjsonprotected": "Non si dispone dei permessi necessari alla modifica di questa pagina JSON, in quanto contiene le impostazioni personali di un altro utente.",
        "customjsprotected": "Non si dispone dei permessi necessari alla modifica di questa pagina JavaScript, in quanto contiene le impostazioni personali di un altro utente.",
+       "sitecssprotected": "Non si dispone dei permessi necessari per modificare questa pagina CSS perché può influire su tutti i visitatori.",
+       "sitejsonprotected": "Non si dispone dei permessi necessari per modificare questa pagina JSON perché può influire su tutti i visitatori.",
+       "sitejsprotected": "Non si dispone dei permessi necessari per modificare questa pagina JavaScript perché può influire su tutti i visitatori.",
        "mycustomcssprotected": "Non si dispone dei permessi necessari per modificare questa pagina CSS.",
        "mycustomjsonprotected": "Non si dispone dei permessi necessari per modificare questa pagina JSON.",
        "mycustomjsprotected": "Non si dispone dei permessi necessari per modificare questa pagina JavaScript.",
        "revdelete-show-file-submit": "Sì",
        "revdelete-selected-text": "{{PLURAL:$1|Versione selezionata|Versioni selezionate}} di [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Versione selezionata|Versioni selezionate}} del file [[:$2]]:",
-       "logdelete-selected": "{{PLURAL:$1|Evento del registro selezionato|Eventi del registro selezionato}}:",
+       "logdelete-selected": "{{PLURAL:$1|Evento del registro selezionato|Eventi del registro selezionati}}:",
        "revdelete-text-text": "Le versioni cancellate appariranno ancora nella cronologia della pagina, ma parte del loro contenuto sarà inaccessibile al pubblico.",
        "revdelete-text-file": "Le versioni di file cancellati appariranno ancora nella cronologia del file, ma parti del loro contenuto sarà inaccessibile al pubblico.",
        "logdelete-text": "Gli eventi cancellati appariranno ancora nei registri, ma parti del loro contenuto sarà inaccessibile al pubblico.",
        "confirm-unwatch-top": "Rimuovere questa pagina dalla tua lista degli osservati speciali?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Ripristinare le modifiche di questa pagina?",
+       "confirm-mcrundo-title": "Annulla una modifica",
+       "mcrundofailed": "Annullamento fallito",
+       "mcrundo-missingparam": "Parametri obbligatori mancanti nella richiesta.",
        "percent": "$1&#160;%",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← pagina precedente",
index 297cf75..0aed4be 100644 (file)
        "updated": "(更新)",
        "note": "<strong>お知らせ:</strong>",
        "previewnote": "<strong>これはプレビューです。</strong>\n変更内容はまだ保存されていません!",
-       "continue-editing": "ç·¨é\9b\86ã\82\92ç¶\9aè¡\8c",
+       "continue-editing": "ç·¨é\9b\86ã\82¨ã\83ªã\82¢ã\81«ç§»å\8b\95ã\81\99ã\82\8b",
        "previewconflict": "これは、上の編集エリアの文章を保存した場合にどう表示されるかを示すプレビューです。",
        "session_fail_preview": "申し訳ありません! セッションデータが消失したため編集を処理できませんでした。\n\nアカウントがログアウトされている可能性があります。<strong>アカウントにログインしていることを確認して、もう一度やり直してください</strong>。\nそれでも失敗する場合、[[Special:UserLogout|ログアウト]]してからログインし直し、現在使用しているブラウザでこのサイトからのクッキーが許可されていることを確認してください。",
        "session_fail_preview_html": "申し訳ありません! セッション データが消失したため編集を処理できませんでした。\n\n<em>{{SITENAME}}では生のHTMLが有効であり、JavaScriptでの攻撃を予防するためにプレビューを表示していません。</em>\n\n<strong>この編集が問題ない場合はもう一度保存してください。</strong>\nそれでも失敗する場合、[[Special:UserLogout|ログアウト]]してからログインし直し、現在使用しているブラウザでこのサイトからのクッキーが許可されていることを確認してください。",
        "expansion-depth-exceeded-warning": "ページが展開の深さ制限を超えました",
        "parser-unstrip-loop-warning": "unstrip のループを検出しました",
        "unstrip-depth-warning": "unstrip の再帰 ($1) が上限を超えました",
+       "unstrip-size-warning": "\"unstrip\" のサイズが上限 ($1) を超えました",
+       "unstrip-size-category": "ページの  \"unstrip\" サイズが上限を超えました",
        "converter-manual-rule-error": "手動の言語変換規則でエラーを検出しました。",
        "undo-success": "この編集を取り消せます。\n下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。",
        "undo-failure": "中間の版での編集と競合したため、取り消せませんでした。",
+       "undo-main-slot-only": "メインスロット以外の内容を含むため、取り消せませんでした。",
        "undo-norev": "取り消そうとした編集が存在しないか削除済みのため取り消せませんでした。",
        "undo-nochange": "指定した編集は既に取り消されたようです。",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|トーク]]) による版 $1 を取り消し",
        "diff-paragraph-moved-toold": "文章は移動しました。クリックすると元の場所が開きます。",
        "difference-missing-revision": "指定された{{PLURAL:$2|$2版}}の差分 ($1) が見つかりませんでした。\n\n通常、削除されたページの版への古い差分表示や固定リンクをたどった際に、このようなことが起きます。 \n詳細は[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 削除記録]を参照してください。",
        "searchresults": "検索結果",
+       "search-filter-title-prefix": "ページ名が 「$1」で始まるページだけを検索する",
        "search-filter-title-prefix-reset": "すべてのページを検索",
        "searchresults-title": "「$1」の検索結果",
        "titlematches": "ページ名と一致",
        "rcfilters-filter-watchlistactivity-unseen-label": "未読の変更",
        "rcfilters-filter-watchlistactivity-unseen-description": "ウォッチリストに登録されていて、前回訪れた後に更新があったページ。",
        "rcfilters-filter-watchlistactivity-seen-label": "閲覧済みの変更",
+       "rcfilters-filter-watchlistactivity-seen-description": "前回訪れた後に更新があったページへの変更",
        "rcfilters-filtergroup-changetype": "変更の種類",
        "rcfilters-filter-pageedits-label": "ページの編集",
        "rcfilters-filter-pageedits-description": "ウィキの本文、議論、カテゴリの説明などの編集",
        "rcfilters-preference-label": "最近の更新の改善版を隠す",
        "rcfilters-preference-help": "2017年のインターフェース更新およびそれ以降に追加された新しいツールを無効化します。",
        "rcfilters-watchlist-preference-label": "ウォッチリストの改善版を隠す",
+       "rcfilters-watchlist-preference-help": "2017年のインターフェース刷新と、左記実施以降の全てのツール追加を以前の内容に戻します。",
        "rcfilters-filter-showlinkedfrom-label": "指定されたページのリンク先の変更を表示",
-       "rcfilters-filter-showlinkedfrom-option-label": "指定されたページから<strong>リンクされているページ</strong>",
+       "rcfilters-filter-showlinkedfrom-option-label": "指定されたページから<strong>リンクされているページ(リンク先)</strong>",
        "rcfilters-filter-showlinkedto-label": "指定されたページのリンク元の変更を表示",
-       "rcfilters-filter-showlinkedto-option-label": "指定されたページに<strong>リンクしているページ</strong>",
+       "rcfilters-filter-showlinkedto-option-label": "指定されたページに<strong>リンクしているページ(リンク元)</strong>",
        "rcfilters-target-page-placeholder": "ページ名(またはカテゴリ名)を入力",
        "rcnotefrom": "以下は<strong>$3 $4</strong>以降の{{PLURAL:$5|更新です}} (最大 <strong>$1</strong> 件)。",
        "rclistfromreset": "日時指定をリセット",
        "uploadstash-bad-path-unrecognized-thumb-name": "サムネイル名が認識できません。",
        "uploadstash-bad-path-no-handler": "ファイル $2 の MIME $1 に対するハンドラが見つかりません。",
        "uploadstash-bad-path-bad-format": "キー「$1」は適切な形式ではありません。",
+       "uploadstash-file-not-found": "キー「$1」はスタッシュに存在しません。",
        "uploadstash-file-not-found-no-thumb": "サムネイルを取得できませんでした。",
        "uploadstash-file-not-found-no-local-path": "スケーリングされた項目のローカルパスはありません。",
        "uploadstash-file-not-found-no-object": "サムネイルのローカルファイルオブジェクトを作成できませんでした。",
        "uploadstash-zero-length": "ファイルのサイズがゼロです。",
        "invalid-chunk-offset": "無効なチャンクオフセット",
        "img-auth-accessdenied": "アクセスが拒否されました",
-       "img-auth-nopathinfo": "PATH_INFO が見つかりません。\nサーバーが、この情報を渡すように構成されていません。\nCGI ベースであるため、img_auth に対応できない可能性もあります。\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization をご覧ください。",
+       "img-auth-nopathinfo": "URL のパス情報が見つかりません。\nサーバーは、変数 REQUEST_URI または PATH_INFO の一方または両方でパス情報を渡すように構成する必要があります。\nすでに設定済みの場合は、$wgUsePathInfo を有効にすることをお試しください。\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization をご覧ください。",
        "img-auth-notindir": "要求されたパスは、設定済みのアップロード先ディレクトリ内にありません。",
        "img-auth-badtitle": "「$1」からは有効なページ名を構築できません。",
        "img-auth-nologinnWL": "ログインしておらず、さらに「$1」はホワイトリストに入っていません。",
        "cachedspecial-refresh-now": "最新版を表示します。",
        "categories": "カテゴリ",
        "categories-submit": "表示",
-       "categoriespagetext": "以ä¸\8bã\81®{{PLURAL:$1|ã\82«ã\83\86ã\82´ã\83ª}}ã\81«ã\81¯ã\83\9aã\83¼ã\82¸ã\81¾ã\81\9fã\81¯ã\83¡ã\83\87ã\82£ã\82¢ã\81\8cã\81\82ã\82\8aã\81¾ã\81\99ã\80\82\n[[Special:UnusedCategories|使ã\82\8fã\82\8cã\81¦ã\81\84ã\81ªã\81\84ã\82«ã\83\86ã\82´ã\83ª]]ã\81¯ã\81\93ã\81\93ã\81«ã\81¯è¡¨ç¤ºã\81\97ã\81¦ã\81\84ã\81¾ã\81\9bã\82\93。\n[[Special:WantedCategories|カテゴリページが存在しないカテゴリ]]も参照してください。",
+       "categoriespagetext": "以ä¸\8bã\81®{{PLURAL:$1|ã\82«ã\83\86ã\82´ã\83ª}}ã\81¯ã\82¦ã\82£ã\82­ä¸\8aã\81«ã\81\82ã\82\8aã\80\81æ\9cªä½¿ç\94¨ã\81§ã\81\82ã\82\8bå ´å\90\88ã\82\82ã\81\82ã\82\8aã\81¾ã\81\99。\n[[Special:WantedCategories|カテゴリページが存在しないカテゴリ]]も参照してください。",
        "categoriesfrom": "最初に表示するカテゴリ:",
        "deletedcontributions": "利用者の削除された投稿",
        "deletedcontributions-title": "利用者の削除された投稿",
        "confirm-unwatch-top": "このページをウォッチリストから除去しますか?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "このページの編集を差し戻しますか?",
+       "confirm-mcrundo-title": "直前の変更を取り消す",
+       "mcrundofailed": "取り消しに失敗しました",
+       "mcrundo-missingparam": "リクエストに必要なパラメーターが見当たりません。",
        "semicolon-separator": ";&#32;",
        "comma-separator": "、",
        "colon-separator": ":&#32;",
        "limitreport-expansiondepth-value": "$1/$2",
        "limitreport-expensivefunctioncount": "高負荷パーサー関数の数",
        "limitreport-expensivefunctioncount-value": "$1/$2",
+       "limitreport-unstrip-depth": "\"unstrip\" を再帰的に実行する回数",
        "limitreport-unstrip-depth-value": "$1/$2",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|バイト}}",
        "expandtemplates": "テンプレートを展開",
index f7ab4f8..d649fba 100644 (file)
        "customcssprotected": "여기에는 다른 사용자의 개인 설정이 포함되어 있기 때문에 이 CSS 문서를 편집할 수 없습니다.",
        "customjsonprotected": "다른 사용자의 개인 설정이 포함되어 있기 때문에 이 JSON 문서를 편집할 권한이 없습니다.",
        "customjsprotected": "여기에는 다른 사용자의 개인 설정이 포함되어 있기 때문에 이 자바스크립트 문서를 편집할 수 없습니다.",
-       "sitecssprotected": "모든 방문자에 영향을 미칠 수 있기 때문에 이 CSS를 편집할 권한이 없습니다",
-       "sitejsonprotected": "모든 방문자에게 영향을 미칠 수 있기 때문에 이 JSON 문서를 편집할 권한이 없습니다",
-       "sitejsprotected": "모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다",
+       "sitecssprotected": "모든 방문자에 영향을 미칠 수 있기 때문에 이 CSS를 편집할 권한이 없습니다.",
+       "sitejsonprotected": "모든 방문자에게 영향을 미칠 수 있기 때문에 이 JSON 문서를 편집할 권한이 없습니다.",
+       "sitejsprotected": "모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다.",
        "mycustomcssprotected": "이 CSS 문서를 편집할 권한이 없습니다.",
        "mycustomjsonprotected": "이 JSON 문서를 편집할 권한이 없습니다.",
        "mycustomjsprotected": "이 자바스크립트 문서를 편집할 권한이 없습니다.",
        "cannotcreateaccount-text": "이 위키에서 직접 계정 만들기는 활성화되어 있지 않습니다.",
        "yourdomainname": "도메인 이름:",
        "password-change-forbidden": "이 위키에서 비밀번호를 바꿀 수 없습니다.",
-       "externaldberror": "인증 데이터베이스에 오류가 있거나 바깥 계정을 새로 고칠 권한이 없습니다.",
+       "externaldberror": "인증 데이터베이스에 오류가 있거나 외부 계정을 새로 고칠 권한이 없습니다.",
        "login": "로그인",
        "login-security": "사용자 정보 확인",
        "nav-login-createaccount": "로그인 / 계정 만들기",
        "powersearch-toggleall": "모두",
        "powersearch-togglenone": "모두 제외",
        "powersearch-remember": "향후 검색에 선택 기억하기",
-       "search-external": "바깥 검색",
+       "search-external": "외부 검색",
        "searchdisabled": "{{SITENAME}} 검색이 비활성화되어 있습니다.\n검색이 작동하지 않는 동안 Google을 통해 검색할 수 있습니다.\n검색 엔진의 내용은 최신이 아닐 수 있다는 점을 참고하세요.",
        "search-error": "검색하는 동안 오류가 발생했습니다: $1",
        "search-warning": "검색하는 동안 경고가 발생했습니다: $1",
        "img-auth-nofile": "\"$1\" 파일이 없습니다.",
        "img-auth-isdir": "\"$1\" 디렉터리에 접근을 시도했습니다.\n파일에만 접근할 수 있습니다.",
        "img-auth-streaming": "\"$1\" 파일을 전송하는 중입니다.",
-       "img-auth-public": "img_auth.php는 개인 위키 파일을 바깥 사이트로 전송하는 기능입니다.\n이 기능은 기본적으로 공개적인 위키에서 사용하도록 설계되어 있습니다.\n보안적인 문제로 기본적으로 img_auth.php 기능은 비활성화되어 있습니다.",
+       "img-auth-public": "img_auth.php의 기능은 개인 위키의 파일을 외부로 전송하는 기능입니다.\n이 위키는 공개된 위키로 구성되어 있습니다.\n최적의 보안을 위해 img_auth.php는 비활성화되어 있습니다.",
        "img-auth-noread": "\"$1\" 파일을 볼 권한이 없습니다.",
        "http-invalid-url": "잘못된 URL: $1",
        "http-invalid-scheme": "\"$1\"(으)로 시작하는 URL은 지원되지 않습니다.",
        "wantedpages-summary": "다른 문서들에 링크는 걸려 있지만 존재하지 않는 문서들 중, 넘겨주기 문서를 제외한 목록입니다. 존재하지 않는 문서로 넘겨주는 문서 목록을 보려면 [[{{#special:BrokenRedirects}}|끊긴 넘겨주기 목록]]을 참조하세요.",
        "wantedpages-badtitle": "문서 제목이 잘못되었습니다: $1",
        "wantedfiles": "필요한 파일 목록",
-       "wantedfiletext-cat": "다음 파일은 쓰이고는 있지만 없는 파일입니다. 바깥 저장소에 있는 파일은 실제로는 있지만 여기 올라 있을 수 있습니다. 그런 오류는 <del>삭제선</del>이 그어질 것입니다. 또한 없는 파일을 포함하고 있는 문서는 [[:$1]]에 올라 있습니다.",
+       "wantedfiletext-cat": "다음 파일은 쓰이고는 있지만 없는 파일입니다. 외부 저장소의 파일은 존재하더라도 여기에 나열될 수 있습니다. 이러한 오류는 <del>삭제선</del>이 그어질 것입니다. 또한 없는 파일을 포함하고 있는 문서는 [[:$1]]에 나열됩니다.",
        "wantedfiletext-cat-noforeign": "다음 파일은 쓰이고 있지만 존재하지 않습니다. 또한, 존재하지 않는 파일이 포함된 문서가 [[:$1]]에 나열되어 있습니다.",
-       "wantedfiletext-nocat": "다음 파일은 쓰이고 있지만 존재하지 않습니다. 바깥 저장소에 있는 파일은 실제로는 있지만 여기 올라 있을 수 있습니다. 그런 오류는 <del>삭제선</del>이 그어질 것입니다.",
+       "wantedfiletext-nocat": "다음 파일은 쓰이고는 있지만 없는 파일입니다. 외부 저장소의 파일은 존재하더라도 여기에 나열될 수 있습니다. 이러한 오류는 <del>삭제선</del>이 그어질 것입니다.",
        "wantedfiletext-nocat-noforeign": "다음 파일은 쓰이고 있지만 존재하지 않습니다.",
        "wantedtemplates": "필요한 틀 목록",
        "mostlinked": "가장 많이 연결된 문서 목록",
        "booksources-search-legend": "책 원본 검색",
        "booksources-isbn": "ISBN:",
        "booksources-search": "검색",
-       "booksources-text": "ì\95\84ë\9e\98ì\9d\98 ëª©ë¡\9dì\9d\80 ì\83\88 ì±\85ì\9d´ë\82\98 ì¤\91ê³  ì±\85ì\9d\84 í\8c\90매í\95\98ë\8a\94 ë°\94ê¹¥ ì\82¬ì\9d´í\8a¸ë¡\9c, ì\9b\90í\95\98ë\8a\94 ì±\85ì\9d\98 ì \95보를 ì\96»ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.",
+       "booksources-text": "ì\95\84ë\9e\98ì\97\90 ì\83\88 ì±\85ì\9d´ë\82\98 ì¤\91ê³  ì±\85ì\9d\84 í\8c\90매í\95\98ë\8a\94 ë\8b¤ë¥¸ ì\82¬ì\9d´í\8a¸ì\9d\98 ë§\81í\81¬ ëª©ë¡\9dì\9d´ ì\9e\88ì\9c¼ë©°, ì\9b\90í\95\98ë\8a\94 ì±\85ì\9d\98 ì¶\94ê°\80 ì \95ë³´ë\8f\84 í\99\95ì\9d¸í\95  ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:",
        "booksources-invalid-isbn": "입력한 ISBN이 올바르지 않은 것으로 보입니다. 원본과 대조해 문제가 있는지 확인해보세요.",
        "magiclink-tracking-rfc": "RFC 매직 링크를 사용하는 문서",
        "magiclink-tracking-rfc-desc": "이 문서는 RFC 매직 링크를 사용합니다. 이관 방법을 보려면 [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org]를 참조하십시오.",
        "ipaddressorusername": "IP 주소 또는 사용자 이름:",
        "ipbexpiry": "기한:",
        "ipbreason": "이유:",
-       "ipbreason-dropdown": "*일반적인 차단 이유\n** 거짓 정보를 넣음\n** 문서 내용을 지움\n** 바깥 사이트의 광고성 링크를 넣음\n** 문서에 장난성 내용을 넣음\n** 협박성 행동\n** 다중 계정 악용\n** 부적절한 사용자 이름",
+       "ipbreason-dropdown": "*일반적인 차단 이유\n** 거짓 정보를 넣음\n** 문서 내용을 지움\n** 외부 사이트의 광고성 링크를 넣음\n** 문서에 장난성 내용을 넣음\n** 협박성 행동\n** 다중 계정 악용\n** 부적절한 사용자 이름",
        "ipb-hardblock": "이 IP를 이용하는 로그인한 사용자가 편집하는 것을 막기",
        "ipbcreateaccount": "계정 만들기를 막기",
        "ipbemailban": "이메일을 보내지 못하도록 막기",
        "confirm-unwatch-top": "이 문서를 주시문서 목록에서 뺄까요?",
        "confirm-rollback-button": "확인",
        "confirm-rollback-top": "이 문서의 편집을 되돌리시겠습니까?",
+       "confirm-mcrundo-title": "변경사항 취소",
+       "mcrundofailed": "실행 취소를 실패했습니다",
+       "mcrundo-missingparam": "요청에 필요한 변수가 존재하지 않습니다.",
+       "mcrundo-changed": "차이를 본 이후로 문서가 변경되었습니다. 새로운 변경사항을 검토해 주십시오.",
        "quotation-marks": "“$1”",
        "imgmultipageprev": "← 이전 페이지",
        "imgmultipagenext": "다음 페이지 →",
        "specialpages-group-developer": "개발자 도구",
        "blankpage": "빈 문서",
        "intentionallyblankpage": "일부러 비워 둔 문서입니다.",
-       "external_image_whitelist": " #이 줄은 그대로 두십시오<pre>\n#정규 표현식(// 사이에 있는 부분)을 아래에 입력하세요.\n#이 목록은 바깥 그림의 URL과 대조할 것입니다.\n#이 목록과 일치하는 것은 그림으로 표시되지만, 그렇지 않은 경우 그림을 가리키는 링크만 보이게 될 것입니다.\n#\"#\" 문자에서 줄의 끝까지는 주석입니다\n#이 목록은 대소문자를 구별하지 않습니다\n\n#모든 정규 표현식은 이 줄 위에 넣어 주십시오. 그리고 이 줄은 그대로 두십시오.</pre>",
+       "external_image_whitelist": " #이 줄은 그대로 두십시오<pre>\n#정규 표현식(// 사이에 있는 부분)을 아래에 입력하세요.\n#이 목록은 외부 그림의 URL과 대조할 것입니다.\n#이 목록과 일치하는 것은 그림으로 표시되지만, 그렇지 않은 경우 그림을 가리키는 링크만 보이게 될 것입니다.\n#\"#\" 문자에서 줄의 끝까지는 주석입니다\n#이 목록은 대소문자를 구별하지 않습니다\n\n#모든 정규 표현식은 이 줄 위에 넣어 주십시오. 그리고 이 줄은 그대로 두십시오.</pre>",
        "tags": "올바른 편집 태그",
        "tag-filter": "[[Special:Tags|태그]] 필터:",
        "tag-filter-submit": "필터",
        "passwordpolicies-policy-passwordcannotmatchusername": "비밀번호는 사용자 이름과 같을 수 없습니다",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "비밀번호는 블랙리스트에 있는 비밀번호와 일치할 수 없습니다",
        "passwordpolicies-policy-maximalpasswordlength": "비밀번호는 적어도 $1 {{PLURAL:$1|자}} 미만이어야 합니다",
-       "passwordpolicies-policy-passwordcannotbepopular": "비밀번호는 {{PLURAL:$1|저명한 비밀번호가 될|$1개의 저명한 비밀번호에 속할}} 수 없습니다"
+       "passwordpolicies-policy-passwordcannotbepopular": "비밀번호는 {{PLURAL:$1|저명한 비밀번호가 될|$1개의 저명한 비밀번호에 속할}} 수 없습니다",
+       "easydeflate-invaliddeflate": "주어진 컨텐츠가 적절히 압축되지 않았습니다"
 }
index a7450a5..2cb3e4c 100644 (file)
        "confirm-unwatch-top": "Dës Säit vun Ärer Iwwerwaachungslëscht erofhuelen?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Ännerunge vun dëser Säit zrécksetzen?",
+       "confirm-mcrundo-title": "Eng Ännerung réckgängeg maachen",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← Vireg Säit",
        "imgmultipagenext": "nächst Säit →",
index 3849fa2..8356723 100644 (file)
        "aboutpage": "Project:Informaçioìn",
        "copyright": "O contegno o l'è disponibile in base a-a liçensa $1, se no diversamente speçificou.",
        "copyrightpage": "{{ns:project}}:Driti d'autô",
-       "currentevents": "Atualitæ",
-       "currentevents-url": "Project:Atualitæ",
+       "currentevents": "Atoalitæ",
+       "currentevents-url": "Project:Atoalitæ",
        "disclaimers": "Averténse",
        "disclaimerpage": "Project:Avertense generâli",
        "edithelp": "Agiùtto",
        "recentchangeslinked-feed": "Cangiamenti correlæ",
        "recentchangeslinked-toolbox": "Cangiaménti corelæ",
        "recentchangeslinked-title": "Modiffiche correlæ a \"$1\"",
-       "recentchangeslinked-summary": "Scrivi o nomme de 'na pagina pe vèdde i cangiamenti a-e pagine coleghæ a ò da quésta pagina. (Pe védde i menbri de 'na catgorîa, scrive Category:Nomme da catgorîa). Cangiamenti e-e pagine insce [[Special:Watchlist|your Watchlist]] són in <strong>bold</strong>.",
+       "recentchangeslinked-summary": "Scrîvi o nómme de 'na pàgina pe védde e modìfiche a-e pàgine che són colegòu o che colégan a quélle pàgine. (Pe védde i ménbri de 'na catgorîa, scrive {{ns:category}}:Nómme da catgorîa). E moìfiche a-e pàgine in sce [[Special:Watchlist|òservæ speciâli]] són evidençiòu in <strong>grascétto</strong>.",
        "recentchangeslinked-page": "Nómme da pàgina:",
        "recentchangeslinked-to": "Fanni védde sôlo i cangiaménti a-e pàggine conligæ a-a pàggina specificâ",
        "recentchanges-page-added-to-category": "[[:$1]] azonto a-a categoria",
index e3a3066..dcd8560 100644 (file)
@@ -27,7 +27,8 @@
                        "Zuiks",
                        "Martinsdzerve",
                        "Nixiéoffset",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Mailman"
                ]
        },
        "tog-underline": "Pasvītrot saites:",
        "title-invalid-characters": "Pieprasītais lapas nosaukums satur nederīgus simbolus: \"$1\".",
        "title-invalid-magic-tilde": "Pieprasītās lapas nosaukums satur nederīgu maģiskās tildes virkni (<nowiki>~~~</nowiki>).",
        "title-invalid-leading-colon": "Pieprasītās lapas nosaukums satur neatļautu kolu tā sākumā.",
-       "perfcached": "Šie dati ir no servera kešatmiņas un var būt novecojuši. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
+       "perfcached": "Šie dati ir no servera kešatmiņas un var būt novecojuši. Kešatmiņā ir {{PLURAL:$1|pieejami|pieejams|pieejami}} ne vairāk kā {{PLURAL:$1|$1 rezultāti|viens rezultāts|$1 rezultāti}}.",
        "perfcachedts": "Šie dati ir no servera kešatmiņas (''cache''), kas pēdējo reizi bija atjaunota $1. Kešatmiņā {{PLURAL:$4|pieejami|pieejams|pieejami}} ne vairāk kā {{PLURAL:$4|$4 rezultāti|viens rezultāts|$4 rezultāti}}.",
        "querypage-no-updates": "Šīs lapas atjaunošana pagaidām ir atslēgta. Te esošie dati tuvākajā laikā netiks atjaunoti.",
        "viewsource": "Aplūkot kodu",
        "cannotchangeemail": "Konta e-pasta adresi nevar nomainīt šajā wiki.",
        "emaildisabled": "Šī vietne nevar nosūtīt e-pastus.",
        "accountcreated": "Konts izveidots",
-       "accountcreatedtext": "Lietotāja konts priekš $1 tika izveidots.",
+       "accountcreatedtext": "Lietotāja konts priekš [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|diskusija]]) tika izveidots.",
        "createaccount-title": "Dalībnieka konta izveidošana {{grammar:lokatīvs|{{SITENAME}}}}",
        "login-throttled": "Jūs esat veicis pārāk daudz pieslēgšanās mēģinājumus.\nLūdzu, uzgaidiet $1 pirms mēģiniet vēlreiz.",
        "login-abort-generic": "Pieteikšanās neizdevās — darbība pārtraukta",
        "yourtext": "Tavs teksts",
        "storedversion": "Saglabātā versija",
        "editingold": "'''BRĪDINĀJUMS: Saglabājot šo lapu, tu izmainīsi šīs lapas novecojušu versiju, un ar to tiks dzēstas visas izmaiņas, kas izdarītas pēc šīs versijas.'''",
+       "unicode-support-fail": "Izskatās, ka tava pārlūkprogramma neatbalsta Unicode. Labojums netika saglabāts.",
        "yourdiff": "Atšķirības",
        "copyrightwarning": "Lūdzu, ņem vērā, ka viss ieguldījums, kas veikts {{grammar:lokatīvs|{{SITENAME}}}}, ir uzskatāms par publiskotu saskaņā ar $2 (vairāk info skatīt $1).\nJa nevēlies, lai Tevis rakstīto kāds labo un izplata tālāk, tad, lūdzu, nepievieno to šeit!<br />\n\nIzvēloties \"Saglabāt lapu\", Tu apliecini, ka šo rakstu esi rakstījis vai papildinājis pats vai izmantojis informāciju no darba, ko neaizsargā autortiesības, vai tamlīdzīga brīvi pieejama resursa.\n'''BEZ ATĻAUJAS NEPIEVIENO DARBU, KO AIZSARGĀ AUTORTIESĪBAS!'''",
        "copyrightwarning2": "Lūdz ņem vērā, ka visu ieguldījumu {{grammar:lokatīvs|{{SITENAME}}}} var rediģēt, mainīt vai izdzēst citi lietotāji. Ja negribi lai ar tavu rakstīto tā izrīkojas, nepievieno to šeit.\n\nTu apliecini, ka šo rakstu esi rakstījis vai papildinājis pats vai izmantojis informāciju no darba, ko neaizsargā autortiesības, vai tamlīdzīga brīvi pieejama resursa (sīkāk skatīt $1).\n\n'''BEZ ATĻAUJAS NEPIEVIENO DARBU, KO AIZSARGĀ AUTORTIESĪBAS!'''",
        "page_last": "pēdējā",
        "histlegend": "Atšķirību izvēle: atzīmē vajadzīgo versiju apaļās pogas un spied \"Salīdzināt izvēlētās versijas\".<br />\nApzīmējumi:\n\"ar pašreizējo\" = salīdzināt ar pašreizējo versiju,\n\"ar iepriekšējo\" = salīdzināt ar iepriekšējo versiju,\nm = maznozīmīgs labojums.",
        "history-fieldset-title": "Versiju meklēšana",
-       "history-show-deleted": "Tikai dzēstās",
+       "history-show-deleted": "Tikai dzēstie labojumi",
        "histfirst": "Senākās",
        "histlast": "Jaunākās",
        "historysize": "({{PLURAL:$1|$1 baiti|1 baits|$1 baiti}})",
        "group-autoconfirmed": "Automātiski apstiprinātie dalībnieki",
        "group-bot": "Boti",
        "group-sysop": "Administratori",
+       "group-interface-admin": "Interfeisa administrators",
        "group-bureaucrat": "Birokrāti",
        "group-suppress": "Cenzētāji",
        "group-all": "(visi)",
        "grouppage-autoconfirmed": "{{ns:project}}:Automātiski apstiprināti dalībnieki",
        "grouppage-bot": "{{ns:project}}:Boti",
        "grouppage-sysop": "{{ns:project}}:Administratori",
+       "grouppage-interface-admin": "{{ns:project}}:Interfeisa administratori",
        "grouppage-bureaucrat": "{{ns:project}}:Birokrāti",
        "grouppage-suppress": "{{ns:project}}:Cenzētāji",
        "right-read": "Lasīt lapas",
        "right-deletedtext": "Apskatīt izdzēsto tekstu un izmaiņas starp izdzēstām versijām",
        "right-browsearchive": "Meklēt izdzēstās lapas",
        "right-undelete": "Atjaunot lapu",
-       "right-suppressrevision": "Apskatīt un atjaunot versijas, kas paslēptas no adminiem",
+       "right-suppressrevision": "Apskatīt un atjaunot visas lapas versijas",
        "right-suppressionlog": "Skatīt personīgos reģistrus",
        "right-block": "Bloķēt citus dalībniekus (lapu izmainīšana)",
        "right-blockemail": "Bloķēt citus dalībniekus (iespēja sūtīt e-pastu)",
index 64fbb7c..4ba5e6d 100644 (file)
        "customcssprotected": "Немате дозвола да ја менувате оваа страница со CSS бидејќи содржи туѓи лични нагодувања.",
        "customjsonprotected": "Немате дозвола да ја менувате оваа страница со JSON бидејќи содржи туѓи лични нагодувања.",
        "customjsprotected": "Немате дозвола да ја менувате оваа страница со JavaScript  бидејќи содржи туѓи лични нагодувања.",
-       "sitecssprotected": "Немате дозвола да ја менувате оваа страница со CSS бидејќи може да ги засегне сите посетители",
-       "sitejsonprotected": "Немате дозвола да ја менувате оваа страница со JSON бидејќи може да ги засегне сите посетители",
-       "sitejsprotected": "Немате дозвола да ја менувате оваа страница со JavaScript бидејќи може да ги засегне сите посетители",
+       "sitecssprotected": "Немате дозвола да ја менувате оваа страница со CSS бидејќи може да ги засегне сите посетители.",
+       "sitejsonprotected": "Немате дозвола да ја менувате оваа страница со JSON бидејќи може да ги засегне сите посетители.",
+       "sitejsprotected": "Немате дозвола да ја менувате оваа страница со JavaScript бидејќи може да ги засегне сите посетители.",
        "mycustomcssprotected": "Немате дозвола да ја уредувате оваа каскадна стилска страница (CSS).",
        "mycustomjsonprotected": "Немате дозвола да ја уредувате оваа страница со JSON.",
        "mycustomjsprotected": "Немате дозвола да ја уредувате оваа страница со JavaScript.",
        "right-sendemail": "Испраќање на е-пошта до други корисници",
        "right-managechangetags": "Создавање и (де)активирање на [[Special:Tags|ознаки]]",
        "right-applychangetags": "Задавање на [[Special:Tags|ознаки]] заедно со направените измени",
-       "right-changetags": "Ð\94одаваÑ\82е и отстранување на произволни [[Special:Tags|ознаки]] во поединечни преработки и дневнички записи",
+       "right-changetags": "Ð\94одаваÑ\9aе и отстранување на произволни [[Special:Tags|ознаки]] во поединечни преработки и дневнички записи",
        "right-deletechangetags": "Бришење [[Special:Tags|ознаки]] од базата",
        "grant-generic": "Збир права „$1“",
        "grant-group-page-interaction": "Опходување со страници",
        "filehist-filesize": "Големина",
        "filehist-comment": "Коментар",
        "imagelinks": "Употреба на податотеката",
-       "linkstoimage": "Ð\94о Ð¾Ð²Ð°Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека {{PLURAL:$1|води Ñ\81леднава Ñ\81Ñ\82Ñ\80аниÑ\86а|водаÑ\82 следниве $1 страници}}:",
-       "linkstoimage-more": "Ð\9fовеÑ\9cе Ð¾Ð´ {{PLURAL:$1|една Ñ\81Ñ\82Ñ\80аниÑ\86а Ðµ Ð¿Ð¾Ð²Ñ\80зана|$1 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð¿Ð¾Ð²Ñ\80зани}} Ñ\81о Ð¾Ð²Ð°Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека.\nСледниов Ñ\81пиÑ\81ок {{PLURAL:$1|Ñ\98а Ð¿Ñ\80икажÑ\83ва Ñ\81амо Ð¿Ñ\80ваÑ\82а Ð¿Ð¾Ð²Ñ\80зана Ñ\81Ñ\82Ñ\80аниÑ\86а|ги Ð¿Ñ\80икажÑ\83ва Ñ\81амо Ð¿Ñ\80виÑ\82е $1 Ð¿Ð¾Ð²Ñ\80зани Ñ\81Ñ\82Ñ\80аниÑ\86и}} Ð´Ð¾ Ð¾Ð²Ð°Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека.\nЦелоÑ\81ен Ñ\81пиÑ\81ок Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð´Ð¾Ð±Ð¸ете [[Special:WhatLinksHere/$2|тука]].",
+       "linkstoimage": "Ð\9fодаÑ\82оÑ\82екава Ñ\81е ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ð²Ð¾ {{PLURAL:$1|Ñ\81леднава Ñ\81Ñ\82Ñ\80аниÑ\86а|следниве $1 страници}}:",
+       "linkstoimage-more": "Ð\9fодаÑ\82оÑ\82екава Ñ\81е ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ð²Ð¾ Ð¿Ð¾Ð²ÐµÑ\9cе Ð¾Ð´ {{PLURAL:$1|една Ñ\81Ñ\82Ñ\80аниÑ\86а|$1 Ñ\81Ñ\82Ñ\80аниÑ\86и}}.\nСледниов Ñ\81пиÑ\81ок {{PLURAL:$1|Ñ\98а Ð¿Ñ\80икажÑ\83ва Ñ\81амо Ð¿Ñ\80ваÑ\82а Ñ\81Ñ\82Ñ\80аниÑ\86а|ги Ð¿Ñ\80икажÑ\83ва Ñ\81амо Ð¿Ñ\80виÑ\82е $1 Ñ\81Ñ\82Ñ\80аниÑ\86и}} Ñ\88Ñ\82о Ñ\98а ÐºÐ¾Ñ\80иÑ\81Ñ\82аÑ\82 Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82екаÑ\82а.\nЦелоÑ\81ен Ñ\81пиÑ\81ок Ñ\9cе Ð½Ð°Ñ\98дете [[Special:WhatLinksHere/$2|тука]].",
        "nolinkstoimage": "Нема страници што ја користат оваа податотека.",
        "morelinkstoimage": "Погледајте ги [[Special:WhatLinksHere/$1|останатите врски]] кон оваа податотека.",
        "linkstoimage-redirect": "$1 (пренасочување) $2",
        "confirm-unwatch-top": "Да ја отстранам страницава од набљудуваните?",
        "confirm-rollback-button": "ОК",
        "confirm-rollback-top": "Да ги отповикам уредувањата на страницава?",
+       "confirm-mcrundo-title": "Откажи промена",
+       "mcrundofailed": "Откажувањето не успеа",
+       "mcrundo-missingparam": "Недостасуваат задолжителни параметри за барањето.",
+       "mcrundo-changed": "Страницата е изменета откако ги гледавте разликите. Прегледајте ја новата промена.",
        "percent": "$1&#160;%",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "← претходна страница",
        "edit-error-long": "Грешки:\n\n$1",
        "revid": "преработка $1",
        "pageid": "назнака на страницата $1",
-       "interfaceadmin-info": "$1\n\nÐ\94озволиÑ\82е Ð·Ð° Ñ\83Ñ\80едÑ\83ваÑ\9aе Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82еки Ð¾Ð´ Ñ\82иповиÑ\82е CSS/JS/JSON Ð½Ð¸Ð· Ñ\86ело Ð²Ð¸ÐºÐ¸ Ð½ÐµÐ¾Ð´Ð°Ð¼Ð½Ð° Ð±ÐµÐ° Ð¾Ð´Ð²Ð¾ÐµÐ½Ð¸ Ð¾Ð´ Ð¿Ñ\80авоÑ\82о <code>editinterface</code>. Ð\94околкÑ\83 Ð½Ðµ Ð²Ð¸ Ðµ Ñ\98аÑ\81но Ð·Ð¾Ñ\88Ñ\82о Ð²Ð¸ Ñ\81е Ð¿Ð¾ÐºÐ°Ð¶Ñ\83ва Ð¾Ð²Ð°Ð° Ð³Ñ\80еÑ\88ка, Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\98Ñ\82е Ð½а [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nÐ\94озволаÑ\82а Ð·Ð° Ñ\83Ñ\80едÑ\83ваÑ\9aе Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82еки Ð¾Ð´ Ñ\82иповиÑ\82е CSS/JS/JSON Ð½Ð¸Ð· Ñ\86ело Ð²Ð¸ÐºÐ¸ Ð½ÐµÐ¾Ð´Ð°Ð¼Ð½Ð° Ðµ Ð¾Ð´Ð²Ð¾ÐµÐ½Ð¾ Ð¾Ð´ Ð¿Ñ\80авоÑ\82о <code>editinterface</code>. Ð\90ко Ð½Ðµ Ð²Ð¸ ÐµÑ\98 Ð°Ñ\81но Ð·Ð¾Ñ\88Ñ\82о Ñ\98а Ð´Ð¾Ð±Ð¸Ð²Ð°Ñ\82е Ð¾Ð²Ð°Ð° Ð³Ñ\80еÑ\88ка, Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\98Ñ\82е Ñ\98а Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "&lt;html&gt;-ознаките не може да се користат вон нормалните страници.",
        "gotointerwiki": "Го напуштате {{SITENAME}}",
        "gotointerwiki-invalid": "Укажаниот наслов е неважечки.",
index 98c7062..774c4e2 100644 (file)
        "ns-specialprotected": "പ്രത്യേകം എന്ന നാമമേഖലയിൽ വരുന്ന താളുകൾ തിരുത്താനാവുന്നവയല്ല.",
        "titleprotected": "[[User:$1|$1]] എന്ന ഉപയോക്താവ് ഈ താൾ ഉണ്ടാക്കുന്നതു നിരോധിച്ചിരിക്കുന്നു.\n<em>$2</em> എന്നതാണു അതിനു കാണിച്ചിട്ടുള്ള കാരണം.",
        "filereadonlyerror": "പ്രമാണ ശേഖരണി \"$2\" ഇപ്പോൾ \"കാണൽ-മാത്രം\" വിധത്തിൽ ക്രമീകരിച്ചിരിക്കുന്നതിനാൽ \"$1\" എന്ന പ്രമാണത്തിൽ മാറ്റം വരുത്താനാകില്ല.\n\nബന്ധിച്ച സിസ്റ്റം കാര്യ‌നിർവാഹക(ൻ) നൽകിയിരിക്കുന്ന കാരണം \"''$3''\" എന്നാണ്.",
+       "invalidtitle": "അസാധുവായ തലക്കെട്ട്",
        "invalidtitle-knownnamespace": "നാമമേഖല \"$2\", എഴുത്ത് \"$3\" എന്നിവ ഉപയോഗിച്ചുള്ള അസാധുവായ തലക്കെട്ട്",
        "invalidtitle-unknownnamespace": "അപരിചിതമായ നാമമേഖലാ സംഖ്യ $1, എഴുത്ത് \"$2\" എന്നിവ ഉപയോഗിച്ചുള്ള അസാധുവായ തലക്കെട്ട്",
        "exception-nologin": "ലോഗിൻ ചെയ്തിട്ടില്ല",
        "createacct-email-ph": "താങ്കളുടെ ഇമെയിൽ വിലാസം നൽകുക",
        "createacct-another-email-ph": "ഇമെയിൽ വിലാസം നൽകുക",
        "createaccountmail": "തൽക്കാലം ക്രമരഹിതമായി സൃഷ്ടിച്ച ഒരു രഹസ്യവാക്ക് ഉപയോഗിക്കുകയും അത് തന്നിരിക്കുന്ന ഇമെയിൽ വിലാസത്തിലേക്കയക്കുകയും ചെയ്യുക",
+       "createaccountmail-help": "രഹസ്യവാക്ക് മനസ്സിലാക്കാതെ തന്നെ മറ്റൊരാൾക്ക് അംഗത്വം സൃഷ്ടിച്ച് നൽകാൻ ഉപയോഗിക്കാവുന്നതാണ്.",
        "createacct-realname": "ശരിയായ പേര് (നിർബന്ധമില്ല)",
        "createacct-reason": "കാരണം",
        "createacct-reason-ph": "താങ്കൾ എന്തുകൊണ്ടാണ് മറ്റൊരു അംഗത്വം എടുക്കുന്നത്",
+       "createacct-reason-help": "അംഗത്വസൃഷ്ടി രേഖയിൽ കാണിക്കുന്ന സന്ദേശം",
        "createacct-submit": "താങ്കളുടെ അംഗത്വം സൃഷ്ടിക്കുക",
        "createacct-another-submit": "അംഗത്വമെടുക്കുക",
        "createacct-continue-submit": "അംഗത്വം സൃഷ്ടിക്കുന്നത് തുടരുക",
index a225307..28d4714 100644 (file)
@@ -62,7 +62,7 @@
        "thursday": "ꯁꯥꯒꯣꯜꯁꯦꯟ",
        "friday": "ꯏꯔꯥꯏ",
        "saturday": "ꯊꯥꯡꯖꯥ",
-       "sun": "ê¯\85ꯨê¯\83ꯤꯠ",
+       "sun": "ê¯\85ꯣꯡ",
        "mon": "ꯅꯤꯡ",
        "tue": "ꯂꯩ",
        "wed": "ꯌꯨꯝ",
        "tool-link-emailuser": "Email this {{GENDER:$1|user}}",
        "imagepage": "File lamai du ootlu",
        "mediawikipage": "ꯄꯥꯎꯖꯦꯜꯒꯤ ꯂꯥꯃꯥꯏꯗꯨ ꯎꯨꯠꯂꯨ",
-       "templatepage": "ê¯\87ꯦê¯\9dê¯\84ê¯\82ꯦꯠê¯\80ꯤ ê¯\82ꯥê¯\83ꯥê¯\8fê¯\97ꯨ ê¯\8eꯨꯠê¯\82ꯨ",
+       "templatepage": "ꯇꯦꯝꯄꯂꯦꯠꯀꯤ ꯂꯃꯥꯏꯗꯨ ꯎꯨꯠꯂꯨ",
        "viewhelppage": "ꯃꯇꯦꯡ ꯄꯥꯡꯅꯕꯒꯤ ꯂꯥꯃꯥꯏꯗꯨ ꯎꯨꯠꯂꯨ",
-       "categorypage": "Macahkhaiba lamai oootlooo",
+       "categorypage": "ꯃꯆꯥꯈꯥꯏꯕ ꯂꯃꯥꯏꯗꯨ ꯎꯨꯠꯂꯨ",
        "viewtalkpage": "ꯈꯟꯅꯥ ꯅꯩꯅꯕꯗꯨ ꯎꯨꯠꯂꯨ",
        "otherlanguages": "ꯑꯇꯣꯞꯄꯥ ꯂꯣꯟꯁꯤꯡꯗꯥ",
        "redirectedfrom": "(Redirected from $1)",
        "edithelp": "ꯁꯦꯝꯒꯠꯅꯕꯥ ꯃꯥꯇꯦꯡ",
        "helppage-top-gethelp": "ꯃꯥꯇꯦꯡ",
        "mainpage": "ꯃꯔꯨꯑꯣꯏꯕ ꯂꯃꯥꯏ",
-       "mainpage-description": "ꯃꯔꯨ ꯑꯣꯏꯕꯥ ꯂꯃꯥꯏ",
+       "mainpage-description": "ꯃꯔꯨꯑꯣꯏꯕ ꯂꯃꯥꯏ",
        "policy-url": "Project:ꯈꯣꯡꯊꯥꯡ",
        "portal": "ꯃꯤꯌꯥꯝꯒꯤ ꯄꯣꯔꯇꯦꯜ",
        "portal-url": "Project:ꯃꯤꯌꯥꯝꯒꯤ ꯄꯣꯔꯇꯦꯜ",
        "newmessageslinkplural": "{{PLURAL:$1|a new message|999=new messages}}",
        "newmessagesdifflinkplural": "ꯑꯔꯣꯏꯕꯥ {{PLURAL:$1|change|999=changes}}",
        "youhavenewmessagesmulti": "$1 ꯅꯪꯒꯤ ꯑꯅꯧꯕꯥ ꯃꯦꯁꯦꯁ",
-       "editsection": "ꯁꯦꯝꯒꯠꯄ",
-       "editold": "ꯁꯦꯝꯒꯠꯄ",
+       "editsection": "ꯁꯦꯝꯒꯠꯄ",
+       "editold": "ꯁꯦꯝꯒꯠꯄ",
        "viewsourceold": "ꯍꯧꯔꯛꯐꯝ ꯎꯨꯇꯂꯨ",
        "editlink": "ꯁꯦꯝꯒꯠꯄꯥ",
        "viewsourcelink": "ꯍꯧꯔꯛꯐꯝ ꯎꯨꯇꯂꯨ",
        "editsectionhint": "ꯁꯦꯝꯒꯠꯄꯒꯤ ꯁꯔꯨꯛ: $1",
        "toc": "ꯑꯌꯥꯎꯕꯥ",
        "showtoc": "ꯎꯨꯠꯂꯨ",
-       "hidetoc": "ꯂꯣꯇꯄ",
+       "hidetoc": "ꯂꯣꯇꯄ",
        "collapsible-collapse": "ꯁꯨꯞꯆꯤꯟꯕꯥ",
-       "collapsible-expand": "ꯄꯥꯛꯊꯣꯛꯄ",
+       "collapsible-expand": "ꯄꯥꯛꯊꯣꯛꯄ",
        "confirmable-confirm": "Are {{GENDER:$1|you}} sure?",
        "confirmable-yes": "ꯍꯣꯏ",
        "confirmable-no": "ꯅꯠꯇꯦ",
        "red-link-title": "$1 ꯂꯃꯥꯏꯗꯨ ꯂꯩꯇꯔꯦ",
        "sort-descending": "ꯑꯇꯦꯟꯕꯥ ꯍꯟꯊꯔꯛꯂꯤꯕꯥ",
        "sort-ascending": "ꯑꯇꯦꯟꯕꯥ ꯍꯦꯟꯒꯠꯂꯛꯂꯤꯕꯥ",
-       "nstab-main": "ê¯\82ꯥê¯\83ꯥê¯\8f",
-       "nstab-user": "Sijinnariba Lamai",
-       "nstab-media": "ꯃꯦꯗꯤꯌꯥꯒꯤ ꯂꯥꯃꯥꯏ",
-       "nstab-special": "MediaWiki:Bs-wikiadmin-mediawiki-akhannaba-lamai-text/mni",
-       "nstab-project": "ê¯\84ꯥꯡê¯\8aꯣê¯\9bê¯\80ê¯\97ê¯\95ꯥ ê¯\82ꯥê¯\83ꯥê¯\8f",
+       "nstab-main": "ꯂꯃꯥꯏ",
+       "nstab-user": "ꯁꯤꯖꯤꯟꯅꯔꯤꯕ ꯂꯃꯥꯏ",
+       "nstab-media": "ꯃꯦꯗꯤꯌꯥ ꯂꯃꯥꯏ",
+       "nstab-special": "ꯑꯈꯟꯅꯕ ꯂꯃꯥꯏ",
+       "nstab-project": "ꯄꯥꯡꯊꯣꯛꯀꯗꯕꯥ ꯂꯃꯥꯏ",
        "nstab-image": "ꯈꯣꯝꯖꯤꯟꯗꯨꯅꯥ ꯍꯥꯞꯐꯝ",
        "nstab-mediawiki": "ꯄꯥꯎꯖꯦꯜ",
        "nstab-template": "ꯇꯦꯝꯄꯂꯦꯠ",
        "stub-threshold-disabled": "ꯌꯥꯍꯟꯗꯔꯗ",
        "timezonelegend": "ꯃꯇꯝꯒꯤ ꯃꯐꯝ:",
        "localtime": "ꯂꯩꯀꯥꯏꯒꯤ ꯃꯇꯝ:",
-       "timezoneregion-africa": "ꯑꯐꯔꯤꯀ",
+       "timezoneregion-africa": "ê¯\91ê¯\90꯭ê¯\94ꯤê¯\80",
        "timezoneregion-america": "ꯑꯃꯦꯔꯤꯀ",
        "timezoneregion-antarctica": "ꯑꯟꯇꯥꯔꯇꯤꯀ",
        "timezoneregion-arctic": "ꯑꯥꯔꯇꯤꯛ",
        "filehist-comment": "ꯑꯄꯥꯝꯕꯥ ꯐꯣꯡꯗꯣꯛ ꯎ",
        "imagelinks": "ꯐꯥꯏꯜꯒꯤ ꯁꯤꯖꯤꯟꯅꯐꯝ",
        "linkstoimage": "ꯃꯇꯨꯡ ꯏꯟꯕ {{PLURAL:$1|ꯂꯥꯃꯥꯏꯁꯤꯖꯤꯟꯅꯕ|$1ꯂꯥꯃꯥꯏ ꯁꯤꯖꯤꯟꯅꯕ}} ꯃꯁꯤꯒꯤ ꯐꯥꯏꯜ:",
+       "linkstoimage-more": "$1 ꯗꯒꯤ ꯍꯦꯟꯅ {{PLURAL:$1|ꯂꯃꯥꯏ ꯁꯤꯖꯤꯟꯅꯐꯝ|page use}} ꯃꯁꯤ ꯐꯥꯏꯜ ꯫\nThe following list shows the {{PLURAL:$1|ꯑꯍꯥꯟꯕ ꯂꯃꯥꯏ|first $1 pages}} that use this file only.\nA [[Special:WhatLinksHere/$2|ꯄꯔꯤꯡ ꯄꯨꯂꯞ]] ꯁꯤ ꯐꯪꯉꯦ ꯫",
        "nolinkstoimage": "ꯃꯁꯤꯒꯤ ꯐꯥꯏꯜ ꯁꯤ ꯁꯤꯖꯤꯟꯅꯕ ꯂꯥꯃꯥꯏꯁꯤꯡ ꯂꯩꯇꯦ ꯫",
+       "linkstoimage-redirect": "$1 (ꯐꯥꯏꯜ ꯱ꯗꯒꯤ ꯱ ꯗ ꯂꯥꯛꯍꯟꯕ) $2",
        "sharedupload-desc-here": "This file is from $1 and may be used by other projects.\nThe description on its [$2 file description page] there is shown below.",
        "filepage-nofile": "ꯃꯁꯤꯒꯤ ꯐꯥꯏꯜ ꯃꯃꯤꯡ ꯁꯤ ꯒꯥ ꯃꯥꯟꯅꯕ ꯂꯩꯇꯦ",
        "upload-disallowed-here": "ꯃꯁꯤꯒꯤ ꯐꯥꯏꯜꯁꯤ ꯅꯪꯅꯥ ꯑꯃꯨꯛ ꯍꯟꯅꯥ ꯏꯕꯥ ꯌꯥꯔꯣꯏ",
        "logentry-move-move": "$1 {{GENDER:$2|moved}} page $3 to $4",
        "logentry-newusers-create": "User account $1 was {{GENDER:$2|created}}",
        "logentry-upload-upload": "$1 {{GENDER:$2|uploaded}} $3",
+       "logentry-upload-overwrite": "$1 {{GENDER:$2|ꯊꯥꯒꯠꯂꯦ}} $3 ꯒꯤ ꯑꯅꯧꯕ ꯕꯔꯖꯟ",
        "searchsuggest-search": "ꯊꯤꯔꯣ",
        "duration-days": "$1 {{PLURAL:$1|ꯅꯨꯃꯤꯌ|ꯅꯨꯃꯤꯠꯁꯤꯡ}}",
        "randomrootpage": "ꯆꯥꯡ ꯅꯥꯏꯗꯕ ꯂꯥꯃꯥꯏꯒꯤ ꯃꯔꯥ"
index 50f6e19..8c25263 100644 (file)
@@ -26,7 +26,8 @@
                        "Muhdnurhidayat",
                        "Jeluang Terluang",
                        "Zulfadli51",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "MNH48"
                ]
        },
        "tog-underline": "Garis bawah pautan:",
        "permissionserrorstext-withaction": "Anda tidak mempunyai keizinan untuk $2, atas {{PLURAL:$1|sebab|sebab-sebab}} berikut:",
        "contentmodelediterror": "Anda tidak boleh menyunting semakan ini kerana model kandungannya ialah <code>$1</code> padahal model kandungan semasa laman ini ialah <code>$2</code>.",
        "recreate-moveddeleted-warn": "'''Amaran: Anda sedang mencipta semula sebuah laman yang pernah dihapuskan.'''\n\nAnda harus mempertimbangkan perlunya menyunting laman ini.\nUntuk rujukan, yang berikut ialah log penghapusan bagi laman ini:",
-       "moveddeleted-notice": "Laman ini telah dihapuskan.\nLog penghapusan bagi laman ini dilampirkan di bawah untuk rujukan.",
+       "moveddeleted-notice": "Laman ini telah dihapuskan.\nLog penghapusan, perlindungan dan pemindahan bagi laman ini dilampirkan di bawah untuk rujukan.",
        "moveddeleted-notice-recent": "Maaf, laman ini baru-baru sahaja dihapuskan (dalam 24 jam yang lepas).\nLog penghapusan dan pemindahan untuk laman ini dinyatakan di bawah sebagai rujukan.",
        "log-fulllog": "Lihat log lengkap",
        "edit-hook-aborted": "Suntingan anda telah dibatalkan oleh penyangkuk. Tiada sebab diberikan.",
        "page_first": "awal",
        "page_last": "akhir",
        "histlegend": "Pemilihan perbezaan: tandakan butang radio bagi versi-versi yang ingin dibandingkan dan tekan butang ''enter'' atau butang di bawah.<br />\nPetunjuk: (kini) = perbezaan dengan versi terkini,\n(akhir) = perbezaan dengan versi sebelumnya, K = suntingan kecil.",
-       "history-fieldset-title": "Lihat sejarah",
+       "history-fieldset-title": "Cari semakan",
        "history-show-deleted": "Dihapuskan sahaja",
        "histfirst": "terawal",
        "histlast": "terkini",
        "recentchangeslinked-feed": "Perubahan berkaitan",
        "recentchangeslinked-toolbox": "Perubahan berkaitan",
        "recentchangeslinked-title": "Perubahan berkaitan dengan $1",
-       "recentchangeslinked-summary": "Laman khas ini menyenaraikan perubahan terkini bagi laman-laman yang dipaut. Laman-laman yang terdapat dalam senarai pantau anda ditandakan dengan '''teks tebal'''.",
+       "recentchangeslinked-summary": "Masukkan nama laman untuk melihat perubahan pada laman yang dipautkan ke atau dari laman tersebut. (Untuk melihat ahli kategori, masukkan {{ns:category}}:Nama kategori). Perubahan pada laman dalam [[Special:Watchlist|senarai pantau]] anda ditandakan dengan '''teks tebal'''.",
        "recentchangeslinked-page": "Nama laman:",
        "recentchangeslinked-to": "Paparkan perubahan pada laman yang mengandungi pautan ke laman yang diberikan",
        "recentchanges-page-added-to-category": "[[:$1]] ditambahkan kepada kategori",
        "filehist-filesize": "Saiz fail",
        "filehist-comment": "Komen",
        "imagelinks": "Penggunaan fail",
-       "linkstoimage": "{{PLURAL:$1|Laman|$1 buah laman}} berikut mengandungi pautan ke fail ini:",
+       "linkstoimage": "{{PLURAL:$1|Laman|$1 buah laman}} berikut menggunakan fail ini:",
        "linkstoimage-more": "Lebih daripada $1 laman mengandungi pautan ke fail ini.\nYang berikut ialah {{PLURAL:$1||$1}} pautan pertama ke fail ini.\nAnda boleh melihat [[Special:WhatLinksHere/$2|senarai penuh]].",
-       "nolinkstoimage": "Tiada laman yang mengandungi pautan ke fail ini.",
+       "nolinkstoimage": "Tiada laman yang menggunakan fail ini.",
        "morelinkstoimage": "Lihat [[Special:WhatLinksHere/$1|semua pautan]] ke fail ini.",
        "linkstoimage-redirect": "$1 (lencongan fail) $2",
        "duplicatesoffile": "{{PLURAL:$1|Fail|$1 buah fail}} berikut ialah salinan bagi fail ini ([[Special:FileDuplicateSearch/$2|butiran lanjut]]):",
        "whatlinkshere-prev": "{{PLURAL:$1|sebelumnya|$1 sebelumnya}}",
        "whatlinkshere-next": "{{PLURAL:$1|berikutnya|$1 berikutnya}}",
        "whatlinkshere-links": "← pautan",
-       "whatlinkshere-hideredirs": "$1 pelencongan",
+       "whatlinkshere-hideredirs": "$1 lencongan",
        "whatlinkshere-hidetrans": "$1 penyertaan",
        "whatlinkshere-hidelinks": "$1 pautan",
        "whatlinkshere-hideimages": "$1 pautan fail",
        "javascripttest": "Ujian JavaScript",
        "javascripttest-pagetext-unknownaction": "Tindakan \"$1\" tidak dikenali.",
        "javascripttest-qunit-intro": "Lihat [$1 pendokumenan ujian] di mediawiki.org.",
-       "tooltip-pt-userpage": "Laman pengguna anda",
+       "tooltip-pt-userpage": "Laman {{GENDER:|pengguna anda}}",
        "tooltip-pt-anonuserpage": "Laman pengguna bagi alamat IP anda",
-       "tooltip-pt-mytalk": "Laman perbincangan anda",
+       "tooltip-pt-mytalk": "Laman perbincangan {{GENDER:|anda}}",
        "tooltip-pt-anontalk": "Perbincangan mengenai penyuntingan daripada alamat IP anda",
-       "tooltip-pt-preferences": "Keutamaan saya",
+       "tooltip-pt-preferences": "Keutamaan {{GENDER:|anda}}",
        "tooltip-pt-watchlist": "Senarai laman yang anda pantau",
-       "tooltip-pt-mycontris": "Senarai sumbangan anda",
+       "tooltip-pt-mycontris": "Senarai sumbangan {{GENDER:|anda}}",
        "tooltip-pt-login": "Walaupun tidak wajib, anda digalakkan supaya log masuk.",
        "tooltip-pt-logout": "Log keluar",
        "tooltip-pt-createaccount": "Anda digalakkan untuk membuka akaun dan log masuk; namun begitu ianya tidak diwajibkan",
        "tooltip-t-recentchangeslinked": "Perubahan terkini bagi semua laman yang dipaut dari laman ini",
        "tooltip-feed-rss": "Suapan RSS bagi laman ini",
        "tooltip-feed-atom": "Suapan Atom bagi laman ini",
-       "tooltip-t-contributions": "Lihat senarai sumbangan pengguna ini",
+       "tooltip-t-contributions": "Senarai sumbangan {{GENDER:$1|pengguna ini}}",
        "tooltip-t-emailuser": "Kirim e-mel kepada pengguna ini",
        "tooltip-t-info": "Maklumat lanjut mengenai laman ini",
        "tooltip-t-upload": "Muat naik imej atau fail media",
        "version-libraries-description": "Keterangan",
        "version-libraries-authors": "Pengarang",
        "redirect": "Lencongkan mengikut ID fail, pengguna, halaman atau semakan",
-       "redirect-summary": "Halaman khas ini melencong kepada fail (dengan nama fail), halaman (dengan ID semakan atau ID halaman) atau halaman pengguna (dengan ID pengguna berangka). Penggunaan: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], atau [[{{#Special:Redirect}}/user/101]].",
+       "redirect-summary": "Halaman khas ini melencong kepada fail (dengan nama fail), halaman (dengan ID semakan atau ID halaman) atau halaman pengguna (dengan ID pengguna berangka), atau entri log (dengan ID log). Kegunaan: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], atau [[{{#Special:Redirect}}/user/101]].",
        "redirect-submit": "Pergi",
        "redirect-lookup": "Cari:",
        "redirect-value": "Nilai:",
        "feedback-thanks": "Terima kasih! Maklum balas anda telah dicatatkan pada laman \"[$2 $1]\".",
        "feedback-thanks-title": "Terima kasih!",
        "feedback-useragent": "Ejen pengguna:",
-       "searchsuggest-search": "Cari",
+       "searchsuggest-search": "Cari dalam {{SITENAME}}",
        "searchsuggest-containing": "mengandungi...",
        "api-error-badtoken": "Ralat dalaman: token tak elok.",
        "api-error-emptypage": "Anda tidak dibenarkan membuat laman baru yang kosong.",
index f1a5324..7017d5d 100644 (file)
        "about": "အကြောင်း",
        "article": "မာတိကာစာမျက်နှာ",
        "newwindow": "(ဝင်းဒိုးအသစ်တစ်ခုတွင် ဖွင့်ရန်)",
-       "cancel": "မ​လုပ်​တော့​",
+       "cancel": "မ​လုပ်​တော့​ပါ",
        "moredotdotdot": "နောက်ထပ်...",
        "morenotlisted": "ဤစာရင်းမှာ မပြည့်စုံနိုင်ပါ။",
        "mypage": "စာမျက်နှာ",
        "updatedmarker": "နောက်ဆုံးကြည့်ပြီးသည့်နောက်ပိုင်း တည်းဖြတ်ထားသည်။",
        "printableversion": "ပရင့်ထုတ်နိုင်သော ဗားရှင်း",
        "permalink": "ပုံ​သေ​လိပ်​စာ​",
-       "print": "ပရင့်",
+       "print": "ပရင့်ထုတ်",
        "view": "ကြည့်ရန်",
        "view-foreign": "$1 တွင် ကြည့်ရန်",
        "edit": "ပြင်ဆင်ရန်",
        "editinginterface": "<strong>သတိပေးချက်။</strong> သင်သည် ဆော့ဖ်ဝဲလ်၏ အသွင်အပြင်စာသားများကို အထောက်အကူပြုရာတွင် သုံးသော စာမျက်နှာအား တည်းဖြတ်နေသည်။\nဤစာမျက်နှာတွင် ပြောင်းလဲမှုများသည် ဤဝီကီရှိ အခြားအသုံးပြုသူများ၏ အသုံးပြုသူ အသွင်အပြင်များအပေါ် အကျိုးသက်ရောက်ပါလိမ့်မည်။",
        "translateinterface": "ဝီကီများအားလုံးအတွက် ဘာသာပြန်များကို ပေါင်းထည့်၊ ပြင်ဆင်ရန်အတွက် မီဒီယာဝီကီ၏ ဒေသတွင်းပြုမှု ပရောဂျက် [https://translatewiki.net/ translatewiki.net] ကို အသုံးပြုပါ။",
        "namespaceprotected": "'''$1''' စာညွှန်းဖြင့် စာမျက်နှာကို တည်းဖြတ်ရန် ခွင့်ပြုချက် မရှိပါ။",
+       "customcssprotected": "အခြားသောအသုံးပြုသူ၏ ပုဂ္ဂိုလ်ရေးအပြင်အဆင်များပါဝင်သည့် ဤ CSS စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
+       "customjsonprotected": "အခြားသောအသုံးပြုသူ၏ ပုဂ္ဂိုလ်ရေးအပြင်အဆင်များပါဝင်သည့် ဤ JSON စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
+       "customjsprotected": "အခြားသောအသုံးပြုသူ၏ ပုဂ္ဂိုလ်ရေးအပြင်အဆင်များပါဝင်သည့် ဤ JavaScript စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
+       "sitecssprotected": "ရောက်လာသူအားလုံးကို အကျိုးသက်ရောက်နိုင်သောကြောင့် ဤ CSS စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
+       "sitejsonprotected": "ရောက်လာသူအားလုံးကို အကျိုးသက်ရောက်နိုင်သောကြောင့် ဤ JSON စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
+       "sitejsprotected": "ရောက်လာသူအားလုံးကို အကျိုးသက်ရောက်နိုင်သောကြောင့် ဤ JavaScript စာမျက်နှာကို တည်းဖြတ်ရန် သင့်တွင် ခွင့်ပြုချက်မရှိပါ။",
        "mycustomcssprotected": "ဤ CSS စာမျက်နှာကို သင်တည်းဖြတ်ပြင်ဆင်ခွင့် မရှိပါ။",
+       "mycustomjsonprotected": "ဤ JSON စာမျက်နှာကို သင်တည်းဖြတ်ပြင်ဆင်ခွင့် မရှိပါ။",
        "mycustomjsprotected": "ဤ JavaScript စာမျက်နှာကို သင်တည်းဖြတ်ပြင်ဆင်ခွင့် မရှိပါ။",
        "myprivateinfoprotected": "သင်သည် သင်၏ ပုဂ္ဂိုလ်ရေးရာ အချက်အလက်များကို ပြင်ဆင်ခွင့် မရှိပါ။",
        "mypreferencesprotected": "သင်သည် သင်၏ ရွေးချယ်စရာများကို ပြင်ဆင်ခွင့်မရှိပါ။",
        "yourpasswordagain": "စကားဝှက် ပြန်​ရိုက်​ပါ -",
        "createacct-yourpasswordagain": "စကားဝှက်ကို အတည်ပြုပါ",
        "createacct-yourpasswordagain-ph": "စကားဝှက်ကို ထပ်မံ ရိုက်ထည့်ပါ",
-       "userlogin-remembermypassword": "Log in ဝင်ထားမည်",
+       "userlogin-remembermypassword": "အကောင့်ထဲ ဝင်ထားမည်",
        "userlogin-signwithsecure": "လုံခြုံသော ဆက်သွယ်မှုကို သုံးမည်",
        "cannotlogin-title": "လော့ဂ်အင် မဝင်ရောက်နိုင်ပါ",
        "cannotlogin-text": "အကောင့်ထဲ ဝင်ရောက်ခြင်းမှာ မဖြစ်နိုင်ပါ",
        "userlogin-resetpassword-link": "စကားဝှက် မေ့နေသလား။",
        "userlogin-helplink2": "log in အကူအညီ",
        "userlogin-loggedin": "သင်သည် {{GENDER:$1|$1}} အနေဖြင့် လော့အင်ဝင်ထားပြီး ဖြစ်သည်။ အခြားအသုံးပြုသူ အနေဖြင့် ဝင်ရောက်ရန် အောက်ပါပုံစံကို အသုံးပြုပါ။",
-       "userlogin-reauth": "သင်သည် {{GENDER:$1|}} ဖြစ်ကြောင်း အတည်ပြုရန်အတွက် အကောင့်ထဲ ထပ်မံဝင်ရောက်ရပါမည်။",
+       "userlogin-reauth": "သင် {{GENDER:$1|}}ဖြစ်ကြောင်း အတည်ပြုရန်အတွက် အကောင့်ထဲ ထပ်မံဝင်ရောက်ရပါမည်။",
        "userlogin-createanother": "အခြားအကောင့် ဖန်တီးရန်",
        "createacct-emailrequired": "အီးမေး လိပ်စာ",
        "createacct-emailoptional": "အီးမေး လိပ်စာ (ဖြည့်လိုက)",
        "blocked-mailpassword": "သင်၏ အိုင်ပီလိပ်စာကို တည်းဖြတ်ခြင်းမှ ပိတ်ပင်တားဆီးထားပါသည်။ အလွဲသုံးစားပြုလုပ်ခြင်းမှ ကာကွယ်ရန်အတွက် ဤအိုင်ပီလိပ်စာမှ စကားဝှက်အား ပြန်လည်ဆယ်ယူခြင်းကို ခွင့်မပြုထားပါ။",
        "mailerror": "မေးပို့ခြင်း အမှား - $1",
        "emailauthenticated": "သင့်အီးမေးလိပ်စာကို $2 နေ့ $3 အချိန်တွင် အတည်ပြုပြီး ဖြစ်သည်။",
+       "emailnotauthenticated": "သင်၏အီးမေးလ်လိပ်စာမှာ အတည်မပြုရသေးပါ။ အောက်ပါ မည်သည့်ဝိသေသလက္ခဏာများအတွက် အီးမေးလ်များ ပို့ဆောင်မည်မဟုတ်ပါ။",
+       "noemailprefs": "ဤဝိသေသလက္ခဏာများ အလုပ်ဖြစ်စေရန် သင်၏ရွေးချယ်စရာများထဲတွင် အီးမေးလ်လိပ်စာတစ်ခု သတ်မှတ်ပါ။",
        "emailconfirmlink": "အီးမေးကိုအတည်ပြုပါ",
        "cannotchangeemail": "ဤဝီကီတွင် အကောင့်အီးမေးလ်လိပ်စာကို မပြောင်းလဲနိုင်ပါ။",
        "emaildisabled": "ဤဆိုဒ်သည် အီးမေးလ်များ ပို၍မရနိုင်ပါ။",
        "passwordreset-emailelement": "အသုံးပြုသူအမည်:\n$1\n\nယာယီ စကားဝှက်:\n$2",
        "passwordreset-invalidemail": "တရားမဝင်သော အီးမေးလ်လိပ်စာ",
        "changeemail": "အီးမေးလိပ်စာ ပြင်ဆင် သို့ ဖယ်ရှားရန်",
+       "changeemail-no-info": "ဤစာမျက်နှာကို တိုက်ရိုက်အသုံးပြုနိုင်ရန်အတွက် Log in ဝင်ထားရပါမည်။",
        "changeemail-oldemail": "လက်ရှိ အီးမေးလ်လိပ်စာ:",
        "changeemail-newemail": "အီးမေးလ်လိပ်စာအသစ်:",
        "changeemail-none": "(ဗလာ)",
        "headline_tip": "အဆင့် ၂ ခေါင်းစီး",
        "nowiki_sample": "ဖောမတ်မလုပ်ထားသော စာများကို ဤနေရာတွင် ထည့်ရန်",
        "nowiki_tip": "ဝီကီပုံစံ ဖော်မတ်များကို လျစ်လျူရှုရန်",
+       "image_sample": "ဥပမာ.jpg",
        "image_tip": "Embedded ထည့်ထားသော ဖိုင်",
+       "media_sample": "ဥပမာ.ogg",
        "media_tip": "ဖိုင်လင့်",
        "sig_tip": "အချိန်ပါပြသော သင့်လက်မှတ်",
        "hr_tip": "မျဉ်းလဲ (စိစစ်သုံးရန်)",
        "summary": "အ​ကျဉ်း​ချုပ်​ -",
-       "subject": "အကြောင်းအရာ -",
+       "subject": "အကြောင်းအရာ:",
        "minoredit": "အရေးမကြီးသော ​ပြင်​ဆင်​မှု ​ဖြစ်​သည်​",
        "watchthis": "ဤစာမျက်နှာကို စောင့်ကြည့်ရန်",
        "savearticle": "ဤစာမျက်နှာကို သိမ်းရန်",
        "newarticletext": "သင်သည် မရှိသေးသော စာမျက်နှာလင့် ကို ရောက်လာခြင်းဖြစ်သည်။\nစာမျက်နှာအသစ်စတင်ရန် အောက်မှ သေတ္တာထဲတွင် စတင်ရိုက်ထည့်ပါ (နောက်ထပ် သတင်းအချက်အလက်များအတွက်[$1 အကူအညီ စာမျက်နှာ]ကို ကြည့်ပါ)။\nမတော်တဆရောက်လာခြင်း ဖြစ်ပါက ဘရောက်ဆာ၏ နောက်ပြန်ပြန်သွားသော <strong>back</strong> ခလုတ်ကို နှိပ်ပါ။",
        "anontalkpagetext": "----\n<em>ဤသည်မှာ အကောင့်မဖန်တီးသော သို့မဟုတ် အကောင့်မရှိသော အမည်မသိ အသုံးပြုသူတစ်ဦးအတွက် ဆွေးနွေးချက် စာမျက်နှာ ဖြစ်သည်။</em>\nသို့အတွက် ကျွန်ုပ်တို့အနေဖြင့် အိုင်ပီလိပ်စာဂဏန်းကိုသာ သူ/သူမ အားခွဲခြားနိုင်ရန် အသုံးပြုရပါသည်။\nထိုသို့သော အိုင်ပီလိပ်စာများကို အသုံးပြုသူများစွာမှ မျှဝေသုံးစွဲနေနိုင်ပါသည်။\nသင်သည် အမည်မသိ အသုံးပြုသူတစ်ဦးဖြစ်ပြီး မသက်ဆိုင်သော သုံးသပ်ဆွေးနွေးချက်များက သင့်အား အနှောက်အယှက်ဖြစ်စေပါက၊ ကျေးဇူးပြု၍ [[Special:CreateAccount|အကောင့်တစ်ခု ဖန်တီးပါ]] သို့မဟုတ် [[Special:UserLogin|လော့ဂ်အင်ဝင်ရောက်ပြီး]] အခြား အမည်မသိအသုံးပြုသူများနှင့် ရောထွေးနေနိုင်ခြင်းကို ရှောင်ကြဉ်နိုင်ပါသည်။",
        "noarticletext": "ဤစာမျက်နှာတွင် ယခုလက်ရှိတွင် မည်သည့်စာသားမှ မရှိပါ။\nသင်သည် အခြားစာမျက်နှာများတွင် [[Special:Search/{{PAGENAME}}|ဤစာမျက်နှာ၏ ခေါင်းစဉ်ကို ရှာနိုင်သည်]]၊ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ဆက်စပ်ရာ မှတ်တမ်းများကို ရှာနိုင်သည်]၊ သို့မဟုတ် [{{fullurl:{{FULLPAGENAME}}|action=edit}} ဤစာမျက်နှာကို ဖန်တီးနိုင်သည်]</span>။",
-       "noarticletext-nopermission": "ဤစာမျက်နှာတွင် ယခုလက်ရှိတွင် မည်သည့်စာသားမှ မရှိပါ။\nသင်သည် အခြားစာမျက်နှာများတွင် [[Special:Search/{{PAGENAME}}|ဤစာမျက်နှာ၏ ခေါင်းစဉ်ကို ရှာနိုင်သည်]]၊ သို့မဟုတ် <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ဆက်စပ်ရာ Logs များကို ရှာနိုင်သည်]</span>။ သို့သော် ဤစာမျက်နှာကို ဖန်တီးရန် သင့်တွင် အခွင့်အရေး မရှိပါ။",
+       "noarticletext-nopermission": "ဤစာမျက်နှာတွင် ယခုလက်ရှိတွင် မည်သည့်စာသားမှ မရှိပါ။\nသင်သည် အခြားစာမျက်နှာများတွင် [[Special:Search/{{PAGENAME}}|ဤစာမျက်နှာ၏ ခေါင်းစဉ်ကို ရှာနိုင်သည်]]၊ သို့မဟုတ် <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ဆက်စပ်ရာ မှတ်တမ်းများကို ရှာနိုင်သည်]</span>။ သို့သော် ဤစာမျက်နှာကို ဖန်တီးရန် သင့်တွင် အခွင့်အရေး မရှိပါ။",
        "userpage-userdoesnotexist": "အသုံးပြုသူအကောင့် \"$1\" ကို မှတ်ပုံတင် မလုပ်ရသေးပါ။ ဤစာမျက်နှာကို ဖန်တီး/တည်းဖြတ်လိုပါက ကျေးဇူးပြု၍ စစ်ဆေးပေးပါ။",
        "userpage-userdoesnotexist-view": "အသုံးပြုသူအကောင့် \"$1\" သည် မှတ်ပုံမတင်ထားပါ။",
        "blocked-notice-logextract": "ဤအသုံးပြုသူအား လတ်တလောတွင် ပိတ်ပင်ထားသည်။\nနောက်ဆုံးပိတ်ပင်မှု မှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "email-allow-new-users-label": "အသစ်စက်စက် အသုံးပြုသူများဆီမှ အီးမေးလ်လက်ခံရန် ခွင့်ပြုမည်",
        "email-blacklist-label": "ဤအသုံးပြုသူများ မိမိအား အီးမေးလ်ပို့ခြင်းကို ပိတ်ထားမည်",
        "prefs-searchoptions": "ရှာဖွေရန်",
-       "prefs-namespaces": "အမည်ညွှန်း",
+       "prefs-namespaces": "အမည်ညွှန်းများ",
        "default": "ပုံမှန်အားဖြင့်",
        "prefs-files": "ဖိုင်များ",
        "prefs-custom-css": "စိတ်ကြိုက် CSS",
        "recentchanges-label-plusminus": "စာမျက်နှာ အရွယ်အစားမှာ အောက်ပါ ဘိုက်ပမာဏ ပြောင်းလဲသွားခဲ့သည်",
        "recentchanges-legend-heading": "<strong>အညွှန်း:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|စာမျက်နှာသစ်များ စာရင်း]]ကိုလည်း ကြည့်ရန်)",
+       "recentchanges-legend-plusminus": "(<em>±၁၂၃</em>)",
        "recentchanges-submit": "ပြသရန်",
        "rcfilters-tag-remove": "'$1' ကို ဖယ်ရှားရန်",
        "rcfilters-legend-heading": "<strong>အတိုကောက်များ စာရင်း:</strong>",
        "rcfilters-highlighted-filters-list": "မီးမောင်းထိုးပြထားသည်: $1",
        "rcfilters-quickfilters": "သိမ်းထားသော စိစစ်မှုများ",
        "rcfilters-quickfilters-placeholder-title": "မည်သည့် စိစစ်မှုမှ မသိမ်းရသေးပါ",
+       "rcfilters-quickfilters-placeholder-description": "သင်၏စိစစ်မှု အပြင်အဆင်များကို သိမ်းဆည်းရန်နှင့် နောင်အခါပြန်အသုံးပြုရန်အတွက် သက်ဝင်နေသော စိစစ်မှုဧရိယာရှိ bookmark အိုင်ကွန်ကို ကလစ်ပါ။",
        "rcfilters-savedqueries-defaultlabel": "သိမ်းထားသော စိစစ်မှုများ",
        "rcfilters-savedqueries-rename": "အမည်ပြန်ပြောင်းရန်",
        "rcfilters-savedqueries-setdefault": "မူလပုံသေအဖြစ် သတ်မှတ်ရန်",
        "destfilename": "အလိုရှိရာဖိုင်အမည် -",
        "upload-maxfilesize": "အကြီးဆုံးဖိုင်အရွယ်အစား - $1",
        "upload-description": "ဖိုင်ဖော်ပြချက်",
-       "upload-options": "Upload တင်သည့် ရွေးချယ်မှုများ",
+       "upload-options": "ဖိုင်တင်သည့် ရွေးချယ်မှုများ",
        "watchthisupload": "ဤဖိုင်အား စောင့်ကြည့်ရန်",
        "upload-misc-error": "upload တင်ရာတွင် အမည်မသိ အမှား",
        "upload-dialog-title": "ဖိုင်​တင်​ရန်​",
        "listfiles_size": "အရွယ်အစား",
        "listfiles_description": "ဖော်ပြချက်",
        "listfiles_count": "ဗားရှင်းများ",
+       "listfiles-show-all": "ဖိုင်များ၏ ဗားရှင်းဟောင်း အပါအဝင်",
        "listfiles-latestversion": "လက်ရှိဗားရှင်း",
        "listfiles-latestversion-yes": "မှန်",
        "listfiles-latestversion-no": "မဟုတ်",
        "sharedupload-desc-create": "ဤဖိုင်သည် $1 မှဖြစ်ပြီး အခြားပရောဂျက်များတွင်လည်း အသုံးပြုနိုင်သည်။ [$2 ဖိုင်ဖော်ပြချက် စာမျက်နှာ]ပေါ်ရှိ ဖော်ပြချက်ကို တည်းဖြတ်နိုင်သည်။",
        "filepage-nofile": "ဤအမည်ဖြင့် မည်သည့်ဖိုင်မှ မရှိပါ။",
        "filepage-nofile-link": "ဤအမည်ဖြင့် မည်သည့်ဖိုင်မှ မရှိပါ။ သိုရာတွင် ယင်းကို [$1 upload တင်]နိုင်သည်။",
-       "uploadnewversion-linktext": "ဤဖိုင်၏ နောက်ဆုံး version ကို upload တင်ရန်",
+       "uploadnewversion-linktext": "ဤဖိုင်၏ နောက်ဆုံးဗားရှင်းကို အပ်လုပ်တင်ရန်",
        "shared-repo-from": "$1 ထံမှ",
        "shared-repo-name-wikimediacommons": "ဝီကီမီဒီယာ ကွန်မွန်းစ်",
        "upload-disallowed-here": "သင်သည် ဤဖိုင်အား ထပ်၍ ရေးသားမရနိုင်ပါ။",
        "filerevert-submit": "ပြောင်းရန်",
        "filedelete": "$1 ကိုဖျက်ပါ",
        "filedelete-legend": "ဖိုင်ကိုဖျက်ပါ",
+       "filedelete-intro": "သင်သည် <strong>[[Media:$1|$1]]</strong> ဖိုင်အား ယင်း၏ ရာဇဝင်နှင့်တကွ ဖျက်ပစ်တော့မည် ဖြစ်သည်။",
        "filedelete-comment": "အ​ကြောင်း​ပြ​ချက်:",
        "filedelete-submit": "ဖျက်",
        "filedelete-success": "'''$1''' ကို ဖျက်ပစ်လိုက်ပြီ။",
        "checkbox-select": "ရွေးချယ်: $1",
        "checkbox-all": "အားလုံး",
        "checkbox-none": "ဘာမှမရှိ",
+       "checkbox-invert": "ပြောင်းပြန်",
        "allpages": "စာမျက်နှာအားလုံး",
        "nextpage": "နောက်ထပ်စာမျက်နှာ ($1)",
        "prevpage": "ယခင် စာမျက်နှာ ($1)",
        "protectedpagemovewarning": "<strong>သတိပေးချက်။</strong> ဤစာမျက်နှာအား စီမံခန့်ခွဲသူအဆင့်ရှိသူများသာ ရွှေ့ပြောင်းနိုင်ရန် ကာကွယ်ထားသည်။\nနောက်ဆုံးမှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "semiprotectedpagemovewarning": "<strong>မှတ်ချက်။</strong> ဤစာမျက်နှာအား အလိုအလျောက် အတည်ပြုထားသော အသုံးပြုသူအဆင့်ရှိသူများသာ ရွှေ့ပြောင်းနိုင်ရန် ကာကွယ်ထားသည်။\nနောက်ဆုံးမှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "export": "စာမျက်နှာများကို Export ထုတ်ရန်",
-       "export-submit": "Export ထုတ်ရန်",
+       "export-submit": "တင်ပို့ရန်",
        "export-addcattext": "ကဏ္ဍမှ စာမျက်နှာများကို ပေါင်းထည့်ရန် -",
        "export-addcat": "ပေါင်းထည့်ရန်",
        "export-addnstext": "အမည်ညွှန်းမှ စာမျက်နှာများကို ပေါင်းထည့်ရန်",
        "allmessages": "စနစ်၏ သတင်းများ",
        "allmessagesname": "အမည်",
        "allmessagesdefault": "ပုံမှန် အသိပေးချက် စာသား",
+       "allmessagescurrent": "လက်ရှိ မက်ဆေ့စာသား",
        "allmessages-filter-legend": "စစ်ထုတ်ခြင်း",
        "allmessages-filter-unmodified": "မပြုပြင်ထားသော",
        "allmessages-filter-all": "အားလုံး",
        "pageinfo-robot-index": "ခွင့်ပြုပြီး",
        "pageinfo-robot-noindex": "ခွင့်မပြုထားပါ",
        "pageinfo-watchers": "စာမျက်နှာ စောင့်ကြည့်သူများ အရေအတွက်",
+       "pageinfo-visiting-watchers": "လတ်တလောတည်းဖြတ်မှုများကို အလည်လာသော စာမျက်နှာစောင့်ကြည့်သူများ အရေအတွက်",
        "pageinfo-few-watchers": "{{PLURAL:$1|စောင့်ကြည့်သူ|စောင့်ကြည့်သူများ}} $1 ဦးထက် နည်းသော",
        "pageinfo-redirects-name": "ဤစာမျက်နှာသို့ ပြန်ညွှန်းထားသည့် အရေအတွက်",
        "pageinfo-subpages-name": "ဤစာမျက်နှာ၏ စာမျက်နှာခွဲများ အရေအတွက်",
        "filedeleteerror-short": "ဖိုင်ဖျက်ရာတွင် အမှားအယွင်း - $1",
        "previousdiff": "← တည်းဖြတ်မူ အဟောင်း",
        "nextdiff": "ပိုသစ်သော တည်းဖြတ်မှု",
+       "imagemaxsize": "ပုံအရွယ်အစား ကန့်သတ်ချက်:<br /><em>(ဖိုင်ဖော်ပြချက် စာမျက်နှာများအတွက်)</em>",
+       "thumbsize": "နမူနာပုံငယ် အရွယ်အစား:",
        "widthheightpage": "$1 × $2, {{PLURAL:$3|စာမျက်နှာ|စာမျက်နှာများ}} $3 ခု",
        "file-info-size": "$1 × $2 pixels, ဖိုင်အရွယ်အစား - $3, MIME အမျိုးအစား $4",
        "file-info-size-pages": "$1 × $2 pixels, ဖိုင်အရွယ်အစား: $3, MIME အမျိုးအစား: $4, {{PLURAL:$5|စာမျက်နှာ|စာမျက်နှာများ}} $5 ခု",
        "show-big-image-other": "အခြား {{PLURAL:$2|ပုံရိပ်ပြတ်သားမှု|ပုံရိပ်ပြတ်သားမှု}}: $1။",
        "show-big-image-size": "$1 × $2 ပစ်ဇယ်",
        "newimages": "ပုံအသစ်များပြခန်း",
+       "newimages-summary": "ဤအထူးစာမျက်နှာမှာ နောက်ဆုံးတင်ထားသော ဖိုင်များကို ပြသပေးသည်။",
        "newimages-legend": "စိစစ်မှု",
        "newimages-label": "ဖိုင်အမည် (သို့ ယင်း၏အစိတ်အပိုင်း) -",
        "newimages-user": "အိုင်ပီလိပ်စာ သို့ အသုံးပြုသူအမည်",
        "newimages-newbies": "အကောင့်အသစ်များ၏ ပံ့ပိုးမှုများကိုသာ ပြရန်",
+       "newimages-showbots": "ဘော့များ တင်ထားသည်ကို ပြရန်",
        "newimages-mediatype": "မီဒီယာ အမျိုးအစား:",
        "noimages": "ကြည့်စရာဘာမှ မရှိပါ။",
        "ilsubmit": "ရှာဖွေရန်",
        "exif-datetimedigitized": "ဒီဂျစ်တယ်ပြောင်းသည့် နေ့ရက်နှင့် အချိန်",
        "exif-exposuretime-format": "$1 စက္ကန့် ($2)",
        "exif-shutterspeedvalue": "APEX ရှပ်တာ အမြန်နှုန်း",
+       "exif-lightsource": "အလင်းရင်းမြစ်",
        "exif-flash": "ဖလက်ရှ်",
        "exif-filesource": "ဖိုင်ရင်းမြစ်",
+       "exif-devicesettingdescription": "စက်ပစ္စည်းအပြင်အဆင်များ ဖော်ပြချက်",
+       "exif-gpslatituderef": "မြောက် သို့မဟုတ် တောင်လတ္တီကျု",
        "exif-gpslatitude": "လတ္တီကျု",
+       "exif-gpslongituderef": "အရှေ့ သို့မဟုတ် အနောက်လတ္တီကျု",
        "exif-gpslongitude": "လောင်ဂျီကျု",
        "exif-gpsaltitude": "အမြင့်",
+       "exif-gpstimestamp": "ဂျီပီအက်စ်အချိန် (အက်တော့မစ် နာရီ)",
+       "exif-gpstrack": "ရွေ့လျား လားရာ",
        "exif-gpsimgdirection": "ရုပ်ပုံ၏ လမ်းကြောင်း",
+       "exif-gpsareainformation": "ဂျီပီအက်စ် ဧရိယာအမည်",
        "exif-gpsdatestamp": "ဂျီပီအက်စ်ရက်စွဲ",
        "exif-objectname": "ခေါင်းစဉ်တို",
+       "exif-source": "ရင်းမြစ်",
        "exif-contact": "ဆက်သွယ်ရန် လိပ်စာ",
        "exif-languagecode": "ဘာသာစကား",
        "exif-iimcategory": "ကဏ္ဍ",
        "exif-lightsource-9": "ကောင်းမွန်သော ရာသီဥတု",
        "exif-lightsource-10": "တိမ်ထူသော ရာသီဥတု",
        "exif-lightsource-11": "အရိပ်",
+       "exif-lightsource-255": "အခြား အလင်းရင်းမြစ်",
        "exif-focalplaneresolutionunit-2": "လက်မှတ်",
        "exif-sensingmethod-1": "မသတ်မှတ်ထားသော",
        "exif-scenecapturetype-3": "ညနေပုံ",
        "fileduplicatesearch-filename": "ဖိုင်အမည်:",
        "fileduplicatesearch-submit": "ရှာဖွေရန်",
        "specialpages": "အထူး စာမျက်နှာများ",
-       "specialpages-note-top": "á\80\99á\80¾á\80\90á\80ºá\80\81á\80»á\80\80á\80º",
+       "specialpages-note-top": "á\80¡á\80\8aá\80½á\80¾á\80\94á\80ºá\80¸",
        "specialpages-note-restricted": "* ပုံမှန် အထူးစာမျက်နှာများ။\n* <span class=\"mw-specialpagerestricted\">ကန့်သတ်ထားသော အထူးစာမျက်နှာများ။</span>",
        "specialpages-group-maintenance": "ထိန်းသိမ်းမှု အစီရင်ခံချက်များ",
        "specialpages-group-other": "အခြားအထူးစာမျက်နှာများ",
        "tag-mw-undo": "နောက်ပြန် ပြန်ပြင်ခြင်း",
        "tags-title": "အမည်တွဲများ",
        "tags-tag": "အမည်တွဲ အမည်",
+       "tags-description-header": "ဆိုလိုရင်းအဓိပ္ပာယ် အပြည့်အစုံ",
+       "tags-source-header": "ရင်းမြစ်",
        "tags-active-yes": "မှန်",
        "tags-active-no": "မလုပ်ပါ",
        "tags-source-extension": "ဆော့ဝဲလ်မှ သတ်မှတ်ထားသော",
        "htmlform-submit": "ထည့်သွင်းရန်",
        "htmlform-reset": "ပြောင်းလဲထားသည်များ မလုပ်တော့ရန်",
        "htmlform-selectorother-other": "အခြား",
+       "htmlform-no": "မလုပ်ပါ",
        "htmlform-chosen-placeholder": "လုပ်ဆောင်ချက်တစ်ခု ရွေးချယ်ရန်",
        "htmlform-cloner-create": "ပို၍ ထပ်ပေါင်းရန်",
        "htmlform-cloner-delete": "ဖယ်ရှားရန်",
        "log-action-filter-rights": "အခွင့်အရေးပြောင်းလဲမှု အမျိုးအစား:",
        "log-action-filter-all": "အားလုံး",
        "log-action-filter-block-block": "ပိတ်ပင်",
+       "log-action-filter-block-unblock": "မပိတ်ပင်တော့ရန်",
        "log-action-filter-contentmodel-change": "မာတိကာမော်ဒယ်၏ ပြောင်းလဲမှု",
        "log-action-filter-delete-delete": "စာမျက်နှာ ဖျက်ပစ်ခြင်း",
        "log-action-filter-delete-event": "မှတ်တမ်း ဖျက်ပစ်ခြင်း",
index 0701bd7..37a9f4d 100644 (file)
        "table_pager_limit_submit": "Lâi-khì",
        "autosumm-blank": "Kā ia̍h ê loē-iông the̍h tiāu",
        "autoredircomment": "Choán khì [[$1]]",
+       "autosumm-removed-redirect": "Kā liân kòe [[$1]] ê choán-ia̍h the̍h-tiāu",
        "autosumm-changed-redirect-target": "Choán-ia̍h bo̍k-phiau kái [[$1]] kòe [[$2]] oân-sêng",
        "autosumm-new": "$1 ê ia̍h í-keng kiàn-li̍p",
        "watchlistedit-normal-submit": "Mài kàm-sī",
        "tag-filter": "[[Special:Tags|Piau-chhiam]] chhoē mi̍h:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|piau-chhiam}}]]: $2)",
        "tag-mw-new-redirect": "Sin choán-ia̍h",
+       "tag-mw-removed-redirect": "Choán-ia̍h the̍h-tiāu",
        "tag-mw-changed-redirect-target": "Choán-ia̍h bo̍k-phiau kái-piàn",
        "logentry-delete-delete_redir": "$1 ēng têng-siá lâi kā choán-ia̍h $3 {{GENDER:$2|thâi-tiāu}}",
        "logentry-move-move": "$1 {{GENDER:$2|sóa}} $3 chit ia̍h khì $4",
index 1918083..bc1eb57 100644 (file)
        "ns-specialprotected": "'E ppaggene spiciale nun se ponno cagnà.",
        "titleprotected": "'A criazione 'e stu titolo è stata bloccata 'a ll'utente [[User:$1|$1]].\n'A ragione è chesta: <em>$2</em>.",
        "filereadonlyerror": "Nun se può cagnà 'o file \"$1\" pecché 'o repository 'e file \"$2\" sta 'n modo sulo-lettura.\n\nL'ammenistratore 'e sistema che l'ave arrestato ha dato sta ragione: \"$3\".",
+       "invalidtitle": "Titolo invalido",
        "invalidtitle-knownnamespace": "Titolo nun buono c' 'o namespace \"$2\" e testo \"$3\"",
        "invalidtitle-unknownnamespace": "Titolo nun buono c' 'o namespace scanusciuto \"$1\" e testo \"$2\"",
        "exception-nologin": "Acciesso nun affettuato",
        "resetpass-submit-loggedin": "Cagna password",
        "resetpass-submit-cancel": "Scancella",
        "resetpass-wrong-oldpass": "'A password temporanea o attuale nun è bbona.\n'A password putesse avé cagnato, o pure s'è addimannata na password temporanea nova.",
-       "resetpass-recycled": "Pe piacere riabbiate 'a password e mettete na password differénte a chella 'e mmò.",
+       "resetpass-recycled": "Pe piacere cagnat 'a password e mettete na password differénte a chella 'e mmò.",
        "resetpass-temp-emailed": "Sì trasuto cu nu codece temporaneo, mannato via e-mail. Pe' fà cumpleta 'a riggistraziona, avite 'e abbià na password nova ccà:",
        "resetpass-temp-password": "Password temporanea:",
        "resetpass-abort-generic": "'O cagnamiento d' 'a password s'è spezzato 'a na stensione.",
        "resetpass-expired": "'A pasword è ammaturata. Avite 'e ffà na password nova pe putè trasì.",
-       "resetpass-expired-soft": "'A pasword toja è ammaturata e s'adda riabbià. Avite 'e scegliere na password nova mò, o ffà click ncopp'a \"{{int:authprovider-resetpass-skip-label}}\" p' 'a riabbià aroppo.",
-       "resetpass-validity-soft": "'A password toja nun è bbona: $1\n\nAvite 'e scegliere na password nova mò, o ffà click ncopp'a \"{{int:authprovider-resetpass-skip-label}}\" p' 'a riabbià aròppo.",
+       "resetpass-expired-soft": "'A pasword vuost è ammaturata e s'adda cagnà. Avite 'e scegliere na password nova mò, o ffà click ncopp'a \"{{int:authprovider-resetpass-skip-label}}\" p' 'a cagnà aroppo.",
+       "resetpass-validity-soft": "'A password toja nun è bbona: $1\n\nAvite 'e scegliere na password nova mò, o ffà click ncopp'a \"{{int:authprovider-resetpass-skip-label}}\" p' 'a cagnà aròppo.",
        "passwordreset": "Riabbìa 'a password",
        "passwordreset-text-one": "Ghienche stu modulo pe' ricevere na mmasciata e-mail c' 'a password temporanea.",
        "passwordreset-text-many": "{{PLURAL:$1|Ghienche uno d' 'e campe pe' ricevere na password temporanea cu na mmasciata e-mail.}}",
        "parser-template-loop-warning": "È stato scummigliato n'aniello d' 'o template: [[$1]]",
        "template-loop-category": "Paggene ca chiammassero a esse stisse",
        "template-loop-category-desc": "Sta paggena tenesse nu template ca chiammasse a essa stissa, cioè nu template addò sta mmescat' 'o template ca 'o chiammasse.",
+       "template-loop-warning": "<strong>Attenziò:</strong> sta paggena chiammass' a [[:$1]] e stu fatto 'a facess addeventà nu loop (na chiammata infinita d' 'o template).",
        "parser-template-recursion-depth-warning": "È arrivato 'o lemmeto 'e ricurzione d' 'o template ($1)",
        "language-converter-depth-warning": "'O fùto d' 'o lemmeto d' 'o scagnatòre 'e lengua è appassato ($1)",
        "node-count-exceeded-category": "Paggene addò 'o nummero 'e núrece è stato appassato",
        "expansion-depth-exceeded-warning": "Sta paggena ha appassato 'o lemmeto 'e futo 'e spansione",
        "parser-unstrip-loop-warning": "Scummigliato aniello Unstrip",
        "unstrip-depth-warning": "Appassato 'o lémmeto 'e ricurzione d' Unstrip ($1)",
+       "unstrip-depth-category": "Paggene addò ll' unstrip depth limit è assaje for o limmeto",
+       "unstrip-size-warning": "Appassato 'o lémmeto 'e gruosso d' Unstrip ($1)",
+       "unstrip-size-category": "Paggene addò 'o lémmeto 'e gruosso e unstrip è appassatt",
        "converter-manual-rule-error": "È stato scummigliato n'errore dint'a regola manuale 'e converziona 'e lengua",
        "undo-success": "'O cagnamiento se può annullà.\nPe' piacere vedete 'e differenze mmustate nfra 'e verziune pe' te ffà capace ca 'e cuntenute songo bbuone, e astipate 'e cagnamiente ccà abbascio pe' fernì e accussì turnà arreto.",
        "undo-failure": "Nun se può fà turnà arreto 'o cagnamiento pecché ce sta nu conflitto ch' 'e cagnamiente intermedie.",
+       "undo-main-slot-only": "Stu cagnamento nun se pò turnà arreto pecché ce vulessero 'e cuntenute for' 'o main slot.",
        "undo-norev": "Nun se può fà turnà arreto 'o cagnamiento pecché nun esiste o s'è scancellato.",
        "undo-nochange": "Pare ca sto cagnamiento s'ha scancellato già.",
        "undo-summary": "Scancella 'o càgno $1 'e [[Special:Contributions/$2|$2]] ([[User talk:$2|Chiàcchiera]])",
        "diff-multi-sameuser": "({{PLURAL:$1|Na verziona ntermedia|$1 verziune ntermedie}} 'e n'utente stisso nun {{PLURAL:$1|è mmustata|songo mmustate}})",
        "diff-multi-otherusers": "({{PLURAL:$1|Na virzione ntermedia|$1 verziune ntermedie}} 'a {{PLURAL:$2|n'at'utente|$2 n'ati ddoj'utente}} nun è mmustata)",
        "diff-multi-manyusers": "({{PLURAL:$1|Na virzione ntermedia|$1 verziune ntermedie}} 'a cchiù 'e $2 {{PLURAL:$2|utente|utente}} nun è mmustata)",
+       "diff-paragraph-moved-tonew": "'O paragrafo è stato spustat. Facite clic pe' puté cagnà dint'a nova posiziona.",
        "difference-missing-revision": "{{PLURAL:$2|Na virziona|$2 verziune}} 'e sta differenza ($1) {{PLURAL:$2|nun è stata truvata|nun so' state truvate}}.\n\nChest'è succiesso quanno s'è secutato nu diff obsoleto a na paggena scancellata.\n'E dettaglie se ponno truvà dint'a [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 'o riggistro 'e scancellamiente].",
        "searchresults": "Risultato d''a recerca",
        "searchresults-title": "Ascià risultate ppe \"$1\"",
index dee448f..39f7825 100644 (file)
        "confirm-unwatch-top": "Fjern denne siden fra overvåkningslisten din?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Tilbakestill redigeringer på denne siden?",
+       "confirm-mcrundo-title": "Fjern en endring",
+       "mcrundofailed": "Fjerning mislyktes",
+       "mcrundo-missingparam": "Manglende parameter ved forespørsel.",
+       "mcrundo-changed": "Siden har blitt endret siden du sist så diffen. Sjekk også den nye endringen.",
        "ellipsis": "…",
        "percent": "$1&nbsp;%",
        "quotation-marks": "«$1»",
index e8d6c7a..42bb96c 100644 (file)
        "protect-summary-cascade": "kaskade",
        "protect-expiring": "löp aof op $1 (UTC)",
        "protect-expiring-local": "vervölt op $1",
-       "protect-expiry-indefinite": "onbepark",
+       "protect-expiry-indefinite": "unbetöänd",
        "protect-cascade": "Kaskadebeveiliging (beveilig alle ziejen en mallen die in disse zied op-eneumen bin)",
        "protect-cantedit": "Je kunnen t beveiligingsnivo van disse zied niet wiezigen, umda'j gien rechten hebben um t te bewarken.",
        "protect-othertime": "Aandere tiedsduur:",
index 1e731ee..8842f3a 100644 (file)
@@ -89,7 +89,8 @@
                        "Ooswesthoesbes",
                        "MarcoSwart",
                        "Pahles",
-                       "Optilete"
+                       "Optilete",
+                       "Goefie"
                ]
        },
        "tog-underline": "Verwijzingen onderstrepen:",
        "customcssprotected": "U kunt deze CSS-pagina niet bewerken, omdat die persoonlijke instellingen van een andere gebruiker bevat.",
        "customjsonprotected": "U kunt deze JSONpagina niet bewerken, omdat die persoonlijke instellingen van een andere gebruiker bevat.",
        "customjsprotected": "U kunt deze JavaScriptpagina niet bewerken, omdat die persoonlijke instellingen van een andere gebruiker bevat.",
-       "sitecssprotected": "U hebt geen toestemming om deze CSS-pagina te bewerken omdat het invloed kan hebben op alle bezoekers",
-       "sitejsonprotected": "U hebt geen toestemming om deze JSON-pagina te bewerken omdat het invloed kan hebben op alle bezoekers",
-       "sitejsprotected": "U hebt geen toestemming om deze JavaScript-pagina te bewerken omdat het invloed kan hebben op alle bezoekers",
+       "sitecssprotected": "U hebt geen toestemming om deze CSS-pagina te bewerken omdat het invloed kan hebben op alle bezoekers.",
+       "sitejsonprotected": "U hebt geen toestemming om deze JSON-pagina te bewerken omdat het invloed kan hebben op alle bezoekers.",
+       "sitejsprotected": "U hebt geen toestemming om deze JavaScript-pagina te bewerken omdat het invloed kan hebben op alle bezoekers.",
        "mycustomcssprotected": "U hebt geen rechten om deze CSS-pagina te bewerken.",
        "mycustomjsonprotected": "U hebt geen rechten om deze JSONpagina te bewerken.",
        "mycustomjsprotected": "U hebt geen rechten om deze JavaScriptpagina te bewerken.",
        "group-autoconfirmed": "autobevestigde gebruikers",
        "group-bot": "bots",
        "group-sysop": "beheerders",
-       "group-interface-admin": "interfacemoderatoren",
+       "group-interface-admin": "interfacebeheerders",
        "group-bureaucrat": "bureaucraten",
        "group-suppress": "toezichthouders",
        "group-all": "(iedereen)",
        "filehist-comment": "Opmerking",
        "imagelinks": "Bestandsgebruik",
        "linkstoimage": "Dit bestand wordt op de volgende {{PLURAL:$1|pagina|$1 pagina's}} gebruikt:",
-       "linkstoimage-more": "Meer dan $1 {{PLURAL:$1|pagina gebruikt|pagina's gebruiken}} dit bestand.\nDe volgende lijst geeft alleen de eerste {{PLURAL:$1|pagina|$1 pagina's}} die dit bestand gebruiken weer.\nEr is ook een [[Special:WhatLinksHere/$2|volledige lijst]] beschikbaar.",
+       "linkstoimage-more": "Meer dan $1 {{PLURAL:$1|page uses|pagina's gebruiken}} dit bestand.\nDe volgende lijst geeft alleen de {{PLURAL:$1|first page|eerste $1 pagina's}} weer die dit bestand gebruiken.\nEr is ook een [[Special:WhatLinksHere/$2|volledige lijst]] beschikbaar.",
        "nolinkstoimage": "Geen enkele pagina gebruikt dit bestand.",
        "morelinkstoimage": "[[Special:WhatLinksHere/$1|Meer koppelingen]] naar dit bestand bekijken.",
        "linkstoimage-redirect": "$1 (bestandsdoorverwijzing) $2",
        "confirm-unwatch-top": "Deze pagina verwijderen uit uw volglijst?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Bewerkingen op deze pagina ongedaan maken?",
+       "confirm-mcrundo-title": "Een wijziging ongedaan maken",
+       "mcrundofailed": "Ongedaan maken mislukt",
+       "mcrundo-missingparam": "Er ontbreken nodige parameters in het verzoek.",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← vorige pagina",
        "imgmultipagenext": "volgende pagina →",
index 154264a..2900e99 100644 (file)
        "rcfilters-watchlist-markseen-button": "Merk alle endringar som sette",
        "rcfilters-watchlist-edit-watchlist-button": "Endra lista over sider du overvaker",
        "rcfilters-watchlist-showupdated": "Sider du ikkje har vitja sidan dei vart endra er viste med <strong>feit</strong> skrift.",
+       "rcfilters-filter-showlinkedfrom-label": "Vis endringar på sider det vert lenkja til på sida",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Sider som det vert lenkja til på</strong> den valde sida",
+       "rcfilters-filter-showlinkedto-label": "Vis endringar på sider som lenkjar til sida",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Sider som lenkjar til</strong> den valde sida",
        "rcnotefrom": "Nedanfor er endringane gjorde sidan <strong>$2</strong> viste (opp til <strong>$1</strong> stykke)",
        "rclistfromreset": "Nullstill datoval",
        "rclistfrom": "Vis nye endringar sidan $3 $2",
        "logentry-delete-delete": "$1 {{GENDER:$2|sletta}} sida $3",
        "logentry-delete-delete_redir": "$1 {{GENDER:$2|sletta}} omdirigeringa $3 gjennom overskriving",
        "logentry-delete-restore": "$1 {{GENDER:$2|attoppretta}} sida $3 ($4)",
+       "logentry-delete-restore-nocount": "$1 {{GENDER:$2|attoppretta}} sida $3",
        "restore-count-revisions": "{{PLURAL:$1|éin versjon|$1 versjonar}}",
        "logentry-delete-event": "$1 {{GENDER:$2|endra}} synlegdomen av {{PLURAL:$5|éi loggoppføring|$5 loggoppføringar}} på $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|endra}} synlegdomen til {{PLURAL:$5|éin versjon|$5 versjonar}} på sida $3: $4",
index e9d6018..ade2ce4 100644 (file)
        "logout": "Mag-log out",
        "userlogout": "Mag logout",
        "notloggedin": "E maka login",
+       "userlogin-noaccount": "Ala kang akawnt?",
        "createaccount": "Maglalang kang account",
        "createaccountmail": "kapamilatan ning e-mail",
        "badretype": "Ding password a linub mu ela mibabage.",
        "createaccount-text": "Ating miglalang account para king kekang e-mail address king {{SITENAME}} ($4) a maki lagyung \"$2\", ampong password a \"$3\".\nKailangan mung mag-login ngeni ba meng ayalilan ing kekang password.\n\nMalyari meng e pansinan ining mensahi, nung pamagkamali ing pamaglalang na niting account.",
        "loginlanguagelabel": "Amanu: $1",
        "pt-login-button": "Maglagda (log in)",
+       "pt-createaccount": "Maglalang akawnt",
+       "pt-userlogout": "Lumuwal (''log out'')",
        "changepassword": "Alilan ya ing password",
        "resetpass_announce": "Gagamit kang pansamantalang code a me e-mail keka aniang mig-login ka.\nBang mayari ing kekang pamag-login, kailangan mung mangibiling bayung password keni:",
        "resetpass_header": "Alilan ya ing password",
        "emailsent": "Ing e-mail miparala ya",
        "emailsenttext": "Ing e-mail message mu miparala ne.",
        "watchlist": "Deng kanakung babanten",
-       "mywatchlist": "Deng kakung babanten",
+       "mywatchlist": "Talangbabanten",
        "nowatchlist": "Ala yang laman ing kekang tala ring babanten (watchlist).",
        "watchlistanontext": "Paki $1 ba mong akit o a-edit deng laman ning kekang tala ring babanten (watchlist).",
        "watchnologin": "E maka-login",
        "blanknamespace": "(Pun)",
        "contributions": "{{GENDER:$1|User}} deng ambag",
        "contributions-title": "Deng ambag da reng talagamit para king $1",
-       "mycontris": "Deng kakung ambag",
+       "mycontris": "Deng ambag",
        "anoncontribs": "Deng ambag",
        "contribsub2": "Para $1 ($2)",
        "nocontribs": "Alang pamagbayung pareu/tutud kareng kundisiung deti.",
        "tooltip-n-portal": "Tungkul keng proyektu, nanung agawa mu, nung nu ka makapanintun king kailangan mu",
        "tooltip-n-currentevents": "Maintun kang impormasiun a maki kaugnayan kareng mibabalitang kasulungsungan a malilyari",
        "tooltip-n-recentchanges": "Ing tala da reng bayung mengayalili king wiki.",
-       "tooltip-n-randompage": "Maglulan ka andiang sanung bulung",
+       "tooltip-n-randompage": "Maglulan ka andyang sanung bulung",
        "tooltip-n-help": "Ing lugal nung nu malyaring abalu.",
        "tooltip-t-whatlinkshere": "Tala da reng eganaganang bulung ning wiki a pakasuglung keni",
        "tooltip-t-recentchangeslinked": "Bayung mengayalili kareng bulung a makasuglung ibat king bulung a ini",
index 3faa6ba..e4dfc68 100644 (file)
        "copyrightwarning2": "Wszelki wkład na {{SITENAME}} może być edytowany, zmieniany lub usunięty przez innych użytkowników.\nJeśli nie chcesz, żeby Twój tekst był dowolnie zmieniany przez każdego i rozpowszechniany bez ograniczeń, nie umieszczaj go tutaj.<br />\nZapisując swoją edycję, oświadczasz, że ten tekst jest Twoim dziełem lub pochodzi z materiałów dostępnych na warunkach ''domeny publicznej'' lub kompatybilnych (zobacz także $1).\n'''PROSZĘ NIE WPROWADZAĆ MATERIAŁÓW CHRONIONYCH PRAWEM AUTORSKIM BEZ POZWOLENIA WŁAŚCICIELA!'''",
        "editpage-cannot-use-custom-model": "Model zawartości tej strony nie może być zmieniony.",
        "longpageerror": "'''Błąd! Wprowadzony przez Ciebie tekst ma {{PLURAL:$1|1 kilobajt|$1 kilobajty|$1 kilobajtów}}. Długość tekstu nie może przekraczać {{PLURAL:$2|1 kilobajt|$2 kilobajty|$2 kilobajtów}}. Tekst nie może być zapisany.'''",
-       "readonlywarning": "<strong>Uwaga! Baza danych została zablokowana do celów administracyjnych. W tej chwili nie można zapisać nowej wersji strony. Jeśli chcesz, możesz skopiować ją do pliku, aby móc zapisać ją później.</strong>\n\nAdministrator systemu, który zablokował bazę, podał następujący powód: $1",
+       "readonlywarning": "<strong>Uwaga! Baza danych została zablokowana w celach konserwacyjnych i w tej chwili nie można zapisać nowej wersji strony. Jeśli chcesz, możesz skopiować ją do pliku, aby móc zapisać ją później.</strong>\n\nAdministrator systemu, który zablokował bazę, podał następujący powód: $1",
        "protectedpagewarning": "'''Uwaga! Możliwość modyfikacji tej strony została zabezpieczona. Mogą ją edytować jedynie użytkownicy z uprawnieniami administratora.'''\nOstatni wpis z rejestru jest pokazany poniżej.",
        "semiprotectedpagewarning": "<strong>Uwaga:</strong>  Ta strona została zabezpieczona i tylko zarejestrowani użytkownicy mogą ją edytować.\nOstatni wpis z rejestru jest pokazany poniżej:",
        "cascadeprotectedwarning": "<strong>Uwaga:</strong> Ta strona została zabezpieczona i tylko użytkownicy z [[Special:ListGroupRights|określonymi uprawnieniami]] mogą ją edytować. Została ona osadzona w {{PLURAL:$1|następującej stronie, która została zabezpieczona|następujących stronach, które zostały zabezpieczone}} z włączoną opcją dziedziczenia:",
        "confirm-unwatch-top": "Usunąć tę stronę z listy obserwowanych?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Wycofać edycje tej strony?",
+       "mcrundofailed": "Cofnięcie nie powiodło się",
        "percent": "$1%",
        "quotation-marks": "„$1”",
        "imgmultipageprev": "← poprzednia strona",
index 476a8bc..9a0b8f6 100644 (file)
        "customcssprotected": "Você não tem permissão para editar esta página CSS, porque ele contém configurações pessoais de outro usuário.",
        "customjsonprotected": "Você não tem permissão para editar esta página JSON porque ela contém as configurações pessoais de outro usuário.",
        "customjsprotected": "Você não tem permissão para editar esta página de JavaScript, porque ele contém configurações pessoais de outro usuário.",
-       "sitecssprotected": "Não tem permissão para editar esta página de CSS porque ela pode afetar todos os visitantes",
-       "sitejsonprotected": "Não tem permissão para editar esta página de JSON porque ela pode afetar todos os visitantes",
-       "sitejsprotected": "Não tem permissão para editar esta página de JavaScript porque ela pode afetar todos os visitantes",
+       "sitecssprotected": "Não tem permissão para editar esta página de CSS porque ela pode afetar todos os visitantes.",
+       "sitejsonprotected": "Não tem permissão para editar esta página de JSON porque ela pode afetar todos os visitantes.",
+       "sitejsprotected": "Você não tem permissão para editar esta página JavaScript porque ela pode afetar todos os visitantes.",
        "mycustomcssprotected": "Você não tem permissão para editar esta página CSS",
        "mycustomjsonprotected": "Você não tem permissão para editar esta página JSON.",
        "mycustomjsprotected": "Você não tem permissão para editar esta página JavaScript",
        "confirm-unwatch-top": "Remover esta página das páginas vigiadas?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter edições nesta página?",
+       "confirm-mcrundo-title": "Desfazer uma mudança",
+       "mcrundofailed": "A reversão falhou",
+       "mcrundo-missingparam": "Faltam parâmetros obrigatórios no pedido.",
+       "mcrundo-changed": "Esta página foi alterada desde que começou a ver as diferenças. Reveja a nova mudança, por favor.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
index c22e638..3fe7135 100644 (file)
        "customcssprotected": "Não tem permissão para editar esta página de CSS porque a página contém as configurações pessoais de outro utilizador.",
        "customjsonprotected": "Não tem permissão para editar esta página de JSON porque a página contém as configurações pessoais de outro utilizador.",
        "customjsprotected": "Não tem permissão para editar esta página de JavaScript porque a página contém as configurações pessoais de outro utilizador.",
-       "sitecssprotected": "Não tem permissão para editar esta página de CSS porque ela pode afetar todos os visitantes",
-       "sitejsonprotected": "Não tem permissão para editar esta página de JSON porque ela pode afetar todos os visitantes",
-       "sitejsprotected": "Não tem permissão para editar esta página de JavaScript porque ela pode afetar todos os visitantes",
+       "sitecssprotected": "Não tem permissão para editar esta página de CSS porque ela pode afetar todos os visitantes.",
+       "sitejsonprotected": "Não tem permissão para editar esta página de JSON porque ela pode afetar todos os visitantes.",
+       "sitejsprotected": "Não tem permissão para editar esta página de JavaScript porque ela pode afetar todos os visitantes.",
        "mycustomcssprotected": "Não tem permissão para editar esta página de CSS.",
        "mycustomjsonprotected": "Não tem permissão para editar esta página de JSON.",
        "mycustomjsprotected": "Não tem permissão para editar esta página de JavaScript.",
        "confirm-unwatch-top": "Remover esta página da lista de páginas vigiadas?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter as edições desta página?",
+       "confirm-mcrundo-title": "Desfazer uma mudança",
+       "mcrundofailed": "A reversão falhou",
+       "mcrundo-missingparam": "Faltam parâmetros obrigatórios no pedido.",
+       "mcrundo-changed": "Esta página foi alterada desde que começou a ver as diferenças. Reveja a nova mudança, por favor.",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← página anterior",
        "imgmultipagenext": "página seguinte →",
        "edit-error-long": "Erros:\n\n$1",
        "revid": "revisão $1",
        "pageid": "identificador de página $1",
-       "interfaceadmin-info": "$1\n\nAs permissões de edição de ficheiros CSS/JS/JSON que afetam todo o ''site'' foram recentemente separadas do privilégio <code>editinterface</code>. Se não compreende porque está a receber este erro, consulte [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "A edição de ficheiros CSS/JS/JSON foi recentemente limitada a membros do grupo [[{{int:grouppage-interface-admin}}|{{int:group-interface-admin}}]]. Para mais informações, consulte [[m:Creation of separate user group for editing sitewide CSS/JS]].",
        "rawhtml-notallowed": "As etiquetas &lt;html&gt; não podem ser utilizadas fora de páginas normais.",
        "gotointerwiki": "A sair da wiki {{SITENAME}}",
        "gotointerwiki-invalid": "O título especificado é inválido.",
index b6558b6..8330801 100644 (file)
                        "Avatar6",
                        "Akapochtli",
                        "ديفيد",
-                       "Daimona Eaytoy"
+                       "Daimona Eaytoy",
+                       "A2093064"
                ]
        },
        "sidebar": "{{notranslate}}",
        "edit": "The text of the tab going to the edit form. When the page is protected, you will see {{msg-mw|Viewsource}}. Should be in the infinitive mood.\n\nSee also:\n* {{msg-mw|Edit}}\n* {{msg-mw|Accesskey-ca-edit}}\n* {{msg-mw|Tooltip-ca-edit}}\n{{Identical|Edit}}",
        "edit-local": "The text on the tab going to the edit form for the local description page of a file from a foreign file repository (e.g. Wikimedia Commons). Should be in the infinitive mood.\n\nSee also:\n* {{msg-mw|Edit}}\n* {{msg-mw|Create-local}}",
        "create": "The text on the tab of the edit form on unexisting pages starts editing them. Should be in the infinitive mood.\n\n{{Identical|Create}}",
-       "create-local": "The text on the tab going to the creation form for the (not yet existing) local description page of a file from a foreign file repository (e.g. Wikimedia Commons). Should be in the infinitive mood.\n\nSee also:\n* {{msg-mw|Create}}\n* {{msg-mw|Edit-local}}",
+       "create-local": "The text on the tab going to the creation form for the (not yet existing) local description page of a file from a foreign file repository (e.g. Wikimedia Commons). Should be in the infinitive mood.\n\nSee also:\n* {{msg-mw|Create}}\n* {{msg-mw|Edit-local}}\n* {{msg-mw|Visualeditor-ca-createlocaldescriptionsource}}",
        "delete": "Name of the Delete tab shown for admins. Should be in the infinitive mood.\n\nSee also:\n* {{msg-mw|Delete}}\n* {{msg-mw|Accesskey-ca-delete}}\n* {{msg-mw|Tooltip-ca-delete}}\n{{Identical|Delete}}",
        "undelete_short": "It is tab label. It's really can be named ''nstab-undelete''. Parameters:\n* $1 - number of edits",
        "viewdeleted_short": "Tab label for the undelete button when the user has permission to view the deleted history but not undelete.\n\nParameters:\n* $1 - number of edits",
        "searchdisabled": "{{doc-singularthey}}\nIn this sentence, \"their indexes\" refers to \"Google's indexes\".\n\nShown on [[Special:Search]] when the internal search is disabled.",
        "googlesearch": "{{notranslate}}\nShown when [[mw:Manual:$wgDisableTextSearch|$wgDisableTextSearch]] is set to true and no [[mw:Manual:$wgSearchForwardUrl|$wgSearchForwardUrl]] is set.\n\nParameters:\n* $1 - the search term\n* $2 - \"UTF-8\" (hard-coded)\n* $3 - the message {{msg-mw|Searchbutton}}",
        "search-error": "Shown when an error has occurred when performing a search. Parameters:\n* $1 - the localized error that was returned",
-       "search-warning": "Shown when a warning has occured when performing a search. Parameters:\n* $1 - the localized warning that was returned.",
+       "search-warning": "Shown when a warning has occurred when performing a search. Parameters:\n* $1 - the localized warning that was returned.",
        "opensearch-desc": "{{ignored}}Link description of the [www.opensearch.org/ OpenSearch] link in the HTML head of pages.",
        "preferences": "Title of the [[Special:Preferences]] page.\n{{Identical|Preferences}}",
        "preferences-summary": "{{doc-specialpagesummary|preferences}}",
        "confirm-unwatch-top": "Used as confirmation message.",
        "confirm-rollback-button": "Used as Submit button text.\n{{Identical|OK}}",
        "confirm-rollback-top": "Used as confirmation message.",
+       "confirm-mcrundo-title": "Title for the editless undo form.",
+       "mcrundofailed": "Title of the error page when an editless undo fails.",
+       "mcrundo-missingparam": "Error displayed when parameters for action=mcrundo are missing",
+       "mcrundo-changed": "Message displayed when the page has been edited between the loading and submission of an editless undo.",
        "semicolon-separator": "{{optional}}",
        "comma-separator": "{{optional}}\n\nWarning: languages have different usages of punctuation, and sometimes they are swapped (e.g. openining and closing quotation marks, or full stop and colon in Armenian), or change their form (the full stop in Chinese and Japanese, the prefered \"colon\" in Armenian used in fact as the regular full stop, the comma in Arabic, Armenian, and Chinese...)\n\nTheir spacing (before or after) may also vary across languages (for example French requires a non-breaking space, preferably narrow if the browser supports NNBSP, on the inner side of some punctuations like quotation/question/exclamation marks, colon, and semicolons).",
        "colon-separator": "{{optional}}\nChange it only if your language uses another character for ':' or it needs an extra space before the colon.",
        "edit-error-long": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|edit-error-short}}\n{{Identical|Error}}",
        "revid": "Used to format a revision ID number in text. Parameters:\n* $1 - Revision ID number.\n{{Identical|Revision}}",
        "pageid": "Used to format a page ID number in text. Parameters:\n* $1 - Page ID number.",
-       "interfaceadmin-info": "Used to wrap the normal permission error for actions which used to only require editinterface but now require more permissions. Parameters:\n* $1 - The normal permission error.",
+       "interfaceadmin-info": "Part of the error message shown when someone with the <code>editinterface</code> right but without the appropriate <code>editsite*</code> right tries to edit a sitewide CSS/JSON/JS page.",
        "rawhtml-notallowed": "Error message given when $wgRawHtml = true; is set and a user uses an &lt;html&gt; tag in a system message or somewhere other than a normal page.",
        "gotointerwiki": "{{doc-special|GoToInterwiki}}\n\nSpecial:GoToInterwiki is a warning page displayed before redirecting users to external interwiki links. Its triggered by people going to something like [[Special:Search/google:foo]].\n{{Identical|Leaving}}",
        "gotointerwiki-invalid": "Message shown on Special:GoToInterwiki if given an invalid title.",
index 86d9b67..47a6e11 100644 (file)
                        "Vcohen",
                        "AttemptToCallNil",
                        "Stjn",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Marshmallych",
+                       "Atsirlin",
+                       "Michgrig"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "tog-watchdefault": "Добавлять в список наблюдения изменённые мной страницы и описания файлов",
        "tog-watchmoves": "Добавлять в список наблюдения переименованные мной страницы и файлы",
        "tog-watchdeletion": "Добавлять в список наблюдения удалённые мной страницы и файлы",
-       "tog-watchuploads": "Ð\94обавлÑ\8fÑ\82Ñ\8c Ð·Ð°ÐºÐ°Ñ\87анные мною файлы в список наблюдения",
+       "tog-watchuploads": "Ð\94обавлÑ\8fÑ\82Ñ\8c Ð·Ð°Ð³Ñ\80Ñ\83женные мною файлы в список наблюдения",
        "tog-watchrollback": "Добавлять страницы, где я выполнил откат, в мой список наблюдения",
        "tog-minordefault": "По умолчанию помечать правки как малые",
        "tog-previewontop": "Помещать предпросмотр перед окном редактирования",
        "redirectedfrom": "(перенаправлено с «$1»)",
        "redirectpagesub": "Страница-перенаправление",
        "redirectto": "Перенаправление на:",
-       "lastmodifiedat": "Эта страница последний раз была отредактирована $1 в $2.",
+       "lastmodifiedat": "ЭÑ\82а Ñ\81Ñ\82Ñ\80аниÑ\86а Ð² Ð¿Ð¾Ñ\81ледний Ñ\80аз Ð±Ñ\8bла Ð¾Ñ\82Ñ\80едакÑ\82иÑ\80ована $1 Ð² $2.",
        "viewcount": "К этой странице обращались $1 {{PLURAL:$1|раз|раза|раз}}.",
        "protectedpage": "Защищённая страница",
        "jumpto": "Перейти к:",
        "jumptonavigation": "навигация",
        "jumptosearch": "поиск",
-       "view-pool-error": "Ð\98звиниÑ\82е, Ð² Ð½Ð°Ñ\81Ñ\82оÑ\8fÑ\89ий Ð¼Ð¾Ð¼ÐµÐ½Ñ\82 Ñ\81еÑ\80веÑ\80Ñ\8b Ð¿ÐµÑ\80егÑ\80Ñ\83женÑ\8b.\nЭÑ\82Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 Ð¿Ñ\8bÑ\82аÑ\8eÑ\82Ñ\81Ñ\8f Ð¾Ð´Ð½Ð¾Ð²Ñ\80еменно Ð¿Ñ\80оÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c Ñ\81лиÑ\88ком Ð¼Ð½Ð¾Ð³Ð¸Ðµ.\nПожалуйста, подождите немного перед повторной попыткой обращения к этой странице.\n\n$1",
-       "generic-pool-error": "Извините, в настоящий момент серверы перегружены.\nСлишком много пользователей пытаются просмотреть этот ресурс.\nПожалуйста, подождите и повторите попытку обращения к нему позже.",
+       "view-pool-error": "Ð\98звиниÑ\82е, Ð² Ð½Ð°Ñ\81Ñ\82оÑ\8fÑ\89ий Ð¼Ð¾Ð¼ÐµÐ½Ñ\82 Ñ\81еÑ\80веÑ\80Ñ\8b Ð¿ÐµÑ\80егÑ\80Ñ\83женÑ\8b.\nСлиÑ\88ком Ð¼Ð½Ð¾Ð³Ð¾ Ñ\83Ñ\87аÑ\81Ñ\82ников Ð¿Ñ\8bÑ\82аÑ\8eÑ\82Ñ\81Ñ\8f Ð¿Ñ\80оÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c ÐµÑ\91 Ð¾Ð´Ð½Ð¾Ð²Ñ\80еменно.\nПожалуйста, подождите немного перед повторной попыткой обращения к этой странице.\n\n$1",
+       "generic-pool-error": "Извините, в настоящий момент серверы перегружены.\nСлишком много участников пытаются просмотреть этот ресурс.\nПожалуйста, подождите и повторите попытку обращения к нему позже.",
        "pool-timeout": "Истекло время ожидания блокировки",
-       "pool-queuefull": "Ð\9dакопиÑ\82елÑ\8c запросов полон",
+       "pool-queuefull": "Ð\9fÑ\83л запросов полон",
        "pool-errorunknown": "Неизвестная ошибка",
        "pool-servererror": "Служба счётчика пула недоступна ($1).",
        "poolcounter-usage-error": "Ошибка использования: $1",
        "privacy": "Политика конфиденциальности",
        "privacypage": "Project:Политика конфиденциальности",
        "badaccess": "Ошибка доступа",
-       "badaccess-group0": "Вы не можете выполнять запрошенное действие.",
-       "badaccess-groups": "Ð\97апÑ\80оÑ\88енное Ð´ÐµÐ¹Ñ\81Ñ\82вие Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð²Ñ\8bполнÑ\8fÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\83Ñ\87аÑ\81Ñ\82ники {{PLURAL:$2|1=из Ð³Ñ\80Ñ\83ппÑ\8b Â«$1»|одной Ð¸Ð· Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ð³Ñ\80Ñ\83пп: $1}}",
+       "badaccess-group0": "Вы не можете выполнить запрошенное действие.",
+       "badaccess-groups": "Запрошенное действие могут выполнять участники {{PLURAL:$2|1=из группы «$1»|одной из следующих групп: $1}}",
        "versionrequired": "Требуется MediaWiki версии $1",
-       "versionrequiredtext": "Для работы с этой страницей требуется MediaWiki версии $1. См. [[Special:Version|информацию об программном обеспечении]].",
+       "versionrequiredtext": "Для работы с этой страницей требуется MediaWiki версии $1. См. [[Special:Version|информацию о программном обеспечении]].",
        "ok": "OK",
        "pagetitle": "$1 — {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "nstab-help": "Справка",
        "nstab-category": "Категория",
        "mainpage-nstab": "Заглавная",
-       "nosuchaction": "Такого Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\8f Ð½ÐµÑ\82",
+       "nosuchaction": "Ð\9dеÑ\82 Ñ\82акого Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\8f",
        "nosuchactiontext": "Указанное в URL действие ошибочно.\nВозможно, вы допустили опечатку при наборе URL или перешли по ошибочной ссылке.\nЭто может также указывать на ошибку в проекте {{SITENAME}}.",
        "nosuchspecialpage": "Нет такой служебной страницы",
        "nospecialpagetext": "<strong>Запрошенной вами служебной страницы не существует.</strong>\n\nСписок существующих служебных страниц: [[Special:SpecialPages|{{int:specialpages}}]].",
        "databaseerror-query": "Запрос: $1",
        "databaseerror-function": "Функция: $1",
        "databaseerror-error": "Ошибка: $1",
-       "transaction-duration-limit-exceeded": "Ð\94лÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b Ð¸Ð·Ð±ÐµÐ¶Ð°Ñ\82Ñ\8c Ð±Ð¾Ð»Ñ\8cÑ\88ого Ð»Ð°Ð³Ð° Ð¿Ñ\80и Ñ\80епликаÑ\86ии, Ñ\8dÑ\82а Ñ\82Ñ\80анзакÑ\86иÑ\8f Ð±Ñ\8bла Ð¿Ñ\80еÑ\80вана, Ð¿Ð¾Ñ\81колÑ\8cкÑ\83 Ð¿Ñ\80одолжиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c Ð·Ð°Ð¿Ð¸Ñ\81и ($1) Ð¿Ñ\80евÑ\8bÑ\81ила Ð»Ð¸Ð¼Ð¸Ñ\82 Ð² $2 {{PLURAL:$2|Ñ\81екÑ\83ндÑ\83\81екÑ\83нд|Ñ\81екÑ\83ндÑ\8b}}.\nÐ\95Ñ\81ли Ð²Ñ\8b Ð¸Ð·Ð¼ÐµÐ½Ñ\8fеÑ\82е Ð½ÐµÑ\81колÑ\8cко Ñ\8dлеменÑ\82ов Ð·Ð° Ð¾Ð´Ð¸Ð½ раз, попробуйте вместо этого сделать несколько небольших операций.",
+       "transaction-duration-limit-exceeded": "Ð\94лÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b Ð¸Ð·Ð±ÐµÐ¶Ð°Ñ\82Ñ\8c Ð±Ð¾Ð»Ñ\8cÑ\88ой Ð·Ð°Ð´ÐµÑ\80жки Ð¿Ñ\80и Ñ\80епликаÑ\86ии, Ñ\8dÑ\82а Ñ\82Ñ\80анзакÑ\86иÑ\8f Ð±Ñ\8bла Ð¿Ñ\80еÑ\80вана. Ð\9fÑ\80одолжиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c Ð·Ð°Ð¿Ð¸Ñ\81и ($1) Ð¿Ñ\80евÑ\8bÑ\81ила Ð»Ð¸Ð¼Ð¸Ñ\82 Ð² $2 {{PLURAL:$2|Ñ\81екÑ\83ндÑ\83\81екÑ\83нд|Ñ\81екÑ\83ндÑ\8b}}.\nÐ\95Ñ\81ли Ð²Ñ\8b Ð¸Ð·Ð¼ÐµÐ½Ñ\8fеÑ\82е Ð½ÐµÑ\81колÑ\8cко Ñ\8dлеменÑ\82ов Ð·Ð° раз, попробуйте вместо этого сделать несколько небольших операций.",
        "laggedslavemode": "<strong>Внимание:</strong> на странице могут отсутствовать последние обновления.",
        "readonly": "Запись в базу данных заблокирована",
        "enterlockreason": "Укажите причину и намеченный срок блокировки.",
-       "readonlytext": "Добавление новых статей и другие изменения базы данных сейчас заблокированы: вероятно, в связи с плановым обслуживанием.\n\nСистемный администратор, заблокировавший базу, оставил следующее объяснение: $1",
+       "readonlytext": "Добавление новых статей и другие изменения базы данных сейчас заблокированы, вероятно, в связи с плановым обслуживанием.\n\nСистемный администратор, заблокировавший базу, оставил следующее объяснение: «$1».",
        "missing-article": "В базе данных не найдено запрашиваемого текста страницы «$1» $2, который следовало найти.\n\nПодобная ситуация обычно возникает при попытке перехода по устаревшей ссылке на историю изменения страницы, которая была удалена.\n\nЕсли дело не в этом, то скорее всего, вы обнаружили ошибку в программном обеспечении.\nПожалуйста, сообщите об этом одному из [[Special:ListUsers/sysop|администраторов]], указав данный URL.",
        "missingarticle-rev": "(версия № $1)",
        "missingarticle-diff": "(разность: $1, $2)",
        "perfcachedts": "Данные взяты из кэша; последний раз он обновлялся в $1. В кэше хранится не более {{PLURAL:$4|1=одной записи|$4 записи|$4 записей}}.",
        "querypage-no-updates": "Обновление этой страницы сейчас отключено.\nПредставленные здесь данные не будут обновляться.",
        "viewsource": "Просмотр кода",
-       "viewsource-title": "Ð\9fÑ\80оÑ\81моÑ\82Ñ\80 Ð¸Ñ\81Ñ\85одного Ñ\82екÑ\81Ñ\82а страницы $1",
+       "viewsource-title": "Ð\9fÑ\80оÑ\81моÑ\82Ñ\80 ÐºÐ¾Ð´а страницы $1",
        "actionthrottled": "Ограничение по скорости",
-       "actionthrottledtext": "Ð\94лÑ\8f Ð±Ð¾Ñ\80Ñ\8cбÑ\8b Ñ\81о Ñ\81памом Ð±Ñ\8bло Ñ\83Ñ\81Ñ\82ановлено Ð¾Ð³Ñ\80аниÑ\87ение Ð½Ð° Ð¼Ð°ÐºÑ\81ималÑ\8cное Ñ\87иÑ\81ло Ð¿Ð¾Ð¿Ñ\8bÑ\82ок Ð²Ñ\8bполнениÑ\8f Ñ\8dÑ\82ого Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\8f Ð² ÐºÐ¾Ñ\80оÑ\82кий Ð¿Ñ\80омежÑ\83Ñ\82ок Ð²Ñ\80емени â\80\94 Ð¸ Ð²Ñ\8b Ð¸Ñ\81Ñ\87еÑ\80пали Ñ\8dÑ\82оÑ\82 Ð»Ð¸Ð¼Ð¸Ñ\82Пожалуйста, повторите попытку через несколько минут.",
+       "actionthrottledtext": "Ð\92Ñ\8b Ð¸Ñ\81Ñ\87еÑ\80пали Ñ\83Ñ\81Ñ\82ановленное Ð´Ð»Ñ\8f Ð±Ð¾Ñ\80Ñ\8cбÑ\8b Ñ\81о Ñ\81памом Ð¾Ð³Ñ\80аниÑ\87ение Ð½Ð° Ð¼Ð°ÐºÑ\81ималÑ\8cное ÐºÐ¾Ð»Ð¸Ñ\87еÑ\81Ñ\82во Ð¿Ð¾Ð¿Ñ\8bÑ\82ок Ð²Ñ\8bполнениÑ\8f Ð·Ð°Ð¿Ñ\80оÑ\88енного Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\8f Ð² ÐºÐ¾Ñ\80оÑ\82кий Ð¿Ñ\80омежÑ\83Ñ\82ок Ð²Ñ\80емени.\nПожалуйста, повторите попытку через несколько минут.",
        "protectedpagetext": "Эта страница защищена для предотвращения её редактирования или совершений других действий.",
        "viewsourcetext": "Вы можете просмотреть и скопировать исходный код этой страницы.",
        "viewyourtext": "Вы можете просмотреть и скопировать исходный текст <strong>ваших правок</strong> на этой странице.",
        "editinginterface": "<strong>Внимание:</strong> Вы редактируете страницу, содержащую текст интерфейса программного обеспечения.\nЕё изменение повлияет на внешний вид интерфейса для других пользователей этой вики.",
        "translateinterface": "Чтобы добавить или изменить перевод этого сообщения, пожалуйста, используйте сайт локализации MediaWiki [https://translatewiki.net/ translatewiki.net].",
        "cascadeprotected": "Данная страница защищена от изменений, поскольку она включена в {{PLURAL:$1|1=следующую страницу, для которой|следующие страницы, для которых}} включена каскадная защита:\n$2",
-       "namespaceprotected": "У вас нет разрешения редактировать страницы в пространстве имён «$1».",
-       "customcssprotected": "У вас нет разрешения редактировать эту CSS-страницу, так как она содержит личные настройки другого участника.",
-       "customjsonprotected": "У вас нет разрешения редактировать эту JSON-страницу, так как она содержит личные настройки другого участника.",
-       "customjsprotected": "У вас нет разрешения редактировать эту JavaScript-страницу, так как она содержит личные настройки другого участника.",
-       "sitecssprotected": "У вас нет разрешения редактировать эту CSS-страницу, поскольку её изменение может повлиять на всех посетителей.",
-       "sitejsonprotected": "У вас нет разрешения для редактирования этой JSON-страницы, поскольку её изменение может повлиять на всех посетителей.",
-       "sitejsprotected": "У вас нет разрешения редактировать эту JavaScript страницу, поскольку её изменение может повлиять на всех посетителей.",
-       "mycustomcssprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð´Ð»Ñ\8f Ñ\80едакÑ\82иÑ\80ованиÑ\8f Ñ\8dÑ\82ого CSS страницы.",
-       "mycustomjsonprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð´Ð»Ñ\8f Ñ\80едакÑ\82иÑ\80ованиÑ\8f этой JSON-страницы.",
-       "mycustomjsprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð´Ð»Ñ\8f Ñ\80едакÑ\82иÑ\80ованиÑ\8f JavaScript Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86е.",
-       "myprivateinfoprotected": "У вас нет разрешения на изменение вашей личной информации",
-       "mypreferencesprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð´Ð»Ñ\8f Ñ\80едакÑ\82иÑ\80ованиÑ\8f настроек.",
-       "ns-specialprotected": "СÑ\82Ñ\80аниÑ\86Ñ\8b Ð¿Ñ\80оÑ\81Ñ\82Ñ\80анÑ\81Ñ\82ва Ð¸Ð¼Ñ\91н Â«{{ns:special}}» Ð½Ðµ Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð¿Ñ\80авиÑ\82Ñ\8cÑ\81Ñ\8f.",
+       "namespaceprotected": "У вас нет прав на редактирование страниц в пространстве имён «<strong>$1</strong>».",
+       "customcssprotected": "У вас нет прав на редактирование этой CSS-страницы, поскольку она содержит личные настройки другого участника.",
+       "customjsonprotected": "У вас нет прав на редактирование этой JSON-страницы, поскольку она содержит личные настройки другого участника.",
+       "customjsprotected": "У вас нет прав на редактирование этой JavaScript-страницы, поскольку она содержит личные настройки другого участника.",
+       "sitecssprotected": "У вас нет прав на редактирование этой CSS-страницы, поскольку её изменение может повлиять на всех посетителей.",
+       "sitejsonprotected": "У вас нет прав на редактирование этой JSON-страницы, поскольку её изменение может повлиять на всех посетителей.",
+       "sitejsprotected": "У вас нет прав на редактирование этой JavaScript страницу, поскольку её изменение может повлиять на всех посетителей.",
+       "mycustomcssprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð½Ð° Ñ\80едакÑ\82иÑ\80ование Ñ\8dÑ\82ой CSS страницы.",
+       "mycustomjsonprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð½Ð° Ñ\80едакÑ\82иÑ\80ование этой JSON-страницы.",
+       "mycustomjsprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð½Ð° Ñ\80едакÑ\82иÑ\80ование Ñ\8dÑ\82ой JavaScript-Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b.",
+       "myprivateinfoprotected": "У вас нет прав на изменение вашей личной информации",
+       "mypreferencesprotected": "У Ð²Ð°Ñ\81 Ð½ÐµÑ\82 Ð¿Ñ\80ав Ð½Ð° Ñ\80едакÑ\82иÑ\80ование настроек.",
+       "ns-specialprotected": "СÑ\82Ñ\80аниÑ\86Ñ\8b Ð¿Ñ\80оÑ\81Ñ\82Ñ\80анÑ\81Ñ\82ва Ð¸Ð¼Ñ\91н Â«{{ns:special}}» Ð½Ðµ Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ñ\8b.",
        "titleprotected": "Создание страницы с таким заголовком было запрещено участником [[User:$1|$1]].\nУказана следующая причина: <em>$2</em>.",
        "filereadonlyerror": "Не удаётся изменить файл «$1», так как хранилище «$2» находится в режиме «только для чтения».\n\nСистемный администратор, заблокировавший базу, оставил следующее объяснение: «$3».",
        "invalidtitle": "Недопустимое название",
        "createacct-error": "Ошибка создания учётной записи",
        "createaccounterror": "Невозможно создать учётную запись: $1",
        "nocookiesnew": "Участник зарегистрирован, но не представлен. {{SITENAME}} использует «cookies» для представления участников. У вас «cookies» запрещены. Пожалуйста, разрешите их, а затем представьтесь со своиим новым именем участника и паролем.",
-       "nocookieslogin": "{{SITENAME}} использует «cookies» для представления участников. Вы их отключили. Пожалуйста, включите их и попробуйте снова.",
+       "nocookieslogin": "{{SITENAME}} использует cookie для представления участников.\nВы отключили использование cookie.\nВключите их и попробуйте снова.",
        "nocookiesfornew": "Учётная запись участника не была создана из-за невозможности проверить её источник. \nУбедитесь, что включены «cookies», обновите страницу и попробуйте ещё раз.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "createacct-loginerror": "Учётная запись была успешно создана, но вы не смогли войти в систему автоматически. Пожалуйста, [[Special:UserLogin|авторизуйтесь вручную]].",
        "permissionserrorstext": "У вас нет прав на выполнение этой операции по {{PLURAL:$1|1=следующей причине|следующим причинам}}:",
        "permissionserrorstext-withaction": "У вас нет прав на выполнение действия «$2» по {{PLURAL:$1|1=следующей причине|следующим причинам}}:",
        "contentmodelediterror": "Вы не можете редактировать эту версию, поскольку модель её содержания — <code>$1</code>, отличающаяся от текущей модели содержания страницы — <code>$2</code>.",
-       "recreate-moveddeleted-warn": "'''Внимание. Вы пытаетесь воссоздать страницу, которая ранее удалялась.'''\n\nПроверьте, действительно ли вам нужно воссоздавать эту страницу.\nНиже приведены журналы удалений и переименований этой страницы.",
+       "recreate-moveddeleted-warn": "<strong>Внимание: Вы пытаетесь воссоздать страницу, которая ранее удалялась.</strong>\n\nПроверьте, действительно ли вам нужно воссоздавать эту страницу.\nНиже для справки приведены журналы удаления и переименований этой страницы.",
        "moveddeleted-notice": "Эта страница была удалена.\nНиже для справки приведены журналы удаления, защиты и перемещения для этой страницы.",
        "moveddeleted-notice-recent": "К сожалению, эта страница была недавно удалена (в течение последних 24 часов).\nНиже для справки приведены журналы удаления, защиты и перемещения для этой страницы.",
        "log-fulllog": "Просмотреть журнал целиком",
        "unstrip-size-warning": "Превышен лимит размера Unstrip ($1)",
        "unstrip-size-category": "Страницы с превышенным лимитом размера Unstrip",
        "converter-manual-rule-error": "Ошибка в ручном правиле преобразования языка",
-       "undo-success": "Ð\9fÑ\80авка Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¾Ñ\82менена. Ð\9fожалÑ\83йÑ\81Ñ\82а, Ð¿Ñ\80оÑ\81моÑ\82Ñ\80иÑ\82е Ñ\81Ñ\80авнение Ð²ÐµÑ\80Ñ\81ий, Ñ\87Ñ\82обÑ\8b Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о Ñ\8dÑ\82о Ð¸Ð¼ÐµÐ½Ð½Ð¾ Ñ\82е Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f, ÐºÐ¾Ñ\82оÑ\80Ñ\8bе Ð²Ð°Ñ\81 Ð¸Ð½Ñ\82еÑ\80еÑ\81Ñ\83Ñ\8eÑ\82, Ð¸ Ð½Ð°Ð¶Ð¼Ð¸Ñ\82е Â«Ð\97апиÑ\81аÑ\82Ñ\8c Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83», Ñ\87Ñ\82обÑ\8b Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f Ð²Ñ\81Ñ\82Ñ\83пили Ð² Ñ\81илÑ\83.",
+       "undo-success": "Ð\9fÑ\80авка Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¾Ñ\82менена. Ð\9fожалÑ\83йÑ\81Ñ\82а, Ð¿Ñ\80оÑ\81моÑ\82Ñ\80иÑ\82е Ñ\81Ñ\80авнение Ð²ÐµÑ\80Ñ\81ий, Ñ\87Ñ\82обÑ\8b Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о Ñ\8dÑ\82о Ð¸Ð¼ÐµÐ½Ð½Ð¾ Ñ\82е Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f, ÐºÐ¾Ñ\82оÑ\80Ñ\8bе Ð²Ð°Ñ\81 Ð¸Ð½Ñ\82еÑ\80еÑ\81Ñ\83Ñ\8eÑ\82, Ð¸ Ð½Ð°Ð¶Ð¼Ð¸Ñ\82е Â«Ð\97апиÑ\81аÑ\82Ñ\8c Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83», Ñ\87Ñ\82обÑ\8b Ð²Ð°Ñ\88а Ð¾Ñ\82мена Ð¿Ñ\80авки Ð±Ñ\8bла Ñ\81оÑ\85Ñ\80анена.",
        "undo-failure": "Правка не может быть отменена из-за несовместимости промежуточных изменений.",
        "undo-main-slot-only": "Правка не может быть отменена, поскольку оно включает контент вне основного слота.",
        "undo-norev": "Правка не может быть отменена, так как её не существует или она была удалена.",
        "last": "пред.",
        "page_first": "первая",
        "page_last": "последняя",
-       "histlegend": "Выбор версий: отметьте версии страницы, которые вы хотите сравнить, и нажмите '''{{int:compare-submit}}'''.<br />\nПояснения: '''({{int:cur}})''' — отличия от текущей версии; '''({{int:last}})''' — отличия от предшествующей версии; '''{{int:minoreditletter}}''' — незначительные изменения.",
+       "histlegend": "Выбор версий: отметьте версии страницы, которые вы хотите сравнить, и нажмите <strong>{{int:compare-submit}}</strong>.<br />\nПояснения: <strong>({{int:cur}})</strong> — отличия от текущей версии; <strong>({{int:last}})</strong> — отличия от предшествующей версии; <strong>{{int:minoreditletter}}</strong> — незначительные изменения.",
        "history-fieldset-title": "Поиск правок",
        "history-show-deleted": "Только удалённые правки",
        "histfirst": "старейшие",
        "history-feed-item-nocomment": "$1 в $2",
        "history-feed-empty": "Запрашиваемой страницы не существует.\nОна могла быть удалена или переименована.\nПопробуйте [[Special:Search|найти в вики]] похожие страницы.",
        "history-edit-tags": "Изменить теги выбранных версий",
-       "rev-deleted-comment": "(опиÑ\81ание Ð¿Ñ\80авки Ñ\83далено)",
+       "rev-deleted-comment": "(опиÑ\81ание Ð¿Ñ\80авки Ñ\81Ñ\82Ñ\91Ñ\80Ñ\82о)",
        "rev-deleted-user": "(имя автора стёрто)",
-       "rev-deleted-event": "(деÑ\82али Ð¶Ñ\83Ñ\80нала Ñ\83далены)",
+       "rev-deleted-event": "(подÑ\80обноÑ\81Ñ\82и Ñ\81Ñ\82Ñ\91Ñ\80Ñ\82ы)",
        "rev-deleted-user-contribs": "[имя участника или IP-адрес удалены — правка скрыта со страницы вклада]",
        "rev-deleted-text-permission": "Эта версия страницы была '''удалена'''.\nПодробности приведены в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале удалений].",
        "rev-suppressed-text-permission": "Эта версия страницы была <strong>скрыта</strong>.\nПодробности приведены в [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} журнале сокрытий].",
        "rev-suppressed-diff-view": "Одна из версий этого сравнения версий была <strong>скрыта</strong>.\nВы можете просмотреть это сравнение. Подробности приведены в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале сокрытий].",
        "rev-delundel": "показать/скрыть",
        "rev-showdeleted": "показать",
-       "revisiondelete": "Удалить / восстановить версии страницы",
+       "revisiondelete": "Удалить/восстановить версии страницы",
        "revdelete-nooldid-title": "Не задана целевая версия",
-       "revdelete-nooldid-text": "Ð\92Ñ\8b Ð½Ðµ Ð·Ð°Ð´Ð°Ð»Ð¸ Ñ\86елевÑ\83Ñ\8e Ð²ÐµÑ\80Ñ\81иÑ\8e (веÑ\80Ñ\81ии) Ð´Ð»Ñ\8f Ð²Ñ\8bполнениÑ\8f Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, Ñ\83казаннаÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82, Ð¸Ð»Ð¸ вы пытаетесь скрыть текущую версию.",
+       "revdelete-nooldid-text": "ЦелеваÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ð·Ð°Ð´Ð°Ð½Ñ\8b, Ñ\83казаннаÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 Ð¸Ð»Ð¸ Ð¶Ðµ вы пытаетесь скрыть текущую версию.",
        "revdelete-no-file": "Указанный файл не существует.",
        "revdelete-show-file-confirm": "Вы уверены, что вы хотите просмотреть удалённую версию файла «<nowiki>$1</nowiki>» от $2, $3?",
        "revdelete-show-file-submit": "Да",
        "revdelete-radio-same": "(не изменять)",
        "revdelete-radio-set": "Скрытая",
        "revdelete-radio-unset": "Видимая",
-       "revdelete-suppress": "Скрывать данные также и от администраторов",
-       "revdelete-unsuppress": "Снять ограничения с восстановленных версий",
+       "revdelete-suppress": "Скрыть данные также и от администраторов",
+       "revdelete-unsuppress": "Снять ограничения видимости с восстановленных версий",
        "revdelete-log": "Причина:",
        "revdelete-submit": "Применить к {{PLURAL:$1|1=выбранной версии|выбранным версиям}}",
        "revdelete-success": "Видимость версии обновлена.",
        "revdelete-concurrent-change": "Ошибка изменения записи от $2, $1: её статус был изменён кем-то другим, пока вы пытались изменить его.\nПожалуйста, проверьте журналы.",
        "revdelete-only-restricted": "Ошибка сокрытия записи от $2 $1: вы не можете скрыть запись от просмотра администраторами без выбора одной из других настроек сокрытия.",
        "revdelete-reason-dropdown": "* Стандартные причины удаления\n** Нарушение авторских прав\n** Неуместные личные сведения\n** Неуместное имя участника\n** Потенциально клеветнические сведения",
-       "revdelete-otherreason": "Другая/дополнительная причина:",
+       "revdelete-otherreason": "Другая причина/дополнение:",
        "revdelete-reasonotherlist": "Другая причина",
        "revdelete-edit-reasonlist": "Редактировать список причин",
        "revdelete-offender": "Автор версии страницы:",
        "default": "по умолчанию",
        "prefs-files": "Файлы",
        "prefs-custom-css": "Собственный CSS",
-       "prefs-custom-json": "Ð\9fолÑ\8cзоваÑ\82елÑ\8cÑ\81кий JSON",
+       "prefs-custom-json": "СобÑ\81Ñ\82веннÑ\8bй JSON",
        "prefs-custom-js": "Собственный JS",
        "prefs-common-config": "Общие CSS/JSON/JavaScript для всех тем оформления:",
        "prefs-reset-intro": "Эта страница может быть использована для сброса ваших настроек на стандартные.\nУчтите, что это действие невозможно отменить.",
        "userrights-groupsmember": "Состоит в группах:",
        "userrights-groupsmember-auto": "Неявно состоит в группах:",
        "userrights-groupsmember-type": "$1",
-       "userrights-groups-help": "Вы можете изменить группы, в которые входит {{GENDER:$1|этот участник|эта участница}}.\n* Если около названия группы стоит отметка — {{GENDER:$1|участник|участница}} входит в эту группу.\n* Если отметка не стоит — {{GENDER:$1|участник|участница}} не входит в эту группу.\n* Символ * указывает на то, что вы не сможете удалить {{GENDER:$1|участника|участницу}} из группы, если добавите {{GENDER:$1|его|её}} в неё (или наоборот).\n* Символ # указывает на то, что вы можете только отложить время истечения членства в этой группы, вы не можете перенести его на более ранний срок.",
+       "userrights-groups-help": "Вы можете изменить группы, в которые входит {{GENDER:$1|этот участник|эта участница}}.\n* Если около названия группы стоит отметка — {{GENDER:$1|участник|участница}} входит в эту группу.\n* Если отметка не стоит — {{GENDER:$1|участник|участница}} не входит в эту группу.\n* Символ * означает, что вы не сможете удалить {{GENDER:$1|участника|участницу}} из группы, если добавите {{GENDER:$1|его|её}} в неё (или наоборот).\n* Символ # означает, что вы можете только отложить, но не перенести время истечения членства в этой группе на более ранний срок.",
        "userrights-reason": "Причина:",
        "userrights-no-interwiki": "У вас нет разрешения изменять права участников в других вики.",
        "userrights-nodatabase": "База данных $1 не существует или расположена не локально.",
        "action-editcontentmodel": "редактирование контентной модели страницы",
        "action-managechangetags": "создание и (де)активацию меток",
        "action-applychangetags": " применять теги наряду с Вашими изменениями",
-       "action-changetags": "Ð\94обавлÑ\8fÑ\82Ñ\8c Ð¸ Ñ\83далÑ\8fÑ\82Ñ\8c Ð¿Ñ\80оизволÑ\8cнÑ\8bе Ñ\82еги на отдельных изменениях и записях в журнале",
+       "action-changetags": "добавление Ð¸ Ñ\83даление Ð¿Ñ\80оизволÑ\8cнÑ\8bÑ\85 Ð¼ÐµÑ\82ок на отдельных изменениях и записях в журнале",
        "action-deletechangetags": "удаление меток из базы данных",
        "action-purge": "очистку кэша этой страницы",
        "nchanges": "$1 {{PLURAL:$1|изменение|изменения|изменений}}",
        "rcfilters-highlighted-filters-list": "Подсвечено: $1",
        "rcfilters-quickfilters": "Сохранённые фильтры",
        "rcfilters-quickfilters-placeholder-title": "Сохранённых фильтров ещё нет",
-       "rcfilters-quickfilters-placeholder-description": "ЧÑ\82обÑ\8b Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c Ð½Ð°Ñ\81Ñ\82Ñ\80ойки Ñ\84илÑ\8cÑ\82Ñ\80а Ð¸ Ð¿Ð¾Ð²Ñ\82оÑ\80но Ð¸Ñ\81полÑ\8cзоваÑ\82Ñ\8c Ð¸Ñ\85 Ð¿Ð¾Ð·Ð¶Ðµ, Ñ\89елкниÑ\82е Ð·Ð½Ð°Ñ\87ок Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸ Ð² Ð¾Ð±Ð»Ð°Ñ\81Ñ\82и Â«Ð\90кÑ\82ивнÑ\8bй Ñ\84илÑ\8cÑ\82Ñ\80» ниже.",
+       "rcfilters-quickfilters-placeholder-description": "ЧÑ\82обÑ\8b Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c Ð½Ð°Ñ\81Ñ\82Ñ\80ойки Ñ\84илÑ\8cÑ\82Ñ\80а Ð¸ Ð¿Ð¾Ð²Ñ\82оÑ\80но Ð¸Ñ\81полÑ\8cзоваÑ\82Ñ\8c Ð¸Ñ\85 Ð¿Ð¾Ð·Ð¶Ðµ, Ñ\89елкниÑ\82е Ð·Ð½Ð°Ñ\87ок Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸ Ð² Ð¾Ð±Ð»Ð°Ñ\81Ñ\82и Â«Ð\90кÑ\82ивнÑ\8bе Ñ\84илÑ\8cÑ\82Ñ\80Ñ\8b» ниже.",
        "rcfilters-savedqueries-defaultlabel": "Сохранённые фильтры",
        "rcfilters-savedqueries-rename": "Переименовать",
        "rcfilters-savedqueries-setdefault": "Установить по умолчанию",
        "block": "Блокировка участника",
        "unblock": "Разблокировка участника",
        "blockip": "Заблокировать {{GENDER:$1|участника|участницу}}",
-       "blockiptext": "Используйте форму ниже, чтобы заблокировать возможность записи с определённого IP-адреса или имени участника.\nЭто может быть сделано только для предотвращения вандализма и только в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].\nНиже укажите конкретную причину (к примеру, процитируйте некоторые страницы с признаками вандализма).\nВы можете заблокировать диапазоны IP-адресов, используя [https://ru.wikipedia.org/wiki/Бесклассовая_адресация CIDR]-синтаксис. Максимально допустимый диапазон — /$1 для протокола IPv4 и /$2 для протокола IPv6.",
+       "blockiptext": "Используйте форму ниже, чтобы заблокировать возможность редактирования с определённого IP-адреса или имени участника.\nЭтот инструмент следует использовать для предотвращения вандализма и только в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].\nНиже укажите конкретную причину (к примеру, процитируйте некоторые страницы с признаками вандализма).\nВы можете заблокировать диапазоны IP-адресов, используя [https://ru.wikipedia.org/wiki/Бесклассовая_адресация CIDR]-синтаксис. Максимально допустимый диапазон — /$1 для протокола IPv4 и /$2 для протокола IPv6.",
        "ipaddressorusername": "IP-адрес или имя участника:",
        "ipbexpiry": "Закончится через:",
        "ipbreason": "Причина:",
        "ipboptions": "2 часа:2 hours,1 день:1 day,3 дня:3 days,1 неделя:1 week,2 недели:2 weeks,1 месяц:1 month,3 месяца:3 months,6 месяцев:6 months,1 год:1 year,бессрочно:infinite",
        "ipbhidename": "Скрыть имя участника из правок и списков",
        "ipbwatchuser": "Добавить в список наблюдения личную страницу участника и его страницу обсуждения",
-       "ipb-disableusertalk": "Запретить этому участнику редактировать свою страницу обсуждения во время блокировки",
+       "ipb-disableusertalk": "Запретить этому участнику редактировать свою страницу обсуждения",
        "ipb-change-block": "Переблокировать участника с этими настройками",
        "ipb-confirm": "Подтвердить блокировку",
        "badipaddress": "IP-адрес записан в неправильном формате, или участника с таким именем не существует.",
        "autoblocklist-submit": "Найти",
        "autoblocklist-legend": "Список автоблокировок",
        "autoblocklist-localblocks": "{{PLURAL:$1|Локальная автоблокировка|Локальные автоблокировки}}",
-       "autoblocklist-total-autoblocks": "Ð\92Ñ\81его Ð°Ð²Ñ\82облоков: $1",
+       "autoblocklist-total-autoblocks": "Ð\92Ñ\81его Ð°Ð²Ñ\82облокиÑ\80овок: $1",
        "autoblocklist-empty": "Список автоблокировок пуст.",
        "autoblocklist-otherblocks": "{{PLURAL:$1|Другая автоблокировка|Другие автоблокировки}}",
        "ipblocklist": "Заблокированные участники",
        "moveuserpage-warning": "<strong>Внимание:</strong> вы собираетесь переименовать страницу участника. Пожалуйста, обратите внимание, что переименована будет только страница, участник <strong>не</strong> будет переименован.",
        "movecategorypage-warning": "<strong>Предупреждение:</strong> Вы собираетесь переименовать страницу категории. Пожалуйста, обратите внимание, что будет переименована только эта страница, а все страницы старой категории <em>не</em> будут перекатегоризованы в новую.",
        "movenologintext": "Вы должны [[Special:UserLogin|представиться системе]],\nчтобы иметь возможность переименовать страницы.",
-       "movenotallowed": "У вас нет разрешения переименовывать страницы.",
-       "movenotallowedfile": "У вас нет разрешения переименовывать файлы.",
-       "cant-move-user-page": "У вас нет разрешения переименовывать основные страницы участников.",
+       "movenotallowed": "У вас нет прав на переименовывание страниц.",
+       "movenotallowedfile": "У вас нет прав на переименовывание файлов.",
+       "cant-move-user-page": "У вас нет прав на переименовывание основных страниц участников.",
        "cant-move-to-user-page": "У вас нет прав переименовывать страницу в страницу участника (можно переименовать в подстраницу).",
-       "cant-move-category-page": "У вас нет разрешения переименовывать страницы категорий.",
-       "cant-move-to-category-page": "У вас нет разрешения переименовывать страницы в страницу категории.",
-       "cant-move-subpages": "У вас нет разрешения переименовывать подстраницы.",
+       "cant-move-category-page": "У вас нет прав на переименовывание страниц категорий.",
+       "cant-move-to-category-page": "У вас нет прав на переименовывание страницы в страницу категории.",
+       "cant-move-subpages": "У вас нет прав на переименовывание подстраниц.",
        "namespace-nosubpages": "Пространство имён «$1» не разрешает создание страниц.",
        "newtitle": "Новое название:",
        "move-watch": "Добавить в список наблюдения исходную и целевую страницы",
        "movenosubpage": "У этой страницы нет подстраниц.",
        "movereason": "Причина:",
        "revertmove": "возврат",
-       "delete_and_move_text": "ЦелеваÑ\8f Ñ\81траница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
+       "delete_and_move_text": "Страница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
        "delete_and_move_confirm": "Да, удалить эту страницу",
        "delete_and_move_reason": "Удалено для возможности переименования «[[$1]]»",
        "selfmove": "Невозможно переименовать страницу: исходное и новое имя страницы совпадают.",
        "immobile-target-namespace-iw": "Ссылка интервики не может быть использована для переименования.",
        "immobile-source-page": "Эту страницу нельзя переименовать.",
        "immobile-target-page": "Нельзя присвоить странице это имя.",
-       "bad-target-model": "Невозможно преобразовать $1 в $2: несовместимые модели данных.",
+       "bad-target-model": "Невозможно преобразовать $1 в $2. У страниц несовместимые модели содержимого.",
        "imagenocrossnamespace": "Невозможно дать файлу имя из другого пространства имён",
-       "nonfile-cannot-move-to-file": "Невозможно переименовывать страницы в файлы",
+       "nonfile-cannot-move-to-file": "Невозможно переименовывать не-файловые страницы в файлы",
        "imagetypemismatch": "Новое расширение файла не соответствует его типу",
        "imageinvalidfilename": "Целевое имя файла ошибочно",
        "fix-double-redirects": "Исправить перенаправления, указывающие на прежнее название",
        "anonymous": "{{PLURAL:$1|1=Анонимный участник|Анонимные участники}} {{grammar:genitive|{{SITENAME}}}}",
        "siteuser": "{{GENDER:$2|участник|участница}} {{grammar:genitive|{{SITENAME}}}} $1",
        "anonuser": "анонимный участник {{grammar:genitive|{{SITENAME}}}} $1",
-       "lastmodifiedatby": "Эта страница последний раз была отредактирована $1 в $2, автор изменения — $3.",
+       "lastmodifiedatby": "ЭÑ\82а Ñ\81Ñ\82Ñ\80аниÑ\86а Ð² Ð¿Ð¾Ñ\81ледний Ñ\80аз Ð±Ñ\8bла Ð¾Ñ\82Ñ\80едакÑ\82иÑ\80ована $1 Ð² $2, Ð°Ð²Ñ\82оÑ\80 Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f â\80\94 $3.",
        "othercontribs": "В создании приняли участие: $1.",
        "others": "другие",
        "siteusers": "{{PLURAL:$2|1={{GENDER:$1|участник|участница}}|участники}} {{grammar:genitive|{{SITENAME}}}} $1",
        "filedelete-archive-read-only": "Архивная директория «$1» не доступна для записи веб-серверу.",
        "previousdiff": "← Предыдущая правка",
        "nextdiff": "Следующая правка →",
-       "mediawarning": "'''Внимание'''. Этот тип файла может содержать вредоносный программный код.\nПри его запуске ваша система может быть заражена.",
+       "mediawarning": "<strong>Внимание</strong>. Этот тип файла может содержать вредоносный программный код.\nПри его запуске ваша система может быть заражена.",
        "imagemaxsize": "Ограничение на размер изображения:<br />''(для страницы описания файла)''",
        "thumbsize": "Размер уменьшенной версии изображения:",
        "widthheight": "$1 × $2",
        "confirm-unwatch-top": "Удалить эту страницу из вашего списка наблюдения?",
        "confirm-rollback-button": "ОК",
        "confirm-rollback-top": "Откатить правки на этой странице?",
+       "confirm-mcrundo-title": "Отменить изменение",
+       "mcrundofailed": "Отменить не удалось",
+       "mcrundo-missingparam": "Отсутствуют обязательные параметры по запросу.",
+       "mcrundo-changed": "Эта страница была изменена с тех пор, как вы просмотрели различия. Пожалуйста, проверьте новое изменение.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "edit-error-long": "Ошибки:\n\n$1",
        "revid": "версия $1",
        "pageid": "ID страницы $1",
-       "interfaceadmin-info": "$1\n\nПрава на редактирование общесайтных CSS/JS/JSON были недавно вынесены из права <code>editinterface</code>. Если вы не понимаете, почему вы наткнулись на эту ошибку, см. [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nПрава на редактирование общесайтных CSS/JS/JSON-файлов были недавно вынесены из права <code>editinterface</code>. Если вы не понимаете, почему вы наткнулись на эту ошибку, см. [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "&lt;html&gt; теги могут быть использованы только в пределах обычных страниц.",
        "gotointerwiki": "Покидаем {{grammar:accusative|{{SITENAME}}}}...",
        "gotointerwiki-invalid": "Указан некорректный заголовок.",
index 591f262..1a81188 100644 (file)
        "cascadeprotected": "Сторінка є замнкута, бо є вложена до  {{PLURAL:$1|наслїдуючой сторінкы замкнуты|наслїдуючіх сторінок замнкнутых|наслїдуючіх сторінок замнкнутых}} каскадовым замком:\n$2",
        "namespaceprotected": "Не маєте права едітовати сторінкы в просторї  назв «$1».",
        "customcssprotected": "Не маєте права едітовати тоту сторінку з CSS, бо обсягує персоналны наставлїна іншого хоснователя.",
+       "customjsonprotected": "Не маєте права едітовати тоту сторінку з JSON, бо обсягує персоналны наставлїна іншого хоснователя.",
        "customjsprotected": "Не маєте права едітовати тоту сторінку з JavaScript-ом, бо обсягує персоналны наставлїна іншого хоснователя.",
        "mycustomcssprotected": "Не мате права на управы той CSS сторінкы.",
+       "mycustomjsonprotected": "Не мате права на едітованя той JSON сторінкы.",
        "mycustomjsprotected": "Не мате права на едітованя той JavaScript сторінкы.",
        "myprivateinfoprotected": "Не мате дозволїня мінити свої пріватны інформації.",
        "mypreferencesprotected": "Не мате дозволїня мінити свої наставлїня.",
index 6f2c3b1..b3d4986 100644 (file)
@@ -45,7 +45,7 @@
        "tog-previewonfirst": "ᱯᱟᱹᱦᱤᱞ ᱥᱟᱯᱲᱟᱣ ᱨᱮ ᱩᱱᱩᱫᱩᱜ ᱩᱫᱩᱜᱽ ᱢᱮ",
        "tog-enotifwatchlistpages": "ᱡᱟᱸᱦᱟᱸ ᱥᱟᱦᱴᱟ ᱥᱮ ᱨᱮᱫ ᱤᱧᱟᱜ ᱧᱮᱞᱚᱜ ᱛᱟᱹᱞᱠᱟᱹ ᱨᱮ ᱢᱮᱱᱟᱜ-ᱟ ᱚᱱᱟᱠᱩ ᱵᱚᱫᱚᱞ ᱞᱮᱱ ᱠᱷᱟᱡ ᱤ-ᱢᱮᱞ ᱟᱹᱧᱢᱮ",
        "tog-enotifusertalkpages": "ᱤ-ᱢᱮᱞ ᱟᱹᱧᱢᱮ ᱛᱤᱱᱨᱮ ᱤᱧᱟᱜ ᱨᱚᱲ ᱥᱟᱦᱴᱟ ᱵᱚᱫᱚᱞᱜ-ᱟ",
-       "tog-enotifminoredits": "ᱥᱟᱦᱴᱟ ᱟᱨ ᱨᱮᱫ ᱠᱩ ᱦᱩᱰᱤᱧ ᱥᱟᱯᱲᱟᱣ ᱞᱮᱱ ᱠᱷᱟᱡ ᱦᱚᱸ E-mail ᱟᱹᱧᱢᱮ",
+       "tog-enotifminoredits": "ᱥᱟᱦᱴᱟ ᱟᱨ ᱨᱮᱫ ᱠᱩ ᱦᱩᱰᱤᱧ ᱥᱟᱯᱲᱟᱣ ᱞᱮᱱ ᱠᱷᱟᱡ ᱦᱚᱸ ᱤ-ᱢᱮᱞ ᱟᱹᱧᱢᱮ",
        "tog-enotifrevealaddr": "ᱰᱷᱟᱹᱨᱣᱟᱜ ᱥᱟᱦᱴᱟᱨᱮ ᱤᱧᱟᱜ e-mail ᱴᱷᱤᱠᱱᱟ ᱥᱚᱫᱚᱨ ᱦᱩᱭᱩᱜ ᱢᱟ",
        "tog-shownumberswatching": "ᱧᱮᱞᱚᱜ ᱵᱮᱵᱟᱦᱟᱨᱤᱡ ᱠᱯᱣᱟᱜ ᱮᱞᱮᱞ ᱩᱫᱩᱜᱽ ᱢᱮ",
        "tog-oldsig": "ᱟᱢᱟᱜ ᱥᱩᱦᱤ:",
        "specialpages": "ᱵᱤᱥᱮᱥ ᱥᱟᱦᱴᱟᱠᱚ",
        "external_image_whitelist": "#ᱱᱚᱣᱟ ᱥᱟᱦᱴᱟ ᱫᱚ ᱪᱮᱛ ᱞᱮᱠᱟ ᱢᱮᱱᱟᱜ-ᱟ ᱚᱝᱠᱟᱜᱮ ᱫᱚᱦᱚᱭᱢᱮ\n#ᱡᱚᱛᱚ ᱚᱠᱛᱚ ᱨᱮ ᱡᱟᱹᱦᱤᱨᱮᱱ ᱠᱩᱴᱨᱟᱹ ᱞᱟᱛᱟᱨ ᱨᱮ (ᱠᱷᱟᱹᱞᱤ ᱦᱟᱹᱴᱤᱧ //ᱛᱟᱞᱟᱨᱮ) ᱵᱟᱹᱭᱥᱟᱹᱣᱢᱮ\n#ᱱᱚᱣᱟ ᱠᱚ ᱫᱚ ᱵᱟᱨᱦᱮ ᱨᱮᱭᱟᱜ (hotlinked) ᱪᱤᱛᱟᱹᱨ ᱨᱮᱭᱟᱜ URL ᱥᱟᱶᱛᱮ ᱢᱤᱞᱟᱹᱣ ᱦᱩᱭᱩᱜ-ᱟ\n#ᱚᱠᱟᱠᱩ ᱢᱤᱞᱟᱹᱜ-ᱟ, ᱚᱱᱟᱠᱩ ᱫᱚ ᱪᱤᱛᱟᱹᱨ ᱞᱮᱠᱟᱛᱮ ᱩᱫᱩᱜᱚᱜ-ᱟ, ᱵᱟᱝᱠᱷᱟᱱ ᱫᱚ ᱠᱷᱟᱹᱞᱤ ᱪᱤᱛᱟᱨ ᱡᱚᱱᱚᱲ ᱩᱫᱩᱜᱚᱜ-ᱟ\n#ᱱᱚᱣᱟ ᱞᱟᱭᱤᱱ ᱨᱮᱭᱟᱜ ᱮᱛᱦᱚᱵᱨᱮ # ᱢᱮᱱᱟᱜ-ᱟ ᱚᱱᱟ ᱞᱟᱭᱤᱱᱠᱚ ᱢᱮᱱᱠᱚ ᱦᱤᱥᱟᱹᱵᱛᱮ ᱵᱮᱵᱦᱟᱨ ᱦᱩᱭᱩᱜ-ᱟ\n#ᱱᱚᱣᱟ ᱫᱚ ᱨᱤᱢᱡᱷᱟᱹᱣᱜᱮ\n#ᱱᱚᱣᱟ ᱫᱟᱜᱽ ᱪᱮᱛᱟᱱᱨᱮ regex ᱠᱩᱴᱨᱟᱹ ᱵᱟᱹᱭᱥᱟᱹᱣᱢᱮ᱾ ᱱᱚᱣᱟ ᱞᱟᱭᱤᱱ ᱪᱮᱫᱞᱮᱠᱟ ᱢᱮᱱᱟᱜ-ᱟ ᱚᱝᱠᱟᱜᱮ ᱫᱚᱦᱚᱭᱢᱮ</pre>",
        "tag-filter": "[[Special:Tags|ᱜᱚᱛᱟᱣ]] ᱪᱷᱟᱹᱱᱤ:",
-       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|á±¥á±\9fá±\9bá±\9aá±¢|á±¥á±\9fá±\9bá±\9aᱢᱠᱩ}}]]: $2)",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|á±\9cá±\9aá±\9bá±\9fá±£|á±\9cá±\9aá±\9bá±\9fᱣᱠá±\9a}}]]: $2)",
        "tags-active-yes": "ᱦᱮᱸ",
        "tags-active-no": "ᱵᱟᱝ",
        "tags-hitcount": "$1 {{PLURAL:$1|ᱟᱹᱨᱩ|ᱟᱹᱨᱩᱠᱚ}}",
index 22d343e..9018359 100644 (file)
        "viewsourcetext": "توهان هن صفحي جو ڪوڊ ڏسي ۽ نقل ڪري سگھو ٿا.",
        "protectedinterface": "هي صفحو سافٽ ويئر جو انٽرفيس متعين ڪري ٿو ۽ غلط استعال کان بچڻ لاءِ ان کي تحفظيو ويو آهي.\nتمام وڪي ۾ ترجمو شامل ڪرڻ لاءِ يا هن ۾ تبديلي ڪرڻ لاءِ ميڊياوڪي ترجمو [https://translatewiki.net/ translatewiki.net] استعمال ڪيو.",
        "namespaceprotected": "توهان کي نانءُپولار <strong>$1</strong> جا صفحا سنوارڻ جا اختيار ناهن.",
+       "sitecssprotected": "اوهان وٽ CSS صفحي کي ترميم ڪرڻ جا اختيار ناهن، ڇو ته اهڙيون ترميمون سڄي سائيٽ کي متاثر ڪري سگھن ٿيون.",
        "mycustomcssprotected": "توهان کي هيءُ CSS صفحو سنوارڻ جي اجازت نہ آهي.",
        "mycustomjsprotected": "توهان کي هيءُ جاوا اسڪرپٽ صفحو سنوارڻ جي اجازت حاصل ڪانهي.",
        "myprivateinfoprotected": "توهان کي پنهنجي ذاتي معلومات سنوارڻ جي اجازت حاصل نہ آهي.",
        "group-autoconfirmed": "خودبخود پڪ ڪيل واپرائيندڙَ",
        "group-bot": "بوٽس",
        "group-sysop": "منتظم",
+       "group-interface-admin": "منتظم براءِ حليو",
        "group-bureaucrat": "ڪامورا",
        "group-all": "(سڀ)",
        "group-user-member": "{{GENDER:$1|واپرائيندڙ}}",
        "group-bot-member": "{{GENDER:$1|بوٽ}}",
        "group-sysop-member": "{{GENDER:$1|منتظم}}",
+       "group-interface-admin-member": "{{GENDER:$1|منتظم براءِ حليو}}",
        "group-bureaucrat-member": "{{GENDER:$1|ڪامورو}}",
        "group-suppress-member": "{{GENDER:$1|دٻائيندڙ}}",
        "grouppage-user": "{{ns:project}}:واپرائيندڙ",
        "grouppage-autoconfirmed": "{{ns:project}}:خودڪارنموني پڪ ڪيل رڪن",
        "grouppage-bot": "{{ns:project}}:بوٽس",
        "grouppage-sysop": "{{ns:project}}:منتظمين",
+       "grouppage-interface-admin": "{{ns:project}}:منتظم براءِ حليو",
        "grouppage-bureaucrat": "{{ns:project}}:ڪامورا",
        "grouppage-suppress": "{{ns:project}}:دٻايو",
        "right-read": "صفحا پڙهو",
        "right-unblockself": "ڪنهن تان بندش ختم ڪريو",
        "right-editinterface": "واپرائيندڙ باهمرُو کي سنواريو",
        "right-viewmywatchlist": "پنهنجي نظر ۾ فھرست ڏسو",
+       "right-editmywatchlist": "پنهنجي نگھداشت واري فهرست کي سنواريو. ياد رکو ڪجهه ڪم هن اختيار کان سواءِ پڻ ممڪن آهن.",
+       "right-editmyprivateinfo": "پنهنجي ذاتي معلومات سنواريو (جيئن برق ٽپال، اصل نالو)",
        "right-editmyoptions": "پنهنجون ترجيحون سنواريو",
        "right-import": "ٻين وڪيز کان صفحا درآمديو",
        "right-importupload": "ڪو فائيل چاڙهي صفحا درآمديو",
        "markaspatrolledtext": "ھن صفحي کي گشت ڪيل طور نشان لڳايو",
        "patrol-log-page": "گشت لاگ",
        "confirm-markpatrolled-button": "ٺيڪ (او ڪي) آهي",
-       "previousdiff": "â\86\90 اڳوڻي ترميم",
-       "nextdiff": "Ù\86ئÙ\8aÙ\86 ØªØ± ØªØ±Ù\85Ù\8aÙ\85 â\86\92",
+       "previousdiff": "â\86\92 اڳوڻي ترميم",
+       "nextdiff": "Ù\86ئÙ\8aÙ\86 ØªØ± ØªØ±Ù\85Ù\8aÙ\85 â\86\90",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|صفحو|صفحا}}",
        "file-info-size": "$1 × $2 عڪسلون، فائيل سائيز: $3، MIME ٽائيپ: $4",
        "file-nohires": "اڃان سنھو تحلل ميسر ناھي.",
        "fileduplicatesearch-submit": "ڳوليو",
        "specialpages": "خاص صفحا",
        "specialpages-note-top": "ڪُنجي",
+       "specialpages-note-restricted": "* عام خاص صفحا.\n* <span class=\"mw-specialpagerestricted\">بندشيل خاص صفحا.</span>",
+       "specialpages-group-maintenance": "سنڀال رپورٽ",
+       "specialpages-group-other": "وڌيڪ خاص صفحا",
        "specialpages-group-login": "داخل ٿيو / کاتو کوليو",
+       "specialpages-group-media": "ميڊيا رپورٽ ۽ چاڙهيل",
        "specialpages-group-users": "واپرائيندڙَ ۽ حق",
+       "specialpages-group-highuse": "وڌيڪ استعمال وارا صفحا",
+       "specialpages-group-pages": "صفحن جي فهرست",
+       "specialpages-group-pagetools": "صفحن جا اوزار",
        "blankpage": "خالي صفحو",
        "intentionallyblankpage": "هيءُ صفحو ڄاڻي خالي ڇڏيو ويو آهي.",
        "tag-filter": "[[Special:Tags|ٽيگ]] ڇاڻي:",
index 18a7765..3b52124 100644 (file)
        "cascadeprotected": "Táto stránka bola zamknutá proti úpravám, pretože je použitá na {{PLURAL:$1|nasledovnej stránke, ktorá je zamknutá|nasledovných stránkach, ktoré sú zamknuté}} voľbou „kaskádového zamknutia“:\n$2",
        "namespaceprotected": "Nemáte povolenie upravovať stránky v mennom priestore '''$1'''.",
        "customcssprotected": "Nemáte právo upravovať túto CSS stránku, pretože obsahuje osobné nastavenie iného používateľa.",
+       "customjsonprotected": "Nemáte právo upravovať túto JSON stránku, pretože obsahuje osobné nastavenie iného používateľa.",
        "customjsprotected": "Nemáte právo upravovať túto JavaScript stránku, pretože obsahuje osobné nastavenie iného používateľa.",
        "mycustomcssprotected": "Nemáte povolenie na úpravu tejto CSS stránky.",
+       "mycustomjsonprotected": "Nemáte povolenie na úpravu tejto JSON stránky.",
        "mycustomjsprotected": "Nemáte povolenie na úpravu tejto JavaScriptovej stránky.",
        "myprivateinfoprotected": "Nemáte povolenie na úpravu vašich súkromných informácií.",
        "mypreferencesprotected": "Nemáte povolenie na úpravu vašich nastavení.",
index 4df3c9d..76735d5 100644 (file)
        "edit-hook-aborted": "Urejanje je bilo brez obrazložitve prekinjeno zaradi neznane napake.",
        "edit-gone-missing": "Strani ni mogoče posodobiti.\nIzgleda, da je bila izbrisana.",
        "edit-conflict": "Navzkrižje urejanj.",
-       "edit-no-change": "Vaše urejanje je bilo prezrto, saj ni vsebovalo sprememb.",
+       "edit-no-change": "Tvoje urejanje je bilo prezrto, saj ni vsebovalo sprememb.",
        "postedit-confirmation-created": "Stran je bila ustvarjena.",
        "postedit-confirmation-restored": "Stran je bila obnovljena.",
-       "postedit-confirmation-saved": "Vaše urejanje smo shranili.",
-       "postedit-confirmation-published": "Vaše urejanje smo objavili.",
+       "postedit-confirmation-saved": "Tvoje urejanje je bilo shranjeno.",
+       "postedit-confirmation-published": "Tvoje urejanje smo objavili.",
        "edit-already-exists": "Ni bilo mogoče ustvariti nove strani, ker že obstaja.",
        "defaultmessagetext": "Prednastavljeno besedilo",
        "content-failed-to-parse": "Nisem mogel razčleniti vsebine $2 za obliko $1: $3",
        "confirm-unwatch-top": "Odstranim stran z vašega spiska nadzorov?",
        "confirm-rollback-button": "V redu",
        "confirm-rollback-top": "Povrnemo urejanja te strani?",
+       "confirm-mcrundo-title": "Razveljavi spremembo",
+       "mcrundofailed": "Razveljavitev ni uspela",
+       "mcrundo-missingparam": "Pri zahtevi manjkajo zahtevani parametri.",
+       "mcrundo-changed": "Stran je bila spremenjena, odkar ste si ogledali primerjavo. Prosimo, preglejte nove spremembe.",
        "percent": "$1&#160;%",
        "quotation-marks": "»$1«",
        "imgmultipageprev": "← prejšnja stran",
index 72e7ea5..d6b68a7 100644 (file)
        "virus-badscanner": "Konfiguracion i parregullt: Skaner i panjohur virusesh: ''$1''",
        "virus-scanfailed": "skanimi dështoi (code $1)",
        "virus-unknownscanner": "antivirus i pa njohur:",
-       "logouttext": "'''Ju keni dalë jashtë.''' \n \n Kini parasysh që disa faqe mund të shfaqen sikur të ishit i identifikuar derisa të fshini ''cache''-in e shfletuesit tuaj.",
+       "logouttext": "'''Ju keni dalë jashtë.''' \n \nKini parasysh që disa faqe mund të shfaqen sikur të ishit i/e identifikuar derisa të fshini ''cache''-in e shfletuesit tuaj.",
        "cannotlogoutnow-title": "Nuk mund të çkyçeni tani",
        "cannotlogoutnow-text": "Çregjistrimi nuk është i mundur kur përdorni $1.",
        "welcomeuser": "Mirë se vini, $1!",
index ae7317d..f132cd6 100644 (file)
@@ -42,7 +42,7 @@
                        "Stalker"
                ]
        },
-       "tog-underline": "Ð\9fодвлаÑ\87еÑ\9aе Ð»Ð¸Ð½ÐºÐ¾Ð²а:",
+       "tog-underline": "Ð\9fодвлаÑ\87еÑ\9aе Ð²ÐµÐ·а:",
        "tog-hideminor": "Сакриј мање измене са списка скорашњих измена",
        "tog-hidepatrolled": "Сакриј патролиране измене са списка скорашњих измена",
        "tog-newpageshidepatrolled": "Сакриј патролиране странице са списка нових страница",
        "tog-enotifrevealaddr": "Откриј моју имејл-адресу у порукама обавештења",
        "tog-shownumberswatching": "Прикажи број корисника који надгледају",
        "tog-oldsig": "Ваш постојећи потпис:",
-       "tog-fancysig": "Сматрај потпис као викитекст (без аутоматског линка)",
+       "tog-fancysig": "Сматрај потпис као викитекст (без самоповезивања)",
        "tog-uselivepreview": "Прикажи претпреглед без поновног учитавања странице",
-       "tog-forceeditsummary": "Упозори ме када не унесем резиме измене",
+       "tog-forceeditsummary": "Упозори ме када не унесем опис измене",
        "tog-watchlisthideown": "Сакриј моје измене са списка надгледања",
        "tog-watchlisthidebots": "Сакриј измене ботова са списка надгледања",
        "tog-watchlisthideminor": "Сакриј мање измене са списка надгледања",
        "tog-watchlisthideliu": "Сакриј измене пријављених корисника са списка надгледања",
        "tog-watchlistreloadautomatically": "Аутоматски освежи списак надгледања кад год се филтер промени (потребан JavaScript)",
-       "tog-watchlistunwatchlinks": "Ð\94одаÑ\98 Ð²ÐµÐ·Ðµ Ð·Ð° Ð´Ð¸Ñ\80екÑ\82но Ð´Ð¾Ð´Ð°Ð²Ð°Ñ\9aе/Ñ\83клаÑ\9aаÑ\9aе Ñ\81Ñ\82авки Ñ\81а Ñ\81пиÑ\81ка Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа (поÑ\82Ñ\80ебан JavaScript)",
+       "tog-watchlistunwatchlinks": "Ð\94одаÑ\98 Ð¾Ð·Ð½Ð°Ñ\87иваÑ\87е Ð·Ð° Ð¿Ñ\80екид Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа/нагледаÑ\9aе ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) Ð½Ð° Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ð½Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\81а Ð¿Ñ\80оменама (Ð\88аваÑ\81кÑ\80ипÑ\82 Ñ\98е Ð½ÐµÐ¾Ð¿Ñ\85одан Ð·Ð° Ñ\84Ñ\83нкÑ\86ионалноÑ\81Ñ\82 Ð¿Ñ\80ебаÑ\86иваÑ\9aа)",
        "tog-watchlisthideanons": "Сакриј измене анонимних корисника са списка надгледања",
        "tog-watchlisthidepatrolled": "Сакриј патролиране измене са списка надгледања",
        "tog-watchlisthidecategorization": "Сакриј категоризацију страница",
        "listingcontinuesabbrev": "наст.",
        "index-category": "Пописане странице",
        "noindex-category": "Непописане странице",
-       "broken-file-category": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½ÐµÐ¸Ñ\81пÑ\80авним Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸ма до датотека",
+       "broken-file-category": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½ÐµÐ¸Ñ\81пÑ\80авним Ð²ÐµÐ·Ð°ма до датотека",
        "categoryviewer-pagedlinks": "$1 ($2)",
        "category-header-numerals": "$1–$2",
        "about": "О нама",
        "tagline": "Извор: {{SITENAME}}",
        "help": "Помоћ",
        "search": "Претрага",
-       "search-ignored-headings": " #<!-- Ð½Ðµ Ð¼ÐµÑ\9aаÑ\98Ñ\82е Ð½Ð¸Ñ\88Ñ\82а Ñ\83 Ð¾Ð²Ð¾Ð¼ Ñ\80едÑ\83 --> <pre>\n# Ð\9dаÑ\81лови ÐºÐ¾Ñ\98и Ñ\9bе Ð±Ð¸Ñ\82и Ð·Ð°Ð½ÐµÐ¼Ð°Ñ\80ени Ð¿Ñ\80и Ð¿Ñ\80еÑ\82Ñ\80ази.\n# Ð\9fÑ\80омене Ñ\81Ñ\83 Ð²Ð¸Ð´Ñ\99иве Ð¾Ð´Ð¼Ð°Ñ\85 Ð½Ð°ÐºÐ¾Ð½ Ñ\88Ñ\82о Ñ\81е Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\81ловом Ð¿Ð¾Ð¿Ð¸Ñ\88е.\n# Ð\9cожеÑ\82е Ð¸Ð·Ð½Ñ\83диÑ\82и Ð¿Ð¾Ð½Ð¾Ð²Ð½Ð¾ Ð¿Ð¾Ð¿Ð¸Ñ\81иваÑ\9aе â\80\9eнÑ\83лÑ\82омâ\80\9d Ð¸Ð·Ð¼ÐµÐ½Ð¾Ð¼.\n# Ð¡Ð¸Ð½Ñ\82акÑ\81а Ñ\98е Ñ\81ледеÑ\9bа:\n#  * Ð¡Ð²Ð°ÐºÐ¸ Ñ\80ед ÐºÐ¾Ñ\98и Ð·Ð°Ð¿Ð¾Ñ\87иÑ\9aе Ð·Ð½Ð°ÐºÐ¾Ð¼ â\80\9e\80\9d Ñ\98е ÐºÐ¾Ð¼ÐµÐ½Ñ\82аÑ\80.\n#  * Ð¡Ð²Ð°ÐºÐ¸ Ð½Ðµ Ð¿Ñ\80азни Ñ\80ед Ñ\98е Ñ\82аÑ\87ан Ð½Ð°Ñ\81лов ÐºÐ¾Ñ\98и Ñ\9bе Ð±Ð¸Ñ\82и Ð·Ð°Ð½ÐµÐ¼Ð°Ñ\80ен, Ñ\81 Ñ\82им Ð´Ð° Ñ\81е Ñ\80азликÑ\83Ñ\98Ñ\83 Ð¼Ð°Ð»Ð° Ð¸ Ð²ÐµÐ»Ð¸ÐºÐ° Ñ\81лова Ð¸ Ñ\81ве Ð¾Ñ\81Ñ\82ало\nРеÑ\84еÑ\80енÑ\86е\nСпоÑ\99аÑ\88Ñ\9aи Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸\nТакође погледајте\n #</pre> <!-- не мењајте ништа у овом реду -->",
+       "search-ignored-headings": " #<!-- Ð½Ðµ Ð¼ÐµÑ\9aаÑ\98Ñ\82е Ð½Ð¸Ñ\88Ñ\82а Ñ\83 Ð¾Ð²Ð¾Ð¼ Ñ\80едÑ\83 --> <pre>\n# Ð\9dаÑ\81лови ÐºÐ¾Ñ\98и Ñ\9bе Ð±Ð¸Ñ\82и Ð·Ð°Ð½ÐµÐ¼Ð°Ñ\80ени Ð¿Ñ\80и Ð¿Ñ\80еÑ\82Ñ\80ази.\n# Ð\9fÑ\80омене Ñ\81Ñ\83 Ð²Ð¸Ð´Ñ\99иве Ð¾Ð´Ð¼Ð°Ñ\85 Ð½Ð°ÐºÐ¾Ð½ Ñ\88Ñ\82о Ñ\81е Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\81ловом Ð¿Ð¾Ð¿Ð¸Ñ\88е.\n# Ð\9cожеÑ\82е Ð¸Ð·Ð½Ñ\83диÑ\82и Ð¿Ð¾Ð½Ð¾Ð²Ð½Ð¾ Ð¿Ð¾Ð¿Ð¸Ñ\81иваÑ\9aе â\80\9eнÑ\83лÑ\82омâ\80\9d Ð¸Ð·Ð¼ÐµÐ½Ð¾Ð¼.\n# Ð¡Ð¸Ð½Ñ\82акÑ\81а Ñ\98е Ñ\81ледеÑ\9bа:\n#  * Ð¡Ð²Ð°ÐºÐ¸ Ñ\80ед ÐºÐ¾Ñ\98и Ð·Ð°Ð¿Ð¾Ñ\87иÑ\9aе Ð·Ð½Ð°ÐºÐ¾Ð¼ â\80\9e\80\9d Ñ\98е ÐºÐ¾Ð¼ÐµÐ½Ñ\82аÑ\80.\n#  * Ð¡Ð²Ð°ÐºÐ¸ Ð½Ðµ Ð¿Ñ\80азни Ñ\80ед Ñ\98е Ñ\82аÑ\87ан Ð½Ð°Ñ\81лов ÐºÐ¾Ñ\98и Ñ\9bе Ð±Ð¸Ñ\82и Ð·Ð°Ð½ÐµÐ¼Ð°Ñ\80ен, Ñ\81 Ñ\82им Ð´Ð° Ñ\81е Ñ\80азликÑ\83Ñ\98Ñ\83 Ð¼Ð°Ð»Ð° Ð¸ Ð²ÐµÐ»Ð¸ÐºÐ° Ñ\81лова Ð¸ Ñ\81ве Ð¾Ñ\81Ñ\82ало\nРеÑ\84еÑ\80енÑ\86е\nСпоÑ\99аÑ\88Ñ\9aе Ð²ÐµÐ·Ðµ\nТакође погледајте\n #</pre> <!-- не мењајте ништа у овом реду -->",
        "searchbutton": "Претражи",
        "go": "Иди",
        "searcharticle": "Иди",
        "history_small": "историја",
        "updatedmarker": "ажурирано од моје последње посете",
        "printableversion": "За штампање",
-       "permalink": "ТÑ\80аÑ\98ни Ð»Ð¸Ð½Ðº",
+       "permalink": "ТÑ\80аÑ\98на Ð²ÐµÐ·Ð°",
        "print": "Штампај",
        "view": "Погледај",
        "view-foreign": "Погледај на пројекту $1",
        "views": "Прегледи",
        "toolbox": "Алатке",
        "tool-link-userrights": "Промени {{GENDER:$1|корисничке}} групе",
-       "tool-link-userrights-readonly": "Ð\9fÑ\80еглед {{GENDER:$1|корисничких}} група",
+       "tool-link-userrights-readonly": "Ð\9fÑ\80иказ {{GENDER:$1|корисничких}} група",
        "tool-link-emailuser": "Слање имејла {{GENDER:$1|кориснику|корисници}}",
        "imagepage": "Погледај страницу датотеке",
        "mediawikipage": "Погледај страницу поруке",
        "nstab-category": "Категорија",
        "mainpage-nstab": "Главна страна",
        "nosuchaction": "Нема такве радње",
-       "nosuchactiontext": "Радња која је наведена у URL-у није важећа.\nМожда сте откуцали погрешан URL-а или сте пратили покварен линк.\nОво такође може да указује на грешку у софтверу који користи {{SITENAME}}.",
+       "nosuchactiontext": "Радња која је наведена у URL-у није важећа.\nМожда сте откуцали погрешан URL-а или сте пратили покварену везу.\nОво такође може да указује на грешку у софтверу који користи {{SITENAME}}.",
        "nosuchspecialpage": "Нема такве посебне странице",
        "nospecialpagetext": "<strong>Захтевали сте невалидну посебну страницу.</strong>\n\nСписак валидних посебних страница може да се пронађе на „[[Special:SpecialPages|{{int:specialpages}}]]”.",
        "error": "Грешка",
        "readonly": "База података је закључана",
        "enterlockreason": "Унесите разлог за закључавање, укључујући и време откључавања",
        "readonlytext": "База података је тренутно закључана, што значи да је није могуће мењати.\n\nСистемски администратор је навео следеће објашњење: $1",
-       "missing-article": "ТекÑ\81Ñ\82 Ñ\81Ñ\82Ñ\80аниÑ\86е Ð¿Ð¾Ð´ Ð½Ð°Ð·Ð¸Ð²Ð¾Ð¼ â\80\9e$1â\80\9c ($2) Ð½Ð¸Ñ\98е Ð¿Ñ\80онаÑ\92ен.\n\nУзÑ\80ок Ð¾Ð²Ðµ Ð³Ñ\80еÑ\88ке Ñ\98е Ð¾Ð±Ð¸Ñ\87но Ð·Ð°Ñ\81Ñ\82аÑ\80ела Ð¸Ð·Ð¼ÐµÐ½Ð° Ð¸Ð»Ð¸ Ð»Ð¸Ð½Ðº Ð´Ð¾ Ð¸Ð·Ð±Ñ\80иÑ\81ане Ñ\81Ñ\82Ñ\80аниÑ\86е.\n\nÐ\90ко Ñ\81е Ð½Ðµ Ñ\80ади Ð¾ Ñ\82оме, Ð¾Ð½Ð´Ð° Ñ\81Ñ\82е Ð²ÐµÑ\80оваÑ\82но Ð¿Ñ\80онаÑ\88ли Ð³Ñ\80еÑ\88кÑ\83 Ñ\83 Ñ\81оÑ\84Ñ\82веÑ\80Ñ\83.\nÐ\9fÑ\80иÑ\98авиÑ\82е Ñ\98е [[Special:ListUsers/sysop|админиÑ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\83]] Ñ\83з Ð¾Ð´Ð³Ð¾Ð²Ð°Ñ\80аÑ\98Ñ\83Ñ\9bи Ð»Ð¸Ð½Ðº.",
-       "missingarticle-rev": "(ревизија#: $1)",
+       "missing-article": "ТекÑ\81Ñ\82 Ñ\81Ñ\82Ñ\80аниÑ\86е Ð¿Ð¾Ð´ Ð½Ð°Ð·Ð¸Ð²Ð¾Ð¼ â\80\9e$1â\80\9c ($2) Ð½Ð¸Ñ\98е Ð¿Ñ\80онаÑ\92ен.\n\nУзÑ\80ок Ð¾Ð²Ðµ Ð³Ñ\80еÑ\88ке Ñ\98е Ð¾Ð±Ð¸Ñ\87но Ð·Ð°Ñ\81Ñ\82аÑ\80ела Ð¸Ð·Ð¼ÐµÐ½Ð° Ð¸Ð»Ð¸ Ð²ÐµÐ·Ð° Ð´Ð¾ Ð¸Ð·Ð±Ñ\80иÑ\81ане Ñ\81Ñ\82Ñ\80аниÑ\86е.\n\nÐ\90ко Ñ\81е Ð½Ðµ Ñ\80ади Ð¾ Ñ\82оме, Ð¾Ð½Ð´Ð° Ñ\81Ñ\82е Ð²ÐµÑ\80оваÑ\82но Ð¿Ñ\80онаÑ\88ли Ð³Ñ\80еÑ\88кÑ\83 Ñ\83 Ñ\81оÑ\84Ñ\82веÑ\80Ñ\83.\nÐ\9fÑ\80иÑ\98авиÑ\82е Ñ\98е [[Special:ListUsers/sysop|админиÑ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\83]] Ñ\83з Ð¾Ð´Ð³Ð¾Ð²Ð°Ñ\80аÑ\98Ñ\83Ñ\9bÑ\83 Ð²ÐµÐ·Ñ\83.",
+       "missingarticle-rev": "(измена#: $1)",
        "missingarticle-diff": "(разлика: $1, $2)",
        "readonly_lag": "База података је аутоматски закључана да би се секундарни сервери базе података ускладили с главним.",
        "internalerror": "Унутрашња грешка",
-       "internalerror_info": "Ð\98нÑ\82еÑ\80на грешка: $1",
+       "internalerror_info": "УнÑ\83Ñ\82Ñ\80аÑ\88Ñ\9aа грешка: $1",
        "internalerror-fatal-exception": "Грешка необрађеног изузетка типа „$1“",
        "filecopyerror": "Не могу да копирам датотеку „$1“ у „$2“.",
        "filerenameerror": "Не могу да преименујем датотеку „$1“ у „$2“.",
        "cannotdelete": "Не могу да избришем страницу или датотеку „$1“.\nМогуће је да ју је неко већ избрисао.",
        "cannotdelete-title": "Не могу да избришем страницу „$1“",
        "delete-hook-aborted": "Брисање је прекинула кука.\nНије дато никакво образложење.",
-       "no-null-revision": "Не могу да направим нову ништавну ревизију странице „$1“",
+       "no-null-revision": "Не могу да направим нову ништавну измену странице „$1“",
        "badtitle": "Лош наслов",
        "badtitletext": "Тражени наслов странице је неважећи, празан или је погрешно повезан међујезички или међувики наслов.\nМожда садржи један или више знакова који се не могу користити у насловима.",
        "title-invalid-empty": "Тражено име странице је празно или садржи само назив именског простора.",
        "title-invalid-utf8": "Тражени назив странице садржи неважећи UTF-8 знак.",
-       "title-invalid-interwiki": "Тражени наслов странице садржи унутрашњи вики линк који не може да се користи у насловима.",
+       "title-invalid-interwiki": "Тражени наслов странице садржи међувики везу који не може да се користи у насловима.",
        "title-invalid-talk-namespace": "Тражени наслов странице се односи на страницу за разговор која не може постојати.",
        "title-invalid-characters": "Тражени наслов има неважеће знакове: „$1“.",
        "title-invalid-relative": "Наслов има релативну путању. Релативни наслови страница (./, ../) нису важећи јер ће често бити недоступни у корисничком прегледачу.",
        "cascadeprotected": "Ова страница је закључана јер садржи {{PLURAL:$1|следећу страницу која је заштићена|следеће странице које су заштићене}} „преносивом“ заштитом:\n$2",
        "namespaceprotected": "Немате дозволу да уређујете странице у именском простору: <strong>$1</strong>.",
        "customcssprotected": "Немате дозволу да мењате ову CSS страницу јер садржи лична подешавања другог корисника.",
-       "customjsprotected": "Немате дозволу да мењате ову страницу JavaScript јер садржи лична подешавања другог корисника.",
+       "customjsonprotected": "Немате дозволу да мењате ову JSON страницу зато што садржи лична подешавања другог корисника.",
+       "customjsprotected": "Немате дозволу да мењате ову JavaScript страницу јер садржи лична подешавања другог корисника.",
+       "sitecssprotected": "Немате дозволу да мењате ову CSS страницу зато што може утицати на све посетиоце.",
+       "sitejsonprotected": "Немате дозволу да мењате ову JSON страницу зато што може утицати на све посетиоце.",
+       "sitejsprotected": "Немате дозволу да мењате ову JavaScript страницу зато што може утицати на све посетиоце.",
        "mycustomcssprotected": "Немате дозволу да уређујете ову CSS страницу.",
        "mycustomjsonprotected": "Немате дозволу да уређујете ову JSON страницу.",
        "mycustomjsprotected": "Немате дозволу да уређујете ову страницу с јаваскриптом.",
        "cannotloginnow-title": "Пријава тренутно није могућа",
        "cannotloginnow-text": "Пријава није могућа када се користи $1.",
        "cannotcreateaccount-title": "Не могу да отворим налоге",
-       "cannotcreateaccount-text": "Ð\94иÑ\80екÑ\82но Ð¿Ñ\80авÑ\99ење налога није омогућено на овом викију.",
+       "cannotcreateaccount-text": "Ð\94иÑ\80екÑ\82но Ð¾Ñ\82ваÑ\80ање налога није омогућено на овом викију.",
        "yourdomainname": "Домен:",
        "password-change-forbidden": "Не можете да промените лозинку на овом викију.",
        "externaldberror": "Дошло је до грешке при потврди идентитета базе података или вам није дозвољено да ажурирате свој спољни налог.",
        "createacct-realname": "Право име (опционално)",
        "createacct-reason": "Разлог",
        "createacct-reason-ph": "Зашто правите још један налог?",
-       "createacct-reason-help": "Ð\9fоÑ\80Ñ\83ка ÐºÐ¾Ñ\98а Ñ\81е Ð¿Ñ\80иказÑ\83Ñ\98е Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и Ð¿Ñ\80авÑ\99еÑ\9aа ÐºÐ¾Ñ\80иÑ\81ниÑ\87киÑ\85 налога",
+       "createacct-reason-help": "Ð\9fоÑ\80Ñ\83ка ÐºÐ¾Ñ\98а Ñ\81е Ð¿Ñ\80иказÑ\83Ñ\98е Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 Ð¾Ñ\82ваÑ\80аÑ\9aа налога",
        "createacct-submit": "Отвори свој налог",
        "createacct-another-submit": "Отвори налог",
        "createacct-continue-submit": "Наставите отварање налога",
        "changeemail-no-info": "Морате бити пријављени да бисте приступили овој страници.",
        "changeemail-oldemail": "Актуелна имејл-адреса:",
        "changeemail-newemail": "Нова имејл-адреса:",
+       "changeemail-newemail-help": "Ово поље би требало да оставите празно ако желите да уклоните вашу имејл адресу. Нећете бити у могућности да ресетујете заборављену лозинку и нећете примати мејлове од овог викија ако је имејл адреса уклоњена.",
        "changeemail-none": "(ништа)",
        "changeemail-password": "Ваша лозинка за пројекат {{SITENAME}}:",
        "changeemail-submit": "Промени имејл",
        "bold_tip": "Подебљан текст",
        "italic_sample": "Искошен текст",
        "italic_tip": "Искошен текст",
-       "link_sample": "Ð\9dаÑ\81лов Ð»Ð¸Ð½ÐºÐ°",
-       "link_tip": "УнÑ\83Ñ\82Ñ\80аÑ\88Ñ\9aи Ð»Ð¸Ð½Ðº",
-       "extlink_sample": "http://www.example.com/ Ð½Ð°Ñ\81лов Ð»Ð¸Ð½ÐºÐ°",
-       "extlink_tip": "СпоÑ\99аÑ\88Ñ\9aи Ð»Ð¸Ð½Ðº (са префиксом http://)",
+       "link_sample": "Ð\9dаÑ\81лов Ð²ÐµÐ·Ðµ",
+       "link_tip": "УнÑ\83Ñ\82Ñ\80аÑ\88Ñ\9aа Ð²ÐµÐ·Ð°",
+       "extlink_sample": "http://www.example.com/ Ð½Ð°Ñ\81лов Ð²ÐµÐ·Ðµ",
+       "extlink_tip": "СпоÑ\99аÑ\88Ñ\9aа Ð²ÐµÐ·Ð° (са префиксом http://)",
        "headline_sample": "Текст наслова",
        "headline_tip": "Поднаслов (ниво 2)",
        "nowiki_sample": "Овде уметните необликован текст",
        "image_sample": "Пример.jpg",
        "image_tip": "Уграђивање датотеке",
        "media_sample": "Пример.ogg",
-       "media_tip": "Ð\9bинк до датотеке",
+       "media_tip": "Ð\92еза до датотеке",
        "sig_tip": "Ваш потпис са временском ознаком",
        "hr_tip": "Водоравна линија (користите ретко)",
-       "summary": "Резиме:",
+       "summary": "Ð\9eпиÑ\81 Ð¸Ð·Ð¼ÐµÐ½е:",
        "subject": "Тема:",
        "minoredit": "Ово је мања измена",
        "watchthis": "Надгледај ову страницу",
        "blankarticle": "<strong>Упозорење:</strong> Страница коју правите је празна.\nАко још једном притиснете „$1”, страница ће бити направљена без икаквог садржаја.",
        "anoneditwarning": "<strong>Упозорење:</strong> Нисте пријављени. Ако објавите страницу, ваша IP адреса ће бити јавно видљива у њеној историји измена и другде. Ако се <strong>[$1 пријавите]</strong> или <strong>[$2 отворите налог]</strong>, поред осталих погодности које добијате ваше измене ће бити приписиване вашем корисничком имену.",
        "anonpreviewwarning": "<em>Нисте пријављени. Ако објавите страницу, ваша IP адреса ће бити јавно видљива у њеној историји измена и другде.</em>",
-       "missingsummary": "<strong>Подсетник:</strong> нисте навели резиме измене.\nАко поново кликнете на „$1”, ваша измена ће бити сачувана без резимеа.",
+       "missingsummary": "<strong>Подсетник:</strong> нисте навели опис измене.\nАко поново кликнете на „$1”, ваша измена ће бити сачувана без њега.",
        "selfredirect": "<strong>Упозорење:</strong> Преусмеравате ову страницу на њу саму.\nМожда вам је одредишна страница за преусмерење погрешна или уређујете погрешну страницу.\nАко још једном притиснете „$1”, преусмерење ће свеједно бити направљено.",
        "missingcommenttext": "Молимо унесите коментар.",
        "missingcommentheader": "<strong>Напомена:</strong> Нисте унели наслов теме овог коментара.\nАко поново кликнете на „$1”, измена ће бити сачувана без наслова.",
-       "summary-preview": "Преглед резимеа измене:",
+       "summary-preview": "Преглед описа измене:",
        "subject-preview": "Преглед теме:",
        "previewerrortext": "Дошло је до грешке при покушају прегледа промена.",
        "blockedtitle": "Корисник је блокиран",
        "newarticletext": "Дошли сте на страницу која још не постоји.\nДа бисте је направили, почните да куцате у прозор испод овог текста (погледајте [$1 страницу за помоћ]).\nАко сте овде дошли грешком, вратите се на претходну страницу.",
        "anontalkpagetext": "----\n<em>Ово је страница за разговор с анонимним корисником који још нема налог или га не користи.</em>\nЗбог тога морамо да користимо бројчану IP адресу како бисмо га препознали.\nТакву адресу може делити више корисника.\nАко сте анонимни корисник и мислите да су вам упућене примедбе, [[Special:CreateAccount|отворите налог]] или се [[Special:UserLogin|пријавите]] да бисте избегли будућу забуну с осталим анонимним корисницима.",
        "noarticletext": "На овој страници тренутно нема текста.\nМожете [[Special:Search/{{PAGENAME}}|потражити овај наслов]] на другим страницама,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} претражити сродне извештаје] или [{{fullurl:{{FULLPAGENAME}}|action=edit}} направити ову страницу]</span>.",
-       "noarticletext-nopermission": "ТÑ\80енÑ\83Ñ\82но Ð½ÐµÐ¼Ð° Ñ\82екÑ\81Ñ\82а Ð½Ð° Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и.\nÐ\9cожеÑ\82е Ð´Ð° [[Special:Search/{{PAGENAME}}|поÑ\82Ñ\80ажиÑ\82е Ð¾Ð²Ð°Ñ\98 Ð½Ð°Ñ\81лов Ñ\81Ñ\82Ñ\80аниÑ\86е]] Ð½Ð° Ð´Ñ\80Ñ\83гим Ñ\81Ñ\82Ñ\80аниÑ\86ама Ð¸Ð»Ð¸ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ð¿Ñ\80еÑ\82Ñ\80ажиÑ\82е Ñ\81Ñ\80одне ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е]</span>, али немате дозволу да направите ову страницу.",
-       "missing-revision": "РевизиÑ\98а Ð±Ñ\80. $1 Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86и Ð¿Ð¾Ð´ Ð¸Ð¼ÐµÐ½Ð¾Ð¼ â\80\9e{{FULLPAGENAME}}â\80\9c Ð½Ðµ Ð¿Ð¾Ñ\81Ñ\82оÑ\98и.\n\nÐ\9eво Ñ\81е Ð¾Ð±Ð¸Ñ\87но Ð´ÐµÑ\88ава ÐºÐ°Ð´Ð° Ð¿Ñ\80аÑ\82иÑ\82е Ð·Ð°Ñ\81Ñ\82аÑ\80ели Ð»Ð¸Ð½Ðº Ð´Ð¾ Ñ\81Ñ\82Ñ\80аниÑ\86е ÐºÐ¾Ñ\98а Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана.\nÐ\92иÑ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и брисања].",
+       "noarticletext-nopermission": "ТÑ\80енÑ\83Ñ\82но Ð½ÐµÐ¼Ð° Ñ\82екÑ\81Ñ\82а Ð½Ð° Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и.\nÐ\9cожеÑ\82е Ð´Ð° [[Special:Search/{{PAGENAME}}|поÑ\82Ñ\80ажиÑ\82е Ð¾Ð²Ð°Ñ\98 Ð½Ð°Ñ\81лов Ñ\81Ñ\82Ñ\80аниÑ\86е]] Ð½Ð° Ð´Ñ\80Ñ\83гим Ñ\81Ñ\82Ñ\80аниÑ\86ама Ð¸Ð»Ð¸ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ð¿Ñ\80еÑ\82Ñ\80ажиÑ\82е Ñ\81Ñ\80одне Ð´Ð½ÐµÐ²Ð½Ð¸Ðºе]</span>, али немате дозволу да направите ову страницу.",
+       "missing-revision": "Ð\98змена Ð±Ñ\80. $1 Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86и Ð¿Ð¾Ð´ Ð¸Ð¼ÐµÐ½Ð¾Ð¼ â\80\9e{{FULLPAGENAME}}â\80\9c Ð½Ðµ Ð¿Ð¾Ñ\81Ñ\82оÑ\98и.\n\nÐ\9eво Ñ\81е Ð¾Ð±Ð¸Ñ\87но Ð´ÐµÑ\88ава ÐºÐ°Ð´Ð° Ð¿Ñ\80аÑ\82иÑ\82е Ð·Ð°Ñ\81Ñ\82аÑ\80елÑ\83 Ð²ÐµÐ·Ñ\83 Ð´Ð¾ Ñ\81Ñ\82Ñ\80аниÑ\86е ÐºÐ¾Ñ\98а Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана.\nÐ\92иÑ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 брисања].",
        "userpage-userdoesnotexist": "Кориснички налог „<nowiki>$1</nowiki>“ није отворен.\nРазмислите да ли заиста желите да направите/уредите ову страницу.",
        "userpage-userdoesnotexist-view": "Кориснички налог „$1“ није отворен.",
-       "blocked-notice-logextract": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ан.\nÐ\9fоÑ\81ледÑ\9aи Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и блокирања је наведен испод као референца:",
+       "blocked-notice-logextract": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ан.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 блокирања је наведен испод као референца:",
        "clearyourcache": "<strong>Напомена:</strong> Након чувања, можда ћете морати да очистите кеш прегледача како бисте видели промене.\n* <strong>Фајерфокс / Сафари:</strong> Држите <em>Shift</em> и кликните на <em>Освежи</em> или притисните <em>Ctrl-F5</em> или <em>Ctrl-R</em> (<em>⌘-R</em> на Меку)\n* <strong>Гугл кроум:</strong> Притисните <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> на Меку)\n* <strong>Интернет експлорер:</strong> Држите <em>Ctrl</em> и кликните на <em>Освежи</em> или притисните <em>Ctrl-F5</em>\n* <strong>Опера:</strong> Идите на <em>Алатке → Подешавања</em> (<em>Опера → Подешавања</em> на Меку) и затим <em>Приватност и безбедност → Очистите податке о прегледима → Кеширане слике и датотеке</em>.",
-       "usercssyoucanpreview": "<strong>Савет:<strong> кориситите дугме „{{int:showpreview}}“ да испробате свој нови CSS пре него што га сачувате.",
-       "userjsyoucanpreview": "<strong>Савет:</strong> кориситите дугме „{{int:showpreview}}“ да испробате свој нови јаваскрипт пре него што га сачувате.",
+       "usercssyoucanpreview": "<strong>Савет:<strong> Кориситите дугме „{{int:showpreview}}“ да испробате свој нови CSS пре него што га сачувате.",
+       "userjsonyoucanpreview": "<strong>Савет:</strong> Користите дугме \"{{int:showpreview}}\" да испробате свој нови JSON пре него што га сачувате.",
+       "userjsyoucanpreview": "<strong>Савет:</strong> Кориситите дугме „{{int:showpreview}}“ да испробате свој нови јаваскрипт пре него што га сачувате.",
        "usercsspreview": "<strong>Ово је само преглед CSS-а.\nСтраница још није сачувана!</strong>",
-       "userjspreview": "<strong>Ово је само преглед јаваскрипта.\nСтраница још није сачувана!</strong>",
-       "sitecsspreview": "<strong>Ово је само преглед CSS-а.\nСтраница још није сачувана!</strong>",
+       "userjsonpreview": "<strong>Запамтите да само тестирате/прегледавате вашу корисничку JSON конфигурацију.\nСтраница још није сачувана!</strong>",
+       "userjspreview": "<strong>Запамтите да само тестирате/прегледавате ваш кориснички јаваскрипт.\nСтраница још није сачувана!</strong>",
+       "sitecsspreview": "<strong>Запамтите да је ово само преглед CSS-а.\nСтраница још није сачувана!</strong>",
+       "sitejsonpreview": "<strong>Запамтите да је ово само преглед JSON-а.\nСтраница још није сачувана!</strong>",
        "sitejspreview": "<strong>Ово је само преглед јаваскрипта.\nСтраница још није сачувана!</strong>",
        "userinvalidconfigtitle": "<strong>Упозорење:</strong> не постоји тема „$1“.\nПрилагођене странице CSS, JSON и Јаваскрипт почињу малим словом, нпр. {{ns:user}}:Foo/vector.css, а не {{ns:user}}:Foo/Vector.css.",
        "updated": "(ажурирано)",
        "editconflict": "Сукобљене измене: $1",
        "explainconflict": "Неко други је у међувремену променио ову страницу.\nГорњи оквир садржи садашњи текст странице.\nВаше измене су приказане у доњем оквиру.\nМораћете да унесете своје промене у садашњи текст странице.\n<strong>Само</strong> ће текст у горњем оквиру за уређивање бити сачуван када кликнете на „$1”.",
        "yourtext": "Ваш текст",
-       "storedversion": "Ускладиштена ревизија",
-       "editingold": "<strong>Упозорење: уређујете застарелу ревизију ове странице.</strong>\nАко је сачувате, све промене направљене од ове ревизије ће бити изгубљене.",
+       "storedversion": "Ускладиштена измена",
+       "editingold": "<strong>Упозорење: уређујете застарелу измену ове странице.</strong>\nАко је сачувате, све промене направљене од ове измене ће бити изгубљене.",
        "unicode-support-fail": "Ваш прегледач не подржава Unicode. Он је неопоходан за уређивање страница, па зато не могу сачувати измену.",
        "yourdiff": "Разлике",
        "copyrightwarning": "Имајте на уму да се сви доприноси на овом викију сматрају као објављени под лиценцом $2 (више на $1).\nАко не желите да се ваши текстови мењају и размењују без ограничења, онда их не шаљите овде.<br />\nИсто тако обећавате да сте Ви аутор текста, или да сте га умножили са извора који је у јавном власништву.\n<strong>Не шаљите радове заштићене ауторским правима без дозволе!</strong>",
        "editpage-cannot-use-custom-model": "Модел садржаја ове странице се не може променити.",
        "longpageerror": "<strong>Грешка: текст који сте унели је величине {{PLURAL:$1|један килобајт|$1 килобајта}}, што је веће од {{PLURAL:$2|дозвољеног једног килобајта|дозвољена $2 килобајта|дозвољених $2 килобајта}}.</strong>\nСтраница не може бити сачувана.",
        "readonlywarning": "<strong>Упозорење: база података је закључана ради одржавања, тако да тренутно нећете моћи да сачувате измене.</strong>\nМожда бисте желели сачувати текст за касније у некој текстуалној датотеци.\n\nСистемски администратор је навео следеће објашњење: $1",
-       "protectedpagewarning": "<strong>УпозоÑ\80еÑ\9aе: Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ñ\81а Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\81ким Ð¾Ð²Ð»Ð°Ñ\88Ñ\9bеÑ\9aима Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ñ\83Ñ\80еÑ\92Ñ\83Ñ\98Ñ\83.</strong>\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и је наведен испод као референца:",
-       "semiprotectedpagewarning": "<strong>Ð\9dапомена:</strong> Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо Ð°Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð¿Ð¾Ñ\82вÑ\80Ñ\92ени ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ñ\83Ñ\80еÑ\92Ñ\83Ñ\98Ñ\83.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и је наведен испод као референца:",
+       "protectedpagewarning": "<strong>УпозоÑ\80еÑ\9aе: Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ñ\81а Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\81ким Ð¾Ð²Ð»Ð°Ñ\88Ñ\9bеÑ\9aима Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ñ\83Ñ\80еÑ\92Ñ\83Ñ\98Ñ\83.</strong>\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 је наведен испод као референца:",
+       "semiprotectedpagewarning": "<strong>Ð\9dапомена:</strong> Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо Ð°Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð¿Ð¾Ñ\82вÑ\80Ñ\92ени ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ñ\83Ñ\80еÑ\92Ñ\83Ñ\98Ñ\83.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 је наведен испод као референца:",
        "cascadeprotectedwarning": "<strong>Упозорење:</strong> Ова страница је заштићена тако да само корисници са [[Special:ListGroupRights|одређеним правима]] могу да је уређују, јер је укључена у {{PLURAL:$1|следећу страницу која је заштићена|следеће странице које су заштићене}} преносивом заштитом:",
-       "titleprotectedwarning": "<strong>УпозоÑ\80еÑ\9aе: Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81Ñ\83 Ð¿Ð¾Ñ\82Ñ\80ебна [[Special:ListGroupRights|поÑ\81ебна Ð¿Ñ\80ава]] Ð´Ð° Ñ\81е Ð¾Ð½Ð° Ð½Ð°Ð¿Ñ\80ави.</strong>\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и је наведен испод као референца:",
+       "titleprotectedwarning": "<strong>УпозоÑ\80еÑ\9aе: Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81Ñ\83 Ð¿Ð¾Ñ\82Ñ\80ебна [[Special:ListGroupRights|поÑ\81ебна Ð¿Ñ\80ава]] Ð´Ð° Ñ\81е Ð¾Ð½Ð° Ð½Ð°Ð¿Ñ\80ави.</strong>\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 је наведен испод као референца:",
        "templatesused": "{{PLURAL:$1|Шаблон који се користи|Шаблони који се користе}} на овој страници:",
        "templatesusedpreview": "{{PLURAL:$1|Шаблон|Шаблони}} у овом претпрегледу:",
        "templatesusedsection": "{{PLURAL:$1|Шаблон|Шаблони}} у овом одељку:",
        "permissionserrors": "Грешка у дозволи",
        "permissionserrorstext": "Немате дозволу за ову радњу из {{PLURAL:$1|следећег|следећих}} разлога:",
        "permissionserrorstext-withaction": "Немате дозволу да $2 из {{PLURAL:$1|следећег|следећих}} разлога:",
-       "contentmodelediterror": "Не можете уредити ову ревизију јер је њен модел садржаја <code>$1</code>, што се разликује од актуелног модела садржаја странице <code>$2</code>.",
-       "recreate-moveddeleted-warn": "<strong>Упозорење: Поново правите страницу која је претходно избрисана.</strong>\n\nРазмотрите да ли је прикладно да наставите са уређивањем ове странице.\nОвде је наведена евиденција брисања и премештања са образложењем:",
-       "moveddeleted-notice": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана.\nÐ\95виденÑ\86иÑ\98а Ð±Ñ\80иÑ\81аÑ\9aа, Ð·Ð°Ñ\88Ñ\82иÑ\82е Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð° испод као референца.",
-       "moveddeleted-notice-recent": "Ð\9dажалоÑ\81Ñ\82, Ð¾Ð²Ð° Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð½ÐµÐ´Ð°Ð²Ð½Ð¾ Ð¸Ð·Ð±Ñ\80иÑ\81ана (Ñ\83 Ð¿Ð¾Ñ\81ледÑ\9aиÑ\85 24 Ñ\81аÑ\82а).\nÐ\95виденÑ\86иÑ\98а Ð±Ñ\80иÑ\81аÑ\9aа, Ð·Ð°Ñ\88Ñ\82иÑ\82е Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð° је испод као референца:",
-       "log-fulllog": "Ð\9fогледаÑ\98 Ñ\86елÑ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98Ñ\83",
+       "contentmodelediterror": "Не можете уредити ову измену јер је њен модел садржаја <code>$1</code>, што се разликује од актуелног модела садржаја странице <code>$2</code>.",
+       "recreate-moveddeleted-warn": "<strong>Упозорење: Поново правите страницу која је претходно избрисана.</strong>\n\nРазмотрите да ли је прикладно да наставите са уређивањем ове странице.\nОвде је наведен дневник брисања и премештања са образложењем:",
+       "moveddeleted-notice": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана.\nÐ\94невник Ð±Ñ\80иÑ\81аÑ\9aа, Ð·Ð°Ñ\88Ñ\82иÑ\82е Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е Ð½Ð°Ð²ÐµÐ´ÐµÐ½ испод као референца.",
+       "moveddeleted-notice-recent": "Ð\9dажалоÑ\81Ñ\82, Ð¾Ð²Ð° Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð½ÐµÐ´Ð°Ð²Ð½Ð¾ Ð¸Ð·Ð±Ñ\80иÑ\81ана (Ñ\83 Ð¿Ð¾Ñ\81ледÑ\9aиÑ\85 24 Ñ\81аÑ\82а).\nÐ\94невник Ð±Ñ\80иÑ\81аÑ\9aа, Ð·Ð°Ñ\88Ñ\82иÑ\82е Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½Ð°Ð²ÐµÐ´ÐµÐ½ је испод као референца:",
+       "log-fulllog": "Цео Ð´Ð½ÐµÐ²Ð½Ð¸Ðº",
        "edit-hook-aborted": "Измену је прекинула кука.\nНије дато никакво образложење.",
        "edit-gone-missing": "Не могу да ажурирам страницу.\nИзгледа да је избрисана.",
        "edit-conflict": "Сукоб измена.",
        "undo-failure": "Ова измена се не може поништити због сукоба измена.",
        "undo-norev": "Не могу да вратим измену јер не постоји или је избрисана.",
        "undo-nochange": "Изгледа да је измена већ поништена.",
-       "undo-summary": "Поништена ревизија $1 {{GENDER:$2|корисника|кориснице}} [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]])",
+       "undo-summary": "Поништена измена $1 {{GENDER:$2|корисника|кориснице}} [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]])",
        "undo-summary-username-hidden": "Поништи измену $1 скривеног корисника",
        "cantcreateaccount-text": "Отварање налога с ове IP адресе (<strong>$1</strong>) је блокирао/ла [[User:$3|$3]].\n\nРазлог који је навео/ла $3 је <em>$2</em>",
        "cantcreateaccount-range-text": "Отварање налога са IP адреса у распону <strong>$1</strong>, који укључује и вашу IP адресу (<strong>$4</strong>) је блокирао/ла [[User:$3|$3]].\n\nРазлог који је навео/ла $3 је <em>$2</em>",
-       "viewpagelogs": "Ð\95виденÑ\86иÑ\98е ове странице",
+       "viewpagelogs": "Ð\94невниÑ\86и ове странице",
        "nohistory": "Не постоји историја измена ове странице.",
-       "currentrev": "Ð\90кÑ\82Ñ\83елна Ñ\80евизиÑ\98а",
-       "currentrev-asof": "Најновија ревизија на датум $2 у $3",
-       "revisionasof": "РевизиÑ\98а на датум $2 у $3",
-       "revision-info": "РевизиÑ\98а од $1 од стране {{GENDER:$6|корисника $2|кориснице $2}}$7",
-       "previousrevision": "← Старија ревизија",
-       "nextrevision": "Новија ревизија →",
-       "currentrevisionlink": "Ð\90кÑ\82Ñ\83елна Ñ\80евизиÑ\98а",
+       "currentrev": "Ð\9dаÑ\98новиÑ\98а Ð¸Ð·Ð¼ÐµÐ½а",
+       "currentrev-asof": "Најновија измена на датум $2 у $3",
+       "revisionasof": "Ð\98змена на датум $2 у $3",
+       "revision-info": "Ð\98змена од $1 од стране {{GENDER:$6|корисника $2|кориснице $2}}$7",
+       "previousrevision": "← Старија измена",
+       "nextrevision": "Новија измена →",
+       "currentrevisionlink": "Ð\9dаÑ\98новиÑ\98а Ð¸Ð·Ð¼ÐµÐ½а",
        "cur": "трен",
        "next": "след",
        "last": "разл",
        "page_first": "прва",
        "page_last": "последња",
-       "histlegend": "Избор разлика: означите кутијице ревизија за упоређивање и притисните enter или дугме на дну.<br />\nОбјашњење: <strong>({{int:cur}})</strong> = разлика са актуелном ревизијом, <strong>({{int:last}})</strong> = разлика са претходном ревизијом, <strong>{{int:minoreditletter}}</strong> = мања измена",
+       "histlegend": "Избор разлика: означите кутијице измена за упоређивање и притисните enter или дугме на дну.<br />\nОбјашњење: <strong>({{int:cur}})</strong> = разлика са најновијом изменом, <strong>({{int:last}})</strong> = разлика са претходном изменом, <strong>{{int:minoreditletter}}</strong> = мања измена",
        "history-fieldset-title": "Претрага измена",
-       "history-show-deleted": "Само избрисане ревизије",
+       "history-show-deleted": "Само избрисане измене",
        "histfirst": "најстарије",
        "histlast": "најновије",
        "historysize": "({{PLURAL:$1|1 бајт|$1 бајта|$1 бајтова}})",
        "historyempty": "(празно)",
-       "history-feed-title": "Историја ревизија",
+       "history-feed-title": "Историја измена",
        "history-feed-description": "Историја измена ове странице на викију",
        "history-feed-item-nocomment": "$1 у $2",
        "history-feed-empty": "Тражена страница не постоји.\nМогуће да је избрисана са викија или је преименована.\nПокушајте да [[Special:Search|претражите вики]] за релевантне нове странице.",
-       "history-edit-tags": "Уреди ознаке изабраних ревизија",
+       "history-edit-tags": "Уреди ознаке изабраних измена",
        "rev-deleted-comment": "(опис измене уклоњен)",
        "rev-deleted-user": "(корисничко име уклоњено)",
        "rev-deleted-event": "(детаљи уноса уклоњени)",
        "rev-deleted-user-contribs": "[корисничко име или IP адреса је уклоњена – измена је сакривена са списка доприноса]",
-       "rev-deleted-text-permission": "РевизиÑ\98а Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>обÑ\80иÑ\81ана</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и брисања].",
+       "rev-deleted-text-permission": "Ð\98змена Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>избÑ\80иÑ\81ана</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 брисања].",
        "rev-suppressed-text-permission": "Измена ове странице је <strong>сакривена</strong>. Више детаља можете наћи у [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} историји сакривања].",
-       "rev-deleted-text-unhide": "РевизиÑ\98а Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>обÑ\80иÑ\81ана</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и Ð±Ñ\80иÑ\81аÑ\9aа].\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° [$1 Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\80евизиÑ\98у] ако желите да наставите.",
-       "rev-suppressed-text-unhide": "РевизиÑ\98а Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и Ñ\81акÑ\80иваÑ\9aа].\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° [$1 Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\80евизиÑ\98у] ако желите да наставите.",
+       "rev-deleted-text-unhide": "Ð\98змена Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>избÑ\80иÑ\81ана</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 Ð±Ñ\80иÑ\81аÑ\9aа].\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° [$1 Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ð¸Ð·Ð¼ÐµÐ½у] ако желите да наставите.",
+       "rev-suppressed-text-unhide": "Ð\98змена Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\94еÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 Ñ\81акÑ\80иваÑ\9aа].\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° [$1 Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ð¸Ð·Ð¼ÐµÐ½у] ако желите да наставите.",
        "rev-deleted-text-view": "Измена ове странице је '''обрисана'''.\nМожете је погледати; више детаља можете наћи у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} историји брисања].",
-       "rev-suppressed-text-view": "РевизиÑ\98а Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\9cожеÑ\82е Ñ\98е Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82и; Ð´ÐµÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и сакривања].",
-       "rev-deleted-no-diff": "Не можете да видете ову разлику јер је једна од ревизија <strong>обрисана</strong>.\nДетаљи можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} евиденцији брисања].",
+       "rev-suppressed-text-view": "Ð\98змена Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\9cожеÑ\82е Ñ\98е Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82и; Ð´ÐµÑ\82аÑ\99е Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 сакривања].",
+       "rev-deleted-no-diff": "Не можете да видете ову разлику јер је једна од измена <strong>избрисана</strong>.\nДетаљи можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
        "rev-suppressed-no-diff": "Не можете видети ову разлику јер је једна од измена '''обрисана'''.",
-       "rev-deleted-unhide-diff": "Једна од ревизија у овој разлици је <strong>обрисана</strong>.\nДетаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} евиденцији брисања].\nИпак можете да [$1 погледате ову разлику] ако желите да наставите.",
-       "rev-suppressed-unhide-diff": "Ð\88една Ð¾Ð´ Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð¾Ð²Ð¾Ñ\98 Ñ\80азлиÑ\86и Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\92иÑ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и сакривања].\nИпак можете да [$1 погледате ову разлику] ако желите да наставите.",
-       "rev-deleted-diff-view": "Једна од ревизија у овој разлици је <strong>обрисана</strong>.\nИпак можете да погледате ову разлику; детаљњ можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} евиденцији брисања].",
-       "rev-suppressed-diff-view": "Ð\88една Ð¾Ð´ Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð¾Ð²Ð¾Ñ\98 Ñ\80азлиÑ\86и Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\80азликÑ\83; Ð²Ð¸Ñ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и сакривања].",
+       "rev-deleted-unhide-diff": "Једна од измена у овој разлици је <strong>обрисана</strong>.\nДетаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].\nИпак можете да [$1 погледате ову разлику] ако желите да наставите.",
+       "rev-suppressed-unhide-diff": "Ð\88една Ð¾Ð´ Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð¾Ð²Ð¾Ñ\98 Ñ\80азлиÑ\86и Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\92иÑ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 сакривања].\nИпак можете да [$1 погледате ову разлику] ако желите да наставите.",
+       "rev-deleted-diff-view": "Једна од измена у овој разлици је <strong>избрисана</strong>.\nИпак можете да погледате ову разлику; детаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
+       "rev-suppressed-diff-view": "Ð\88една Ð¾Ð´ Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð¾Ð²Ð¾Ñ\98 Ñ\80азлиÑ\86и Ñ\98е <strong>Ñ\81акÑ\80ивена</strong>.\nÐ\98пак Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\80азликÑ\83; Ð²Ð¸Ñ\88е Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ñ\80онаÑ\92еÑ\82е Ñ\83 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 сакривања].",
        "rev-delundel": "промени видљивост",
        "rev-showdeleted": "прикажи",
-       "revisiondelete": "Брисање/враћање ревизија",
-       "revdelete-nooldid-title": "Неважећа одредишна ревизија",
-       "revdelete-nooldid-text": "Нисте навели одредишну ревизију на којој треба да се изврши ова функција, та ревизија не постоји, или покушавате да сакријете актуелну ревизију.",
+       "revisiondelete": "Брисање/враћање измена",
+       "revdelete-nooldid-title": "Неважећа одредишна измена",
+       "revdelete-nooldid-text": "Нисте навели одредишну измену на којој треба да се изврши ова функција, та измена не постоји, или покушавате да сакријете актуелну измену.",
        "revdelete-no-file": "Тражена датотека не постоји.",
-       "revdelete-show-file-confirm": "Јесте ли сигурни да желите да видите избрисану ревизију датотеке „<nowiki>$1</nowiki>“ од $2; $3?",
+       "revdelete-show-file-confirm": "Јесте ли сигурни да желите да видите избрисану измену датотеке „<nowiki>$1</nowiki>“ од $2; $3?",
        "revdelete-show-file-submit": "Да",
-       "revdelete-selected-text": "{{PLURAL:$1|Изабрана ревизија|Изабране ревизије|Изабраних ревизија}} [[:$2]]:",
+       "revdelete-selected-text": "{{PLURAL:$1|Изабрана измена|Изабране измене|Изабраних измена}} [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Изабрана верзија датотеке|Изабране верзије датотеке}} [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Изабрана ставка у историји|Изабране ставке у историји}}:",
-       "revdelete-text-text": "Избрисане ревизије ће и даље бити видљиве у историји странице, али делови њиховог садржаја неће бити јавно доступни.",
+       "revdelete-text-text": "Избрисане измене ће и даље бити видљиве у историји странице, али делови њиховог садржаја неће бити јавно доступни.",
        "revdelete-text-file": "Избрисане верзије датотеке ће и даље бити видљиве у историји датотеке, али делови њиховог садржаја неће бити јавно доступни.",
-       "logdelete-text": "Ð\98збÑ\80иÑ\81ани Ð´Ð¾Ð³Ð°Ñ\92аÑ\98и Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98ама Ñ\9bе Ñ\81е Ð¸Ð´Ð°Ñ\99е Ð¿Ð¾Ñ\98авÑ\99иваÑ\82и Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и, али ће делови њиховог садржаја бити недоступни јавности.",
+       "logdelete-text": "Ð\98збÑ\80иÑ\81ани Ð´Ð¾Ð³Ð°Ñ\92аÑ\98и Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86има Ñ\9bе Ñ\81е Ð¸Ð´Ð°Ñ\99е Ð¿Ð¾Ñ\98авÑ\99иваÑ\82и Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83, али ће делови њиховог садржаја бити недоступни јавности.",
        "revdelete-text-others": "Остали администратори ће и даље моћи да приступе скривеном садржају и врате га, осим ако се поставе додатна ограничења.",
        "revdelete-confirm": "Потврдите да намеравате ово урадити, да разумете последице и да то чините у складу са [[{{MediaWiki:Policy-url}}|правилима]].",
        "revdelete-suppress-text": "Сакривање измена би требало користити <strong>само</strong> у следећим случајевима:\n* злонамерни или погрдни подаци\n* неприкладни лични подаци\n*: <em>кућна адреса и број телефона, број кредитне картице, ЈМБГ итд.</em>",
        "revdelete-legend": "Ограничења видљивости",
-       "revdelete-hide-text": "Текст ревизије",
+       "revdelete-hide-text": "Текст измене",
        "revdelete-hide-image": "Сакриј садржај датотеке",
        "revdelete-hide-name": "Циљ и параметре",
-       "revdelete-hide-comment": "Резиме измене",
+       "revdelete-hide-comment": "Ð\9eпиÑ\81 измене",
        "revdelete-hide-user": "Корисничко име/IP адреса",
        "revdelete-hide-restricted": "Сакриј податке од администратора и других корисника",
        "revdelete-radio-same": "(не мењај)",
        "revdelete-radio-set": "Сакривено",
        "revdelete-radio-unset": "Видљиво",
        "revdelete-suppress": "Сакриј податке од администратора и других корисника",
-       "revdelete-unsuppress": "Уклони ограничења на враћеним ревизијама",
+       "revdelete-unsuppress": "Уклони ограничења на враћеним изменама",
        "revdelete-log": "Разлог:",
-       "revdelete-submit": "Примени на {{PLURAL:$1|изабрану ревизију|изабране ревизије}}",
+       "revdelete-submit": "Примени на {{PLURAL:$1|изабрану измену|изабране измене}}",
        "revdelete-success": "Видљивост измене је ажурирана.",
-       "revdelete-failure": "Не могу да ажурирам видљивост ревизије:\n$1",
-       "logdelete-success": "Ð\9fоÑ\81Ñ\82авÑ\99ена Ñ\98е Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и.",
+       "revdelete-failure": "Не могу да ажурирам видљивост измене:\n$1",
+       "logdelete-success": "Ð\9fоÑ\81Ñ\82авÑ\99ена Ñ\98е Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83.",
        "logdelete-failure": "'''Не могу да поставим видљивост историје:'''\n$1",
        "revdel-restore": "промени видљивост",
        "pagehist": "Историја странице",
        "deletedhist": "Избрисана историја",
-       "revdelete-hide-current": "Ð\93Ñ\80еÑ\88ка Ð¿Ñ\80и Ñ\81акÑ\80иваÑ\9aÑ\83 Ñ\81Ñ\82авке Ð¾Ð´ $1, $2: Ð¾Ð²Ð¾ Ñ\98е Ð°ÐºÑ\82Ñ\83елна Ñ\80евизиÑ\98а.\nНе може да буде сакривена.",
+       "revdelete-hide-current": "Ð\93Ñ\80еÑ\88ка Ð¿Ñ\80и Ñ\81акÑ\80иваÑ\9aÑ\83 Ñ\81Ñ\82авке Ð¾Ð´ $1, $2: Ð\9eво Ñ\98е Ð°ÐºÑ\82Ñ\83елна Ð¸Ð·Ð¼ÐµÐ½а.\nНе може да буде сакривена.",
        "revdelete-show-no-access": "Грешка при приказивању ставке од $1, $2: означена је као „ограничена“.\nНемате приступ до ње.",
        "revdelete-modify-no-access": "Грешка при мењању ставке од $1, $2: означена је као „ограничена“.\nНемате приступ до ње.",
        "revdelete-modify-missing": "Грешка при мењању ИБ ставке $1: она не постоји у бази података.",
        "revdelete-no-change": "<strong>Упозорење:</strong> ставка од $1, $2 већ поседује затражена подешавања видљивости.",
-       "revdelete-concurrent-change": "Ð\93Ñ\80еÑ\88ка Ð¿Ñ\80и Ð¼ÐµÑ\9aаÑ\9aÑ\83 Ñ\81Ñ\82авке Ð¾Ð´ $1, $2: Ñ\9aен Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81 Ñ\98е Ñ\83 Ð¼ÐµÑ\92Ñ\83вÑ\80еменÑ\83 Ð¿Ñ\80оменио Ð´Ñ\80Ñ\83ги ÐºÐ¾Ñ\80иÑ\81ник.\nÐ\9fÑ\80овеÑ\80иÑ\82е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98Ñ\83.",
+       "revdelete-concurrent-change": "Ð\93Ñ\80еÑ\88ка Ð¿Ñ\80и Ð¼ÐµÑ\9aаÑ\9aÑ\83 Ñ\81Ñ\82авке Ð¾Ð´ $1, $2: Ñ\9aен Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81 Ñ\98е Ñ\83 Ð¼ÐµÑ\92Ñ\83вÑ\80еменÑ\83 Ð¿Ñ\80оменио Ð´Ñ\80Ñ\83ги ÐºÐ¾Ñ\80иÑ\81ник.\nÐ\9fÑ\80овеÑ\80иÑ\82е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº.",
        "revdelete-only-restricted": "Грешка при сакривању ставке од $1, $2: не можете сакрити ставке од администратора без избора других могућности видљивости.",
        "revdelete-reason-dropdown": "*Уобичајени разлози за брисање\n** Кршење ауторског права\n** Неприкладан коментар или лични подаци\n** Неприкладно корисничко име\n** Увредљиви подаци",
        "revdelete-otherreason": "Други/додатни разлог:",
        "revdelete-reasonotherlist": "Други разлог",
        "revdelete-edit-reasonlist": "Уреди разлоге за брисање",
-       "revdelete-offender": "Аутор ревизије:",
-       "suppressionlog": "Ð\95виденÑ\86иÑ\98а сакривања",
+       "revdelete-offender": "Аутор измене:",
+       "suppressionlog": "Ð\94невник сакривања",
        "suppressionlogtext": "Испод се налази списак брисања и блокирања који укључује садржај сакривен од администратора. Погледајте [[Special:BlockList|списак блокирања]] за списак актуелних операција забрана и блокирања.",
        "mergehistory": "Спајање историја странице",
-       "mergehistory-header": "Ова страница вам омогућава да спојите ревизије неке изворне странице у нову страницу.\nЗапамтите да ће ова промена оставити непромењен садржај историје странице.",
+       "mergehistory-header": "Ова страница вам омогућава да спојите измене неке изворне странице у нову страницу.\nЗапамтите да ће ова промена оставити непромењен садржај историје странице.",
        "mergehistory-box": "Споји измене две странице:",
        "mergehistory-from": "Изворна страница:",
        "mergehistory-into": "Одредишна страница:",
        "mergehistory-list": "Спојива историја измена",
-       "mergehistory-merge": "Следеће ревизије странице [[:$1]] могу се спојити са [[:$2]].\nКористите дугмиће у колони да бисте спојили ревизије које су направљене пре наведеног времена.\nКоришћење навигационих линкова ће поништити ову колону.",
+       "mergehistory-merge": "Следеће измене странице [[:$1]] могу се спојити са [[:$2]].\nКористите дугмиће у колони да бисте спојили измене које су направљене пре наведеног времена.\nКоришћење навигационих веза ће поништити ову колону.",
        "mergehistory-go": "Прикажи измене које се могу спојити",
-       "mergehistory-submit": "Споји ревизије",
+       "mergehistory-submit": "Споји измене",
        "mergehistory-empty": "Нема измена за спајање.",
-       "mergehistory-done": "$3 {{PLURAL:$3|ревизија странице $1 је спојена|ревизије странице $1 су спојене|ревизија странице $1 је спојено}} у [[:$2]].",
+       "mergehistory-done": "$3 {{PLURAL:$3|измена странице $1 је спојена|измене странице $1 су спојене|измена странице $1 је спојено}} у [[:$2]].",
        "mergehistory-fail": "Не могу да спојим историје. Проверите страницу и временске параметре.",
        "mergehistory-fail-bad-timestamp": "Временска ознака је неважећа.",
        "mergehistory-fail-invalid-source": "Изворна страница није валидна.",
        "mergehistory-fail-invalid-dest": "Одредишна страница је неважећа.",
-       "mergehistory-fail-no-change": "Спајање историје није спојило ниједну ревизију. Проверите параметре странице и времена.",
+       "mergehistory-fail-no-change": "Спајање историје није спојило ниједну измену. Проверите параметре странице и времена.",
        "mergehistory-fail-permission": "Немате овлашћење за спајање историје.",
        "mergehistory-fail-self-merge": "Изворна и одредишна страница не могу бити исте.",
-       "mergehistory-fail-timestamps-overlap": "Изворне ревизије се преклапају или долазе након одредишних ревизија.",
-       "mergehistory-fail-toobig": "Не могу да извршим спајање историје јер ће више од $1 {{PLURAL:$1|ревизије бити премештене|ревизија бити премештено}}.",
+       "mergehistory-fail-timestamps-overlap": "Изворне измене се преклапају или долазе након одредишних измена.",
+       "mergehistory-fail-toobig": "Не могу да извршим спајање историје јер ће више од $1 {{PLURAL:$1|измене бити премештене|измена бити премештено}}.",
        "mergehistory-no-source": "Изворна страница $1 не постоји.",
        "mergehistory-no-destination": "Одредишна страница $1 не постоји.",
        "mergehistory-invalid-source": "Изворна страница мора имати валидан наслов.",
        "mergehistory-comment": "Страница [[:$1]] је спојена у [[:$2]]: $3",
        "mergehistory-same-destination": "Изворна и одредишна страница не могу бити исте",
        "mergehistory-reason": "Разлог:",
-       "mergelog": "Евиденција спајања",
+       "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
+       "mergelog": "Дневник спајања",
        "revertmerge": "растави",
        "mergelogpagetext": "Испод је списак најскоријих спајања историја двеју страница.",
-       "history-title": "Историја ревизија странице „$1“",
-       "difference-title": "Разлика између ревизија на страници „$1”",
+       "history-title": "Историја измена странице „$1“",
+       "difference-title": "Разлика између измена на страници „$1”",
        "difference-title-multipage": "Разлика између страница „$1“ и „$2“",
        "difference-multipage": "(разлике између страница)",
        "lineno": "Ред $1:",
-       "compareselectedversions": "Упореди изабране ревизије",
-       "showhideselectedversions": "Промени видљивост изабраних ревизија",
+       "compareselectedversions": "Упореди изабране измене",
+       "showhideselectedversions": "Промени видљивост изабраних измена",
        "editundo": "поништи",
        "diff-empty": "(нема разлике)",
-       "diff-multi-sameuser": "({{PLURAL:$1|Једна међуревизија истог корисника није приказана|$1 међуревизија истог корисника нису приказане|$1 међуревизија истог корисника није приказано}})",
-       "diff-multi-otherusers": "({{PLURAL:$1|Једна међуревизија|$1 међуревизије|$1 међуревизија}} од стране {{PLURAL:$2|још једног корисника није приказана|$2 корисника није приказано}})",
+       "diff-multi-sameuser": "({{PLURAL:$1|Једна међуизмена истог корисника није приказана|$1 међуизмена истог корисника нису приказане|$1 међуизмена истог корисника није приказано}})",
+       "diff-multi-otherusers": "({{PLURAL:$1|Једна међуизмена|$1 међуизмене|$1 међуизмена}} од стране {{PLURAL:$2|још једног корисника није приказана|$2 корисника није приказано}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Није приказана међуизмена|Нису приказане $1 међуизмене|Није приказано $1 међуизмена}} од више од $2 корисника)",
        "diff-paragraph-moved-tonew": "Пасус је премештен. Кликните да пређете на нову локацију.",
        "diff-paragraph-moved-toold": "Пасус је премештен. Кликните да пређете на стару локацију.",
-       "difference-missing-revision": "{{PLURAL:$2|Једна ревизија|$2 ревизије}} ове разлике ($1) не {{PLURAL:$2|постоји|постоје}}.\n\nОво се обично дешава када пратите застарели линк до странице која је избрисана.\nДетаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} евиденцији брисања].",
+       "difference-missing-revision": "{{PLURAL:$2|Једна измена|$2 измене}} ове разлике ($1) не {{PLURAL:$2|постоји|постоје}}.\n\nОво се обично дешава када пратите застарелу везу до странице која је избрисана.\nДетаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
        "searchresults": "Резултати претраге",
        "search-filter-title-prefix-reset": "Претражи све странице",
        "searchresults-title": "Резултати претраге за „$1“",
        "prefs-watchlist-edits-max": "Највећи број: 1000",
        "prefs-watchlist-token": "Токен списка надгледања:",
        "prefs-watchlist-managetokens": "Управљај жетонима",
-       "prefs-misc": "Ð\94Ñ\80Ñ\83га Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа",
+       "prefs-misc": "Разно",
        "prefs-resetpass": "промени лозинку",
        "prefs-changeemail": "промени или уклони имејл-адресу",
        "prefs-setemail": "постави имејл-адресу",
        "restoreprefs": "Врати сва подешавања на подразумеване вредности (у свим одељцима)",
        "prefs-editing": "Уређивање",
        "searchresultshead": "Претрага",
-       "stub-threshold": "Праг за обликовање линкова као клице ($1):",
+       "stub-threshold": "Праг за форматирање веза као клице ($1):",
        "stub-threshold-sample-link": "пример",
        "stub-threshold-disabled": "онемогућено",
        "recentchangesdays": "Број дана у скорашњим изменама:",
        "recentchangesdays-max": "Највише $1 {{PLURAL:$1|дан|дана}}",
-       "recentchangescount": "Ð\9fодÑ\80азÑ\83мевани Ð±Ñ\80оÑ\98 Ð¸Ð·Ð¼ÐµÐ½Ð° Ð·Ð° Ð¿Ñ\80иказ Ñ\83 Ñ\81коÑ\80аÑ\88Ñ\9aим Ð¸Ð·Ð¼ÐµÐ½Ð°Ð¼Ð°, Ð¸Ñ\81Ñ\82оÑ\80иÑ\98ама Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¸ ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98ама:",
+       "recentchangescount": "Ð\9fодÑ\80азÑ\83мевани Ð±Ñ\80оÑ\98 Ð¸Ð·Ð¼ÐµÐ½Ð° Ð·Ð° Ð¿Ñ\80иказ Ñ\83 Ñ\81коÑ\80аÑ\88Ñ\9aим Ð¸Ð·Ð¼ÐµÐ½Ð°Ð¼Ð°, Ð¸Ñ\81Ñ\82оÑ\80иÑ\98ама Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¸ Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86има:",
        "prefs-help-recentchangescount": "Највећи број: 1000",
        "prefs-help-watchlist-token2": "Ово је тајни кључ за веб-фид вашег списка надгледања. \nСвако ко зна овај кључ биће у могућности да чита ваш списак надгледања, зато га немојте делити. \nАко је потребно, [[Special:ResetTokens|можете да га ресетујете]].",
        "savedprefs": "Ваша подешавања су сачувана.",
        "prefs-files": "Датотеке",
        "prefs-custom-css": "прилагођени CSS",
        "prefs-custom-json": "Прилагођени JSON",
-       "prefs-custom-js": "прилагођени јаваскрипт",
+       "prefs-custom-js": "прилагођени JavaScript",
        "prefs-common-config": "Дељени CSS/JSON/јаваскрипт за све теме:",
        "prefs-reset-intro": "Можете користити ову страницу да поново поставите своја подешавања на подразумеване вредности сајта.\nОво се не може опозвати.",
        "prefs-emailconfirm-label": "Потврда имејла:",
        "email": "Имејл",
        "prefs-help-realname": "Право име је опционално.\nАко је наведено, биће коришћено за приписивање вашег рада.",
        "prefs-help-email": "Имејл адреса је опционална, али је потребна за ресетовање лозинке, ако је заборавите.",
-       "prefs-help-email-others": "ТакоÑ\92е Ð¼Ð¾Ð¶ÐµÑ\82е Ð¸Ð·Ð°Ð±Ñ\80аÑ\82и Ð´Ð° Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82иÑ\82е Ð´Ñ\80Ñ\83гима Ð´Ð° Ð²Ð°Ñ\81 ÐºÐ¾Ð½Ñ\82акÑ\82иÑ\80аÑ\98Ñ\83 Ð¿Ñ\80еко Ð¸Ð¼ÐµÑ\98ла Ð¿Ñ\83Ñ\82ем Ð»Ð¸Ð½ÐºÐ° на вашој корисничкој страници или страници за разговор.\nВаша имејл адреса неће бити приказана другим корисницима који вас контактирају.",
+       "prefs-help-email-others": "ТакоÑ\92е Ð¼Ð¾Ð¶ÐµÑ\82е Ð¸Ð·Ð°Ð±Ñ\80аÑ\82и Ð´Ð° Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82иÑ\82е Ð´Ñ\80Ñ\83гима Ð´Ð° Ð²Ð°Ñ\81 ÐºÐ¾Ð½Ñ\82акÑ\82иÑ\80аÑ\98Ñ\83 Ð¿Ñ\80еко Ð¸Ð¼ÐµÑ\98ла Ð¿Ñ\83Ñ\82ем Ð²ÐµÐ·Ðµ на вашој корисничкој страници или страници за разговор.\nВаша имејл адреса неће бити приказана другим корисницима који вас контактирају.",
        "prefs-help-email-required": "Имејл-адреса је неопходна.",
        "prefs-info": "Основне информације",
        "prefs-i18n": "Интернационализација",
        "editusergroup": "Учитај корисничке групе",
        "editinguser": "Мењате корисничка права {{GENDER:$1|корисника|кориснице}} <strong>[[User:$1|$1]]</strong> $2",
        "viewinguserrights": "Корисничка права {{GENDER:$1|корисника|кориснице}} <strong>[[User:$1|$1]]</strong> $2",
-       "userrights-editusergroup": "Ð\9fÑ\80омена {{GENDER:$1|корисничких}} група",
-       "userrights-viewusergroup": "Ð\9fÑ\80еглед {{GENDER:$1|корисничких}} група",
+       "userrights-editusergroup": "УÑ\80еÑ\92иваÑ\9aе {{GENDER:$1|корисничких}} група",
+       "userrights-viewusergroup": "Ð\9fÑ\80иказ {{GENDER:$1|корисничких}} група",
        "saveusergroups": "Сачувај {{GENDER:$1|корисничке}} групе",
        "userrights-groupsmember": "Члан група:",
        "userrights-groupsmember-auto": "{{GENDER:$2|Имплицитан члан|Имплицитна чланица}} група:",
+       "userrights-groupsmember-type": "$1",
        "userrights-groups-help": "Можете променити групе којима овај корисник припада:\n* Означен квадратић означава да се корисник налази у тој групи.\n* Неозначен квадратић означава да се корисник не налази у тој групи.\n* Звездица (*) означава да не можете уклонити ту групу ако је додате и обратно.\n* Тараба (#) означава да једино можете одложити време истека чланства у тој групи; не можете га убрзати.",
        "userrights-reason": "Разлог:",
        "userrights-no-interwiki": "Немате дозволу да уређујете корисничка права на другим викијима.",
        "userrights-changeable-col": "Групе које можете да промените",
        "userrights-unchangeable-col": "Групе које не можете да промените",
        "userrights-irreversible-marker": "$1*",
+       "userrights-no-shorten-expiry-marker": "$1#",
        "userrights-expiry-current": "Истиче $1",
        "userrights-expiry-none": "Не истиче",
        "userrights-expiry": "Истиче:",
        "grouppage-sysop": "{{ns:project}}:Администратори",
        "grouppage-interface-admin": "{{ns:project}}:Администратори интерфејса",
        "grouppage-bureaucrat": "{{ns:project}}:Бирократе",
-       "grouppage-suppress": "{{ns:project}}:РевизоÑ\80",
+       "grouppage-suppress": "{{ns:project}}:Ð\91Ñ\80иÑ\81аÑ\87и Ð¸Ð·Ð¼ÐµÐ½Ð°",
        "right-read": "читање страница",
        "right-edit": "уређивање страница",
        "right-createpage": "прављење страница (изузев страница за разговор)",
        "right-writeapi": "коришћење API-ја за писање",
        "right-delete": "брисање страница",
        "right-bigdelete": "брисање страница са великом историјом",
-       "right-deletelogentry": "бÑ\80иÑ\81аÑ\9aе Ð¸ Ð²Ñ\80аÑ\9bаÑ\9aе Ð¾Ð´Ñ\80еÑ\92ениÑ\85 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и",
-       "right-deleterevision": "брисање и враћање одређених ревизија страница",
+       "right-deletelogentry": "бÑ\80иÑ\81аÑ\9aе Ð¸ Ð²Ñ\80аÑ\9bаÑ\9aе Ð¾Ð´Ñ\80еÑ\92ениÑ\85 Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83",
+       "right-deleterevision": "брисање и враћање одређених измена страница",
        "right-deletedhistory": "прегледање избрисаних ставки историје без повезаног текста",
-       "right-deletedtext": "прегледање избрисаног текста и промена између избрисаних ревизија",
+       "right-deletedtext": "прегледање избрисаног текста и промена између избрисаних измена",
        "right-browsearchive": "претрага избрисаних страница",
        "right-undelete": "враћање избрисаних страница",
-       "right-suppressrevision": "прегледање, скривање и враћање одређених ревизија страница од свих корисника",
+       "right-suppressrevision": "прегледање, скривање и враћање одређених измена страница од свих корисника",
        "right-viewsuppressed": "прегледање измена скривених од свих корисника",
-       "right-suppressionlog": "пÑ\80егледаÑ\9aе Ð¿Ñ\80иваÑ\82ниÑ\85 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а",
+       "right-suppressionlog": "пÑ\80егледаÑ\9aе Ð¿Ñ\80иваÑ\82ниÑ\85 Ð´Ð½ÐµÐ²Ð½Ð¸Ðºа",
        "right-block": "блокирање даљих измена других корисника",
        "right-blockemail": "блокирање корисника да шаљу имејл",
        "right-hideuser": "блокирање корисничког имена и његово сакривање од јавности",
-       "right-ipblock-exempt": "заобилажење IP блокада, самоблокада и блокада опсега",
+       "right-ipblock-exempt": "заобилажење IP блокада, аутоблокада и блокада опсега",
        "right-unblockself": "деблокирање самог себе",
        "right-protect": "мењање нивоа заштите и уређивање страница под преносивом заштитом",
        "right-editprotected": "уређивање страница под заштитом „{{int:protect-level-sysop}}“",
        "right-userrights": "уређивање свих корисничких права",
        "right-userrights-interwiki": "уређивање корисничких права на другим викијима",
        "right-siteadmin": "закључавање и откључавање базе података",
-       "right-override-export-depth": "извоз Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\83кÑ\99Ñ\83Ñ\87Ñ\83Ñ\98Ñ\83Ñ\9bи Ð¸ Ð¿Ð¾Ð²Ð°Ð·ÐµÐ½Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ð´Ð¾ Ð´Ñ\83бине Ð¾Ð´ Ð¿ÐµÑ\82 Ð»Ð¸Ð½ÐºÐ¾Ð²а",
+       "right-override-export-depth": "извоз Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\83кÑ\99Ñ\83Ñ\87Ñ\83Ñ\98Ñ\83Ñ\9bи Ð¸ Ð¿Ð¾Ð²Ð°Ð·ÐµÐ½Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ð´Ð¾ Ð´Ñ\83бине Ð¾Ð´ Ð¿ÐµÑ\82 Ð²ÐµÐ·а",
        "right-sendemail": "слање имејла другим корисницима",
        "right-managechangetags": "прављење и (де)активирање [[Special:Tags|ознака]]",
        "right-applychangetags": "примењивање [[Special:Tags|ознака]] на нечије промене",
-       "right-changetags": "додавање и уклањање разних [[Special:Tags|ознака]] на појединачним ревизијама и уносима у евиденцијама",
+       "right-changetags": "додавање и уклањање разних [[Special:Tags|ознака]] на појединачним изменама и уносима у дневницима",
        "right-deletechangetags": "брисање [[Special:Tags|ознака]] из базе података",
        "grant-generic": "Скуп права „$1“",
        "grant-group-page-interaction": "Уређивање страница",
        "grant-blockusers": "Блокирање и деблокирање корисника",
        "grant-createaccount": "Отварање налога",
        "grant-createeditmovepage": "Прављење, уређивање и премештање страница",
-       "grant-delete": "Брисање страница, ревизија и уноса у евиденцијама",
-       "grant-editinterface": "УÑ\80еÑ\92иваÑ\9aе Ð\9cедиÑ\98авики Ð¸Ð¼ÐµÐ½Ñ\81ког Ð¿Ñ\80оÑ\81Ñ\82оÑ\80а Ð¸ ÐºÐ¾Ñ\80иÑ\81ниÑ\87киÑ\85 CSS/JSON/Ð\88аваÑ\81кÑ\80ипÑ\82 Ñ\81Ñ\82Ñ\80аниÑ\86а",
+       "grant-delete": "Брисање страница, измена и уноса у дневницима",
+       "grant-editinterface": "УÑ\80еÑ\92иваÑ\9aе Ð¸Ð¼ÐµÐ½Ñ\81ког Ð¿Ñ\80оÑ\81Ñ\82оÑ\80а Ð\9cедиÑ\98авики Ð¸ JSON-а Ñ\81аÑ\98Ñ\82а/коÑ\80иÑ\81ника",
        "grant-editmycssjs": "Уређивање вашег CSS/JSON/Јаваскрипта",
        "grant-editmyoptions": "Уређивање ваших корисничких подешавања",
        "grant-editmywatchlist": "Уређивање вашег списка надгледања",
        "grant-editpage": "Уређивање постојећих страница",
        "grant-editprotected": "Уређивање заштићених страница",
        "grant-highvolume": "Масовно уређивање",
-       "grant-oversight": "Скривање корисника и ревизија",
+       "grant-oversight": "Скривање корисника и измена",
        "grant-patrol": "Патролирање промена на страницама",
        "grant-privateinfo": "Приступи приватним информацијама",
        "grant-protect": "Закључавање и откључавање страница",
        "grant-basic": "Основна права",
        "grant-viewdeleted": "Преглед избрисаних страница и датотека",
        "grant-viewmywatchlist": "Преглед вашег списак надгледања",
-       "grant-viewrestrictedlogs": "Ð\9fÑ\80егледаÑ\9aе Ð¾Ð³Ñ\80аниÑ\87ениÑ\85 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и",
-       "newuserlogpage": "Ð\95виденÑ\86иÑ\98а нових корисника",
-       "newuserlogpagetext": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а о регистрацији нових корисника.",
-       "rightslog": "Ð\95виденÑ\86иÑ\98а корисничких права",
-       "rightslogtext": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а промена корисничких права.",
+       "grant-viewrestrictedlogs": "Ð\9fÑ\80егледаÑ\9aе Ð¾Ð³Ñ\80аниÑ\87ениÑ\85 Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83",
+       "newuserlogpage": "Ð\94невник нових корисника",
+       "newuserlogpagetext": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº о регистрацији нових корисника.",
+       "rightslog": "Ð\94невник корисничких права",
+       "rightslogtext": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº промена корисничких права.",
        "action-read": "читате ову страницу",
        "action-edit": "уређујете ову страницу",
        "action-createpage": "направите ову страницу",
        "action-upload_by_url": "отпремите ову датотеку путем УРЛ-а",
        "action-writeapi": "користите API за писање",
        "action-delete": "избришете ову страницу",
-       "action-deleterevision": "бришете ревизије",
-       "action-deletelogentry": "бÑ\80иÑ\88еÑ\82е Ñ\83ноÑ\81е Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98ама",
+       "action-deleterevision": "бришете измене",
+       "action-deletelogentry": "бÑ\80иÑ\88еÑ\82е Ñ\83ноÑ\81е Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86има",
        "action-deletedhistory": "прегледате избрисану историју странице",
-       "action-deletedtext": "прегледате избрисани текст ревизије",
+       "action-deletedtext": "прегледате избрисани текст измене",
        "action-browsearchive": "претражујете избрисане странице",
        "action-undelete": "враћате странице",
-       "action-suppressrevision": "прегледате и враћате сакривене ревизије",
-       "action-suppressionlog": "прегледате ову приватну евиденције",
+       "action-suppressrevision": "прегледате и враћате сакривене измене",
+       "action-suppressionlog": "прегледате овај приватан дневник",
        "action-block": "блокирате уређивање овом кориснику",
        "action-protect": "промените нивое заштите ове странице",
        "action-rollback": "брзо вратите измене последњег корисника који је уређивао одређену страницу",
        "action-editcontentmodel": "уређујете модел садржаја странице",
        "action-managechangetags": "правите и (де)активирате ознаке",
        "action-applychangetags": "додате ознаке уз сопствене промене",
-       "action-changetags": "додате и уклоните разне ознаке на појединачним ревизијама и уносима у евиденцијама",
+       "action-changetags": "додате и уклоните разне ознаке на појединачним изменама и уносима у дневницима",
        "action-deletechangetags": "бришете ознаке из базе података",
        "action-purge": "освежите ову страницу",
        "nchanges": "$1 {{PLURAL:$1|промена|промене|промена}}",
        "rcfilters-highlighted-filters-list": "Истакнуто: $1",
        "rcfilters-quickfilters": "Сачувани филтери",
        "rcfilters-quickfilters-placeholder-title": "Још нема сачуваних филтера",
-       "rcfilters-quickfilters-placeholder-description": "Ð\94а Ð±Ð¸Ñ\81Ñ\82е Ñ\81аÑ\87Ñ\83вали Ñ\81воÑ\98а Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\84илÑ\82еÑ\80а Ð¸ Ð¿Ð¾Ð½Ð¾Ð²Ð¾ Ð¸Ñ\85 Ñ\83поÑ\82Ñ\80ебÑ\99авали ÐºÐ°Ñ\81ниÑ\98е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° Ð¸ÐºÐ¾Ð½Ñ\83 Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÑ\83 у подручју активних филтера — испод.",
+       "rcfilters-quickfilters-placeholder-description": "Ð\94а Ð±Ð¸Ñ\81Ñ\82е Ñ\81аÑ\87Ñ\83вали Ñ\81воÑ\98а Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\84илÑ\82еÑ\80а Ð¸ Ð¿Ð¾Ð½Ð¾Ð²Ð¾ Ð¸Ñ\85 Ñ\83поÑ\82Ñ\80ебÑ\99авали ÐºÐ°Ñ\81ниÑ\98е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° Ð¸ÐºÐ¾Ð½Ñ\83 Ð·Ð° Ð¾Ð±ÐµÐ»ÐµÐ¶Ð°Ð²Ð°Ñ\9aе у подручју активних филтера — испод.",
        "rcfilters-savedqueries-defaultlabel": "Сачувани филтери",
        "rcfilters-savedqueries-rename": "Преименуј",
        "rcfilters-savedqueries-setdefault": "Постави као подразумевано",
        "rcfilters-filter-editsbyself-label": "Ваше промене",
        "rcfilters-filter-editsbyself-description": "Ваши сопствени доприноси.",
        "rcfilters-filter-editsbyother-label": "Промене других",
-       "rcfilters-filter-editsbyother-description": "Све Ð¸Ð·мене осим ваших.",
+       "rcfilters-filter-editsbyother-description": "Све Ð¿Ñ\80омене осим ваших.",
        "rcfilters-filtergroup-userExpLevel": "Корисничка регистрација и искуство",
        "rcfilters-filter-user-experience-level-registered-label": "Регистровани",
        "rcfilters-filter-user-experience-level-registered-description": "Пријављени уредници.",
        "rcfilters-filtergroup-watchlistactivity": "Стање на списку надгледања",
        "rcfilters-filter-watchlistactivity-unseen-label": "Непогледане промене",
        "rcfilters-filter-watchlistactivity-unseen-description": "Промене на страницама које нисте посетили од када су промене направљене.",
-       "rcfilters-filter-watchlistactivity-seen-label": "Ð\9fогледане Ð¸Ð·мене",
+       "rcfilters-filter-watchlistactivity-seen-label": "Ð\9fогледане Ð¿Ñ\80омене",
        "rcfilters-filter-watchlistactivity-seen-description": "Промене на страницама које сте посетили од када су промене направљене.",
        "rcfilters-filtergroup-changetype": "Тип промене",
        "rcfilters-filter-pageedits-label": "Измене страница",
-       "rcfilters-filter-pageedits-description": "Измене вики садржаја, расправа, описа категорија…",
+       "rcfilters-filter-pageedits-description": "Измене вики садржаја, дискусија, описа категорија…",
        "rcfilters-filter-newpages-label": "Прављење страница",
        "rcfilters-filter-newpages-description": "Измене којима се праве нове странице.",
        "rcfilters-filter-categorization-label": "Промене категорија",
        "rcfilters-filter-categorization-description": "Записи о страницама додатим или уклоњеним из категорија.",
        "rcfilters-filter-logactions-label": "Евидентиране радње",
-       "rcfilters-filter-logactions-description": "Ð\90дминиÑ\81Ñ\82Ñ\80аÑ\82ивне Ñ\80адÑ\9aе, Ð¿Ñ\80авÑ\99ење налога, брисање страница, отпремања…",
+       "rcfilters-filter-logactions-description": "Ð\90дминиÑ\81Ñ\82Ñ\80аÑ\82ивне Ñ\80адÑ\9aе, Ð¾Ñ\82ваÑ\80ање налога, брисање страница, отпремања…",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтер за „мање” измене је у сукобу са једним или више филтера типа промена, зато што одређени типови промена не могу да се означе као „мање”. Сукобљени филтери су означени у подручју Активни филтери, изнад.",
        "rcfilters-hideminor-conflicts-typeofchange": "Одређени типови промена не могу да се означе као „мање”, тако да је овај филтер у сукобу са следећим филтерима типа промена: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овај филтер типа измене је у сукобу са филтером за „мање” измене. Одређени типови измена не могу да се означе као „мање”.",
-       "rcfilters-filtergroup-lastRevision": "Ð\9fоÑ\81ледÑ\9aе Ñ\80евизиÑ\98е",
-       "rcfilters-filter-lastrevision-label": "Ð\9fоÑ\81ледÑ\9aа измена",
+       "rcfilters-filtergroup-lastRevision": "Ð\9dаÑ\98новиÑ\98е Ð¸Ð·Ð¼ÐµÐ½е",
+       "rcfilters-filter-lastrevision-label": "Ð\9dаÑ\98новиÑ\98а измена",
        "rcfilters-filter-lastrevision-description": "Само најновија промена на страници.",
-       "rcfilters-filter-previousrevision-label": "Ð\9dиÑ\98е Ð¿Ð¾Ñ\81ледÑ\9aа Ñ\80евизиÑ\98а",
-       "rcfilters-filter-previousrevision-description": "Све промене које нису „последње ревизије”.",
+       "rcfilters-filter-previousrevision-label": "Ð\9dиÑ\98е Ð½Ð°Ñ\98новиÑ\98а Ð¸Ð·Ð¼ÐµÐ½а",
+       "rcfilters-filter-previousrevision-description": "Све промене које нису „последње измене”.",
        "rcfilters-filter-excluded": "Изузето",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:није</strong> $1",
        "rcfilters-exclude-button-off": "Изузми изабрано",
        "rcfilters-liveupdates-button": "Ажурирај уживо",
        "rcfilters-liveupdates-button-title-on": "Искључите ажурирања уживо",
        "rcfilters-liveupdates-button-title-off": "Прикажите нове промене уживо",
-       "rcfilters-watchlist-markseen-button": "Ð\9eзнаÑ\87и Ñ\81ве Ð¸Ð·мене као погледане",
+       "rcfilters-watchlist-markseen-button": "Ð\9eзнаÑ\87и Ñ\81ве Ð¿Ñ\80омене као погледане",
        "rcfilters-watchlist-edit-watchlist-button": "Промени списак надгледаних страница",
        "rcfilters-watchlist-showupdated": "Промене на страницама које нисте посетили од када је измена извршена су <strong>подебљане</strong>, с испуњеним ознакама.",
        "rcfilters-preference-label": "Сакриј побољшану верзију скорашњих измена",
        "rcfilters-preference-help": "Поништава редизајн интерфејса из 2017. и све алатке додате тада и после.",
        "rcfilters-watchlist-preference-label": "Сакриј побољшану верзију списка надгледања",
+       "rcfilters-watchlist-preference-help": "Уклања редизајн интерфејса из 2017. године и све алатке додате тада и од тада.",
        "rcfilters-filter-showlinkedfrom-label": "Прикажи промене на страницама са којих долазе везе",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Странице са којих долазе везе до</strong> изабране странице",
        "rcfilters-filter-showlinkedto-label": "Прикажи промене на страницама ка којима воде везе",
        "upload_directory_missing": "Фасцикла за слање ($1) недостаје и сервер је не може направити.",
        "upload_directory_read_only": "Сервер не може да пише по фасцикли за слање ($1).",
        "uploaderror": "Грешка при отпремању",
-       "upload-recreate-warning": "<strong>УпозоÑ\80еÑ\9aе: Ð\94аÑ\82оÑ\82ека Ñ\81а Ñ\82им Ð¸Ð¼ÐµÐ½Ð¾Ð¼ Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана Ð¸Ð»Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82ена.</strong>\n\nÐ\95виденÑ\86иÑ\98а Ð±Ñ\80иÑ\81аÑ\9aа Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð° је испод са образложењем:",
+       "upload-recreate-warning": "<strong>УпозоÑ\80еÑ\9aе: Ð\94аÑ\82оÑ\82ека Ñ\81а Ñ\82им Ð¸Ð¼ÐµÐ½Ð¾Ð¼ Ñ\98е Ð¸Ð·Ð±Ñ\80иÑ\81ана Ð¸Ð»Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82ена.</strong>\n\nÐ\94невник Ð±Ñ\80иÑ\81аÑ\9aа Ð¸ Ð¿Ñ\80емеÑ\88Ñ\82аÑ\9aа Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½Ð°Ð²ÐµÐ´ÐµÐ½ је испод са образложењем:",
        "uploadtext": "Користите образац испод да бисте отпремили датотеке.\nЗа преглед или претрагу постојећих датотека, погледајте [[Special:FileList|списак отпремљених датотека]], поновна отпремања су наведена у [[Special:Log/upload|евиденцији отпремања]], а брисања у [[Special:Log/delete|евиденцији брисања]].\n\nДатотеку додајете на жељену страницу користећи следеће обрасце:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Слика.jpg]]</nowiki></code>''' за верзију слике у пуној величини\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Слика.png|200п|мини|лево|опис]]</nowiki></code>''' за верзију слике с величином од 200 пиксела која је приказана у засебном оквиру, заједно с описом.\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Датотека.ogg]]</nowiki></code>''' за директно повезивање с датотеком без њеног приказивања",
        "upload-permitted": "Дозвољени {{PLURAL:$2|тип|типови}} датотека: $1.",
        "upload-preferred": "Препоручени {{PLURAL:$2|тип|типови}} датотека: $1.",
        "upload-prohibited": "Забрањени {{PLURAL:$2|тип|типови}} датотека: $1.",
-       "uploadlogpage": "Ð\95виденÑ\86иÑ\98а отпремања",
+       "uploadlogpage": "Ð\94невник отпремања",
        "uploadlogpagetext": "Испод је списак недавних отпремања.\nПогледајте [[Special:NewFiles|галерију нових датотека]] за лепши преглед.",
        "filename": "Назив датотеке",
-       "filedesc": "Резиме",
-       "fileuploadsummary": "Резиме:",
+       "filedesc": "Ð\9eпиÑ\81 Ð¸Ð·Ð¼ÐµÐ½е",
+       "fileuploadsummary": "Ð\9eпиÑ\81 Ð¸Ð·Ð¼ÐµÐ½е:",
        "filereuploadsummary": "Промене датотеке:",
        "filestatus": "Статус ауторског права:",
        "filesource": "Извор:",
        "fileexists": "Датотека с овим именом већ постоји. Погледајте <strong>[[:$1]]</strong> ако нисте сигурни да ли желите да је промените.\n[[$1|thumb]]",
        "filepageexists": "Страница с описом ове датотеке је већ направљена овде <strong>[[:$1]]</strong>, иако датотека не постоји.\nОпис који сте навели се неће појавити на страници с описом.\nДа би се ваш опис овде нашао, потребно је да га ручно измените.\n[[$1|thumb]]",
        "fileexists-extension": "Датотека са сличним називом већ постоји: [[$2|thumb]]\n* Назив датотеке коју шаљете: <strong>[[:$1]]</strong>\n* Назив постојеће датотеке: <strong>[[:$2]]</strong>\nДа ли желите да користите препознатљивије име?",
-       "fileexists-thumbnail-yes": "Ð\98згледа Ð´Ð° Ñ\98е Ð´Ð°Ñ\82оÑ\82ека Ñ\83маÑ\9aено Ð¸Ð·Ð´Ð°Ñ\9aе Ñ\81лике ''(thumbnail)''.\n[[$1|thumb]]\nÐ\9fÑ\80овеÑ\80иÑ\82е Ð´Ð°Ñ\82оÑ\82екÑ\83 <strong>[[:$1]]</strong>.\nÐ\90ко Ñ\98е Ð¿Ñ\80овеÑ\80ена Ð´Ð°Ñ\82оÑ\82ека Ð¸Ñ\81Ñ\82а Ñ\81лика Ð¾Ñ\80игиналне Ð²ÐµÐ»Ð¸Ñ\87ине, Ð½Ð¸Ñ\98е Ð¿Ð¾Ñ\82Ñ\80ебно Ñ\81лаÑ\82и Ð´Ð¾Ð´Ð°Ñ\82нÑ\83 Ñ\81лику.",
-       "file-thumbnail-no": "Ð\94аÑ\82оÑ\82ека Ð¿Ð¾Ñ\87иÑ\9aе Ñ\81а <strong>$1</strong>.\nÐ\98згледа Ð´Ð° Ñ\81е Ñ\80ади Ð¾ Ñ\83маÑ\9aеноÑ\98 Ñ\81лиÑ\86и ''(thumbnail)''.\nУколико Ð¸Ð¼Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\81ликÑ\83 Ñ\83 Ð¿Ñ\83ноÑ\98 Ð²ÐµÐ»Ð¸Ñ\87ини, Ð¿Ð¾Ñ\88аÑ\99иÑ\82е Ñ\98е, Ð° Ð°ÐºÐ¾ Ð½ÐµÐ¼Ð°Ñ\82е, Ð¿Ñ\80омениÑ\82е Ð½Ð°Ð·Ð¸Ð² датотеке.",
+       "fileexists-thumbnail-yes": "Ð\98згледа Ð´Ð° Ñ\98е Ð´Ð°Ñ\82оÑ\82ека Ñ\81лика Ñ\83маÑ\9aене Ð²ÐµÐ»Ð¸Ñ\87ине <em>(Ñ\81лиÑ\87иÑ\86а)</em>.\n[[$1|thumb]]\nÐ\9fÑ\80овеÑ\80иÑ\82е Ð´Ð°Ñ\82оÑ\82екÑ\83 <strong>[[:$1]]</strong>.\nÐ\90ко Ñ\98е Ð¿Ñ\80овеÑ\80ена Ð´Ð°Ñ\82оÑ\82ека Ð¸Ñ\81Ñ\82а Ñ\81лика Ð¿Ñ\80вобиÑ\82не Ð²ÐµÐ»Ð¸Ñ\87ине, Ð½Ð¸Ñ\98е Ð¿Ð¾Ñ\82Ñ\80ебно Ð¾Ñ\82пÑ\80емаÑ\82и Ð´Ð¾Ð´Ð°Ñ\82ну.",
+       "file-thumbnail-no": "Ð\98ме Ð´Ð°Ñ\82оÑ\82еке Ð¿Ð¾Ñ\87иÑ\9aе Ñ\81а <strong>$1</strong>.\nÐ\98згледа Ð´Ð° Ñ\81е Ñ\80ади Ð¾ Ñ\81лиÑ\86и Ñ\83маÑ\9aене Ð²ÐµÐ»Ð¸Ñ\87ине <em>(Ñ\81лиÑ\87иÑ\86а)</em>.\nÐ\90ко Ð¸Ð¼Ð°Ñ\82е Ð¾Ð²Ñ\83 Ñ\81ликÑ\83 Ñ\83 Ð¿Ñ\83ноÑ\98 Ñ\80езолÑ\83Ñ\86иÑ\98и, Ð¾Ñ\82пÑ\80емиÑ\82е Ñ\98е, Ñ\83 Ð¿Ñ\80оÑ\82ивном, Ð¿Ñ\80омениÑ\82е Ð¸Ð¼Ðµ датотеке.",
        "fileexists-forbidden": "Датотека с овим називом већ постоји и не може се заменити.\nАко и даље желите да пошаљете датотеку, вратите се и изаберите други назив.\n[[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Датотека са овим именом већ постоји у заједничкој остави.\nАко још увек желите да отпремите датотеку, вратите се и користите ново име.\n[[File:$1|thumb|center|$1]]",
        "fileexists-no-change": "Датотека је дупликат актуелне верзије <strong>[[:$1]]</strong>.",
        "php-uploaddisabledtext": "Отпремање датотека је онемогућено у PHP-у.\nПроверите подешавања file_uploads.",
        "uploadscripted": "Датотека садржи HTML или скриптни код који може бити погрешно протумачен од стране прегледача.",
        "upload-scripted-pi-callback": "Датотека која садржи инструкције за обраду XML стилског облика се не може отпремити.",
-       "upload-scripted-dtd": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð¾Ñ\82пÑ\80емим SVG Ð´Ð°Ñ\82оÑ\82еке које садрже нестандардну DTD декларацију.",
+       "upload-scripted-dtd": "Ð\9dиÑ\98е Ð¼Ð¾Ð³Ñ\83Ñ\9bе Ð¾Ñ\82пÑ\80емаÑ\9aе SVG Ð´Ð°Ñ\82оÑ\82ека које садрже нестандардну DTD декларацију.",
        "uploaded-script-svg": "Пронађен скриптни елеменат „$1“ у постављеној SVG датотеци.",
        "uploaded-hostile-svg": "Пронађен небезбедан CSS у стилском елементу постављене SVG датотеке.",
        "uploaded-event-handler-on-svg": "Није дозвољено постављање атрибута који контролишу догађаје <code>$1=\"$2\"</code> у SVG датотекама.",
        "upload-options": "Опције отпремања",
        "watchthisupload": "Надгледај ову датотеку",
        "filewasdeleted": "Датотека са овим именом је раније оптремљена и након тога избрисана.\nТребате да проверите $1 пре него што наставите са њеним поновним оптремањем.",
+       "filename-thumb-name": "Ово изгледа као назив сличице. Молимо вас да не отпремате сличице на исти вики. У супротном, молимо вас, поправите име датотеке тако да је корисније и нема префикс сличице.",
        "filename-bad-prefix": "Назив датотеке коју шаљете почиње са <strong>„$1“</strong>, а њега обично додељују дигитални фотоапарати.\nИзаберите назив датотеке који описује њен садржај.",
        "filename-prefix-blacklist": " #<!-- оставите овај ред онаквим какав јесте --> <pre>\n# Синтакса је следећа:\n#   * Све од тарабе па до краја реда је коментар\n#   * Сваки ред означава префикс типичних назива датотека које додељивају дигитални апарати\nCIMG # Касио\nDSC_ # Никон\nDSCF # Фуџи\nDSCN # Никон\nDUW # неки мобилни телефони\nIMG # опште\nJD # Џеноптик\nMGP # Пентакс\nPICT # разно\n #</pre> <!-- оставите овај ред онаквим какав јесте -->",
        "upload-proto-error": "Неважећи протокол",
        "upload-dialog-button-upload": "Отпреми",
        "upload-form-label-infoform-title": "Детаљи",
        "upload-form-label-infoform-name": "Назив",
+       "upload-form-label-infoform-name-tooltip": "Јединствени описни наслов за датотеку, који ће служити као име датотеке. Можете користити чист језик са размацима. Не укључујте проширење датотеке.",
        "upload-form-label-infoform-description": "Опис",
        "upload-form-label-usage-title": "Употребе",
        "upload-form-label-usage-filename": "Назив датотеке",
        "upload-form-label-own-work": "Ово је моје сопствено дело",
        "upload-form-label-infoform-categories": "Категорије",
        "upload-form-label-infoform-date": "Датум",
+       "upload-form-label-own-work-message-generic-local": "Ја потврђујем да отпремам ову датотеку поштујући услове коришћења услуге и лиценцирање на {{SITENAME}}.",
+       "upload-form-label-not-own-work-message-generic-local": "Ако нисте у могућности да отпремите ову датотеку под условима {{SITENAME}}, молимо вас да затворите овај дијалог и покушате другом методом.",
        "upload-form-label-not-own-work-local-generic-local": "Такође можете покушати [[Special:Upload|подразумевану страницу за отпремање]].",
        "backend-fail-stream": "Не могу да емитујем датотеку $1.",
        "backend-fail-backup": "Не могу да направим резерву датотеке $1.",
        "uploadstash-badtoken": "Извршавање ове радње није успело, разлог томе може бити истек времена за уређивање. Покушајте поново.",
        "uploadstash-errclear": "Чишћење датотека није успело.",
        "uploadstash-refresh": "Освежи списак датотека",
-       "uploadstash-thumbnail": "погледај минијатуру",
+       "uploadstash-thumbnail": "погледај сличицу",
        "uploadstash-exception": "Не могу сачувати датотеку у складиште ($1): „$2“.",
        "uploadstash-bad-path": "Путања не постоји.",
        "uploadstash-bad-path-invalid": "Путања није валидна.",
        "uploadstash-bad-path-unrecognized-thumb-name": "Непрепознато име минијатуре.",
        "uploadstash-bad-path-bad-format": "Кључ „$1“ није у одговарајућем облику.",
        "uploadstash-file-not-found": "Кључ „$1” није пронађен у складишту.",
-       "uploadstash-file-not-found-no-thumb": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð¾Ð±Ð¸Ñ\82и Ð¼Ð¸Ð½Ð¸Ñ\98аÑ\82Ñ\83Ñ\80у.",
+       "uploadstash-file-not-found-no-thumb": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð¿Ñ\80ибавим Ñ\81лиÑ\87иÑ\86у.",
        "uploadstash-file-not-found-no-local-path": "Нема локалне путање за умањену ставку.",
-       "uploadstash-file-not-found-no-object": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð½Ð°Ð¿Ñ\80авиÑ\82и Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸ Ð´Ð°Ñ\82оÑ\82еÑ\87ни Ð¾Ð±Ñ\98екаÑ\82 Ð·Ð° Ð¼Ð¸Ð½Ð¸Ñ\98аÑ\82Ñ\83Ñ\80у.",
+       "uploadstash-file-not-found-no-object": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð½Ð°Ð¿Ñ\80авим Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸ Ð´Ð°Ñ\82оÑ\82еÑ\87ни Ð¾Ð±Ñ\98екаÑ\82 Ð·Ð° Ñ\81лиÑ\87иÑ\86у.",
        "uploadstash-file-not-found-no-remote-thumb": "Добављање минијатуре није успело: $1\nАдреса = $2",
        "uploadstash-file-not-found-missing-content-type": "Недостаје заглавље за тип садржаја.",
        "uploadstash-file-not-found-not-exists": "Не могу наћи путању или ово није обична датотека.",
        "listfiles-userdoesnotexist": "Кориснички налог „$1“ није отворен.",
        "imgfile": "датотека",
        "listfiles": "Списак датотека",
-       "listfiles_thumb": "Ð\9cиниÑ\98аÑ\82Ñ\83Ñ\80а",
+       "listfiles_thumb": "СлиÑ\87иÑ\86а",
        "listfiles_date": "Датум",
        "listfiles_name": "Назив",
        "listfiles_user": "Корисник",
        "filehist-revert": "врати",
        "filehist-current": "актуелна",
        "filehist-datetime": "Датум/време",
-       "filehist-thumb": "Ð\9cиниÑ\98аÑ\82Ñ\83Ñ\80а",
+       "filehist-thumb": "СлиÑ\87иÑ\86а",
        "filehist-thumbtext": "Минијатура за верзију на дан $1",
-       "filehist-nothumb": "Ð\9dема Ñ\83маÑ\9aеног Ð¿Ñ\80иказа",
+       "filehist-nothumb": "Ð\91ез Ñ\81лиÑ\87иÑ\86е",
        "filehist-user": "Корисник",
        "filehist-dimensions": "Димензије",
        "filehist-filesize": "Величина датотеке",
        "linkstoimage": "{{PLURAL:$1|Следећа страница користи|$1 следеће странице користе|$1 следећих страница користи}} ову датотеку:",
        "linkstoimage-more": "Више од $1 {{PLURAL:$1|страница користи|странице користе|страница користи}} ову датотеку.\nСледећи списак приказује {{PLURAL:$1|прву страницу која користи|прве $1 странице које користе|првих $1 страница које користе}} само ову датотеку.\nДоступан је и [[Special:WhatLinksHere/$2|потпуни списак]].",
        "nolinkstoimage": "Нема страница које користе ову датотеку.",
-       "morelinkstoimage": "Ð\9fогледаÑ\98Ñ\82е [[Special:WhatLinksHere/$1|виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а]] до ове датотеке.",
+       "morelinkstoimage": "Ð\9fогледаÑ\98Ñ\82е [[Special:WhatLinksHere/$1|виÑ\88е Ð²ÐµÐ·а]] до ове датотеке.",
        "linkstoimage-redirect": "$1 (преусмерење датотеке) $2",
        "duplicatesoffile": "{{PLURAL:$1|Следећа датотека је дупликат|Следеће $1 датотеке су дупликати|Следећих $1 датотека су дупликати}} ове датотеке ([[Special:FileDuplicateSearch/$2|детаљније]]):",
        "sharedupload": "Ова датотека се налази на $1 и може се користити и на другим пројектима.",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] има [[$3|{{PLURAL:$2|један дупликат|$2 дупликата}}]].",
        "unusedtemplates": "Некоришћени шаблони",
        "unusedtemplatestext": "Ова страница наводи све странице у именском простору {{ns:template}} које нису укључене ни на једној другој страници.\nПре брисања проверите да ли друге странице воде до тих шаблона.",
-       "unusedtemplateswlh": "оÑ\81Ñ\82али Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸",
+       "unusedtemplateswlh": "оÑ\81Ñ\82але Ð²ÐµÐ·Ðµ",
        "randompage": "Случајна страница",
        "randompage-nopages": "Нема страница у {{PLURAL:$2|следећем именском простору|следећим именским просторима}}: $1.",
        "randomincategory": "Случајна страница у категорији",
        "pageswithprop-prophidden-long": "сакривено дуго текстуално својство ($1)",
        "pageswithprop-prophidden-binary": "сакривено дуго бинарно својство ($1)",
        "doubleredirects": "Двострука преусмерења",
-       "doubleredirectstext": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¿Ñ\80иказÑ\83Ñ\98е Ñ\81Ñ\82Ñ\80аниÑ\86е ÐºÐ¾Ñ\98е Ð¿Ñ\80еÑ\83Ñ\81меÑ\80аваÑ\98Ñ\83 Ð½Ð° Ð´Ñ\80Ñ\83га Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nСваки Ñ\80ед Ñ\81адÑ\80жи Ð»Ð¸Ð½ÐºÐ¾Ð²е према првом и другом преусмерењу, као и одредишну страницу другог преусмерења која је обично „прави“ чланак на кога прво преусмерење треба да упућује.\n<del>Прецртани</del> уноси су већ решени.",
+       "doubleredirectstext": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¿Ñ\80иказÑ\83Ñ\98е Ñ\81Ñ\82Ñ\80аниÑ\86е ÐºÐ¾Ñ\98е Ð¿Ñ\80еÑ\83Ñ\81меÑ\80аваÑ\98Ñ\83 Ð½Ð° Ð´Ñ\80Ñ\83га Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nСваки Ñ\80ед Ñ\81адÑ\80жи Ð²ÐµÐ·е према првом и другом преусмерењу, као и одредишну страницу другог преусмерења која је обично „прави“ чланак на кога прво преусмерење треба да упућује.\n<del>Прецртани</del> уноси су већ решени.",
        "double-redirect-fixed-move": "[[$1]] је премештен.\nАутоматски је ажурирано и сада преусмерава на [[$2]].",
        "double-redirect-fixed-maintenance": "Аутоматски исправља двострука преусмерења из [[$1]] у [[$2]] као део одржавања",
        "double-redirect-fixer": "Исправљач преусмерења",
        "brokenredirectstext": "Следећа преусмерења воде на непостојеће странице:",
        "brokenredirects-edit": "уреди",
        "brokenredirects-delete": "избриши",
-       "withoutinterwiki": "СÑ\82Ñ\80аниÑ\86е Ð±ÐµÐ· Ñ\98езиÑ\87киÑ\85 Ð»Ð¸Ð½ÐºÐ¾Ð²а",
-       "withoutinterwiki-summary": "СледеÑ\9bе Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½ÐµÐ¼Ð°Ñ\98Ñ\83 Ð»Ð¸Ð½ÐºÐ¾Ð²е према верзијама на другим језицима.",
+       "withoutinterwiki": "СÑ\82Ñ\80аниÑ\86е Ð±ÐµÐ· Ñ\98езиÑ\87киÑ\85 Ð²ÐµÐ·а",
+       "withoutinterwiki-summary": "СледеÑ\9bе Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½ÐµÐ¼Ð°Ñ\98Ñ\83 Ð²ÐµÐ·е према верзијама на другим језицима.",
        "withoutinterwiki-legend": "Префикс",
        "withoutinterwiki-submit": "Прикажи",
-       "fewestrevisions": "Странице са најмање ревизија",
+       "fewestrevisions": "Странице са најмање измена",
        "nbytes": "$1 {{PLURAL:$1|бајт|бајта|бајтова}}",
        "ncategories": "$1 {{PLURAL:$1|категорија|категорије|категорија}}",
        "ninterwikis": "$1 {{PLURAL:$1|међувики|међувикија|међувикија}}",
        "nlinks": "$1 {{PLURAL:$1|линк|линка|линкова}}",
        "nmembers": "$1 {{PLURAL:$1|члан|члана|чланова}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|члан|члана|чланова}}",
-       "nrevisions": "$1 {{PLURAL:$1|ревизија|ревизије|ревизија}}",
+       "nrevisions": "$1 {{PLURAL:$1|измена|измене|измена}}",
        "nimagelinks": "Користи се на $1 {{PLURAL:$1|страници|странице|страница}}",
        "ntransclusions": "користи се на $1 {{PLURAL:$1|страници|странице|страница}}",
        "specialpage-empty": "Нема резултата за овај извештај.",
        "unusedimages": "Некоришћене датотеке",
        "wantedcategories": "Тражене категорије",
        "wantedpages": "Тражене странице",
-       "wantedpages-summary": "СпиÑ\81ак Ð½ÐµÐ¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а до њих, на овом списку се не налазе странице до којих воде преусмерења. За списак покварених преусмерења погледајте [[{{#special:BrokenRedirects}}|списак покварених преусмерења]].",
+       "wantedpages-summary": "СпиÑ\81ак Ð½ÐµÐ¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·а до њих, на овом списку се не налазе странице до којих воде преусмерења. За списак покварених преусмерења погледајте [[{{#special:BrokenRedirects}}|списак покварених преусмерења]].",
        "wantedpages-badtitle": "Невалидан наслов у скупу резултата: $1",
        "wantedfiles": "Тражене датотеке",
        "wantedfiletext-cat": "Следеће датотеке се користе, али не постоје. Датотеке из других ризница могу бити наведене иако не постоје. Такве датотеке ће бити <del>поништене</del> са списка. Поред тога, странице које садрже непостојеће датотеке се налазе [[:$1|овде]].",
        "wantedfiletext-nocat": "Следеће датотеке се користе, али не постоје. Датотеке из других ризница могу бити наведене иако не постоје. Такве датотеке ће бити <del>поништене</del> са списка.",
        "wantedfiletext-nocat-noforeign": "Следеће датотеке се користе, али не постоје.",
        "wantedtemplates": "Тражени шаблони",
-       "mostlinked": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а",
-       "mostlinkedcategories": "Ð\9aаÑ\82егоÑ\80иÑ\98е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а",
-       "mostlinkedtemplates": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а",
+       "mostlinked": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·а",
+       "mostlinkedcategories": "Ð\9aаÑ\82егоÑ\80иÑ\98е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·а",
+       "mostlinkedtemplates": "СÑ\82Ñ\80аниÑ\86е Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·а",
        "mostcategories": "Странице са највише категорија",
-       "mostimages": "Ð\94аÑ\82оÑ\82еке Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð»Ð¸Ð½ÐºÐ¾Ð²а",
+       "mostimages": "Ð\94аÑ\82оÑ\82еке Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·а",
        "mostinterwikis": "Странице са највише међувикија",
-       "mostrevisions": "Странице са највише ревизија",
+       "mostrevisions": "Странице са највише измена",
        "prefixindex": "Све странице са префиксом",
        "prefixindex-namespace": "Све странице с предметком (именски простор $1)",
        "prefixindex-submit": "Прикажи",
        "shortpages": "Кратке странице",
        "longpages": "Дугачке странице",
        "deadendpages": "Ћорсокаци",
-       "deadendpagestext": "СледеÑ\9bе Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½ÐµÐ¼Ð°Ñ\98Ñ\83 Ð»Ð¸Ð½ÐºÐ¾Ð²е до других страница на овом викију.",
+       "deadendpagestext": "СледеÑ\9bе Ñ\81Ñ\82Ñ\80аниÑ\86е Ð½ÐµÐ¼Ð°Ñ\98Ñ\83 Ð²ÐµÐ·е до других страница на овом викију.",
        "protectedpages": "Заштићене странице",
        "protectedpages-filters": "Филтери:",
        "protectedpages-indef": "Само неограничене заштите",
        "apisandbox-loading": "Учитавам информације за API модул „$1”...",
        "apisandbox-load-error": "Дошло је до грешке приликом учитавања информација за API модул \"$1\": $2",
        "apisandbox-no-parameters": "Овај API модул нема параметре.",
-       "apisandbox-helpurls": "Ð\9bинкови за помоћ",
+       "apisandbox-helpurls": "Ð\92езе за помоћ",
        "apisandbox-examples": "Примери",
        "apisandbox-dynamic-parameters": "Додатни параметри",
        "apisandbox-dynamic-parameters-add-label": "Додај параметар:",
        "booksources-search-legend": "Претражи штампане изворе",
        "booksources-isbn": "ISBN:",
        "booksources-search": "Претражи",
-       "booksources-text": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð»Ð¸Ð½ÐºÐ¾Ð²а ка сајтовима који се баве продајом нових и половних књига, а који би могли имати додатне податке о књигама које тражите:",
+       "booksources-text": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð²ÐµÐ·а ка сајтовима који се баве продајом нових и половних књига, а који би могли имати додатне податке о књигама које тражите:",
        "booksources-invalid-isbn": "Наведени ISBN број није валидан. Проверите да није дошло до грешке при копирању из првобитног извора.",
-       "magiclink-tracking-rfc": "Странице са магичним RFC линковима",
-       "magiclink-tracking-pmid": "Странице са магичним PMID линковима",
-       "magiclink-tracking-isbn": "Странице са ISBN магичним линковима",
+       "magiclink-tracking-rfc": "Странице са чаробним RFC везама",
+       "magiclink-tracking-pmid": "Странице са чаробним PMID везама",
+       "magiclink-tracking-isbn": "Странице са чаробним ISBN везама",
        "specialloguserlabel": "Извршилац:",
        "speciallogtitlelabel": "Циљ (наслов или {{ns:user}}:корисничко име):",
-       "log": "Ð\95виденÑ\86иÑ\98е",
+       "log": "Ð\94невниÑ\86и",
        "logeventslist-submit": "Прикажи",
-       "logeventslist-more-filters": "Ð\9fÑ\80иказ Ð´Ð¾Ð´Ð°Ñ\82ниÑ\85 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а:",
-       "logeventslist-patrol-log": "Ð\95виденÑ\86иÑ\98а патролирања",
-       "logeventslist-tag-log": "Ð\95виденÑ\86иÑ\98а ознака",
-       "all-logs-page": "Све Ñ\98авне ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е",
-       "alllogstext": "СкÑ\83пни Ð¿Ñ\80иказ Ñ\81виÑ\85 Ð´Ð¾Ñ\81Ñ\82Ñ\83пниÑ\85 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а Ñ\81а Ð¾Ð²Ð¾Ð³ Ð²Ð¸ÐºÐ¸Ñ\98а.\nÐ\9cожеÑ\82е Ñ\81Ñ\83зиÑ\82и Ð¿Ñ\80иказ Ð¸Ð·Ð°Ð±Ð¸Ñ\80аÑ\9aем Ñ\82ипа ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е, корисничког имена (осетљиво на мала и велика слова) или тражене странице (такође осетљиво на мала и велика слова).",
-       "logempty": "Ð\9dема Ð¿Ñ\80онаÑ\92ениÑ\85 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и.",
+       "logeventslist-more-filters": "Ð\9fÑ\80иказ Ð´Ð¾Ð´Ð°Ñ\82ниÑ\85 Ð´Ð½ÐµÐ²Ð½Ð¸Ðºа:",
+       "logeventslist-patrol-log": "Ð\94невник патролирања",
+       "logeventslist-tag-log": "Ð\94невник ознака",
+       "all-logs-page": "Сви Ñ\98авни Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86и",
+       "alllogstext": "СкÑ\83пни Ð¿Ñ\80иказ Ñ\81виÑ\85 Ð´Ð¾Ñ\81Ñ\82Ñ\83пниÑ\85 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ° Ñ\81а Ð¾Ð²Ð¾Ð³ Ð²Ð¸ÐºÐ¸Ñ\98а.\nÐ\9cожеÑ\82е Ñ\81Ñ\83зиÑ\82и Ð¿Ñ\80иказ Ð¸Ð·Ð°Ð±Ð¸Ñ\80аÑ\9aем Ñ\82ипа Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ°, корисничког имена (осетљиво на мала и велика слова) или тражене странице (такође осетљиво на мала и велика слова).",
+       "logempty": "Ð\9dема Ð¿Ñ\80онаÑ\92ениÑ\85 Ñ\81Ñ\82авки Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83.",
        "log-title-wildcard": "Претражи наслове који почињу са овим текстом",
-       "showhideselectedlogentries": "Ð\9fÑ\80омени Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð¸Ð·Ð°Ð±Ñ\80аниÑ\85 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и",
-       "log-edit-tags": "УÑ\80еди Ð¾Ð·Ð½Ð°ÐºÐµ Ð¸Ð·Ð°Ð±Ñ\80аниÑ\85 Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98ама",
+       "showhideselectedlogentries": "Ð\9fÑ\80омени Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð¸Ð·Ð°Ð±Ñ\80аниÑ\85 Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83",
+       "log-edit-tags": "УÑ\80еди Ð¾Ð·Ð½Ð°ÐºÐµ Ð¸Ð·Ð°Ð±Ñ\80аниÑ\85 Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83",
        "checkbox-select": "Изабери: $1",
        "checkbox-all": "Све",
        "checkbox-none": "Ништа",
        "deletedcontributions": "Избрисани кориснички доприноси",
        "deletedcontributions-title": "Избрисани кориснички доприноси",
        "sp-deletedcontributions-contribs": "доприноси",
-       "linksearch": "Ð\9fÑ\80еÑ\82Ñ\80ага Ñ\81поÑ\99аÑ\88Ñ\9aиÑ\85 Ð»Ð¸Ð½ÐºÐ¾Ð²а",
+       "linksearch": "Ð\9fÑ\80еÑ\82Ñ\80ага Ñ\81поÑ\99аÑ\88Ñ\9aиÑ\85 Ð²ÐµÐ·а",
        "linksearch-pat": "Образац претраге:",
        "linksearch-ns": "Именски простор:",
        "linksearch-ok": "Претражи",
        "listgrants": "Дозволе",
        "listgrants-grant": "Дозвола",
        "listgrants-rights": "Права",
+       "listgrants-grant-display": "$1 <code>($2)</code>",
        "trackingcategories": "Категорије за праћење",
        "trackingcategories-summary": "Ова посебна страница је списак категорија које су део Медијавикија, оне се аутоматски ажурирају и њихови називи се могу мењати уређивањем системских порука у именском простору {{ns:8}}.",
        "trackingcategories-msg": "Категорије за праћење",
        "restricted-displaytitle-ignored": "Странице са занемареним насловима за приказ",
        "noindex-category-desc": "Странице које у себи имају магичну реч <code><nowiki>__NOINDEX__</nowiki></code>.",
        "index-category-desc": "Странице које у себи имају магичну реч <code><nowiki>__INDEX__</nowiki></code> и самим тим су индексиране од стране робота.",
-       "broken-file-category-desc": "Страница садржи покварени линк до датотеке (линк за уграђивање датотеке када она не постоји).",
+       "broken-file-category-desc": "Страница садржи покварену везу до датотеке (веза за уграђивање датотеке када она не постоји).",
        "hidden-category-category-desc": "Категорије које у себи имају магичну реч <code><nowiki>__HIDDENCAT__</nowiki></code> и самим тим се не приказују у одељку за категорије на страницама.",
        "trackingcategories-nodesc": "Опис није доступан.",
        "trackingcategories-disabled": "Категорија је онемогућена",
        "addedwatchtext-short": "Страница „$1“ је додата на ваш списак надгледања.",
        "removewatch": "Уклони са списка надгледања",
        "removedwatchtext": "Страница „[[:$1]]“ и њена страница за разговор је уклоњена са вашег [[Special:Watchlist|списка надгледања]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" и његове повезане странице су уклоњене са вашег [[Special:Watchlist|списка надгледања]].",
        "removedwatchtext-short": "Страница „$1“ је уклоњена са вашег списка надгледања.",
        "watch": "Надгледај",
        "watchthispage": "Надгледај ову страницу",
        "unwatch": "Прекини надгледање",
        "unwatchthispage": "Прекини надгледање",
        "notanarticle": "Није страница са садржајем",
-       "notvisiblerev": "Последња ревизија другог корисника је избрисана.",
+       "notvisiblerev": "Последња измена другог корисника је избрисана.",
        "watchlist-details": "Имате {{PLURAL:$1|$1 страницу|$1 странице|$1 страница}} на свом списку надгледања (плус странице за разговор).",
        "wlheader-enotif": "Обавештење имејлом је омогућено.",
        "wlheader-showupdated": "Странице које су промењене откад сте их последњи пут посетили су <strong>подебљане</strong>.",
        "enotif_subject_restored": "Страницу $1 на {{SITENAME}} {{GENDER:$2|вратио је|вратила је|вратио је}} $2",
        "enotif_subject_changed": "Страницу $1 на {{SITENAME}} {{GENDER:$2|променио|променила}} је $2",
        "enotif_body_intro_deleted": "Страницу $1 на {{SITENAME}} {{GENDER:$2|обрисао|обрисала}} је $2 дана $PAGEEDITDATE Погледајте $3.",
-       "enotif_body_intro_created": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|направио корисник|направила корисница}} $2 на датум $PAGEEDITDATE Актуелна ревизија се налази на $3.",
-       "enotif_body_intro_moved": "Страницу $1 на {{SITENAME}} је {{GENDER:$2|преместио корисник|преместила корисница}} $2 на датум $PAGEEDITDATE Актуелна ревизија се налази на $3.",
-       "enotif_body_intro_restored": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|вратио корисник|вратила корисница}} $2 на датум $PAGEEDITDATE Актуелна ревизија се налази на $3.",
-       "enotif_body_intro_changed": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|променио корисник|променила корисница}} $2 на датум $PAGEEDITDATE Актуелна ревизија се налази на $3.",
+       "enotif_body_intro_created": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|направио корисник|направила корисница}} $2 на датум $PAGEEDITDATE Актуелна измена се налази на $3.",
+       "enotif_body_intro_moved": "Страницу $1 на {{SITENAME}} је {{GENDER:$2|преместио корисник|преместила корисница}} $2 на датум $PAGEEDITDATE Актуелна измена се налази на $3.",
+       "enotif_body_intro_restored": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|вратио корисник|вратила корисница}} $2 на датум $PAGEEDITDATE Актуелна измена се налази на $3.",
+       "enotif_body_intro_changed": "Страницу $1 на пројекту {{SITENAME}} је {{GENDER:$2|променио корисник|променила корисница}} $2 на датум $PAGEEDITDATE Актуелна измена се налази на $3.",
        "enotif_lastvisited": "За све промене од последње посете, погледајте $1.",
        "enotif_lastdiff": "Да бисте видели ову промену, погледајте $1.",
        "enotif_anon_editor": "анониман корисник $1",
        "exbeforeblank": "садржај пре брисања је био: „$1“",
        "delete-confirm": "Брисање странице „$1“",
        "delete-legend": "Брисање",
-       "historywarning": "<strong>Упозорење:</strong> Страница коју желите да избришете има историју са $1 {{PLURAL:$1|ревизијом|ревизије|ревизија}}:",
+       "historywarning": "<strong>Упозорење:</strong> Страница коју желите да избришете има историју са $1 {{PLURAL:$1|ревизијом|измене|измена}}:",
        "historyaction-submit": "Прикажи",
        "confirmdeletetext": "Управо ћете избрисати страницу, укључујући и њену историју.\nПотврдите своју намеру, да разумете последице и да ово радите у складу са [[{{MediaWiki:Policy-url}}|правилима]].",
        "actioncomplete": "Радња је завршена",
        "actionfailed": "Радња није успела",
        "deletedtext": "Страница „$1“ је избрисана.\nПогледајте $2 за запис недавних брисања.",
-       "dellogpage": "Ð\95виденÑ\86иÑ\98а брисања",
+       "dellogpage": "Ð\94невник брисања",
        "dellogpagetext": "Испод је списак недавних брисања.",
-       "deletionlog": "евиденÑ\86иÑ\98а брисања",
-       "log-name-create": "Ð\95виденÑ\86иÑ\98а прављења страница",
+       "deletionlog": "дневник брисања",
+       "log-name-create": "Ð\94невник прављења страница",
        "log-description-create": "Испод је списак недавних прављења страница.",
        "logentry-create-create": "$1 је {{GENDER:$2|направио|направила}} страницу $3",
-       "reverted": "Враћено на ранију ревизију",
+       "reverted": "Враћено на ранију измену",
        "deletecomment": "Разлог:",
        "deleteotherreason": "Други/додатни разлог:",
        "deletereasonotherlist": "Други разлог",
        "deletereason-dropdown": "* Уобичајени разлози за брисање\n** Непожељан садржај\n** Вандализам\n** Кршење ауторских права\n** Захтев аутора\n** Покварено преусмерење",
        "delete-edit-reasonlist": "Уреди разлоге брисања",
-       "delete-toobig": "Ова страница има велику историју измена, преко $1 {{PLURAL:$1|ревизија|ревизије|ревизија}}.\nБрисање таквих страница је ограничено да би се спречило случајно оптерећење сервера.",
-       "delete-warning-toobig": "Ова страница има велику историју измена, преко $1 {{PLURAL:$1|ревизија|ревизије|ревизија}}.\nЊено брисање може да поремети базу података, стога поступајте с опрезом.",
+       "delete-toobig": "Ова страница има велику историју измена, преко $1 {{PLURAL:$1|измена|измене|измена}}.\nБрисање таквих страница је ограничено да би се спречило случајно оптерећење сервера.",
+       "delete-warning-toobig": "Ова страница има велику историју измена, преко $1 {{PLURAL:$1|измена|измене|измена}}.\nЊено брисање може да поремети базу података, стога поступајте с опрезом.",
        "deleteprotected": "Не можете да избришете ову страницу јер је заштићена.",
        "deleting-backlinks-warning": "<strong>Упозорење:</strong> бришете страницу која је укључена у [[Special:WhatLinksHere/{{FULLPAGENAME}}|друге странице]] или друге странице воде на њу.",
        "deleting-subpages-warning": "<strong>Упозорење:</strong> Страница коју желите избрисати има [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|подстраницу|$1 подстранице|$1 подстраница|51=преко 50 подстраница}}]].",
        "rollbacklinkcount-morethan": "врати више од $1 {{PLURAL:$1|измене|измене|измена}}",
        "rollbackfailed": "Враћање није успело",
        "rollback-missingparam": "Недостаје потребан параметар на захтеву.",
-       "rollback-missingrevision": "Не могу да учитам податке о ревизији.",
+       "rollback-missingrevision": "Не могу да учитам податке о измени.",
        "cantrollback": "Не могу да вратим измену.\nПоследњи аутор је уједно и једини.",
        "alreadyrolled": "Враћање последње измене странице [[:$1]] од стране {{GENDER:$2|корисника|кориснице|корисника}} [[User:$2|$2]] ([[User talk:$2|разговор]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) није успело; неко други је у међувремену изменио или вратио страницу.\n\nПоследњу измену је {{GENDER:$3|направио|направила|направио}} [[User:$3|$3]] ([[User talk:$3|разговор]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Резиме измене је био: <em>$1</em>.",
-       "revertpage": "Враћене измене {{GENDER:$2|корисника|кориснице}} [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]]) на последњу ревизију {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
-       "revertpage-nouser": "Враћене измене скривеног корисника на последњу ревизију {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
-       "rollback-success": "Враћене измене {{GENDER:$1|корисника|кориснице}} {{GENDER:$3|$1}}  на последњу ревизију {{GENDER:$2|корисника|кориснице}} {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Враћене измене корисника $1;\nвраћено на последњу ревизију корисника $2. [$3 Прикажи промене]",
+       "revertpage": "Враћене измене {{GENDER:$2|корисника|кориснице}} [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]]) на последњу измену {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
+       "revertpage-nouser": "Враћене измене скривеног корисника на последњу измену {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
+       "rollback-success": "Враћене измене {{GENDER:$1|корисника|кориснице}} {{GENDER:$3|$1}}  на последњу измену {{GENDER:$2|корисника|кориснице}} {{GENDER:$4|$2}}.",
+       "rollback-success-notify": "Враћене измене корисника $1;\nвраћено на последњу измену корисника $2. [$3 Прикажи промене]",
        "sessionfailure-title": "Сесија је окончана",
        "sessionfailure": "Изгледа да постоји проблем с вашом сесијом;\nова радња је отказана да би се избегла злоупотреба.\nМолимо, поново пошаљите образац.",
        "changecontentmodel": "Промена модела садржаја странице",
        "changecontentmodel-nodirectediting": "Модел садржаја $1 не подржава изравно уређивање",
        "changecontentmodel-emptymodels-title": "Нема доступних модела садржаја",
        "changecontentmodel-emptymodels-text": "Модел садржаја странице [[:$1]] се не може конвертовати ни у један други тип.",
-       "log-name-contentmodel": "Ð\95виденÑ\86иÑ\98а промене модела садржаја",
+       "log-name-contentmodel": "Ð\94невник промене модела садржаја",
        "log-description-contentmodel": "Ова страница приказује измене у моделима садржаја страница и странице које су направљене са моделом садржаја који се разликује од подразумеваног.",
        "logentry-contentmodel-new": "$1 је {{GENDER:$2|направио|направила}} страницу $3 с нестандардним моделом садржаја „$5“",
        "logentry-contentmodel-change": "$1 је {{GENDER:$2|променио|променила}} модел садржаја странице $3 из „$4“ у „$5“",
        "logentry-contentmodel-change-revertlink": "врати",
        "logentry-contentmodel-change-revert": "врати",
-       "protectlogpage": "Ð\95виденÑ\86иÑ\98а заштите",
+       "protectlogpage": "Ð\94невник заштите",
        "protectlogtext": "Испод је списак заштићених страница.\nПогледајте [[Special:ProtectedPages|списак заштићених страница]] за више детаља.",
        "protectedarticle": "је {{GENDER:|заштитио|заштитила}} страницу „[[$1]]“",
        "modifiedarticleprotection": "је {{GENDER:|променио|променила}} ниво заштите странице „[[$1]]“",
        "protect-fallback": "Дозвољено само корисницима са дозволом „$1“",
        "protect-level-autoconfirmed": "Допуштено само аутоматски потврђеним корисницима",
        "protect-level-sysop": "Допуштено само администраторима",
+       "protect-summary-desc": "[$1=$2] ($3)",
        "protect-summary-cascade": "преносива заштита",
        "protect-expiring": "истиче $1 (UTC)",
        "protect-expiring-local": "истиче $1",
        "restriction-level-all": "сви нивои",
        "undelete": "Преглед избрисаних страница",
        "undeletepage": "Преглед и враћање избрисаних страница",
-       "undeletepagetitle": "<strong>Следећи садржај се састоји од избрисаних ревизија странице [[:$1|$1]]</strong>.",
+       "undeletepagetitle": "<strong>Следећи садржај се састоји од избрисаних измена странице [[:$1|$1]]</strong>.",
        "viewdeletedpage": "Преглед избрисаних страница",
        "undeletepagetext": "{{PLURAL:$1|Следећа страница је избрисана, али је још у архиви и може бити враћена|Следеће $1 странице су избрисане, али су још у архиви и могу бити враћене|Следећих $1 страница је избрисано, али су још у архиви и могу бити враћене}}.\nАрхива се повремено чисти од оваквих страница.",
-       "undelete-fieldset-title": "Враћање ревизија",
-       "undeleteextrahelp": "Да бисте вратили целу историју странице, оставите све кућице неозначене и кликните на дугме <strong><em>{{int:undeletebtn}}</em></strong>.\nАко желите да вратите одређене ревизије, означите их и кликните на <strong><em>{{int:undeletebtn}}</em></strong>.",
-       "undeleterevisions": "{{PLURAL:$1|Избрисана је|Избрисане су|Избрисано је}} $1 {{PLURAL:$1|ревизија|ревизије|ревизија}}",
-       "undeletehistory": "Ако вратите страницу, све ревизије ће бити враћене њеној историји.\nАко је у међувремену направљена нова страница с истим називом, враћене ревизије ће се појавити у њеној ранијој историји.",
-       "undeleterevdel": "Враћање неће бити извршено ако је резултат тога делимично брисање последње ревизије.\nУ таквим случајевима морате искључити или открити најновије избрисане ревизије.",
-       "undeletehistorynoadmin": "Ова страница је избрисана.\nРазлог за брисање се налази испод, заједно са детаљима о кориснику који је уредио ову страницу пре брисања.\nТекст избрисаних ревизија је доступан само администраторима.",
-       "undelete-revision": "Избрисана ревизија странице $1 (дана $4; $5) од стране {{GENDER:$3|корисника|кориснице}} $3:",
-       "undeleterevision-missing": "Неважећа или недостајућа ревизија.\nМожда сте унели лош линк или је ревизија враћена или уклоњена из архиве.",
-       "undeleterevision-duplicate-revid": "Не могу вратити {{PLURAL:$1|ревизију|$1 ревизије|$1 ревизија}} јер се {{PLURAL:$1|њен|њихов}} <code>rev_id</code> већ користи.",
+       "undelete-fieldset-title": "Враћање измена",
+       "undeleteextrahelp": "Да бисте вратили целу историју странице, оставите све кућице неозначене и кликните на дугме <strong><em>{{int:undeletebtn}}</em></strong>.\nАко желите да вратите одређене измене, означите их и кликните на <strong><em>{{int:undeletebtn}}</em></strong>.",
+       "undeleterevisions": "{{PLURAL:$1|Избрисана је|Избрисане су|Избрисано је}} $1 {{PLURAL:$1|измена|измене|измена}}",
+       "undeletehistory": "Ако вратите страницу, све измене ће бити враћене њеној историји.\nАко је у међувремену направљена нова страница с истим називом, враћене измене ће се појавити у њеној ранијој историји.",
+       "undeleterevdel": "Враћање неће бити извршено ако је резултат тога делимично брисање последње измене.\nУ таквим случајевима морате искључити или открити најновије избрисане измене.",
+       "undeletehistorynoadmin": "Ова страница је избрисана.\nРазлог за брисање се налази испод, заједно са детаљима о кориснику који је уредио ову страницу пре брисања.\nТекст избрисаних измена је доступан само администраторима.",
+       "undelete-revision": "Избрисана измена странице $1 (дана $4; $5) од стране {{GENDER:$3|корисника|кориснице}} $3:",
+       "undeleterevision-missing": "Неважећа или недостајућа измена.\nМожда сте унели лошу везу или је измена враћена или уклоњена из архиве.",
+       "undeleterevision-duplicate-revid": "Не могу вратити {{PLURAL:$1|измену|$1 измене|$1 измена}} јер се {{PLURAL:$1|њен|њихов}} <code>rev_id</code> већ користи.",
        "undelete-nodiff": "Претходне измене нису пронађене.",
        "undeletebtn": "Врати",
        "undeletelink": "погледај/врати",
        "undelete-search-full": "Прикажи наслове који садрже:",
        "undelete-search-submit": "Претражи",
        "undelete-no-results": "Није пронађена одговарајућа страница у архиви брисања.",
-       "undelete-filename-mismatch": "Не могу да вратим ревизију датотеке од $1: назив датотеке се не поклапа.",
+       "undelete-filename-mismatch": "Не могу да вратим измену датотеке од $1: назив датотеке се не поклапа.",
        "undelete-bad-store-key": "Не могу да вратим измену датотеке од $1: датотека је недостајала пре брисања.",
        "undelete-cleanup-error": "Грешка при брисању некоришћене архиве „$1“.",
        "undelete-missing-filearchive": "Не могу да вратим архиву с ИБ $1 јер се она не налази у бази података.\nМожда је већ била враћена.",
        "undelete-error": "Дошло је до грешке при враћању избрисане странице",
        "undelete-error-short": "Грешка при враћању датотеке: $1",
        "undelete-error-long": "Дошло је до грешке при враћању датотеке:\n\n$1",
-       "undelete-show-file-confirm": "Јесте ли сигурни да желите да погледате избрисану ревизију датотеке „<nowiki>$1</nowiki>“ од $2 у $3?",
+       "undelete-show-file-confirm": "Јесте ли сигурни да желите да погледате избрисану измену датотеке „<nowiki>$1</nowiki>“ од $2 у $3?",
        "undelete-show-file-submit": "Да",
+       "undelete-revision-row2": "$1 ($2) $3 . . $4 $5 $6 $7 $8",
        "namespace": "Именски простор:",
        "invert": "Обрни избор",
        "tooltip-invert": "Означите ову кутијуцу да бисте сакрили промене на страницана у изабраном именском простору (и повезаним именским просторима, ако је означено)",
-       "tooltip-whatlinkshere-invert": "Ð\9eзнаÑ\87иÑ\82е Ð¾Ð²Ñ\83 ÐºÑ\83Ñ\82иÑ\98иÑ\86Ñ\83 Ð·Ð° Ñ\81акÑ\80иваÑ\9aе Ð»Ð¸Ð½ÐºÐ¾Ð²а са страница у изабраном именском простору.",
+       "tooltip-whatlinkshere-invert": "Ð\9eзнаÑ\87иÑ\82е Ð¾Ð²Ñ\83 ÐºÑ\83Ñ\82иÑ\98иÑ\86Ñ\83 Ð·Ð° Ñ\81акÑ\80иваÑ\9aе Ð²ÐµÐ·а са страница у изабраном именском простору.",
        "namespace_association": "Повезани именски простор",
        "tooltip-namespace_association": "Означите ову кутијицу да бисте укључили и разговор или именски простор теме која је повезана са изабраним именским простором",
        "blanknamespace": "(главни)",
        "sp-contributions-newbies": "Прикажи само доприносе нових налога",
        "sp-contributions-newbies-sub": "За нове кориснике",
        "sp-contributions-newbies-title": "Доприноси нових корисника",
-       "sp-contributions-blocklog": "евиденÑ\86иÑ\98а блокирања",
+       "sp-contributions-blocklog": "дневник блокирања",
        "sp-contributions-suppresslog": "избрисани доприноси {{GENDER:$1|корисника|кориснице}}",
        "sp-contributions-deleted": "избрисани доприноси {{GENDER:$1|корисника|кориснице}}",
        "sp-contributions-uploads": "отпремања",
-       "sp-contributions-logs": "евиденÑ\86иÑ\98е",
+       "sp-contributions-logs": "дневниÑ\86и",
        "sp-contributions-talk": "разговор",
        "sp-contributions-userrights": "управљање правима {{GENDER:$1|корисника|кориснице}}",
-       "sp-contributions-blocked-notice": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ан. \nÐ\9fоÑ\81ледÑ\9aи Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и блокирања је наведен испод као референца:",
-       "sp-contributions-blocked-notice-anon": "Ð\9eва IP Ð°Ð´Ñ\80еÑ\81а Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ана.\nÐ\9fоÑ\81ледÑ\9aи Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и блокирања је наведен испод као референца:",
+       "sp-contributions-blocked-notice": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ан. \nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 блокирања је наведен испод као референца:",
+       "sp-contributions-blocked-notice-anon": "Ð\9eва IP Ð°Ð´Ñ\80еÑ\81а Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ана.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 блокирања је наведен испод као референца:",
        "sp-contributions-search": "Претрага доприноса",
        "sp-contributions-username": "IP адреса или корисничко име:",
-       "sp-contributions-toponly": "Прикажи само измене које су најновије ревизије",
+       "sp-contributions-toponly": "Прикажи само измене које су најновије измене",
        "sp-contributions-newonly": "Само измене којима су направљене нове странице",
        "sp-contributions-hideminor": "Сакриј мање измене",
        "sp-contributions-submit": "Претражи",
        "nolinkshere-ns": "Ниједна страница не води на страницу <strong>$2</strong> у изабраном именском простору.",
        "isredirect": "преусмерење",
        "istemplate": "укључивање",
-       "isimage": "линк до датотеке",
+       "isimage": "веза до датотеке",
        "whatlinkshere-prev": "{{PLURAL:$1|претходни|претходна $1|претходних $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|следећи|следећа $1|следећих $1}}",
-       "whatlinkshere-links": "â\86\90 Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸",
+       "whatlinkshere-links": "â\86\90 Ð²ÐµÐ·Ðµ",
        "whatlinkshere-hideredirs": "$1 преусмерења",
        "whatlinkshere-hidetrans": "$1 укључивања",
-       "whatlinkshere-hidelinks": "$1 Ð»Ð¸Ð½ÐºÐ¾Ð²е",
-       "whatlinkshere-hideimages": "$1 Ð»Ð¸Ð½ÐºÐ¾Ð²а до датотеке",
+       "whatlinkshere-hidelinks": "$1 Ð²ÐµÐ·е",
+       "whatlinkshere-hideimages": "$1 Ð²ÐµÐ·а до датотеке",
        "whatlinkshere-filters": "Филтери",
        "whatlinkshere-submit": "Иди",
        "autoblockid": "Аутоматско блокирање #$1",
        "ipaddressorusername": "IP адреса или корисничко име:",
        "ipbexpiry": "Истиче:",
        "ipbreason": "Разлог:",
-       "ipbreason-dropdown": "*Ð\9dаÑ\98Ñ\87еÑ\88Ñ\9bи Ñ\80азлози Ð·Ð° Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aе\n** Ð£Ð¼ÐµÑ\82аÑ\9aе Ð»Ð°Ð¶Ð½Ð¸Ñ\85 Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а\n** Ð£ÐºÐ»Ð°Ñ\9aаÑ\9aе Ñ\81адÑ\80жаÑ\98а Ñ\81а Ñ\81Ñ\82Ñ\80аниÑ\86а\n** Ð\94одаваÑ\9aе Ð½ÐµÐ¿Ð¾Ð¶ÐµÑ\99ниÑ\85 Ð»Ð¸Ð½ÐºÐ¾Ð²а до спољашњих сајтова\n** Уношење бесмислица/графита у странице\n** Непристојно понашање\n** Употреба више налога\n** Неприхватљиво корисничко име",
+       "ipbreason-dropdown": "*Ð\9dаÑ\98Ñ\87еÑ\88Ñ\9bи Ñ\80азлози Ð·Ð° Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aе\n** Ð£Ð¼ÐµÑ\82аÑ\9aе Ð»Ð°Ð¶Ð½Ð¸Ñ\85 Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а\n** Ð£ÐºÐ»Ð°Ñ\9aаÑ\9aе Ñ\81адÑ\80жаÑ\98а Ñ\81а Ñ\81Ñ\82Ñ\80аниÑ\86а\n** Ð\94одаваÑ\9aе Ð½ÐµÐ¿Ð¾Ð¶ÐµÑ\99ниÑ\85 Ð²ÐµÐ·а до спољашњих сајтова\n** Уношење бесмислица/графита у странице\n** Непристојно понашање\n** Употреба више налога\n** Неприхватљиво корисничко име",
        "ipb-hardblock": "Спречи пријављене кориснике да уређују с ове IP адресе",
        "ipbcreateaccount": "Онемогући отварање налога",
        "ipbemailban": "Спречи корисника да шаље имејлове",
        "ipb-confirm": "Потврди блокирање",
        "badipaddress": "Неважећа IP адреса",
        "blockipsuccesssub": "Блокирање је успело",
-       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] је {{GENDER:$1|блокиран|блокирана|блокиран}}.<br />\nБлокирања можете да погледате [[Special:BlockList|овде]].",
+       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] је {{GENDER:$1|блокиран|блокирана}}.<br />\nПогледајте [[Special:BlockList|списак]] за преглед блокада.",
        "ipb-blockingself": "Овом радњом ћете блокирати себе! Јесте ли сигурни да то желите?",
        "ipb-confirmhideuser": "Управо ћете блокирати корисника с укљученом могућношћу „сакриј корисника“. Овим ће корисничко име бити сакривено у свим списковима и извештајима. Желите ли то да урадите?",
        "ipb-confirmaction": "Ако сте сигурни да желите наставити означите поље „{{int:ipb-confirm}}“ на дну странице.",
        "contribslink": "доприноси",
        "emaillink": "пошаљи имејл",
        "autoblocker": "Аутоматски сте блокирани јер делите IP адресу с корисником/цом [[User:$1|$1]].\nРазлог блокирања корисника/це $1 је „$2“",
-       "blocklogpage": "Ð\95виденÑ\86иÑ\98а блокирања",
+       "blocklogpage": "Ð\94невник блокирања",
        "blocklog-showlog": "{{GENDER:$1|Овај корисник је раније блокиран|Ова корисница је раније блокирана}}.\nИсторија блокирања се налази испод:",
        "blocklog-showsuppresslog": "{{GENDER:$1|Овај корисник је раније блокиран и сакривен|Ова корисница је раније блокирана и сакривена}}.\nИсторија сакривања се налази испод:",
        "blocklogentry": "је блокирао [[$1]] са временом истицања од $2 $3",
        "reblock-logentry": "{{GENDER:|је променио|је променила}} подешавања за блокирање {{GENDER:$1|корисника|кориснице}} [[$1]] са временом истека од $2 ($3)",
-       "blocklogtext": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а радњи блокирања и деблокирања корисника.\nАутоматски блокиране IP адресе нису наведене.\nПогледајте [[Special:BlockList|списак блокирања]] за списак актуелних операција забрана и блокирања.",
+       "blocklogtext": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº радњи блокирања и деблокирања корисника.\nАутоматски блокиране IP адресе нису наведене.\nПогледајте [[Special:BlockList|списак блокирања]] за списак актуелних операција забрана и блокирања.",
        "unblocklogentry": "је деблокирао $1",
        "block-log-flags-anononly": "само анонимни корисници",
        "block-log-flags-nocreate": "онемогућено отварање налога",
        "sorbs": "DNSBL",
        "sorbsreason": "Ваша IP адреса је наведена као отворени посредник у DNSBL-у који користи {{SITENAME}}.",
        "sorbs_create_account_reason": "Ваша IP адреса је наведена као отворени посредник у DNSBL-у који користи {{SITENAME}}.\nНе можете да отворите налог.",
+       "softblockrangesreason": "Анонимни доприноси нису дозвољени са ваше ИП адресе ($1). Молимо вас да се пријавите.",
        "cant-see-hidden-user": "Корисник којег покушавате да блокирате је већ блокиран и сакривен.\nС обзиром на то да немате права за сакривање корисника, не можете да погледате нити уредите корисничку блокаду.",
        "ipbblocked": "Не можете забранити или вратити приступ другим корисницима јер сте и сами блокирани",
        "ipbnounblockself": "Није вам дозвољено да деблокирате себе",
        "lockedbyandtime": "(од $1 дана $2 у $3)",
        "move-page": "Премештање „$1”",
        "move-page-legend": "Премештање странице",
-       "movepagetext": "Ð\94оÑ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ñ\9bе Ð¿Ñ\80еименоваÑ\82и Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, Ð¿Ñ\80емеÑ\88Ñ\82аÑ\98Ñ\83Ñ\9bи Ñ\86елÑ\83 Ð¸Ñ\81Ñ\82оÑ\80иÑ\98Ñ\83 Ð½Ð° Ð½Ð¾Ð²Ð¾ Ð¸Ð¼Ðµ.\nСÑ\82аÑ\80и Ð½Ð°Ñ\81лов Ð¿Ð¾Ñ\81Ñ\82аÑ\9bе Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aе Ð½Ð° Ð½Ð¾Ð²Ð¸.\nÐ\9cожеÑ\82е Ð°Ð¶Ñ\83Ñ\80иÑ\80аÑ\82и Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа ÐºÐ¾Ñ\98а Ð²Ð¾Ð´Ðµ Ð´Ð¾ Ð¸Ð·Ð²Ð¾Ñ\80ног Ð½Ð°Ñ\81лова;\nпогледаÑ\98Ñ\82е [[Special:DoubleRedirects|двоÑ\81Ñ\82Ñ\80Ñ\83ка]] Ð¸Ð»Ð¸ [[Special:BrokenRedirects|покваÑ\80ена]] Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nÐ\9dа Ð²Ð°Ð¼Ð° Ñ\98е Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80ноÑ\81Ñ\82 Ð´Ð° Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸ и даље иду тамо где треба.\n\nСтраница <strong>неће</strong> бити премештена ако већ постоји страница с тим именом (осим ако је празна, садржи преусмерење или нема историју измена).\nТо значи да можете вратити страницу на претходно име ако погрешите, али не можете ''преписати'' постојећу.\n\n<strong>Напомена:</strong>\nОво може представљати драстичну и неочекивану измену за популарну страницу;\nдобро размислите о последицама пре него што наставите.",
-       "movepagetext-noredirectfixer": "Ð\94оÑ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ñ\9bе Ð¿Ñ\80еименоваÑ\82и Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, Ð¿Ñ\80емеÑ\88Ñ\82аÑ\98Ñ\83Ñ\9bи Ñ\86елÑ\83 Ð¸Ñ\81Ñ\82оÑ\80иÑ\98Ñ\83 Ð½Ð° Ð½Ð¾Ð²Ð¾ Ð¸Ð¼Ðµ.\nСÑ\82аÑ\80и Ð½Ð°Ñ\81лов Ð¿Ð¾Ñ\81Ñ\82аÑ\9bе Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aе Ð½Ð° Ð½Ð¾Ð²Ð¸.\nÐ\9fогледаÑ\98Ñ\82е [[Special:DoubleRedirects|двоÑ\81Ñ\82Ñ\80Ñ\83ка]] Ð¸Ð»Ð¸ [[Special:BrokenRedirects|покваÑ\80ена]] Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nÐ\9dа Ð²Ð°Ð¼Ð° Ñ\98е Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80ноÑ\81Ñ\82 Ð´Ð° Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸ и даље иду тамо где треба.\n\nСтраница <strong>неће</strong> бити премештена ако већ постоји страница с тим именом (осим ако је празна, садржи преусмерење или нема историју измена).\nТо значи да можете вратити страницу на претходно име ако погрешите, али не можете ''преписати'' постојећу.\n\n<strong>Напомена:</strong>\nОво може представљати драстичну и неочекивану измену за популарну страницу;\nдобро размислите о последицама пре него што наставите.",
+       "movepagetext": "Ð\94оÑ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ñ\9bе Ð¿Ñ\80еименоваÑ\82и Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, Ð¿Ñ\80емеÑ\88Ñ\82аÑ\98Ñ\83Ñ\9bи Ñ\86елÑ\83 Ð¸Ñ\81Ñ\82оÑ\80иÑ\98Ñ\83 Ð½Ð° Ð½Ð¾Ð²Ð¾ Ð¸Ð¼Ðµ.\nСÑ\82аÑ\80и Ð½Ð°Ñ\81лов Ð¿Ð¾Ñ\81Ñ\82аÑ\9bе Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aе Ð½Ð° Ð½Ð¾Ð²Ð¸.\nÐ\9cожеÑ\82е Ð°Ð¶Ñ\83Ñ\80иÑ\80аÑ\82и Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа ÐºÐ¾Ñ\98а Ð²Ð¾Ð´Ðµ Ð´Ð¾ Ð¸Ð·Ð²Ð¾Ñ\80ног Ð½Ð°Ñ\81лова;\nпогледаÑ\98Ñ\82е [[Special:DoubleRedirects|двоÑ\81Ñ\82Ñ\80Ñ\83ка]] Ð¸Ð»Ð¸ [[Special:BrokenRedirects|покваÑ\80ена]] Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nÐ\9dа Ð²Ð°Ð¼Ð° Ñ\98е Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80ноÑ\81Ñ\82 Ð´Ð° Ð²ÐµÐ·Ðµ и даље иду тамо где треба.\n\nСтраница <strong>неће</strong> бити премештена ако већ постоји страница с тим именом (осим ако је празна, садржи преусмерење или нема историју измена).\nТо значи да можете вратити страницу на претходно име ако погрешите, али не можете ''преписати'' постојећу.\n\n<strong>Напомена:</strong>\nОво може представљати драстичну и неочекивану измену за популарну страницу;\nдобро размислите о последицама пре него што наставите.",
+       "movepagetext-noredirectfixer": "Ð\94оÑ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ñ\9bе Ð¿Ñ\80еименоваÑ\82и Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, Ð¿Ñ\80емеÑ\88Ñ\82аÑ\98Ñ\83Ñ\9bи Ñ\86елÑ\83 Ð¸Ñ\81Ñ\82оÑ\80иÑ\98Ñ\83 Ð½Ð° Ð½Ð¾Ð²Ð¾ Ð¸Ð¼Ðµ.\nСÑ\82аÑ\80и Ð½Ð°Ñ\81лов Ð¿Ð¾Ñ\81Ñ\82аÑ\9bе Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aе Ð½Ð° Ð½Ð¾Ð²Ð¸.\nÐ\9fогледаÑ\98Ñ\82е [[Special:DoubleRedirects|двоÑ\81Ñ\82Ñ\80Ñ\83ка]] Ð¸Ð»Ð¸ [[Special:BrokenRedirects|покваÑ\80ена]] Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа.\nÐ\9dа Ð²Ð°Ð¼Ð° Ñ\98е Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80ноÑ\81Ñ\82 Ð´Ð° Ð²ÐµÐ·Ðµ и даље иду тамо где треба.\n\nСтраница <strong>неће</strong> бити премештена ако већ постоји страница с тим именом (осим ако је празна, садржи преусмерење или нема историју измена).\nТо значи да можете вратити страницу на претходно име ако погрешите, али не можете ''преписати'' постојећу.\n\n<strong>Напомена:</strong>\nОво може представљати драстичну и неочекивану измену за популарну страницу;\nдобро размислите о последицама пре него што наставите.",
        "movepagetalktext": "Ако сте означили овај квадратић, одговарајућа страница за разговор биће аутоматски премештена на нови наслов, осим ако већ постоји страница за разговор са истим насловом.\n\nУ том случају, мораћете ручно да је преместите или спојите, ако има потребе за тим.",
        "moveuserpage-warning": "'''Упозорење:''' на путу сте да преместите корисничку страницу. Имајте у виду да ће само страница бити премештена, а сам корисник ''неће'' бити преименован.",
        "movecategorypage-warning": "<strong>Упозорење:</strong> премештате страницу категорије. Имајте на уму да ће само страница бити премештена и да све странице у старој категорији <em>неће</em> бити рекатегорисане у нову категорију.",
        "movepage-page-moved": "Страница $1 је премештена на $2.",
        "movepage-page-unmoved": "Страница $1 не може да се премести на $2.",
        "movepage-max-pages": "Највише $1 {{PLURAL:$1|страница је премештена|странице су премештене|страница је премештено}} и више не може да буде аутоматски премештено.",
-       "movelogpage": "Ð\95виденÑ\86иÑ\98а премештања",
+       "movelogpage": "Ð\94невник премештања",
        "movelogpagetext": "Испод се налази списак премештања страница.",
        "movesubpage": "{{PLURAL:$1|Подстраница|Подстранице}}",
        "movesubpagetext": "Ова страница има $1 {{PLURAL:$1|подстраницу приказану|подстранице приказане|подстраница приказаних}} испод.",
        "selfmove": "Наслов је истоветан;\nне можете преместити страницу преко саме себе.",
        "immobile-source-namespace": "Не могу преместити странице у именски простор „$1“.",
        "immobile-target-namespace": "Не могу преместити странице у именски простор „$1“.",
-       "immobile-target-namespace-iw": "Ð\9cеÑ\92Ñ\83вики Ð»Ð¸Ð½Ðº није важеће одредиште за премештање странице.",
+       "immobile-target-namespace-iw": "Ð\9cеÑ\92Ñ\83вики Ð²ÐµÐ·Ð° није важеће одредиште за премештање странице.",
        "immobile-source-page": "Ова страница се не може преместити.",
        "immobile-target-page": "Не могу да преместим на жељени наслов.",
        "bad-target-model": "Жељено одредиште користи другачији модел садржаја. Не могу да претворим из $1 у $2.",
        "imageinvalidfilename": "Циљано име датотеке је неважеће",
        "fix-double-redirects": "Ажурирајте сва преусмерења која воде до првобитног наслова",
        "move-leave-redirect": "Остави преусмерење",
-       "protectedpagemovewarning": "'''УпозоÑ\80еÑ\9aе:''' Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ñ\81а Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\81ким Ð¾Ð²Ð»Ð°Ñ\88Ñ\9bеÑ\9aима Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ð¿Ñ\80емеÑ\81Ñ\82е.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и је наведен испод као референца:",
-       "semiprotectedpagemovewarning": "<strong>Ð\9dапомена:</strong> Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо Ð°Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð¿Ð¾Ñ\82вÑ\80Ñ\92ени ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ð¿Ñ\80емеÑ\81Ñ\82е.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и је наведен испод као референца:",
+       "protectedpagemovewarning": "'''УпозоÑ\80еÑ\9aе:''' Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ñ\81а Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\81ким Ð¾Ð²Ð»Ð°Ñ\88Ñ\9bеÑ\9aима Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ð¿Ñ\80емеÑ\81Ñ\82е.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 је наведен испод као референца:",
+       "semiprotectedpagemovewarning": "<strong>Ð\9dапомена:</strong> Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°Ñ\88Ñ\82иÑ\9bена, Ñ\82ако Ð´Ð° Ñ\81амо Ð°Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð¿Ð¾Ñ\82вÑ\80Ñ\92ени ÐºÐ¾Ñ\80иÑ\81ниÑ\86и Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\98е Ð¿Ñ\80емеÑ\81Ñ\82е.\nÐ\9dаÑ\98новиÑ\98и Ñ\83ноÑ\81 Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 је наведен испод као референца:",
        "move-over-sharedrepo": "[[:$1]] се налази на дељеном складишту. Ако преместите датотеку на овај наслов, то ће заменити дељену датотеку.",
        "file-exists-sharedrepo": "Наведени назив датотеке се већ користи у дељеном складишту.\nИзаберите други назив.",
        "export": "Извоз страница",
-       "exporttext": "Можете да извезете текст и историју измена одређене странице или скупа страница уклљених у XML формату.\nОво онда може да буде увезено у други вики који користи Медијавики софтвер преко [[Special:Import|странице за увоз]].\n\nДа бисте извезли странице, унесите називе у оквиру испод, с једним насловом по реду, и изаберите да ли желите актуелну ревизију и све остале, или само актуелну ревизију с подацима о последњој измени.\n\nУ другом случају, можете користити и линк, на пример [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] за страницу [[{{MediaWiki:Mainpage}}]].",
+       "exporttext": "Можете да извезете текст и историју измена одређене странице или скупа страница уклљених у XML формату.\nОво онда може да буде увезено у други вики који користи Медијавики софтвер преко [[Special:Import|странице за увоз]].\n\nДа бисте извезли странице, унесите називе у оквиру испод, с једним насловом по реду, и изаберите да ли желите актуелну измену и све остале, или само актуелну измену с подацима о последњој измени.\n\nУ другом случају, можете користити и везе, на пример [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] за страницу [[{{MediaWiki:Mainpage}}]].",
        "exportall": "Извези све странице",
-       "exportcuronly": "Укључи само актуелну ревизију, не целу историју",
+       "exportcuronly": "Укључи само актуелну измену, не целу историју",
        "exportnohistory": "----\n'''Напомена:''' извоз пуне историје страница преко овог обрасца је онемогућено из техничких разлога.",
        "exportlistauthors": "Укључи целокупан списак доприносилаца за сваку страницу",
        "export-submit": "Извези",
        "allmessages-filter-translate": "Преведи",
        "thumbnail-more": "Повећајте",
        "filemissing": "Недостаје датотека",
-       "thumbnail_error": "Грешка при стварању минијатуре: $1",
+       "thumbnail_error": "Грешка при прављењу сличице: $1",
        "thumbnail_error_remote": "Порука о грешци из $1:\n$2",
        "djvu_page_error": "DjVu страница је ван опсега",
        "djvu_no_xml": "Не могу да преузмем XML за DjVu датотеку.",
-       "thumbnail-temp-create": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð½Ð°Ð¿Ñ\80авим Ð¿Ñ\80ивÑ\80еменÑ\83 Ð´Ð°Ñ\82оÑ\82екÑ\83 Ð¼Ð¸Ð½Ð¸Ñ\98аÑ\82Ñ\83Ñ\80е",
+       "thumbnail-temp-create": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð½Ð°Ð¿Ñ\80авим Ð¿Ñ\80ивÑ\80еменÑ\83 Ð´Ð°Ñ\82оÑ\82екÑ\83 Ð·Ð° Ñ\81лиÑ\87иÑ\86Ñ\83",
        "thumbnail-dest-create": "Не могу да сачувам минијатуру у одредишту",
        "thumbnail_invalid_params": "Неважећи параметри сличице",
        "thumbnail_toobigimagearea": "Датотека са величинама већим од $1",
        "thumbnail_gd-library": "Недовршена подешавања графичке библиотеке: недостаје функција $1",
        "thumbnail_image-size-zero": "Изгледа да је величина датотеке нула.",
        "thumbnail_image-missing": "Датотека недостаје: $1",
-       "thumbnail_image-failure-limit": "Било је превише недавних неуспешних покушаја ($1 или више) рендеровања ове минијатуре. Покушајте поново касније.",
+       "thumbnail_image-failure-limit": "Било је превише недавних неуспелих покушаја ($1 или више) рендеровања ове сличице. Покушајте поново касније.",
        "import": "Увоз страница",
        "importinterwiki": "Увоз са другог викија",
-       "import-interwiki-text": "Изаберите вики и наслов странице за увоз.\nДатуми ревизија и имена уредника ће бити сачувани.\nСве радње при увозу с других викија су евидентиране у [[Special:Log/import|евиденцији увоза]].",
+       "import-interwiki-text": "Изаберите вики и наслов странице за увоз.\nДатуми измена и имена уредника ће бити сачувани.\nСве радње при увозу с других викија су евидентиране у [[Special:Log/import|евиденцији увоза]].",
        "import-interwiki-sourcewiki": "Изворна вики:",
        "import-interwiki-sourcepage": "Изворна страница:",
-       "import-interwiki-history": "Копирај све ревизије историје за ову страницу",
+       "import-interwiki-history": "Копирај све измене историје за ову страницу",
        "import-interwiki-templates": "Укључи све шаблоне",
        "import-interwiki-submit": "Увези",
        "import-mapping-default": "Исто као и изворне странице",
        "import-mapping-subpage": "Увези као подстранице следеће странице:",
        "import-upload-filename": "Назив датотеке:",
        "import-upload-username-prefix": "Међувики префикс:",
+       "import-assign-known-users": "Додељивање измена локалним корисницима где именовани корисник постоји локално",
        "import-comment": "Коментар:",
        "importtext": "Извезите датотеку сa изворног викија користећи [[Special:Export|алат за извоз]].\nСачувајте је на рачунар и оптремите овде.",
        "importstart": "Увозим странице…",
-       "import-revision-count": "$1 {{PLURAL:$1|ревизија|ревизије|ревизија}}",
+       "import-revision-count": "$1 {{PLURAL:$1|измена|измене|измена}}",
        "importnopages": "Нема страница за увоз.",
        "imported-log-entries": "{{PLURAL:$1|Увезена је $1 ставка извештаја|Увезене су $1 ставке извештаја|Увезено је $1 ставки извештаја}}.",
        "importfailed": "Неуспешан увоз: <nowiki>$1</nowiki>",
        "importunknownsource": "Непознат изворни тип увоза",
        "importnoprefix": "Није наведен међувики префикс",
        "importcantopen": "Не могу да отворим датотеку за увоз.",
-       "importbadinterwiki": "Лош међувики линк",
+       "importbadinterwiki": "Лоша међувики веза",
        "importsuccess": "Увожење је завршено!",
        "importnosources": "Није одређен ниједан извор за увоз, тако да је отпремање историје онемогућено.",
        "importnofile": "Увозна датотека није послата.",
        "importuploaderrortemp": "Не могу да пошаљем датотеку за увоз.\nНедостаје привремена фасцикла.",
        "import-parse-failure": "Погрешно рашчлањивање XML-а.",
        "import-noarticle": "Нема странице за увоз!",
-       "import-nonewrevisions": "Ниједна ревизија није увезена (све су већ присутне или су прескочене због грешака).",
+       "import-nonewrevisions": "Ниједна измена није увезена (све су већ присутне или су прескочене због грешака).",
        "xml-error-string": "$1 у реду $2, колона $3 (бајт $4): $5",
        "import-upload": "Отпремање XML података",
        "import-token-mismatch": "Губитак података о сесији.\n\nМожда сте одјављени. '''Молимо Вас проверите да ли сте још увек пријављени и покушајте поново'''.\n\nАко и даље не ради, покушајте се [[Special:UserLogout|одјавити]] и поново пријавити и проверите да ли ваш веб-претраживач дозвољава колачиће са овог сајта.",
        "import-error-interwiki": "Не могу да увезем страницу „$1“ јер је њен назив резервисан за спољно повезивање (међувики).",
        "import-error-special": "Не могу да увезем страницу „$1“ јер она припада посебном именском простору које не прихвата странице.",
        "import-error-invalid": "Страница „$1“ није увезена јер је име под којим се треба увости неважеће на овом викију.",
-       "import-error-unserialize": "Не могу да десеријализујем ревизију $2 странице $1. Записано је да ревизија користи $3 модел садржаја у $4 формату.",
+       "import-error-unserialize": "Не могу да десеријализујем измену $2 странице $1. Записано је да измена користи $3 модел садржаја у $4 формату.",
        "import-options-wrong": "{{PLURAL:$2|Погрешна опција|Погрешне опције}}: <nowiki>$1</nowiki>",
        "import-rootpage-invalid": "Наведена основна страница има неважећи наслов.",
        "import-rootpage-nosubpage": "Именски простор „$1“ основне странице не дозвољава подстранице.",
-       "importlogpage": "Ð\95виденÑ\86иÑ\98а увоза",
+       "importlogpage": "Ð\94невник увоза",
        "importlogpagetext": "Административни увози страница с историјама измена с других викија.",
-       "import-logentry-upload-detail": "$1 {{PLURAL:$1|ревизија увезена|ревизије увезене|ревизија увезено}}",
-       "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|ревизија увезена|ревизије увезене|ревизија увезено}} из $2",
+       "import-logentry-upload-detail": "$1 {{PLURAL:$1|измена увезена|измене увезене|измена увезено}}",
+       "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|измена увезена|измене увезене|измена увезено}} из $2",
        "javascripttest": "Тестирање јавасктипта",
        "javascripttest-pagetext-unknownaction": "Непозната радња „$1“.",
        "javascripttest-qunit-intro": "Погледајте [$1 документацију за тестирање] на mediawiki.org.",
        "tooltip-ca-edit": "Уредите ову страницу",
        "tooltip-ca-addsection": "Започните нови одељак",
        "tooltip-ca-viewsource": "Ова страница је закључана. \nМожете да погледате њен изворник",
-       "tooltip-ca-history": "Претходне ревизије ове странице",
+       "tooltip-ca-history": "Претходне измене ове странице",
        "tooltip-ca-protect": "Заштитите ову страницу",
        "tooltip-ca-unprotect": "Промени заштиту ове странице",
        "tooltip-ca-delete": "Избришите ову страницу",
        "tooltip-t-upload": "Отпремите датотеке",
        "tooltip-t-specialpages": "Списак свих посебних страница",
        "tooltip-t-print": "Верзија ове странице за штампање",
-       "tooltip-t-permalink": "ТÑ\80аÑ\98ни Ð»Ð¸Ð½Ðº ÐºÐ° Ð¾Ð²Ð¾Ñ\98 Ñ\80евизиÑ\98и странице",
+       "tooltip-t-permalink": "ТÑ\80аÑ\98на Ð²ÐµÐ·Ð° ÐºÐ° Ð¾Ð²Ð¾Ñ\98 Ð¸Ð·Ð¼ÐµÐ½и странице",
        "tooltip-ca-nstab-main": "Погледајте страницу са садржајем",
        "tooltip-ca-nstab-user": "Погледајте корисничку страницу",
        "tooltip-ca-nstab-media": "Погледајте медијску страницу",
        "tooltip-publish": "Објавите своје измене",
        "tooltip-preview": "Прегледајте своје промене. Користите ово дугме пре чувања.",
        "tooltip-diff": "Погледајте које промене сте направили на тексту",
-       "tooltip-compareselectedversions": "Погледаjте разлике између две изабране ревизије ове странице",
+       "tooltip-compareselectedversions": "Погледаjте разлике између две изабране измене ове странице",
        "tooltip-watch": "Додајте ову страницу на свој списак надгледања",
        "tooltip-watchlistedit-normal-submit": "Уклоните наслове",
        "tooltip-watchlistedit-raw-submit": "Ажурирај списак",
        "tooltip-rollback": "„Врати“ враћа измене последњег доприносиоца ове странице једним кликом",
        "tooltip-undo": "„Поништи” враћа ову измену и отвара образац за уређивање у претпрегледном моду. Дозвољава додавање разлога у резимеу.",
        "tooltip-preferences-save": "Сачувај подешавања",
-       "tooltip-summary": "Унесите кратак резиме",
+       "tooltip-summary": "Унесите кратак опис",
        "interlanguage-link-title": "$1 — $2",
        "interlanguage-link-title-nonlang": "$1 — $2",
        "common.css": "/* CSS постављен овде ће се одразити на све теме */",
        "print.css": "/* CSS постављен овде ће утицати на издање за штампу */",
        "noscript.css": "/* CSS постављен овде ће утицати на све кориснике којима је онемогућен јаваскрипт */",
        "group-autoconfirmed.css": "/* CSS постављен овде ће утицати на самопотврђене кориснике */",
+       "group-user.css": "/* CSS постављен овде ће утицати само на регистроване кориснике */",
        "group-bot.css": "/* CSS постављен овде ће утицати само на ботове */",
        "group-sysop.css": "/* CSS постављен овде ће утицати само на системске операторе */",
        "group-bureaucrat.css": "/* CSS постављен овде ће утицати само на бирократе */",
+       "common.json": "/* JSON постављен овде ће се користити за све кориснике при отварању сваке странице. */",
        "common.js": "/* Јаваскрипт постављен овде ће се користити за све кориснике при отварању сваке странице. */",
        "group-autoconfirmed.js": "/* Јаваскрипт постављен овде ће се учитати за самопотврђене кориснике */",
+       "group-user.js": "/* Јаваскрипт постављен овде ће се учитати за регистроване кориснике */",
        "group-bot.js": "/* Јаваскрипт постављен овде ће се учитати само за ботове */",
-       "group-sysop.js": "/* Јаваскрипт постављен овде ће се учитати само за системске операторе */",
+       "group-sysop.js": "/* JavaScript постављен овде ће се учитати само за системске операторе */",
        "group-bureaucrat.js": "/* Јаваскрипт постављен овде ће се учитати само за бирократе */",
        "anonymous": "Анонимни {{PLURAL:$1|корисник|корисници}} пројекта {{SITENAME}}",
        "siteuser": "{{SITENAME}} корисник $1",
        "creditspage": "Аутори странице",
        "nocredits": "Не постоје подаци о аутору ове странице.",
        "spamprotectiontitle": "Филтер за заштиту од непожељних порука",
-       "spamprotectiontext": "ФилÑ\82еÑ\80а Ð¿Ñ\80оÑ\82ив Ð½ÐµÐ¶ÐµÑ\99ениÑ\85 Ð¿Ð¾Ñ\80Ñ\83ка Ñ\98е Ð±Ð»Ð¾ÐºÐ¸Ñ\80ао Ñ\87Ñ\83ваÑ\9aе Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е.\nÐ\9eво Ñ\98е Ð²ÐµÑ\80оваÑ\82но Ð¸Ð·Ð°Ð·Ð²Ð°Ð½Ð¾ Ð»Ð¸Ð½ÐºÐ¾Ð¼ Ð´Ð¾ Ñ\81поÑ\99аÑ\88Ñ\9aег Ñ\81аÑ\98Ñ\82а ÐºÐ¾Ñ\98и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ð½Ð° Ñ\86Ñ\80ном Ñ\81пиÑ\81кÑ\83.",
+       "spamprotectiontext": "ФилÑ\82еÑ\80а Ð¿Ñ\80оÑ\82ив Ð½ÐµÐ¶ÐµÑ\99ениÑ\85 Ð¿Ð¾Ñ\80Ñ\83ка Ñ\98е Ð±Ð»Ð¾ÐºÐ¸Ñ\80ао Ñ\87Ñ\83ваÑ\9aе Ð¾Ð²Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е.\nÐ\9eво Ñ\98е Ð²ÐµÑ\80оваÑ\82но Ð¸Ð·Ð°Ð·Ð²Ð°Ð½Ð¾ Ð²ÐµÐ·Ð¾Ð¼ Ð´Ð¾ Ñ\81поÑ\99аÑ\88Ñ\9aег Ñ\81аÑ\98Ñ\82а ÐºÐ¾Ñ\98и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ð½Ð° Ñ\86Ñ\80ноÑ\98 Ð»Ð¸Ñ\81Ñ\82и.",
        "spamprotectionmatch": "Следећи текст је активирао наш филтер за нежељене поруке: $1",
        "spambot_username": "Чишћење непожељних порука у Медијавикији",
-       "spam_reverting": "Враћам на последњу ревизију која не садржи линкове до $1",
-       "spam_blanking": "Све ревизије садрже линкове до $1. Празним",
-       "spam_deleting": "Све ревизије садрже линкове до $1. Бришем",
+       "spam_reverting": "Враћам на последњу измену која не садржи везе до $1",
+       "spam_blanking": "Све измене садрже везе до $1. Празним",
+       "spam_deleting": "Све измене садрже везе до $1. Бришем",
        "simpleantispam-label": "Провера против нежељеног садржаја. \n<strong>Не</strong> попуњавајте ово!",
        "pageinfo-title": "Информације за „$1“",
-       "pageinfo-not-current": "Нажалост, немогуће је навести ове инфомације за старије ревизије.",
+       "pageinfo-not-current": "Нажалост, немогуће је навести ове инфомације за старије измене.",
        "pageinfo-header-basic": "Основне информације",
        "pageinfo-header-edits": "Историја измена",
        "pageinfo-header-restrictions": "Заштита странице",
        "markaspatrolledtext": "Означи страницу као патролирану",
        "markaspatrolledtext-file": "Означи ову верзију датотеке као патролирану",
        "markedaspatrolled": "Означено као патролирано",
-       "markedaspatrolledtext": "Изабрана ревизија странице [[:$1]] означена је као патролирана.",
+       "markedaspatrolledtext": "Изабрана измена странице [[:$1]] означена је као патролирана.",
        "rcpatroldisabled": "Патролирање скорашњих измена је онемогућено",
        "rcpatroldisabledtext": "Могућност патролирања скорашњих измена је актуелно онемогућена.",
        "markedaspatrollederror": "Не могу да означим као патролирано.",
-       "markedaspatrollederrortext": "Морате навести ревизију да бисте је означили као патролирану.",
+       "markedaspatrollederrortext": "Морате навести измену да бисте је означили као патролирану.",
        "markedaspatrollederror-noautopatrol": "Не можете да означите своје промене као патролиране.",
        "markedaspatrollednotify": "Ова измена на страници „$1” означена је као патролирана.",
        "markedaspatrollederrornotify": "Означавање ове измене патролираном није успело.",
-       "patrol-log-page": "Ð\95виденÑ\86иÑ\98а патролирања",
-       "patrol-log-header": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а Ð¿Ð°Ñ\82Ñ\80олиÑ\80аниÑ\85 Ñ\80евизиÑ\98а.",
+       "patrol-log-page": "Ð\94невник патролирања",
+       "patrol-log-header": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº Ð¿Ð°Ñ\82Ñ\80олиÑ\80аниÑ\85 Ð¸Ð·Ð¼ÐµÐ½а.",
        "confirm-markpatrolled-button": "У реду",
-       "confirm-markpatrolled-top": "Означити ревизију $3 странице $2 као патролирану?",
-       "deletedrevision": "Избрисана стара ревизија $1.",
+       "confirm-markpatrolled-top": "Означити измену $3 странице $2 као патролирану?",
+       "deletedrevision": "Избрисана стара измена $1.",
        "filedeleteerror-short": "Грешка при брисању датотеке: $1",
        "filedeleteerror-long": "Дошло је до грешака при брисању датотеке:\n\n$1",
        "filedelete-missing": "Не могу да избришем датотеку „$1“ јер не постоји.",
-       "filedelete-old-unregistered": "Наведена ревизија датотеке „$1“ не постоји у бази података.",
+       "filedelete-old-unregistered": "Наведена измена датотеке „$1“ не постоји у бази података.",
        "filedelete-current-unregistered": "Наведена датотека „$1“ не постоји у бази података.",
        "filedelete-archive-read-only": "Сервер не може да пише по складишној фасцикли ($1).",
        "previousdiff": "← Старија измена",
        "nextdiff": "Новија измена →",
        "mediawarning": "<strong>Упозорење:</strong> овај тип датотеке може да садржи штетан код.\nЊеговим извршавањем можете да угрозите ваш систем.",
        "imagemaxsize": "Ограничење величине слике:<br /><em>(на страницама за опис датотека)</em>",
-       "thumbsize": "Величина минијатуре:",
+       "thumbsize": "Величина сличице:",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|страница|странице|страница}}",
        "file-info": "величина датотеке: $1, MIME тип: $2",
        "file-info-png-looped": "петља",
        "file-info-png-repeat": "поновљено $1 {{PLURAL:$1|пут|пута|пута}}",
        "file-info-png-frames": "$1 {{PLURAL:$1|кадар|кадра|кадрова}}",
-       "file-no-thumb-animation": "'''Напомена: због техничких ограничења, минијатуре ове датотеке се неће анимирати.'''",
+       "file-no-thumb-animation": "<strong>Напомена: Због техничких ограничења, сличице ове датотеке неће да се анимирају.</strong>",
        "file-no-thumb-animation-gif": "'''Напомена: због техничких ограничења, минијатуре GIF слика високе резолуције као што је ова неће се анимирати.'''",
        "newimages": "Галерија нових датотека",
        "imagelisttext": "Испод је списак од '''$1''' {{PLURAL:$1|датотеке|датотеке|датотека}} поређаних $2.",
        "newimages-hidepatrolled": "Сакриј патролирана отпремања",
        "newimages-mediatype": "Тип датотеке:",
        "noimages": "Нема ништа.",
-       "gallery-slideshow-toggle": "минијатуре",
+       "gallery-slideshow-toggle": "сличице",
        "ilsubmit": "Претражи",
        "bydate": "по датуму",
        "sp-newimages-showfrom": "прикажи нове датотеке почевши од $1, $2",
        "saturday-at": "у суботу у $1",
        "sunday-at": "у недељу у $1",
        "yesterday-at": "Јуче у $1",
-       "bad_image_list": "ФоÑ\80маÑ\82 Ñ\98е Ñ\81ледеÑ\9bи:\n\nРазмаÑ\82Ñ\80аÑ\98Ñ\83 Ñ\81е Ñ\81амо Ð½Ð°Ð±Ñ\80аÑ\98аÑ\9aа (Ñ\80едови ÐºÐ¾Ñ\98и Ð¿Ð¾Ñ\87иÑ\9aÑ\83 Ñ\81а Ð·Ð²ÐµÐ·Ð´Ð¸Ñ\86ом).\nÐ\9fÑ\80ви Ð»Ð¸Ð½Ðº Ñ\83 Ñ\80едÑ\83 Ð¼Ð¾Ñ\80а Ð´Ð° Ð±Ñ\83де Ð»Ð¸Ð½Ðº Ð´Ð¾ Ð½ÐµÐ¸Ñ\81пÑ\80авне Ð´Ð°Ñ\82оÑ\82еке.\nСви Ð´Ð°Ñ\99Ñ\9aи Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸ у истом реду сматрају се изузецима.",
+       "bad_image_list": "ФоÑ\80маÑ\82 Ñ\98е Ñ\81ледеÑ\9bи:\n\nРазмаÑ\82Ñ\80аÑ\98Ñ\83 Ñ\81е Ñ\81амо Ð½Ð°Ð±Ñ\80аÑ\98аÑ\9aа (Ñ\80едови ÐºÐ¾Ñ\98и Ð¿Ð¾Ñ\87иÑ\9aÑ\83 Ñ\81а Ð·Ð²ÐµÐ·Ð´Ð¸Ñ\86ом).\nÐ\9fÑ\80ва Ð²ÐµÐ·Ð° Ñ\83 Ñ\80едÑ\83 Ð¼Ð¾Ñ\80а Ð´Ð° Ð±Ñ\83де Ð²ÐµÐ·Ð° Ð´Ð¾ Ð½ÐµÐ¸Ñ\81пÑ\80авне Ð´Ð°Ñ\82оÑ\82еке.\nСве Ð´Ð°Ñ\99Ñ\9aе Ð²ÐµÐ·Ðµ у истом реду сматрају се изузецима.",
        "variantname-zh-hans": "hans",
        "variantname-zh-hant": "hant",
        "variantname-zh-cn": "cn",
        "variantname-shi-tfng": "shi-Tfng",
        "variantname-shi-latn": "shi-Latn",
        "variantname-shi": "shi",
+       "variantname-uz": "uz",
+       "variantname-uz-latn": "uz-Latn",
+       "variantname-uz-cyrl": "uz-Cyrl",
+       "variantname-crh": "crh",
+       "variantname-crh-latn": "crh-Latn",
+       "variantname-crh-cyrl": "crh-Cyrl",
        "metadata": "Метаподаци",
        "metadata-help": "Ова датотека садржи додатне податке, који вероватно долазе од дигиталног фотоапарата или скенера коришћеног за дигитализацију.\nАко је првобитно стање датотеке промењено, могуће је да неки детаљи не описују измењену датотеку у потпуности.",
        "metadata-expand": "Прикажи детаље",
        "exif-ycbcrsubsampling": "Однос величине Y према C",
        "exif-ycbcrpositioning": "Положај Y и C",
        "exif-xresolution": "Водоравна резолуција",
-       "exif-yresolution": "УÑ\81пÑ\80авна резолуција",
+       "exif-yresolution": "Ð\92еÑ\80Ñ\82икална резолуција",
        "exif-stripoffsets": "Локација података слике",
        "exif-rowsperstrip": "Број редова по линији",
        "exif-stripbytecounts": "Бајтова по сажетом блоку",
        "exif-originaldocumentid": "Јединствени ID изворног документа",
        "exif-licenseurl": "Адреса лиценце за ауторска права",
        "exif-morepermissionsurl": "Резервни подаци о лиценцирању",
-       "exif-attributionurl": "Ð\9fÑ\80и Ð¿Ð¾Ð½Ð¾Ð²Ð½Ð¾Ð¼ ÐºÐ¾Ñ\80иÑ\88Ñ\9bеÑ\9aÑ\83 Ð¾Ð²Ð¾Ð³ Ñ\80ада, ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð»Ð¸Ð½Ðº до",
+       "exif-attributionurl": "Ð\9fÑ\80и Ð¿Ð¾Ð½Ð¾Ð²Ð½Ð¾Ð¼ ÐºÐ¾Ñ\80иÑ\88Ñ\9bеÑ\9aÑ\83 Ð¾Ð²Ð¾Ð³ Ñ\80ада, ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð²ÐµÐ·Ñ\83 до",
        "exif-preferredattributionname": "При поновном коришћењу овог рада, поставите заслуге",
        "exif-pngfilecomment": "Коментар на датотеку PNG",
        "exif-disclaimer": "Одрицање одговорности",
        "exif-photometricinterpretation-1": "Црно-бело (црна је 0)",
        "exif-photometricinterpretation-2": "RGB",
        "exif-photometricinterpretation-3": "Палета",
+       "exif-photometricinterpretation-4": "Маска транспарентности",
        "exif-photometricinterpretation-6": "YCbCr",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
        "exif-unknowndate": "Непознат датум",
        "exif-orientation-1": "Нормално",
        "exif-orientation-2": "Обрнуто по хоризонтали",
        "monthsall": "све",
        "confirmemail": "Потврда имејл-адресе",
        "confirmemail_noemail": "Нисте поставили важећу имејл-адресу у [[Special:Preferences|корисничким подешавањима]].",
-       "confirmemail_text": "{{SITENAME}} Ð·Ð°Ñ\85Ñ\82ева Ð´Ð° Ð¿Ð¾Ñ\82вÑ\80диÑ\82е Ð¸Ð¼ÐµÑ\98л Ð°Ð´Ñ\80еÑ\81Ñ\83 Ð¿Ñ\80е Ð½ÐµÐ³Ð¾ Ñ\88Ñ\82о Ð¿Ð¾Ñ\87неÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и Ð¸Ð¼ÐµÑ\98ла.\nÐ\9aликниÑ\82е Ð½Ð° Ð´Ñ\83гме Ð¸Ñ\81под Ð·Ð° Ñ\81лаÑ\9aе Ð¿Ð¾Ñ\80Ñ\83ке Ð½Ð° Ð²Ð°Ñ\88Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83.\nУ Ð¿Ð¾Ñ\80Ñ\83Ñ\86и Ñ\9bе Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸Ñ\82и Ð»Ð¸Ð½Ðº са потврдним кодом;\nунесите је у прегледач да бисте потврдили да је ваша имејл адреса важећа.",
+       "confirmemail_text": "{{SITENAME}} Ð·Ð°Ñ\85Ñ\82ева Ð´Ð° Ð¿Ð¾Ñ\82вÑ\80диÑ\82е Ð¸Ð¼ÐµÑ\98л Ð°Ð´Ñ\80еÑ\81Ñ\83 Ð¿Ñ\80е Ð½ÐµÐ³Ð¾ Ñ\88Ñ\82о Ð¿Ð¾Ñ\87неÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и Ð¸Ð¼ÐµÑ\98ла.\nÐ\9aликниÑ\82е Ð½Ð° Ð´Ñ\83гме Ð¸Ñ\81под Ð·Ð° Ñ\81лаÑ\9aе Ð¿Ð¾Ñ\80Ñ\83ке Ð½Ð° Ð²Ð°Ñ\88Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83.\nУ Ð¿Ð¾Ñ\80Ñ\83Ñ\86и Ñ\9bе Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸Ñ\82и Ð²ÐµÐ·Ð° са потврдним кодом;\nунесите је у прегледач да бисте потврдили да је ваша имејл адреса важећа.",
        "confirmemail_pending": "Код за потврду вам је већ послат имејлом.\nАко сте недавно отворили налог, можда треба да сачекате неколико минута да пристигне пре него што поново затражите нови код.",
        "confirmemail_send": "Пошаљи код за потврду",
        "confirmemail_sent": "Потврдна порука је послата.",
        "confirmemail_success": "Ваша имејл-адреса је потврђена.\nСада можете да се [[Special:UserLogin|пријавите]] и уживате у викију.",
        "confirmemail_loggedin": "Ваша имејл-адреса је сада потврђена.",
        "confirmemail_subject": "{{SITENAME}} – потврда имејл-адресе",
-       "confirmemail_body": "Неко, вероватно Ви, са IP адресе $1,\nрегистровао је налог „$2“ са овом имејл адресом на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и активирали могућности имејла на пројекту {{SITENAME}}, отворите овај линк у прегледачу:\n\n$3\n\nАко ви *нисте* регистровали налог, пратите овај линк\nда бисте отказали потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче у $4.",
-       "confirmemail_body_changed": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и поново активирали могућности имејла, отворите следећи линк у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећи линк да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $6 у $7",
-       "confirmemail_body_set": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на {{SITENAME}}.\n\nДа бисмо потврдили да овај налог стварно припада вама и поново активирали\nмогућности имејла на {{SITENAME}}, отворите следећи линк у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећи линк да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $4.",
+       "confirmemail_body": "Неко, вероватно Ви, са IP адресе $1,\nрегистровао је налог „$2“ са овом имејл адресом на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и активирали могућности имејла на пројекту {{SITENAME}}, отворите ова у прегледачу:\n\n$3\n\nАко ви *нисте* регистровали налог, пратите ову везу\nда бисте отказали потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче у $4.",
+       "confirmemail_body_changed": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и поново активирали могућности имејла, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $6 у $7",
+       "confirmemail_body_set": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на {{SITENAME}}.\n\nДа бисмо потврдили да овај налог стварно припада вама и поново активирали\nмогућности имејла на {{SITENAME}}, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $4.",
        "confirmemail_invalidated": "Потврда имејл адресе је отказана",
        "invalidateemail": "Отказивање потврде имејла",
        "notificationemail_subject_changed": "Регистрована имејл адреса на пројекту {{SITENAME}} је промењена",
+       "notificationemail_subject_removed": "Регистрована имејл адреса на пројекту {{SITENAME}} је уклоњена",
        "notificationemail_body_changed": "Неко, вероватно Ви је променио имејл адресу налога из $2“ у „$3“ са IP адресе $1 на сајту {{SITENAME}}.\n\nАко ово нисте били Ви, одмах обавестите администраторе сајта.",
        "notificationemail_body_removed": "Неко, вероватно Ви, с IP адресе $1, \nуклонио је имејл адресу за налог „$2“ на {{SITENAME}}.\n\nАко ово нисте били Ви, контактирајте администраторе сајта одмах.",
        "scarytranscludedisabled": "[Међувики укључивање шаблона је онемогућено]",
        "confirm-purge-title": "Освежи ову страницу",
        "confirm_purge_button": "У реду",
        "confirm-purge-top": "Очистити кеш ове странице?",
-       "confirm-purge-bottom": "Освежавање странице чисти кеш и намеће најновију ревизију.",
+       "confirm-purge-bottom": "Освежавање странице чисти кеш и намеће најновију измену.",
        "confirm-watch-button": "У реду",
        "confirm-watch-top": "Додати ову страницу у списак надгледања?",
        "confirm-unwatch-button": "У реду",
        "confirm-unwatch-top": "Уклонити ову страницу са списка надгледања?",
        "confirm-rollback-button": "У реду",
        "confirm-rollback-top": "Врати измене на овој страници?",
+       "confirm-mcrundo-title": "Поништавање промене",
+       "mcrundofailed": "Поништавање није успело",
+       "mcrundo-missingparam": "Недостаје потребан параметар на захтеву.",
+       "mcrundo-changed": "Страница је промењена док сте гледали разлику. Прегледајте нову промену.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "ellipsis": "…",
        "percent": "$1%",
        "parentheses": "($1)",
+       "brackets": "[$1]",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "← претходна страница",
        "imgmultipagenext": "следећа страница →",
        "imgmultigo": "Иди!",
        "imgmultigoto": "Иди на страницу $1",
+       "img-lang-opt": "$2 ($1)",
        "img-lang-default": "(подразумевани језик)",
        "img-lang-info": "Рендеруј ову слику у $1. $2",
        "img-lang-go": "Иди",
        "size-kilobytes": "$1 kB",
        "size-megabytes": "$1 MB",
        "size-gigabytes": "$1 GB",
+       "size-terabytes": "$1 TB",
+       "size-petabytes": "$1 PB",
+       "size-exabytes": "$1 EB",
+       "size-zetabytes": "$1 ZB",
+       "size-yottabytes": "$1 YB",
+       "size-pixel": "$1 {{PLURAL:$1|пиксел|пиксела}}",
+       "size-kilopixel": "$1 KP",
+       "size-megapixel": "$1 MP",
+       "size-gigapixel": "$1 GP",
+       "size-terapixel": "$1 TP",
+       "size-petapixel": "$1 PP",
+       "size-exapixel": "$1 EP",
+       "size-zetapixel": "$1 ZP",
+       "size-yottapixel": "$1 YP",
+       "bitrate-bits": "$1 bps",
+       "bitrate-kilobits": "$1 kbps",
+       "bitrate-megabits": "$1 Mbps",
+       "bitrate-gigabits": "$1 Gbps",
+       "bitrate-terabits": "$1 Tbps",
+       "bitrate-petabits": "$1 Pbps",
+       "bitrate-exabits": "$1 Ebps",
+       "bitrate-zetabits": "$1 Zbps",
+       "bitrate-yottabits": "$1 Ybps",
        "lag-warn-normal": "Промене новије од $1 {{PLURAL:$1|секунде|секунде|секунди}} неће бити приказане.",
        "lag-warn-high": "Због преоптерећења базе података, промене новије од $1 {{PLURAL:$1|1=секунде|секунде|секунди}} неће бити приказане.",
        "watchlistedit-normal-title": "Уређивање списка надгледања",
        "watchlistedit-clear-titles": "Наслови:",
        "watchlistedit-clear-submit": "Очисти списак надгледања (Ово је неповратно!)",
        "watchlistedit-clear-done": "Ваш списак надгледања је очишћен.",
+       "watchlistedit-clear-jobqueue": "Ваш списак надгледања ће бити очишћен. Ово може потрајати неко време!",
        "watchlistedit-clear-removed": "{{PLURAL:$1|1 наслов је уклоњен|$1 наслова су уклоњена|$1 наслова је уклоњено}}:",
        "watchlistedit-too-many": "Има превише страница за приказ овде.",
        "watchlisttools-clear": "очисти списак надгледања",
        "version-entrypoints": "Адресе улазне тачке",
        "version-entrypoints-header-entrypoint": "Улазна тачка",
        "version-entrypoints-header-url": "Адреса",
+       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Article path]",
+       "version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath Script path]",
        "version-libraries": "Инсталиране библиотеке",
        "version-libraries-library": "Библиотека",
        "version-libraries-version": "Верзија",
        "version-libraries-license": "Лиценца",
        "version-libraries-description": "Опис",
        "version-libraries-authors": "Аутори",
-       "redirect": "Преусмерење на датотеку, корисника, страницу, ревизију или дневник (ID)",
-       "redirect-summary": "Ова посебна страница преусмерава до датотеке (с датим именом датотеке), странице (с датим ID-ом ревизије или ID-ом странице), корисничке странице (с датим нумеричким корисничким ID-ом), или уноса у дневнику (с датим дневничким ID-ом). Употреба: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
+       "redirect": "Преусмерење на датотеку, корисника, страницу, измену или дневник (ID)",
+       "redirect-summary": "Ова посебна страница преусмерава до датотеке (с датим именом датотеке), странице (с датим ID-ом измене или ID-ом странице), корисничке странице (с датим нумеричким корисничким ID-ом), или уноса у дневнику (с датим дневничким ID-ом). Употреба: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Иди",
        "redirect-lookup": "Тип вредности:",
        "redirect-value": "Вредност:",
        "redirect-page": "ID странице",
        "redirect-revision": "Ревизија странице",
        "redirect-file": "Назив датотеке",
-       "redirect-logid": "ID ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е",
+       "redirect-logid": "ID Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ°",
        "redirect-not-exists": "Вредност није пронађена",
        "fileduplicatesearch": "Претрага дупликата датотека",
        "fileduplicatesearch-summary": "Претрага дуплираних датотека према хеш вредности.",
        "specialpages-group-maintenance": "Извештаји одржавања",
        "specialpages-group-other": "Остале посебне странице",
        "specialpages-group-login": "Пријава / регистрација",
-       "specialpages-group-changes": "Ð\9dедавне Ð¿Ñ\80омене Ð¸ ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е",
+       "specialpages-group-changes": "Ð\9dедавне Ð¿Ñ\80омене Ð¸ Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86и",
        "specialpages-group-media": "Извештаји о мултимедијалном садржају и отпремања",
        "specialpages-group-users": "Корисници и корисничка права",
        "specialpages-group-highuse": "Најчешће коришћене странице",
        "specialpages-group-developer": "Програмерске алатке",
        "blankpage": "Празна страница",
        "intentionallyblankpage": "Ова страница је намерно остављена празном.",
-       "external_image_whitelist": " #Ð\9eÑ\81Ñ\82авиÑ\82е Ð¾Ð²Ð°Ñ\98 Ñ\80ед Ð¾Ð½Ð°ÐºÐ²Ð¸Ð¼ ÐºÐ°ÐºÐ°Ð² Ñ\98еÑ\81Ñ\82е<pre>\n#Ð\98Ñ\81под Ð´Ð¾Ð´Ð°Ñ\98Ñ\82е Ð¾Ð´Ð»Ð¾Ð¼ÐºÐµ Ñ\80егÑ\83лаÑ\80ниÑ\85 Ð¸Ð·Ñ\80аза (Ñ\81амо Ð´ÐµÐ¾ ÐºÐ¾Ñ\98и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ð¸Ð·Ð¼ÐµÑ\92Ñ\83 //)\n#Ð\9eни Ñ\9bе Ð±Ð¸Ñ\82и Ñ\83поÑ\80еÑ\92ени Ñ\81 Ð°Ð´Ñ\80еÑ\81ама Ñ\81поÑ\99аÑ\88Ñ\9aиÑ\85 Ñ\81лика\n#Ð\9eне ÐºÐ¾Ñ\98е Ñ\81е Ð¿Ð¾ÐºÐ»Ð°Ð¿Ð°Ñ\98Ñ\83 Ð±Ð¸Ñ\9bе Ð¿Ñ\80иказане ÐºÐ°Ð¾ Ñ\81лике, Ð° Ð¿Ñ\80еоÑ\81Ñ\82але ÐºÐ°Ð¾ Ð»Ð¸Ð½ÐºÐ¾Ð²Ð¸ до слика\n#Редови који почињу с тарабом се сматрају коментарима\n#Сви уноси су осетљиви на мала и велика слова\n\n#Додајте све одломке регуларних израза изнад овог реда. Овај ред не дирајте</pre>",
+       "external_image_whitelist": " #Ð\9eÑ\81Ñ\82авиÑ\82е Ð¾Ð²Ð°Ñ\98 Ñ\80ед Ð¾Ð½Ð°ÐºÐ²Ð¸Ð¼ ÐºÐ°ÐºÐ°Ð² Ñ\98еÑ\81Ñ\82е<pre>\n#Ð\98Ñ\81под Ð´Ð¾Ð´Ð°Ñ\98Ñ\82е Ð¾Ð´Ð»Ð¾Ð¼ÐºÐµ Ñ\80егÑ\83лаÑ\80ниÑ\85 Ð¸Ð·Ñ\80аза (Ñ\81амо Ð´ÐµÐ¾ ÐºÐ¾Ñ\98и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ð¸Ð·Ð¼ÐµÑ\92Ñ\83 //)\n#Ð\9eни Ñ\9bе Ð±Ð¸Ñ\82и Ñ\83поÑ\80еÑ\92ени Ñ\81 Ð°Ð´Ñ\80еÑ\81ама Ñ\81поÑ\99аÑ\88Ñ\9aиÑ\85 Ñ\81лика\n#Ð\9eне ÐºÐ¾Ñ\98е Ñ\81е Ð¿Ð¾ÐºÐ»Ð°Ð¿Ð°Ñ\98Ñ\83 Ð±Ð¸Ñ\9bе Ð¿Ñ\80иказане ÐºÐ°Ð¾ Ñ\81лике, Ð° Ð¿Ñ\80еоÑ\81Ñ\82але ÐºÐ°Ð¾ Ð²ÐµÐ·Ðµ до слика\n#Редови који почињу с тарабом се сматрају коментарима\n#Сви уноси су осетљиви на мала и велика слова\n\n#Додајте све одломке регуларних израза изнад овог реда. Овај ред не дирајте</pre>",
        "tags": "Важеће ознаке промена",
        "tag-filter": "Филтер [[Special:Tags|ознака]]:",
        "tag-filter-submit": "Филтрирај",
        "tags-create-reason": "Разлог:",
        "tags-create-submit": "Направи",
        "tags-create-no-name": "Морате да наведете име ознаке.",
+       "tags-create-invalid-chars": "Имена ознака не смеју садржати (<code>,</code>), (<code>|</code>) или (<code>/</code>).",
+       "tags-create-invalid-title-chars": "Имена ознака не смеју садржати карактере који се не могу користити у насловима страница.",
        "tags-create-already-exists": "Ознака „$1“ већ постоји.",
        "tags-create-warnings-below": "Правите нову ознаку, желите ли да наставите?",
        "tags-delete-title": "Брисање ознака",
        "tags-delete-explanation-warning": "Ова радња је <strong>неповратна</strong> и <strong>не може да се поништи</strong>. Ово не могу да ураде чак ни администратори базе података. Будите сигурни да је ово ознака коју желите избрисати.",
        "tags-delete-reason": "Разлог:",
        "tags-delete-submit": "Неповратно избриши ову ознаку",
+       "tags-delete-not-allowed": "Ознаке које су дефинисане екстензијом не могу се избрисати осим ако их екстензија не дозвољава.",
        "tags-delete-not-found": "Ознака „$1“ не постоји.",
-       "tags-delete-too-many-uses": "Ознака „$1” је примењена на више од $2 {{PLURAL:$2|ревизије|ревизија}}, што значи да се не може избрисати.",
+       "tags-delete-too-many-uses": "Ознака „$1” је примењена на више од $2 {{PLURAL:$2|измене|измена}}, што значи да се не може избрисати.",
        "tags-delete-no-permission": "Немате дозволу да бришете ознаке промена.",
        "tags-activate-title": "Активирање ознака",
        "tags-activate-question": "Активирате ознаку „$1“.",
        "tags-deactivate-not-allowed": "Није могуће деактивирати ознаку „$1“.",
        "tags-deactivate-submit": "Декативирај",
        "tags-apply-no-permission": "Немате дозволу да примените ознаке промена заједно са својим променама.",
-       "tags-update-no-permission": "Немате дозволу да додате или уклоните ознаке промена из појединачних ревизија или уноса у евиденцији.",
+       "tags-apply-blocked": "Не можете да примените ознаке тагова заједно са вашим променама све док сте блокирани.",
+       "tags-update-no-permission": "Немате дозволу да додате или уклоните ознаке промена из појединачних измена или уноса у дневнику.",
        "tags-update-blocked": "Не можете додавати нити уклањати ознаке измена док {{GENDER:$1|сте}} блокирани.",
        "tags-update-add-not-allowed-one": "Није дозвољено да се ознака „$1” додаје ручно.",
        "tags-edit-title": "Уреди ознаке",
        "tags-edit-manage-link": "Управљај ознакама",
-       "tags-edit-revision-selected": "{{PLURAL:$1|Изабрана ревизија|Изабране ревизије}} странице [[:$2]]:",
-       "tags-edit-revision-legend": "Додајте или уклоните ознаке са {{PLURAL:$1|ове ревизије|свих $1 ревизија}}",
+       "tags-edit-revision-selected": "{{PLURAL:$1|Изабрана измена|Изабране измене}} странице [[:$2]]:",
+       "tags-edit-revision-legend": "Додајте или уклоните ознаке са {{PLURAL:$1|ове измене|свих $1 измена}}",
        "tags-edit-existing-tags": "Постојеће ознаке:",
        "tags-edit-existing-tags-none": "<em>Нема</em>",
        "tags-edit-new-tags": "Нове ознаке:",
        "tags-edit-chosen-placeholder": "Изабери неке ознаке",
        "tags-edit-chosen-no-results": "Одговарајуће ознаке нису пронађене",
        "tags-edit-reason": "Разлог:",
-       "tags-edit-revision-submit": "Примени промене {{PLURAL:$1|овој ревизији|$1 ревизијама}}",
+       "tags-edit-revision-submit": "Примени промене {{PLURAL:$1|овој измени|$1 изменама}}",
        "tags-edit-success": "Промене су примењене.",
        "tags-edit-failure": "Не могу да применим измене:\n$1",
-       "tags-edit-nooldid-title": "Неважећа одредишна ревизија",
+       "tags-edit-nooldid-title": "Неважећа одредишна измена",
+       "tags-edit-nooldid-text": "Нисте одредили било коју циљану измену на којој ће се извршити ова функција или ако наведена измена не постоји.",
        "tags-edit-none-selected": "Изаберите бар једну ознаку коју треба додати или уклонити.",
        "comparepages": "Упоређивање страница",
        "compare-page1": "Страница 1",
        "compare-title-not-exists": "Наведени наслов не постоји.",
        "compare-revision-not-exists": "Ревизија коју сте навели не постоји.",
        "diff-form": "Разлике",
-       "diff-form-oldid": "ID старе ревизије (опционално)",
+       "diff-form-oldid": "ID старе измене (опционално)",
        "diff-form-revid": "ID измене или разлике",
        "diff-form-submit": "Прикажи разлике",
-       "permanentlink": "ТÑ\80аÑ\98ни Ð»Ð¸Ð½Ðº",
-       "permanentlink-revid": "ID ревизије",
+       "permanentlink": "ТÑ\80аÑ\98на Ð²ÐµÐ·Ð°",
+       "permanentlink-revid": "ID измене",
        "permanentlink-submit": "Иди на измену",
        "dberr-problems": "Дошло је до техничких проблема.",
        "dberr-again": "Сачекајте неколико минута и поново учитајте страницу.",
        "htmlform-date-toolow": "Вредност коју сте навели је пре најранијег дозвољеног датума – $1.",
        "htmlform-date-toohigh": "Вредност коју сте навели је после крајњег дозвољеног датума – $1.",
        "htmlform-time-toolow": "Вредност коју сте навели је пре најранијег дозвољеног времена – $1.",
+       "htmlform-time-toohigh": "Вредност коју сте навели је последње дозвољено време од $1.",
+       "htmlform-datetime-toolow": "Вредност коју сте навели је најранији датум и време од $1.",
+       "htmlform-datetime-toohigh": "Вредност коју сте навели је најновији датум и време од $1.",
        "htmlform-title-badnamespace": "[[:$1]] није у именском простору „{{ns:$2}}“.",
        "htmlform-title-not-creatable": "Страница „$1“ се не може направити",
        "htmlform-title-not-exists": "$1 не постоји.",
        "logentry-delete-delete_redir": "$1 је {{GENDER:$2|обрисао|обрисала}} преусмерење $3 преписивањем",
        "logentry-delete-restore": "$1 је {{GENDER:$2|вратио|вратила}} страницу $3 ($4)",
        "logentry-delete-restore-nocount": "$1 је {{GENDER:$2|вратио|вратила}} страницу $3",
-       "restore-count-revisions": "{{PLURAL:$1|1 ревизија|$1 ревизије|$1 ревизија}}",
+       "restore-count-revisions": "{{PLURAL:$1|1 измена|$1 измене|$1 измена}}",
        "restore-count-files": "{{PLURAL:$1|1 датотека|$1 датотеке|$1 датотека}}",
-       "logentry-delete-event": "$1 Ñ\98е {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 {{PLURAL:$5|догаÑ\92аÑ\98а|$5 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а}} Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и на страници „$3”: $4",
-       "logentry-delete-revision": "$1 је {{GENDER:$2|променио|променила}} видљивост {{PLURAL:$5|ревизије|$5 ревизије|$5 ревизија}} на страници $3: $4",
-       "logentry-delete-event-legacy": "$1 Ñ\98е {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и на страници „$3”",
-       "logentry-delete-revision-legacy": "$1 је {{GENDER:$2|променио|променила}} видљивост ревизија на страници $3",
+       "logentry-delete-event": "$1 Ñ\98е {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 {{PLURAL:$5|догаÑ\92аÑ\98а|$5 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а}} Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 на страници „$3”: $4",
+       "logentry-delete-revision": "$1 је {{GENDER:$2|променио|променила}} видљивост {{PLURAL:$5|измене|$5 измене|$5 измена}} на страници $3: $4",
+       "logentry-delete-event-legacy": "$1 Ñ\98е {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 на страници „$3”",
+       "logentry-delete-revision-legacy": "$1 је {{GENDER:$2|променио|променила}} видљивост измена на страници $3",
        "logentry-suppress-delete": "$1 је {{GENDER:$2|потиснуо|потиснула}} страницу $3",
-       "logentry-suppress-event": "$1 Ñ\98е Ñ\82аÑ\98но {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 {{PLURAL:$5|догаÑ\92аÑ\98а|$5 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а}} Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и на страници „$3”: $4",
-       "logentry-suppress-revision": "$1 је тајно {{GENDER:$2|променио|променила}} видљивост {{PLURAL:$5|ревизије|$5 ревизија}} на страници $3: $4",
-       "logentry-suppress-event-legacy": "$1 Ñ\98е Ð¿Ð¾Ñ\82аÑ\98но {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и на страници „$3”",
-       "logentry-suppress-revision-legacy": "$1 је тајно {{GENDER:$2|променио|променила}} видљивост ревизија на страници $3",
+       "logentry-suppress-event": "$1 Ñ\98е Ñ\82аÑ\98но {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 {{PLURAL:$5|догаÑ\92аÑ\98а|$5 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а}} Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 на страници „$3”: $4",
+       "logentry-suppress-revision": "$1 је тајно {{GENDER:$2|променио|променила}} видљивост {{PLURAL:$5|измене|$5 измена}} на страници $3: $4",
+       "logentry-suppress-event-legacy": "$1 Ñ\98е Ð¿Ð¾Ñ\82аÑ\98но {{GENDER:$2|пÑ\80оменио|пÑ\80оменила}} Ð²Ð¸Ð´Ñ\99ивоÑ\81Ñ\82 Ð´Ð¾Ð³Ð°Ñ\92аÑ\98а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 на страници „$3”",
+       "logentry-suppress-revision-legacy": "$1 је тајно {{GENDER:$2|променио|променила}} видљивост измена на страници $3",
        "revdelete-content-hid": "садржај је сакривен",
-       "revdelete-summary-hid": "резиме измене је сакривен",
+       "revdelete-summary-hid": "опис измене је сакривен",
        "revdelete-uname-hid": "корисничко име је сакривено",
        "revdelete-content-unhid": "садржај је откривен",
-       "revdelete-summary-unhid": "резиме измене је откривен",
+       "revdelete-summary-unhid": "опис измене је откривен",
        "revdelete-uname-unhid": "корисничко име је откривено",
        "revdelete-restricted": "примењена ограничења за администраторе",
        "revdelete-unrestricted": "уклоњена ограничења за администраторе",
        "logentry-suppress-block": "$1 је {{GENDER:$2|блокирао|блокирала}} {{GENDER:$4|$3}} у трајању од $5 $6",
        "logentry-suppress-reblock": "$1 је {{GENDER:$2|променио|променила}} подешавања за блокирање {{GENDER:$4|корисника|кориснице}} {{GENDER:$4|$3}} у трајању од $5 $6",
        "logentry-import-upload": "$1 је {{GENDER:$2|увезао|увезла}} $3 отпремањем датотеке",
-       "logentry-import-upload-details": "$1 је {{GENDER:$2|увезао|увезла}} $3 отпремањем датотеке ($4 {{PLURAL:$4|ревизија|ревизије|ревизија}})",
+       "logentry-import-upload-details": "$1 је {{GENDER:$2|увезао|увезла}} $3 отпремањем датотеке ($4 {{PLURAL:$4|измена|измене|измена}})",
        "logentry-import-interwiki": "$1 је {{GENDER:$2|увезао|увезла}} $3 с другог викија",
-       "logentry-import-interwiki-details": "$1 је {{GENDER:$2|увезао|увезла}} $3 из $5 ($4 {{PLURAL:$4|ревизија|ревизије|ревизија}})",
+       "logentry-import-interwiki-details": "$1 је {{GENDER:$2|увезао|увезла}} $3 из $5 ($4 {{PLURAL:$4|измена|измене|измена}})",
        "logentry-merge-merge": "$1 је {{GENDER:$2|спојио|спојила}} $3 у $4 (све до измене $5)",
        "logentry-move-move": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4",
        "logentry-move-move-noredirect": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4 без остављања преусмерења",
        "logentry-move-move_redir": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4 преко преусмерења",
        "logentry-move-move_redir-noredirect": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4 преко преусмерења без остављања преусмерења",
-       "logentry-patrol-patrol": "$1 је {{GENDER:$2|означио|означила}} ревизију $4 странице $3 као патролирану",
-       "logentry-patrol-patrol-auto": "$1 је аутоматски {{GENDER:$2|означио|означила}} ревизију $4 странице $3 као патролирану",
+       "logentry-patrol-patrol": "$1 је {{GENDER:$2|означио|означила}} измену $4 странице $3 као патролирану",
+       "logentry-patrol-patrol-auto": "$1 је аутоматски {{GENDER:$2|означио|означила}} измену $4 странице $3 као патролирану",
        "logentry-newusers-newusers": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create2": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог $3",
        "logentry-upload-upload": "$1 је {{GENDER:$2|отпремио|отпремила}} $3",
        "logentry-upload-overwrite": "$1 је {{GENDER:$2|отпремио|отпремила}} нову верзију датотеке $3",
        "logentry-upload-revert": "$1 је {{GENDER:$2|отпремио|отпремила}} $3",
-       "log-name-managetags": "Ð\95виденÑ\86иÑ\98а управљања ознакама",
-       "log-description-managetags": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð²ÐµÐ·Ð¸ [[Special:Tags|ознака]]. Ð\95виденÑ\86иÑ\98а Ñ\81адÑ\80жи Ñ\81амо Ñ\80адÑ\9aе ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\80Ñ\83Ñ\87но Ð¸Ð·Ð²Ñ\80Ñ\88или Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80и; Ñ\83ноÑ\81и Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÐµ ÐºÐ¾Ñ\98е Ñ\98е Ð½Ð°Ð¿Ñ\80авио Ð¸Ð»Ð¸ Ð¸Ð·Ð±Ñ\80иÑ\81ао Ð²Ð¸ÐºÐ¸ Ñ\81оÑ\84Ñ\82веÑ\80а Ñ\81е Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\83 Ð¾Ð²Ð¾Ñ\98 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и.",
+       "log-name-managetags": "Ð\94невник управљања ознакама",
+       "log-description-managetags": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð²ÐµÐ·Ð¸ [[Special:Tags|ознака]]. Ð\94невник Ñ\81адÑ\80жи Ñ\81амо Ñ\80адÑ\9aе ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\80Ñ\83Ñ\87но Ð¸Ð·Ð²Ñ\80Ñ\88или Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80и; Ñ\83ноÑ\81и Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÐµ ÐºÐ¾Ñ\98е Ñ\98е Ð½Ð°Ð¿Ñ\80авио Ð¸Ð»Ð¸ Ð¸Ð·Ð±Ñ\80иÑ\81ао Ð²Ð¸ÐºÐ¸ Ñ\81оÑ\84Ñ\82веÑ\80а Ñ\81е Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\83 Ð¾Ð²Ð¾Ð¼ Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83.",
        "logentry-managetags-create": "$1 је {{GENDER:$2|направио|направила}} ознаку „$4“",
-       "logentry-managetags-delete": "$1 Ñ\98е {{GENDER:$2|обÑ\80иÑ\81ао|обÑ\80иÑ\81ала}} Ð¾Ð·Ð½Ð°ÐºÑ\83 â\80\9e$4â\80\9c (Ñ\83клоÑ\9aена Ñ\98е Ð¸Ð· $5 {{PLURAL:$5|Ñ\80евизиÑ\98е Ð¸Ð»Ð¸ Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и|Ñ\80евизиÑ\98а Ð¸/или Ñ\83ноÑ\81а Ñ\83 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и}})",
+       "logentry-managetags-delete": "$1 Ñ\98е {{GENDER:$2|избÑ\80иÑ\81ао|избÑ\80иÑ\81ала}} Ð¾Ð·Ð½Ð°ÐºÑ\83 â\80\9e$4â\80\9c (Ñ\83клоÑ\9aена Ñ\98е Ð¸Ð· $5 {{PLURAL:$5|измене Ð¸Ð»Ð¸ Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83|измена Ð¸/или Ñ\83ноÑ\81а Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83}})",
        "logentry-managetags-activate": "$1 је {{GENDER:$2|активирао|активирала}} ознаку „$4“ за употребу од стране корисника и ботова",
        "logentry-managetags-deactivate": "$1 је {{GENDER:$2|деактивирао|деактивирала}} ознаку „$4“ за употребу од стране корисника и ботова",
-       "log-name-tag": "Ð\95виденÑ\86иÑ\98а ознака",
-       "log-description-tag": "Ова страница приказује када су корисници додали/уклонили [[Special:Tags|ознаке]] с појединачних ревизија или уноса у евиденцијама. Евиденција не приказује радње означавања када су се догодиле приликом уређивања, брисања или сличне радње.",
+       "log-name-tag": "Ð\94невник ознака",
+       "log-description-tag": "Ова страница приказује када су корисници додали/уклонили [[Special:Tags|ознаке]] с појединачних измена или уноса у дневницима. Дневник не приказује радње означавања када су се догодиле приликом уређивања, брисања или сличне радње.",
        "rightsnone": "(нема)",
        "rightslogentry-temporary-group": "$1 (привремено, до $2)",
-       "feedback-adding": "Додајем повратну информацију на страницу…",
+       "feedback-adding": "Додајем повратне информације на страницу…",
        "feedback-back": "Назад",
-       "feedback-bugcheck": "Одлично! Проверите да ли је грешка [$1 позната од пре].",
+       "feedback-bugcheck": "Одлично! Проверите да се не ради о некој [$1 познатој грешци].",
        "feedback-bugnew": "Проверено. Пријави нову грешку",
        "feedback-bugornote": "Ако сте спремни да детаљно опишете технички проблем, онда [$1 пријавите грешку].\nУ супротном, послужите се једноставним обрасцем испод. Ваш коментар ће стајати на страници „[$3 $2]“, заједно с корисничким именом и прегледачем који користите.",
        "feedback-cancel": "Откажи",
-       "feedback-close": "УÑ\80аÑ\92ено",
-       "feedback-external-bug-report-button": "Ð\9fÑ\80иÑ\98ави Ð³Ñ\80еÑ\88кÑ\83",
-       "feedback-dialog-title": "СлаÑ\9aе Ð¿Ð¾Ð²Ñ\80аÑ\82не Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98е",
-       "feedback-error1": "Грешка: непрепознат резултат од АПИ-ја",
+       "feedback-close": "Ð\93оÑ\82ово",
+       "feedback-external-bug-report-button": "Ð\90Ñ\80Ñ\85ивиÑ\80аÑ\98 Ñ\82еÑ\85ниÑ\87ки Ð·Ð°Ð´Ð°Ñ\82ак",
+       "feedback-dialog-title": "СлаÑ\9aе Ð¿Ð¾Ð²Ñ\80аÑ\82ниÑ\85 Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а",
+       "feedback-error1": "Грешка: непрепознат резултат од API-ја",
        "feedback-error2": "Грешка: уређивање није успело",
-       "feedback-error3": "Грешка: нема одговора од АПИ-ја",
+       "feedback-error3": "Грешка: нема одговора од API-ја",
+       "feedback-error4": "Грешка: не могу да поставим повратне информације на дати наслов",
        "feedback-message": "Порука:",
-       "feedback-subject": "Ð\9dаÑ\81лов:",
+       "feedback-subject": "Тема:",
        "feedback-submit": "Пошаљи",
        "feedback-termsofuse": "Прихватам да пошаљем повратне информације у складу са условима коришћења.",
        "feedback-thanks": "Хвала! Ваша повратна информација је постављена на страницу „[$2 $1]“.",
        "searchsuggest-search": "Претрага",
        "searchsuggest-containing": "садржи…",
        "api-error-badtoken": "Унутрашња грешка: лош токен.",
-       "api-error-emptypage": "СÑ\82ваÑ\80ање нових празних страница није дозвољено.",
+       "api-error-emptypage": "Ð\9fÑ\80авÑ\99ење нових празних страница није дозвољено.",
        "api-error-publishfailed": "Унутрашња грешка: сервер није успео да објави привремену датотеку.",
-       "api-error-stashfailed": "УнÑ\83Ñ\82Ñ\80аÑ\88Ñ\9aа Ð³Ñ\80еÑ\88ка: Ñ\81еÑ\80веÑ\80 Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ñ\81аÑ\87Ñ\83ва привремену датотеку.",
+       "api-error-stashfailed": "УнÑ\83Ñ\82Ñ\80аÑ\88Ñ\9aа Ð³Ñ\80еÑ\88ка: Ñ\81еÑ\80веÑ\80 Ð½Ð¸Ñ\98е Ñ\83Ñ\81пео Ð´Ð° Ñ\81меÑ\81Ñ\82и привремену датотеку.",
        "api-error-unknown-warning": "Непознато упозорење: „$1”.",
-       "api-error-unknownerror": "Ð\9dепознаÑ\82а Ð³Ñ\80еÑ\88ка: â\80\9e$1â\80\9c.",
+       "api-error-unknownerror": "Ð\9dепознаÑ\82а Ð³Ñ\80еÑ\88ка: â\80\9e$1â\80\9d.",
        "duration-seconds": "$1 {{PLURAL:$1|секунд|секунда|секунди}}",
-       "duration-minutes": "$1 {{PLURAL:$1|минут|минута|минута}}",
+       "duration-minutes": "$1 {{PLURAL:$1|минут|минута}}",
        "duration-hours": "$1 {{PLURAL:$1|сат|сата|сати}}",
-       "duration-days": "$1 {{PLURAL:$1|дан|дана|дана}}",
+       "duration-days": "$1 {{PLURAL:$1|дан|дана}}",
        "duration-weeks": "$1 {{PLURAL:$1|недеља|недеље|недеља}}",
        "duration-years": "$1 {{PLURAL:$1|година|године|година}}",
        "duration-decades": "$1 {{PLURAL:$1|деценија|деценије|деценија}}",
        "duration-centuries": "$1 {{PLURAL:$1|век|века|векова}}",
-       "duration-millennia": "$1 {{PLURAL:$1|миленијум|миленијума|миленијума}}",
-       "rotate-comment": "Слика је ротирана за $1° у смеру казаљке на сату",
+       "duration-millennia": "$1 {{PLURAL:$1|миленијум|миленијума}}",
+       "rotate-comment": "Слика је ротирана за $1 {{PLURAL:$1|степен|степена|степени}} у смеру казаљке на сату",
        "limitreport-title": "Подаци профилисања анализатора:",
-       "limitreport-cputime": "Време коришћења CPU",
+       "limitreport-cputime": "Време коришћења CPU",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|секунд|секунда|секунди}}",
        "limitreport-walltime": "Коришћење у реалном времену",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|секунд|секунда|секунди}}",
        "limitreport-ppvisitednodes": "Број предпроцесираних посећених нодова",
+       "limitreport-ppvisitednodes-value": "$1/$2",
        "limitreport-ppgeneratednodes": "Број предпроцесираних генерисаних нодова",
+       "limitreport-ppgeneratednodes-value": "$1/$2",
        "limitreport-postexpandincludesize": "Укључена величина након проширења",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|бајт|бајта|бајтова}}",
        "limitreport-templateargumentsize": "Величина аргумената шаблона",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|бајт|бајта|бајтова}}",
        "limitreport-expansiondepth": "Највећа дубина проширења",
+       "limitreport-expansiondepth-value": "$1/$2",
        "limitreport-expensivefunctioncount": "Број „скупих” функција анализатора",
+       "limitreport-expensivefunctioncount-value": "$1/$2",
        "limitreport-unstrip-depth": "Unstrip дубина рекурзије",
+       "limitreport-unstrip-depth-value": "$1/$2",
        "limitreport-unstrip-size": "Unstrip величина након проширења",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|бајт|бајта|бајтова}}",
        "expandtemplates": "Проширавање шаблона",
        "expand_templates_intro": "Ова посебна страница узима викитекст и мења све шаблоне у њему рекурзивно.\nТакође мења функције парсера као што је <code><nowiki>{{</nowiki>#language:…}}</code> и променљиве као што је <code><nowiki>{{</nowiki>CURRENTDAY}}</code>. \nЗаправо практично све што се налази између витичастих заграда.",
-       "expand_templates_title": "Назив контекста; за {{СТРАНИЦА}} итд.:",
+       "expand_templates_title": "Наслов контекста, за {{FULLPAGENAME}} итд.:",
        "expand_templates_input": "Унос викитекста:",
        "expand_templates_output": "Резултат",
        "expand_templates_xml_output": "XML излаз",
        "expand_templates_ok": "У реду",
        "expand_templates_remove_comments": "Уклони коментаре",
        "expand_templates_remove_nowiki": "Поништава ефекат <nowiki> тагова у приказу чланака",
-       "expand_templates_generate_xml": "Прикажи XML стабло",
+       "expand_templates_generate_xml": "Прикажи XML стабло за рашчлањивање",
        "expand_templates_generate_rawhtml": "Прикажи сиров HTML",
        "expand_templates_preview": "Претпреглед",
+       "expand_templates_input_missing": "Морате да обезбедите барем неки улазни викитекст.",
        "pagelanguage": "Промена језика странице",
        "pagelang-name": "Страница",
        "pagelang-language": "Језик",
        "pagelang-select-lang": "Изабери језик",
        "pagelang-reason": "Разлог",
        "pagelang-submit": "Пошаљи",
-       "pagelang-nonexistent-page": "Страница $1 не постоји.",
-       "pagelang-unchanged-language": "Страница $1  је већ постављена на језик $2.",
-       "pagelang-db-failed": "База података није успела променити језик странице.",
+       "pagelang-nonexistent-page": "Страница „$1” не постоји.",
+       "pagelang-unchanged-language": "Страница „$1” је већ постављена на језик $2.",
+       "pagelang-unchanged-language-default": "Страница $1 је већ подешена на подразумевани језик викија.",
+       "pagelang-db-failed": "База података није успела да промени језик странице.",
        "right-pagelang": "мењање језика странице",
        "action-pagelang": "промените језик странице",
-       "log-name-pagelang": "Ð\95виденÑ\86иÑ\98а промене језика",
-       "log-description-pagelang": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а промена у језицима страница.",
-       "logentry-pagelang-pagelang": "$1 је {{GENDER:$2|променио|променила}} језик странице $3 из $4 у $5.",
+       "log-name-pagelang": "Ð\94невник промене језика",
+       "log-description-pagelang": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº промена у језицима страница.",
+       "logentry-pagelang-pagelang": "$1 је {{GENDER:$2|променио|променила}} језик странице „$3” из $4 у $5.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (омогућена)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>онемогућена</strong>)",
        "mediastatistics": "Статистика медија",
        "mediastatistics-summary": "Статистике о типовима отпремљених датотека. Овде су урачунате само најскорије верзије датотека. Старе или избрисане верзије нису урачунате.",
+       "mediastatistics-nfiles": "$1 ($2%)",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 бајт|$1 бајта|$1 бајтова}} ($2; $3%)",
        "mediastatistics-bytespertype": "Укупна величина датотеке овог одељка: {{PLURAL:$1|$1 бајт|$1 бајта|$1 бајтова}} ($2; $3%).",
        "mediastatistics-allbytes": "Укупна величина свих датотека: {{PLURAL:$1|$1 бајт|$1 бајта|$1 бајтова}} ($2).",
        "mediastatistics-table-mimetype": "MIME тип",
        "mediastatistics-table-extensions": "Могући додаци",
        "mediastatistics-table-count": "Број датотека",
-       "mediastatistics-table-totalbytes": "УкÑ\83пна величина",
+       "mediastatistics-table-totalbytes": "Ð\9aомбинована величина",
        "mediastatistics-header-unknown": "Непознато",
        "mediastatistics-header-bitmap": "Битмап слике",
        "mediastatistics-header-drawing": "Цртежи (векторске слике)",
-       "mediastatistics-header-audio": "Ð\90Ñ\83дио",
-       "mediastatistics-header-video": "Ð\92идео",
+       "mediastatistics-header-audio": "Ð\97вÑ\83к",
+       "mediastatistics-header-video": "Ð\92идеи",
        "mediastatistics-header-multimedia": "Обогаћени медији",
        "mediastatistics-header-office": "Канцеларија",
        "mediastatistics-header-text": "Текстуалне",
        "mediastatistics-header-executable": "Извршне",
-       "mediastatistics-header-archive": "Компресоване",
+       "mediastatistics-header-archive": "Компресовани формати",
+       "mediastatistics-header-3d": "3D",
        "mediastatistics-header-total": "Све датотеке",
        "json-warn-trailing-comma": "$1 {{PLURAL:$1|пратећа тачка је уклоњена|пратеће тачке су уклоњене|пратећих тачки је уклоњено}} из JSON-a",
        "json-error-unknown": "Догодио се проблем с JSON-ом. Грешка: $1",
        "json-error-recursion": "Једна или више рекурзивних референци у вредности коју треба енкодирати.",
        "json-error-inf-or-nan": "Једна или више NAN или INF вредности у вредности коју треба енкодирати",
        "json-error-unsupported-type": "Дата је вредност типа која се не може енкодирати",
-       "headline-anchor-title": "Ð\9bинк до овог одељка",
+       "headline-anchor-title": "Ð\92еза до овог одељка",
        "special-characters-group-latin": "Латиница",
        "special-characters-group-latinextended": "Проширена латиница",
        "special-characters-group-ipa": "МФА",
        "special-characters-group-cyrillic": "Ћирилица",
        "special-characters-group-arabic": "Арапски",
        "special-characters-group-arabicextended": "Проширени арапски",
-       "special-characters-group-persian": "персијски",
+       "special-characters-group-persian": "Ð\9fерсијски",
        "special-characters-group-hebrew": "Хебрејски",
        "special-characters-group-bangla": "Бенгалски",
        "special-characters-group-tamil": "Тамилски",
        "special-characters-group-khmer": "Кмерски",
        "special-characters-group-canadianaboriginal": "Канадски абориџински",
        "special-characters-title-endash": "цртица",
-       "special-characters-title-emdash": "дÑ\83га Ñ\86Ñ\80Ñ\82иÑ\86а",
-       "special-characters-title-minus": "минус",
+       "special-characters-title-emdash": "дуга црта",
+       "special-characters-title-minus": "знак Ð·Ð° Ð¼Ð¸Ð½Ñ\83Ñ\81",
        "mw-widgets-dateinput-no-date": "Датум није изабран",
        "mw-widgets-dateinput-placeholder-day": "ГГГГ-ММ-ДД",
        "mw-widgets-dateinput-placeholder-month": "ГГГГ-ММ",
-       "mw-widgets-mediasearch-input-placeholder": "Ð\9fÑ\80еÑ\82Ñ\80ажиÑ\82е Ð´Ð°Ñ\82оÑ\82еке",
-       "mw-widgets-mediasearch-noresults": "Ð\9dема Ñ\80езÑ\83лÑ\82аÑ\82а.",
+       "mw-widgets-mediasearch-input-placeholder": "Ð\9fÑ\80еÑ\82Ñ\80ажиÑ\82е Ð¼ÐµÐ´Ð¸Ñ\98е",
+       "mw-widgets-mediasearch-noresults": "РезÑ\83лÑ\82аÑ\82и Ð½Ð¸Ñ\81Ñ\83 Ð¿Ñ\80онаÑ\92ени.",
        "mw-widgets-titleinput-description-new-page": "страница још увек не постоји",
        "mw-widgets-titleinput-description-redirect": "преусмерава на $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Додајте категорију…",
-       "mw-widgets-usersmultiselect-placeholder": "Додај још...",
+       "mw-widgets-usersmultiselect-placeholder": "Додајте још…",
        "date-range-from": "Од датума:",
        "date-range-to": "До датума:",
+       "sessionmanager-tie": "Не можете да комбинујете више типова потврде идентитета: $1.",
        "sessionprovider-generic": "$1 сесије",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "сесије са колачићима",
-       "sessionprovider-nocookies": "Колачићи су можда онемогућени. Уверите се да су колачићи омогућени и почните поново.",
+       "sessionprovider-nocookies": "Колачићи су можда онемогућени. Уверите се да имате колачиће омогућене и почните поново.",
        "randomrootpage": "Случајна коренска страница",
        "log-action-filter-block": "Тип блокирања:",
        "log-action-filter-contentmodel": "Тип промене модела садржаја:",
        "log-action-filter-import": "Тип увоза:",
        "log-action-filter-managetags": "Тип радње управљања ознакама:",
        "log-action-filter-move": "Тип премештања:",
-       "log-action-filter-newusers": "Тип Ð½Ð¾Ð²Ð¾Ð³ налога:",
+       "log-action-filter-newusers": "Тип Ð¾Ñ\82ваÑ\80аÑ\9aа налога:",
        "log-action-filter-patrol": "Тип патролирања:",
        "log-action-filter-protect": "Тип заштите:",
        "log-action-filter-rights": "Тип промене корисничких права:",
        "log-action-filter-block-reblock": "измена блокирања",
        "log-action-filter-block-unblock": "деблокирање",
        "log-action-filter-contentmodel-change": "Промена модела садржаја",
-       "log-action-filter-contentmodel-new": "Ð\9dова Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81 нестандардним моделом садржаја",
+       "log-action-filter-contentmodel-new": "Ð\9fÑ\80авÑ\99еÑ\9aе Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\81а нестандардним моделом садржаја",
        "log-action-filter-delete-delete": "брисање странице",
        "log-action-filter-delete-delete_redir": "преснимавање преусмерења",
        "log-action-filter-delete-restore": "враћање странице",
-       "log-action-filter-delete-event": "бÑ\80иÑ\81аÑ\9aе ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98е",
-       "log-action-filter-delete-revision": "брисање ревизија",
+       "log-action-filter-delete-event": "бÑ\80иÑ\81аÑ\9aе Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ°",
+       "log-action-filter-delete-revision": "брисање измена",
        "log-action-filter-import-interwiki": "Међувики увоз",
        "log-action-filter-import-upload": "Увоз постављањем XML-а",
-       "log-action-filter-managetags-create": "нова Ð¾Ð·Ð½Ð°ÐºÐ°",
+       "log-action-filter-managetags-create": "пÑ\80авÑ\99еÑ\9aе Ð¾Ð·Ð½Ð°ÐºÐµ",
        "log-action-filter-managetags-delete": "брисање ознаке",
        "log-action-filter-managetags-activate": "активирање ознаке",
        "log-action-filter-managetags-deactivate": "деактивирање ознаке",
        "log-action-filter-protect-move_prot": "премештање заштите",
        "log-action-filter-rights-rights": "ручно",
        "log-action-filter-rights-autopromote": "аутоматски",
-       "log-action-filter-suppress-event": "Скривање уноса у евиденцији",
-       "log-action-filter-suppress-revision": "скривање ревизија",
+       "log-action-filter-suppress-event": "сакривање дневника",
+       "log-action-filter-suppress-revision": "скривање измена",
        "log-action-filter-suppress-delete": "Скривање странице",
        "log-action-filter-suppress-block": "Скривање корисника блокирањем",
        "log-action-filter-suppress-reblock": "Скривање корисника поновним блокирањем",
        "authmanager-authn-no-local-user-link": "Пружени су важећи акредитиви, али нису повезани ни с једним корисником на овом викију. Пријавите се на неки други начин или направите нови кориснички налог, што ће вам дати могућност да повежете претходне акредитиве на нови налог.",
        "authmanager-authn-autocreate-failed": "Не могу да аутоматски направим локални налог: $1",
        "authmanager-change-not-supported": "Не могу да променим пружене акредитиве јер их ништа не би користило.",
-       "authmanager-create-disabled": "Онемогућено прављење налога.",
+       "authmanager-create-disabled": "Отварање налога је онемогућено.",
        "authmanager-create-from-login": "Попуните поља да бисте направили налог.",
-       "authmanager-create-not-in-progress": "Ð\9fÑ\80авÑ\99еÑ\9aе Ð½Ð°Ð»Ð¾Ð³Ð° Ð½Ð¸Ñ\98е Ñ\83 Ñ\82окÑ\83 Ð¸Ð»Ð¸ Ñ\81Ñ\83 Ð¿Ð¾Ð´Ð°Ñ\86и Ð¾ Ñ\81еÑ\81иÑ\98и Ð¸Ð·Ð³Ñ\83бÑ\99ени. Ð\9fоÑ\87ниÑ\82е испочетка.",
-       "authmanager-create-no-primary": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð¸Ñ\81коÑ\80иÑ\81Ñ\82им Ð¿Ñ\80Ñ\83жене Ð°ÐºÑ\80едиÑ\82иве Ð·Ð° Ð¿Ñ\80авÑ\99ење налога.",
+       "authmanager-create-not-in-progress": "Ð\9eÑ\82ваÑ\80аÑ\9aе Ð½Ð°Ð»Ð¾Ð³Ð° Ð½Ð¸Ñ\98е Ñ\83 Ñ\82окÑ\83 Ð¸Ð»Ð¸ Ñ\81Ñ\83 Ð¿Ð¾Ð´Ð°Ñ\86и Ð¾ Ñ\81еÑ\81иÑ\98и Ð¸Ð·Ð³Ñ\83бÑ\99ени. Ð\9fоÑ\87ниÑ\82е Ð¿Ð¾Ð½Ð¾Ð²Ð¾ испочетка.",
+       "authmanager-create-no-primary": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð¸Ñ\81коÑ\80иÑ\81Ñ\82им Ð¿Ñ\80Ñ\83жене Ð°ÐºÑ\80едиÑ\82иве Ð·Ð° Ð¾Ñ\82ваÑ\80ање налога.",
        "authmanager-link-no-primary": "Не могу да искористим пружене акредитиве за спајање налога.",
        "authmanager-link-not-in-progress": "Спајање налога није у току или је дошло до губитка података о сесији. Почните испочетка.",
        "authmanager-authplugin-setpass-failed-title": "Неуспешна промена лозинке",
        "authmanager-authplugin-setpass-failed-message": "Додатак за потврду идентитета је одбио промену лозинке.",
-       "authmanager-authplugin-create-fail": "Ð\94одаÑ\82ак Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð¸Ð´ÐµÐ½Ñ\82иÑ\82еÑ\82а Ñ\98е Ð¾Ð´Ð±Ð¸Ð¾ Ð¿Ñ\80авÑ\99ење налога.",
+       "authmanager-authplugin-create-fail": "Ð\94одаÑ\82ак Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð¸Ð´ÐµÐ½Ñ\82иÑ\82еÑ\82а Ñ\98е Ð¾Ð´Ð±Ð¸Ð¾ Ð¾Ñ\82ваÑ\80ање налога.",
        "authmanager-authplugin-setpass-denied": "Додатак за потврду идентитета не дозвољава мењање лозику.",
        "authmanager-authplugin-setpass-bad-domain": "Неважећи домен.",
-       "authmanager-autocreate-noperm": "Аутоматско прављење налога није дозвољено.",
+       "authmanager-autocreate-noperm": "Аутоматско отварање налога није дозвољено.",
+       "authmanager-autocreate-exception": "Аутоматско креирање налога је привремено онемогућено због претходних грешака.",
        "authmanager-userdoesnotexist": "Кориснички налог „$1“ није отворен.",
        "authmanager-username-help": "Корисничко име за потврду идентитета.",
        "authmanager-password-help": "Лозинка за потврду идентитета.",
        "authmanager-domain-help": "Домен за спољашњу потврду идентитета.",
        "authmanager-retype-help": "Поновите лозинку да би сте потврдили.",
        "authmanager-email-label": "Имејл",
-       "authmanager-email-help": "Имејл адреса",
+       "authmanager-email-help": "Имејл-адреса",
        "authmanager-realname-label": "Право име",
        "authmanager-realname-help": "Право име корисника",
        "authmanager-provider-password": "Потврда идентитета лозинком",
        "authprovider-confirmlink-option": "$1 ($2)",
        "authprovider-confirmlink-request-label": "Рачуни који се требају повезати",
        "authprovider-confirmlink-success-line": "$1: Успешно повезано.",
+       "authprovider-confirmlink-failed-line": "$1: $2",
        "authprovider-confirmlink-failed": "Не могу да повежем налог у потпуности: $1",
        "authprovider-confirmlink-ok-help": "Наставите након приказивања порука за неуспело повезивање.",
        "authprovider-resetpass-skip-label": "Прескочи",
        "authpage-cannot-login": "Не могу да започнем пријаву.",
        "authpage-cannot-login-continue": "Не могу да наставим са пријавом. Ваша сесија је највероватније истекла.",
        "authpage-cannot-create": "Не могу да започнем отварање налога.",
+       "authpage-cannot-create-continue": "Не могу да наставим креирање налога. Ваша сесија је највероватније истекла.",
        "authpage-cannot-link": "Не могу да започнем повезивање налога.",
+       "authpage-cannot-link-continue": "Не могу наставити повезивање налога. Ваша сесија је највероватније истекла.",
        "cannotauth-not-allowed-title": "Приступ је одбијен",
        "cannotauth-not-allowed": "Није вам дозвољено да користите ову страницу",
        "changecredentials": "Промена акредитива",
        "linkaccounts-submit": "Повежи налоге",
        "unlinkaccounts": "Раздвајање налога",
        "unlinkaccounts-success": "Налог је обједињен.",
+       "authenticationdatachange-ignored": "Промена података аутенификације није обрађена. Можда ниједан провајдер није конфигурисан?",
        "userjsispublic": "Напомена: JavaScript подстранице не би требале садржавати поверљиве информације будући да су видљиве другим корисницима.",
+       "userjsonispublic": "Напомена: JSON подстранице не би требале садржавати поверљиве информације будући да су видљиве другим корисницима.",
        "usercssispublic": "Напомена: CSS подстранице не би требале садржавати поверљиве информације будући да су видљиве другим корисницима.",
        "restrictionsfield-badip": "Неважећа IP адреса или опсег: $1",
        "restrictionsfield-label": "Дозвољени IP опсези:",
        "edit-error-short": "Грешка: $1",
        "edit-error-long": "Грешке:\n\n$1",
-       "revid": "ревизија $1",
+       "revid": "измена $1",
        "pageid": "ID странице: $1",
        "rawhtml-notallowed": "&lt;html&gt; тагови не могу да се користе ван нормалних страница.",
        "gotointerwiki": "Напуштање пројекта {{SITENAME}}",
        "pagedata-title": "Подаци странице",
        "pagedata-not-acceptable": "Није пронађен одговарајући облик. Подржане MIME-врсте: $1",
        "pagedata-bad-title": "Невалидан наслов: $1.",
+       "unregistered-user-config": "Из безбедоносних разлога JavaScript, CSS и JSON корисничке подстранице не могу бити учитане за нерегистроване кориснике.",
        "passwordpolicies": "Правила за лозинке",
+       "passwordpolicies-summary": "Ово је листа ефикасних смерница за лозинке за корисничке групе дефинисане на овом викију.",
        "passwordpolicies-group": "Група",
        "passwordpolicies-policies": "Правила",
+       "passwordpolicies-policy-display": "<span class=\"passwordpolicies-policy\">$1 <code>($2)</code></span>",
        "passwordpolicies-policy-minimalpasswordlength": "Лозинка мора да има најмање {{PLURAL:$1|један знак|$1 знака|$1 знакова}}",
+       "passwordpolicies-policy-minimumpasswordlengthtologin": "Лозинка мора садржати најмање $1 {{PLURAL:$1|карактер|карактера}} да би сте могли да се пријавите.",
        "passwordpolicies-policy-passwordcannotmatchusername": "Лозинка не може да буде иста као корисничко име",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "Лозинка се не може подударати са лозинкама на црној листи",
        "passwordpolicies-policy-maximalpasswordlength": "Лозинка мора да буде краћа од $1 {{PLURAL:$1|знака|знакова}}",
index c4b1e48..51f5c3c 100644 (file)
                        "Vlad5250"
                ]
        },
-       "tog-underline": "Podvlačenje veza:",
+       "tog-underline": "Podvlačenje linkova:",
        "tog-hideminor": "Sakrij manje izmene sa spiska skorašnjih izmena",
        "tog-hidepatrolled": "Sakrij patrolirane izmene sa spiska skorašnjih izmena",
        "tog-newpageshidepatrolled": "Sakrij patrolirane stranice sa spiska novih stranica",
        "tog-hidecategorization": "Sakrij kategorizaciju stranica",
-       "tog-extendwatchlist": "Proširi spisak nadgledanja za prikaz svih izmena, ne samo skorašnjih",
+       "tog-extendwatchlist": "Proširi spisak nadgledanja za pogled svih promena, ne samo skorašnjih",
        "tog-usenewrc": "Grupiši izmene po stranici u skorašnjim izmenama i spisku nadgledanja",
-       "tog-numberheadings": "Automatski numeriši podnaslove",
-       "tog-showtoolbar": "Traka sa alatkama za uređivanje",
+       "tog-numberheadings": "Automatski numeriši naslove",
+       "tog-showtoolbar": "Prikaži traku sa alatkama za uređivanje",
        "tog-editondblclick": "Uredi stranice dvostrukim klikom",
-       "tog-editsectiononrightclick": "Uređivanje odeljaka desnim klikom na njihove naslove",
-       "tog-watchcreations": "Dodaj stranice koje napravim i datoteke koje otpremim u moj spisak nadgledanja",
-       "tog-watchdefault": "Dodaj stranice i datoteke koje izmenim u moj spisak nadgledanja",
-       "tog-watchmoves": "Dodaj stranice i datoteke koje premestim u moj spisak nadgledanja",
-       "tog-watchdeletion": "Dodaj stranice i datoteke koje obrišem u moj spisak nadgledanja",
-       "tog-watchuploads": "Dodaj datoteke koje otpremim u moj spisak nadgledanja",
-       "tog-watchrollback": "Dodaj stranice na kojima sam vratio izmene u moj spisak nadgledanja",
+       "tog-editsectiononrightclick": "Omogući uređivanje odeljaka desnim klikom na njihove naslove",
+       "tog-watchcreations": "Dodaj stranice koje napravim i datoteke koje otpremim na moj spisak nadgledanja",
+       "tog-watchdefault": "Dodaj stranice i datoteke koje uredim na moj spisak nadgledanja",
+       "tog-watchmoves": "Dodaj stranice i datoteke koje premestim na moj spisak nadgledanja",
+       "tog-watchdeletion": "Dodaj stranice i datoteke koje izbrišem na moj spisak nadgledanja",
+       "tog-watchuploads": "Dodaj datoteke koje otpremim na moj spisak nadgledanja",
+       "tog-watchrollback": "Dodaj stranice na kojima sam izvršio vraćanje izmena na moj spisak nadgledanja",
        "tog-minordefault": "Označavaj sve izmene kao manje",
        "tog-previewontop": "Prikaži pretpregled pre okvira za uređivanje",
        "tog-previewonfirst": "Prikaži pretpregled pri prvoj izmeni",
        "tog-enotifwatchlistpages": "Pošalji mi imejl kada se promeni stranica ili datoteka sa mog spiska nadgledanja",
-       "tog-enotifusertalkpages": "Pošalji mi imejl kad se promeni moja stranica za razgovor",
+       "tog-enotifusertalkpages": "Pošalji mi imejl kad se promeni moja korisnička stranica za razgovor",
        "tog-enotifminoredits": "Pošalji mi imejl i kod manjih izmena stranica i datoteka",
-       "tog-enotifrevealaddr": "Otkrij moju imejl adresu u porukama obaveštenja",
+       "tog-enotifrevealaddr": "Otkrij moju imejl-adresu u porukama obaveštenja",
        "tog-shownumberswatching": "Prikaži broj korisnika koji nadgledaju",
        "tog-oldsig": "Vaš postojeći potpis:",
-       "tog-fancysig": "Smatraj potpis kao vikitekst (bez samopovezivanja)",
+       "tog-fancysig": "Smatraj potpis kao vikitekst (bez automatskog linka)",
        "tog-uselivepreview": "Prikaži pretpregled bez ponovnog učitavanja stranice",
        "tog-forceeditsummary": "Upozori me kada ne unesem opis izmene",
        "tog-watchlisthideown": "Sakrij moje izmene sa spiska nadgledanja",
        "tog-watchlisthidebots": "Sakrij izmene botova sa spiska nadgledanja",
        "tog-watchlisthideminor": "Sakrij manje izmene sa spiska nadgledanja",
        "tog-watchlisthideliu": "Sakrij izmene prijavljenih korisnika sa spiska nadgledanja",
-       "tog-watchlistreloadautomatically": "Automatski osveži spisak nadgledanja kad god se filter izmeni (potreban JavaScript)",
-       "tog-watchlistunwatchlinks": "Dodaj veze za direktno dodavanje/uklanjanje stavki sa spiska nadgledanja (potreban JavaScript)",
+       "tog-watchlistreloadautomatically": "Automatski osveži spisak nadgledanja kad god se filter promeni (potreban JavaScript)",
+       "tog-watchlistunwatchlinks": "Dodaj označivače za prekid nadgledanja/nagledanje ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) na nadgledane stranice sa promenama (Javaskript je neophodan za funkcionalnost prebacivanja)",
        "tog-watchlisthideanons": "Sakrij izmene anonimnih korisnika sa spiska nadgledanja",
        "tog-watchlisthidepatrolled": "Sakrij patrolirane izmene sa spiska nadgledanja",
        "tog-watchlisthidecategorization": "Sakrij kategorizaciju stranica",
        "tog-ccmeonemails": "Pošalji mi kopije imejlova koje pošaljem drugim korisnicima",
        "tog-diffonly": "Ne prikazuj sadržaj stranice ispod razlika",
-       "tog-showhiddencats": "Skrivene kategorije",
+       "tog-showhiddencats": "Prikaži skrivene kategorije",
        "tog-norollbackdiff": "Ne prikazuj razliku nakon izvršenog vraćanja",
-       "tog-useeditwarning": "Upozori me kada napuštam stranicu sa nesačuvanim izmenama",
-       "tog-prefershttps": "Uvek koristi sigurnu vezu dok sam prijavljen.",
+       "tog-useeditwarning": "Upozori me kada napuštam stranicu za uređivanje sa nesačuvanim promenama",
+       "tog-prefershttps": "Uvek koristi sigurnu vezu dok sam prijavljen/na.",
        "underline-always": "uvek",
        "underline-never": "nikad",
        "underline-default": "prema temi ili pregledaču",
        "listingcontinuesabbrev": "nast.",
        "index-category": "Popisane stranice",
        "noindex-category": "Nepopisane stranice",
-       "broken-file-category": "Stranice s neispravnim vezama do datoteka",
+       "broken-file-category": "Stranice sa neispravnim linkovima do datoteka",
        "categoryviewer-pagedlinks": "$1 ($2)",
        "category-header-numerals": "$1–$2",
        "about": "O nama",
        "actions": "Radnje",
        "namespaces": "Imenski prostori",
        "variants": "Varijante",
-       "navigation-heading": "Navigacioni meni",
+       "navigation-heading": "Meni za navigaciju",
        "errorpagetitle": "Greška",
        "returnto": "Nazad na stranicu „$1“.",
        "tagline": "Izvor: {{SITENAME}}",
        "help": "Pomoć",
        "search": "Pretraga",
-       "search-ignored-headings": " #<!-- ne menjajte ništa u ovom redu --> <pre>\n# Naslovi koji će biti zanemareni pri pretrazi.\n# Izmene su vidljive odmah nakon što se stranica sa naslovom popiše.\n# Možete iznuditi ponovno popisivanje „nultom” izmenom.\n# Sintaksa je sledeća:\n#  * Svaki red koji započinje znakom „#” je komentar.\n#  * Svaki ne prazni red je tačan naslov koji će biti zanemaren, s tim da se razlikuju mala i velika slova i sve ostalo\nReference\nSpoljašnje veze\nTakođe pogledajte\n #</pre> <!-- ne menjajte ništa u ovom redu -->",
+       "search-ignored-headings": " #<!-- ne menjajte ništa u ovom redu --> <pre>\n# Naslovi koji će biti zanemareni pri pretrazi.\n# Promene su vidljive odmah nakon što se stranica sa naslovom popiše.\n# Možete iznuditi ponovno popisivanje „nultom” izmenom.\n# Sintaksa je sledeća:\n#  * Svaki red koji započinje znakom „#” je komentar.\n#  * Svaki ne prazni red je tačan naslov koji će biti zanemaren, s tim da se razlikuju mala i velika slova i sve ostalo\nReference\nSpoljašnji linkovi\nTakođe pogledajte\n #</pre> <!-- ne menjajte ništa u ovom redu -->",
        "searchbutton": "Pretraži",
        "go": "Idi",
        "searcharticle": "Idi",
        "history_small": "istorija",
        "updatedmarker": "ažurirano od moje poslednje posete",
        "printableversion": "Za štampanje",
-       "permalink": "Trajna veza",
+       "permalink": "Trajni link",
        "print": "Štampaj",
        "view": "Pogledaj",
        "view-foreign": "Pogledaj na projektu $1",
        "edit-local": "Uredi lokalni opis",
        "create": "Napravi",
        "create-local": "Dodaj lokalni opis",
-       "delete": "Obriši",
-       "undelete_short": "Vrati {{PLURAL:$1|obrisanu izmenu|$1 obrisane izmene|$1 obrisanih izmena}}",
-       "viewdeleted_short": "Pogledaj {{PLURAL:$1|obrisanu izmenu|$1 obrisane izmene|$1 obrisanih izmena}}",
+       "delete": "Izbriši",
+       "undelete_short": "Vrati {{PLURAL:$1|izbrisanu izmenu|$1 izbrisane izmene|$1 izbrisanih izmena}}",
+       "viewdeleted_short": "Pogledaj {{PLURAL:$1|jednu izbrisanu izmenu|$1 izbrisane izmene|$1 izbrisanih izmena}}",
        "protect": "Zaštiti",
        "protect_change": "promeni",
        "unprotect": "Promeni zaštitu",
        "talk": "Razgovor",
        "views": "Pregledi",
        "toolbox": "Alatke",
-       "tool-link-userrights": "Uredi {{GENDER:$1|korisničke}} grupe",
-       "tool-link-userrights-readonly": "{{GENDER:$1|Korisničke}} grupe",
-       "tool-link-emailuser": "Pošalji imejl {{GENDER:$1|korisniku|korisnici}}",
+       "tool-link-userrights": "Promeni {{GENDER:$1|korisničke}} grupe",
+       "tool-link-userrights-readonly": "Prikaz {{GENDER:$1|korisničkih}} grupa",
+       "tool-link-emailuser": "Slanje imejla {{GENDER:$1|korisniku|korisnici}}",
        "imagepage": "Pogledaj stranicu datoteke",
        "mediawikipage": "Pogledaj stranicu poruke",
        "templatepage": "Pogledaj stranicu šablona",
        "jumptonavigation": "navigaciju",
        "jumptosearch": "pretragu",
        "view-pool-error": "Nažalost, serveri su trenutno preopterećeni.\nPreviše korisnika pokušava da pregleda ovu stranicu.\nSačekajte neko vreme pre nego što ponovo pokušate da joj pristupite.\n\n$1",
-       "generic-pool-error": "Nažalost, serveri su trenutno preopterećeni.\nPreviše korisnika pokušava da vidi ovaj resurs.\nSačekajte neko vreme pre nego što ponovo pokušate da mu pristupite.",
+       "generic-pool-error": "Nažalost, serveri su trenutno preopterećeni.\nPreviše korisnika pokušava da pogleda ovaj resurs.\nSačekajte neko vreme pre nego što ponovo pokušate da mu pristupite.",
        "pool-timeout": "Istek vremena čeka na zaključavanje",
        "pool-queuefull": "Red je pun zahteva",
        "pool-errorunknown": "Nepoznata greška",
        "portal-url": "Project:Portal zajednice",
        "privacy": "Politika privatnosti",
        "privacypage": "Project:Politika privatnosti",
-       "badaccess": "Greške u ovlašćenjima",
-       "badaccess-group0": "Nije Vam dozvoljeno da izvršite zahtevanu radnju.",
+       "badaccess": "Greška u dozvolama",
+       "badaccess-group0": "Nije vam dozvoljeno da izvršite radnju koju ste zahtevali.",
        "badaccess-groups": "Radnja koju ste zahtevali je ograničena samo korisnicima u {{PLURAL:$2|sledećoj grupi|sledećim grupama}}: $1.",
        "versionrequired": "Potrebna je verzija $1 Medijavikija",
-       "versionrequiredtext": "Potrebno je izdanje $1 Medijavikija da biste koristili ovu stranicu.\nPogledajte stranicu za [[Special:Version|izdanje]].",
+       "versionrequiredtext": "Potrebna je verzija $1 Medijavikija da biste koristili ovu stranicu.\nPogledajte stranicu [[Special:Version|verzije]].",
        "ok": "U redu",
        "pagetitle": "$1 — {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "youhavenewmessages": "{{PLURAL:$3|Imate}} $1 ($2).",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|Imate}} $1 od {{PLURAL:$3|drugog korisnika|$3 korisnika}} ($2).",
        "youhavenewmessagesmanyusers": "Imate $1 od mnogo korisnika ($2).",
-       "newmessageslinkplural": "{{PLURAL:$1|novu poruku|nove poruke|novih poruka}}",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|poslednja izmena|poslednje izmene|poslednjih izmena}}",
+       "newmessageslinkplural": "{{PLURAL:$1|novu poruku|nove poruke|999=novih poruka}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|poslednja promena|999=poslednje promene}}",
        "youhavenewmessagesmulti": "Imate nove poruke na $1",
        "editsection": "uredi",
        "editold": "uredi",
-       "viewsourceold": "izvorni kod",
+       "viewsourceold": "izvornik",
        "editlink": "uredi",
-       "viewsourcelink": "izvorni kod",
+       "viewsourcelink": "izvornik",
        "editsectionhint": "Uredite odeljak „$1“",
        "toc": "Sadržaj",
        "showtoc": "prikaži",
        "confirmable-no": "Ne",
        "thisisdeleted": "Pogledaj ili vrati $1?",
        "viewdeleted": "Pogledaj $1?",
-       "restorelink": "{{PLURAL:$1|obrisanu izmenu|$1 obrisane izmene|$1 obrisanih izmena}}",
-       "feedlinks": "Dovod:",
-       "feed-invalid": "Neispravna vrsta dovoda.",
-       "feed-unavailable": "Dovodi nisu dostupni",
-       "site-rss-feed": "$1 RSS dovod",
-       "site-atom-feed": "$1 Atom dovod",
-       "page-rss-feed": "„$1“ RSS dovod",
-       "page-atom-feed": "„$1“ Atom dovod",
+       "restorelink": "{{PLURAL:$1|jednu izbrisanu izmenu|$1 izbrisane izmene|$1 izbrisanih izmena}}",
+       "feedlinks": "Fid:",
+       "feed-invalid": "Nevažeći tip prijave na fid.",
+       "feed-unavailable": "Fidovi sindikacije nisu dostupni",
+       "site-rss-feed": "$1 – RSS fid",
+       "site-atom-feed": "$1 – Atom fid",
+       "page-rss-feed": "„$1“ – RSS fid",
+       "page-atom-feed": "„$1“ – Atom fid",
        "feed-atom": "Atom",
        "feed-rss": "RSS",
        "red-link-title": "$1 (stranica ne postoji)",
        "sort-descending": "Poređaj opadajuće",
        "sort-ascending": "Poređaj rastuće",
        "nstab-main": "Stranica",
-       "nstab-user": "{{GENDER:{{BASEPAGENAME}}|Korisnik|Korisnica|Korisnik}}",
+       "nstab-user": "{{GENDER:{{BASEPAGENAME}}|Korisnik|Korisnica}}",
        "nstab-media": "Mediji",
        "nstab-special": "Posebno",
        "nstab-project": "Projekat",
        "nstab-category": "Kategorija",
        "mainpage-nstab": "Glavna strana",
        "nosuchaction": "Nema takve radnje",
-       "nosuchactiontext": "Radnja navedena u adresi nije ispravna.\nMožda ste pogrešno napisali adresu ili ste pratili zastarelu vezu.\nMoguće je i da se radi o grešci u softveru vikija.",
+       "nosuchactiontext": "Radnja koja je navedena u URL-u nije važeća.\nMožda ste otkucali pogrešan URL-a ili ste pratili pokvaren link.\nOvo takođe može da ukazuje na grešku u softveru koji koristi {{SITENAME}}.",
        "nosuchspecialpage": "Nema takve posebne stranice",
-       "nospecialpagetext": "<strong>Posebna stranica koju ste zahtevali ne postoji.</strong>\n\nSpisak svih posebnih stranica nalazi se na „[[Special:SpecialPages|{{int:specialpages}}]]”.",
+       "nospecialpagetext": "<strong>Zahtevali ste nevalidnu posebnu stranicu.</strong>\n\nSpisak validnih posebnih stranica može da se pronađe na „[[Special:SpecialPages|{{int:specialpages}}]]”.",
        "error": "Greška",
        "databaseerror": "Greška u bazi podataka",
-       "databaseerror-text": "Došlo je do greške u upitu baze podataka. Možda je u pitanju programska greška.",
+       "databaseerror-text": "Došlo je do greške u upitu baze podataka. \nOvo može da ukazuje na grešku u softveru.",
        "databaseerror-textcl": "Došlo je do greške u upitu baze podataka.",
        "databaseerror-query": "Upit: $1",
        "databaseerror-function": "Funkcija: $1",
        "databaseerror-error": "Greška: $1",
        "transaction-duration-limit-exceeded": "Zbog izbegavanja velikih kopirajućih zaostajanja, ova transakcija je prekinuta zbog toga što je trajanje zapisivanja ($1) premašilo ($2) sekundi ograničenja. \nUkoliko menjate puno artikala odjednom, pokušajte sa više manjih operacija.",
-       "laggedslavemode": "<strong>Upozorenje:</strong> moguće je da stranica nije ažurirana.",
+       "laggedslavemode": "<strong>Upozorenje:</strong> stranica možda ne sadrži nedavna ažuriranja.",
        "readonly": "Baza podataka je zaključana",
        "enterlockreason": "Unesite razlog za zaključavanje, uključujući i vreme otključavanja",
        "readonlytext": "Baza podataka je trenutno zaključana, što znači da je nije moguće menjati.\n\nSistemski administrator je naveo sledeće objašnjenje: $1",
-       "missing-article": "Tekst stranice pod nazivom „$1“ ($2) nije pronađen.\n\nUzrok ove greške je obično zastarela izmena ili veza do obrisane stranice.\n\nAko se ne radi o tome, onda ste verovatno pronašli grešku u softveru.\nPrijavite je [[Special:ListUsers/sysop|administratoru]] uz odgovarajuću vezu.",
+       "missing-article": "Tekst stranice pod nazivom „$1“ ($2) nije pronađen.\n\nUzrok ove greške je obično zastarela izmena ili link do izbrisane stranice.\n\nAko se ne radi o tome, onda ste verovatno pronašli grešku u softveru.\nPrijavite je [[Special:ListUsers/sysop|administratoru]] uz odgovarajući link.",
        "missingarticle-rev": "(izmena#: $1)",
        "missingarticle-diff": "(razlika: $1, $2)",
        "readonly_lag": "Baza podataka je automatski zaključana da bi se sekundarni serveri baze podataka uskladili s glavnim.",
        "internalerror": "Unutrašnja greška",
-       "internalerror_info": "Interna greška: $1",
-       "internalerror-fatal-exception": "Fatalna greška tipa „$1“",
+       "internalerror_info": "Unutrašnja greška: $1",
+       "internalerror-fatal-exception": "Greška neobrađenog izuzetka tipa „$1“",
        "filecopyerror": "Ne mogu da kopiram datoteku „$1“ u „$2“.",
        "filerenameerror": "Ne mogu da preimenujem datoteku „$1“ u „$2“.",
-       "filedeleteerror": "Ne mogu da obrišem datoteku „$1“.",
+       "filedeleteerror": "Ne mogu da izbrišem datoteku „$1“.",
        "directorycreateerror": "Ne mogu da napravim direktorijum „$1“.",
        "directoryreadonlyerror": "Direktorijum „$1“ je samo za čitanje.",
        "directorynotreadableerror": "Direktorijum „$1“ nije čitljiv.",
        "unexpected": "Neočekivana vrednost: „$1“=„$2“.",
        "formerror": "Greška: ne mogu da pošaljem obrazac.",
        "badarticleerror": "Ova radnja se ne može izvršiti na ovoj stranici.",
-       "cannotdelete": "Ne mogu da obrišem stranicu ili datoteku „$1“.\nVerovatno ju je neko drugi obrisao.",
-       "cannotdelete-title": "Ne mogu da obrišem stranicu „$1“",
+       "cannotdelete": "Ne mogu da izbrišem stranicu ili datoteku „$1“.\nMoguće je da ju je neko već izbrisao.",
+       "cannotdelete-title": "Ne mogu da izbrišem stranicu „$1“",
        "delete-hook-aborted": "Brisanje je prekinula kuka.\nNije dato nikakvo obrazloženje.",
-       "no-null-revision": "Ne mogu da napravim novu praznu verziju za stranicu „$1“",
+       "no-null-revision": "Ne mogu da napravim novu ništavnu izmenu stranice „$1“",
        "badtitle": "Loš naslov",
-       "badtitletext": "Naslov stranice je neispravan, prazan ili je međujezički ili međuviki naslov pogrešno povezan.\nMožda sadrži znakove koji se ne mogu koristiti u naslovima.",
+       "badtitletext": "Traženi naslov stranice je nevažeći, prazan ili je pogrešno povezan međujezički ili međuviki naslov.\nMožda sadrži jedan ili više znakova koji se ne mogu koristiti u naslovima.",
        "title-invalid-empty": "Traženo ime stranice je prazno ili sadrži samo naziv imenskog prostora.",
        "title-invalid-utf8": "Traženi naziv stranice sadrži nevažeći UTF-8 znak.",
-       "title-invalid-interwiki": "Traženi naslov stranice sadrži unutrašnju viki vezu koja ne može biti korištena u naslovima.",
+       "title-invalid-interwiki": "Traženi naslov stranice sadrži unutrašnji viki link koji ne može da se koristi u naslovima.",
        "title-invalid-talk-namespace": "Traženi naslov stranice se odnosi na stranicu za razgovor koja ne može postojati.",
        "title-invalid-characters": "Traženi naslov ima nevažeće znakove: „$1“.",
        "title-invalid-relative": "Naslov ima relativnu putanju. Relativni naslovi stranica (./, ../) nisu važeći jer će često biti nedostupni u korisničkom pregledaču.",
        "title-invalid-magic-tilde": "Traženi naslov stranice sadrži nevažeći sled magičnog znaka tilda (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "Traženi naziv stranice je predugačak. Ne sme biti duži od $1 {{PLURAL:$1|bajta|bajtova}} u UTF-8 kodiranju.",
-       "title-invalid-leading-colon": "Zahtevani naslov stranice sadrži nevažeću dvotačku na početku.",
+       "title-invalid-leading-colon": "Traženi naslov stranice sadrži nevažeću dvotačku na početku.",
        "perfcached": "Sledeći podaci su keširani i možda nisu ažurirani. U kešu {{PLURAL:$1|je dostupan najviše jedan rezultat|su dostupna najviše $1 rezultata|je dostupno najviše $1 rezultata}}.",
        "perfcachedts": "Sledeći podaci su keširani i poslednji put ažurirani na datum $2 u $3 č. U kešu {{PLURAL:$4|je dostupan najviše jedan rezultat|su dostupna najviše $4 rezultata|je dostupno najviše $4 rezultata}}.",
        "querypage-no-updates": "Ažuriranje ove stranice je trenutno onemogućeno.\nPodaci koji se ovde nalaze mogu biti zastareli.",
-       "viewsource": "Izvorni kod",
-       "viewsource-title": "Izvorni kod za stranicu $1",
+       "viewsource": "Izvornik",
+       "viewsource-title": "Izvornik stranice $1",
        "actionthrottled": "Radnja je usporena",
        "actionthrottledtext": "U cilju borbe protiv nepoželjnih poruka, ograničene su vam izmene u određenom vremenu, a upravo ste prešli to ograničenje. Pokušajte ponovo za nekoliko minuta.",
        "protectedpagetext": "Ova stranica je zaključana za izmene i druge radnje.",
        "viewsourcetext": "Možete da čitate i kopirate izvornik ove stranice.",
-       "viewyourtext": "Možete da pogledate i kopirate izvorni kod <strong>Vaših izmena</strong> na ovoj stranici.",
-       "protectedinterface": "Ova stranica sadrži tekst interfejsa za softver na ovom vikiju i zaštićena je radi sprečavanja zloupotrebe.\nDa biste dodali ili izmenili prevode bilo kojeg vikija, posetite [https://translatewiki.net/ translatewiki.net], projekat za lokalizaciju Medijavikija.",
+       "viewyourtext": "Možete da pogledate i kopirate izvornik <strong>Vaših izmena</strong> na ovoj stranici.",
+       "protectedinterface": "Ova stranica sadrži tekst interfejsa za softver na ovom vikiju i zaštićena je radi sprečavanja zloupotrebe.\nDa biste dodali ili promenili prevode bilo kojeg vikija, posetite [https://translatewiki.net/ translatewiki.net], projekat za lokalizaciju Medijavikija.",
        "editinginterface": "<strong>Upozorenje:</strong> uređujete stranicu koja se koristi za prikazivanje teksta korisničkog okruženja.\nIzmene na ovoj stranici će uticati na sve korisnike ovog vikija.",
-       "translateinterface": "Da dodate ili promenite prevode za sve vikije, posetite [https://translatewiki.net/ Translejtviki], projekat za lokalizaciju Medijavikija.",
+       "translateinterface": "Da biste dodali ili promenili prevode za sve vikije, posetite [https://translatewiki.net/ translatewiki.net], projekat za lokalizaciju Medijavikija.",
        "cascadeprotected": "Ova stranica je zaključana jer sadrži {{PLURAL:$1|sledeću stranicu koja je zaštićena|sledeće stranice koje su zaštićene}} „prenosivom“ zaštitom:\n$2",
        "namespaceprotected": "Nemate dozvolu da uređujete stranice u imenskom prostoru: <strong>$1</strong>.",
        "customcssprotected": "Nemate dozvolu da menjate ovu CSS stranicu jer sadrži lična podešavanja drugog korisnika.",
-       "customjsprotected": "Nemate dozvolu da menjate ovu stranicu JavaScript jer sadrži lična podešavanja drugog korisnika.",
-       "mycustomcssprotected": "Nemate dozvolu za menjanje ove CSS stranice.",
-       "mycustomjsonprotected": "Nemate dozvolu za menjanje ove JSON stranice.",
-       "mycustomjsprotected": "Nemate dozvolu za menjanje ove JavaScript stranice.",
-       "myprivateinfoprotected": "Nemate dozvolu za menjanje vaših ličnih informacija.",
-       "mypreferencesprotected": "Nemate dozvolu za menjanje vaših podešavanja.",
+       "customjsonprotected": "Nemate dozvolu da menjate ovu JSON stranicu zato što sadrži lična podešavanja drugog korisnika.",
+       "customjsprotected": "Nemate dozvolu da menjate ovu JavaScript stranicu jer sadrži lična podešavanja drugog korisnika.",
+       "sitecssprotected": "Nemate dozvolu da menjate ovu CSS stranicu zato što može uticati na sve posetioce.",
+       "sitejsonprotected": "Nemate dozvolu da menjate ovu JSON stranicu zato što može uticati na sve posetioce.",
+       "sitejsprotected": "Nemate dozvolu da menjate ovu JavaScript stranicu zato što može uticati na sve posetioce.",
+       "mycustomcssprotected": "Nemate dozvolu da uređujete ovu CSS stranicu.",
+       "mycustomjsonprotected": "Nemate dozvolu da uređujete ovu JSON stranicu.",
+       "mycustomjsprotected": "Nemate dozvolu da uređujete ovu stranicu s javaskriptom.",
+       "myprivateinfoprotected": "Nemate dozvolu da uređujete svoje privatne informacije.",
+       "mypreferencesprotected": "Nemate dozvolu da uređujete svoja podešavanja.",
        "ns-specialprotected": "Posebne stranice se ne mogu uređivati.",
        "titleprotected": "Ovaj naziv je [[User:$1|$1]] zaštitio od pravljenja. Razlog: <em>$2</em>.",
        "filereadonlyerror": "Ne mogu da izmenim datoteku „$1“ jer je riznica „$2“ u režimu za čitanje.\n\nSistemski administrator je naveo sledeće objašnjenje: „$3“.",
-       "invalidtitle-knownnamespace": "Neispravan naslov s imenskim prostorom „$2“ i tekstom „$3“",
-       "invalidtitle-unknownnamespace": "Neispravan naslov s imenskim prostorom br. $1 i tekstom „$2“",
+       "invalidtitle": "Nevažeći naslov",
+       "invalidtitle-knownnamespace": "Nevažeći naslov sa imenskim prostorom „$2“ i tekstom „$3“",
+       "invalidtitle-unknownnamespace": "Nevažeći naslov sa nepoznatim imenskim prostorom br. $1 i tekstom „$2“",
        "exception-nologin": "Niste prijavljeni",
        "exception-nologin-text": "Prijavite se da biste pristupili ovoj stranici ili radnji.",
        "exception-nologin-text-manual": "Morate biti $1 da biste pristupili ovoj stranici ili radnji.",
-       "virus-badscanner": "Neispravno podešavanje: nepoznati skener za viruse: <em>$1</em>",
-       "virus-scanfailed": "neuspešno skeniranje (kod $1)",
+       "virus-badscanner": "Loša konfiguracija: nepoznati skener za viruse: <em>$1</em>",
+       "virus-scanfailed": "skeniranje nije uspelo (kod $1)",
        "virus-unknownscanner": "nepoznati antivirus:",
-       "logouttext": "<strong>Sada ste odjavljeni.</strong>\n\nZapamtite da neke stranice mogu da nastave da se prikazuju kao da ste još uvek prijavljeni, dok ne očistite privremenu memoriju svog pregledača.",
+       "logouttext": "<strong>Sada ste odjavljeni.</strong>\n\nZapamtite da neke stranice mogu nastaviti da se prikazuju kao da ste još uvek prijavljeni, sve dok ne očistite keš svog pregledača.",
        "cannotlogoutnow-title": "Odjava trenutno nije moguća",
        "cannotlogoutnow-text": "Odjava nije moguća tokom upotrebe $1.",
        "welcomeuser": "Dobro došli, $1!",
-       "welcomecreation-msg": "Vaš nalog je otvoren.\nNe zaboravite da promenite svoja [[Special:Preferences|podešavanja]].",
+       "welcomecreation-msg": "Vaš nalog je otvoren.\nMožete da promenite svoja [[Special:Preferences|podešavanja]] na projektu {{SITENAME}} ako želite.",
        "yourname": "Korisničko ime:",
        "userlogin-yourname": "Korisničko ime",
        "userlogin-yourname-ph": "Unesite svoje korisničko ime",
        "cannotlogin-text": "Prijava nije moguća",
        "cannotloginnow-title": "Prijava trenutno nije moguća",
        "cannotloginnow-text": "Prijava nije moguća kada se koristi $1.",
-       "cannotcreateaccount-title": "Otvaranje naloga nije moguće",
-       "cannotcreateaccount-text": "Direktno pravljenje naloga nije omogućeno na ovom vikiju.",
+       "cannotcreateaccount-title": "Ne mogu da otvorim naloge",
+       "cannotcreateaccount-text": "Direktno otvaranje naloga nije omogućeno na ovom vikiju.",
        "yourdomainname": "Domen:",
        "password-change-forbidden": "Ne možete da promenite lozinku na ovom vikiju.",
-       "externaldberror": "Došlo je do greške pri prepoznavanju baze podataka ili nemate ovlašćenja da ažurirate svoj spoljni nalog.",
+       "externaldberror": "Došlo je do greške pri potvrdi identiteta baze podataka ili vam nije dozvoljeno da ažurirate svoj spoljni nalog.",
        "login": "Prijavi me",
-       "login-security": "Verifikacija vašeg indentiteta",
+       "login-security": "Potvrda vašeg indentiteta",
        "nav-login-createaccount": "Prijava/registracija",
        "logout": "Odjava",
        "userlogout": "Odjava",
        "userlogin-resetpassword-link": "Zaboravili ste lozinku?",
        "userlogin-helplink2": "Pomoć pri prijavljivanju",
        "userlogin-loggedin": "Već ste prijavljeni kao {{GENDER:$1|$1}}.\nKoristite donji obrazac da biste se prijavili kao drugi korisnik.",
-       "userlogin-reauth": "Morate se ponovo prijaviti da bi verifikovali da ste {{GENDER:$1|$1}}.",
+       "userlogin-reauth": "Morate da se ponovo prijavite da biste potvrdili da ste {{GENDER:$1|$1}}.",
        "userlogin-createanother": "Otvori još jedan nalog",
-       "createacct-emailrequired": "Imejl adresa",
-       "createacct-emailoptional": "Imejl adresa (neobavezno)",
-       "createacct-email-ph": "Unesite svoju imejl adresu",
-       "createacct-another-email-ph": "Unesite imejl adresu",
-       "createaccountmail": "Koristite privremenu, slučajno stvorenu lozinku i pošaljite na navedenu imejl adresu",
-       "createaccountmail-help": "Može se koristiti da se nekome napravi nalog bez saznanja lozinke.",
-       "createacct-realname": "Pravo ime (neobavezno)",
+       "createacct-emailrequired": "Imejl-adresa",
+       "createacct-emailoptional": "Imejl-adresa (opcionalno)",
+       "createacct-email-ph": "Unesite svoju imejl-adresu",
+       "createacct-another-email-ph": "Unesite imejl-adresu",
+       "createaccountmail": "Koristite privremenu, slučajnu lozinku i pošaljite je na navedenu imejl-adresu",
+       "createaccountmail-help": "Može se koristiti da se nekome otvori nalog bez saznanja lozinke.",
+       "createacct-realname": "Pravo ime (opcionalno)",
        "createacct-reason": "Razlog",
        "createacct-reason-ph": "Zašto pravite još jedan nalog?",
-       "createacct-reason-help": "Poruka koja se prikazuje u dnevniku stvaranja korisničkih naloga",
-       "createacct-submit": "Otvori nalog",
+       "createacct-reason-help": "Poruka koja se prikazuje u evidenciji pravljenja korisničkih naloga",
+       "createacct-submit": "Otvori svoj nalog",
        "createacct-another-submit": "Otvori nalog",
        "createacct-continue-submit": "Nastavite otvaranje naloga",
        "createacct-another-continue-submit": "Nastavite otvaranje naloga",
        "createacct-benefit-body3": "nedavno {{PLURAL:$1|aktivni korisnik|aktivna korisnika|aktivnih korisnika}}",
        "badretype": "Unete lozinke se ne poklapaju.",
        "usernameinprogress": "Nalog za ovo korisničko ime se već pravi, sačekajte.",
-       "userexists": "Korisničko ime je zauzeto. Izaberite drugo.",
+       "userexists": "Uneseno korisničko ime je već u upotrebi.\nOdaberite drugo.",
        "loginerror": "Greška pri prijavljivanju",
        "createacct-error": "Došlo je do greške pri otvaranju naloga",
        "createaccounterror": "Ne mogu da otvorim nalog: $1.",
        "nocookiesfornew": "Korisnički nalog nije otvoren jer njegov izvor nije potvrđen.\nOmogućite kolačiće na pregledaču i ponovo učitajte stranicu.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "createacct-loginerror": "Nalog je uspešno napravljen, ali se ne možete automatski prijaviti. Pređite na [[Special:UserLogin|ručno prijavljivanje]].",
-       "noname": "Uneli ste neispravno korisničko ime.",
+       "noname": "Niste naveli važeće korisničko ime.",
        "loginsuccesstitle": "Uspešno prijavljivanje",
        "loginsuccess": "<strong>Prijavljeni ste na {{SITENAME}} kao „$1”.</strong>",
        "nosuchuser": "Ne postoji korisnik s imenom „$1“.\nKorisnička imena su osetljiva na mala i velika slova.\nProverite da li ste ga dobro uneli ili [[Special:CreateAccount|otvorite novi nalog]].",
        "nosuchusershort": "Korisnik s imenom „$1“ ne postoji.\nProverite da li ste pravilno napisali.",
        "nouserspecified": "Morate navesti korisničko ime.",
        "login-userblocked": "{{GENDER:$1|Ovaj korisnik je blokiran|Ova korisnica je blokirana|Ovaj korisnik je blokiran}}. Prijava nije dozvoljena.",
-       "wrongpassword": "Uneli ste neispravno korisničko ime ili lozinku. Pokušajte ponovo.",
+       "wrongpassword": "Uneli ste neispravno korisničko ime ili lozinku.\nPokušajte ponovo.",
        "wrongpasswordempty": "Niste uneli lozinku. Pokušajte ponovo.",
        "passwordtooshort": "Lozinka mora imati najmanje {{PLURAL:$1|jedan znak|$1 znaka|$1 znakova}}.",
        "passwordtoolong": "Lozinke ne mogu biti duže od {{PLURAL:$1|$1 znaka|$1 znakova}}.",
-       "passwordtoopopular": "Često izabrane lozinke ne mogu da se koriste. Izaberite lozinku koju je teže pogoditi.",
+       "passwordtoopopular": "Često odabrane lozinke ne mogu da se koriste. Odaberite lozinku koju je teže pogoditi.",
        "password-name-match": "Lozinka se mora razlikovati od korisničkog imena.",
        "password-login-forbidden": "Korišćenje ovog korisničkog imena i lozinke je zabranjeno.",
        "mailmypassword": "Resetuj lozinku",
        "passwordremindertitle": "{{SITENAME}} — privremena lozinka",
        "passwordremindertext": "Neko sa IP adrese $1 je zatražio novu lozinku na vikiju {{SITENAME}} ($4).\nStvorena je privremena lozinka za {{GENDER:$2|korisnika|korisnicu|korisnika}} $2 koja glasi $3.\nUkoliko je ovo vaš zahtev, sada se prijavite i postavite novu lozinku.\nPrivremena lozinka ističe za {{PLURAL:$5|jedan dan|$5 dana}}.\n\nAko je neko drugi zatražio promenu lozinke, ili ste se setili vaše lozinke i ne želite da je menjate, zanemarite ovu poruku.",
-       "noemail": "Ne postoji imejl adresa za {{GENDER:$1|korisnika|korisnicu}} $1.",
-       "noemailcreate": "Morate navesti ispravnu imejl adresu.",
-       "passwordsent": "Nova lozinka je poslata na imejl adresu {{GENDER:$1|korisnika|korisnice|korisnika}} $1.\nPrijavite se pošto je primite.",
-       "blocked-mailpassword": "Vaša IP adresa ima zabranu uređivanja. Radi sprečavanja zloupotrebe, nije dozvoljeno vraćanje lozinke sa nje.",
-       "eauthentsent": "Na navedenu imejl adresu je poslat potvrdni kôd.\nPre nego što pošaljemo daljnje poruke, pratite uputstva s imejla da biste potvrdili da ste Vi otvorili nalog.",
+       "noemail": "Ne postoji imejl-adresa za {{GENDER:$1|korisnika|korisnicu}} $1.",
+       "noemailcreate": "Morate da navedete važeću imejl-adresu.",
+       "passwordsent": "Nova lozinka je poslata na imejl-adresu {{GENDER:$1|korisnika|korisnice}} $1.\nPonovo se prijavite nakon što je primite.",
+       "blocked-mailpassword": "Uređivanje sa vaše IP adrese je blokirano. Radi sprečavanja zloupotrebe, zabranjena je i funkcija vraćanja lozinke sa nje.",
+       "eauthentsent": "Imejl o potvrdi je poslat na navedenu imejl-adresu.\nPre bilo kojih drugih slanja imejlova na nalog, moraćete pratiti uputstva u imejlu da biste potvrdili da je nalog zaista vaš.",
        "throttled-mailpassword": "Poruka za promenu lozinke je poslata u {{PLURAL:$1|1=poslednjih sat vremena|poslednja $1 sata|poslednjih $1 sati}}.\nDa bismo sprečili zloupotrebu, podsetnik šaljemo samo jednom u roku od {{PLURAL:$1|1=sat vremena|$1 sata|$1 sati}}.",
        "mailerror": "Greška pri slanju poruke: $1",
        "acct_creation_throttle_hit": "Posetioci ovog vikija koji koriste vašu IP adresu su već otvorili {{PLURAL:$1|1=jedan nalog|$1 naloga}} prethodni $2, što je najveći dozvoljeni broj u tom vremenskom periodu.\nZbog toga posetioci s ove IP adrese trenutno ne mogu otvoriti više naloga.",
-       "emailauthenticated": "Vaša imejl adresa je potvrđena na dan $2 u $3.",
-       "emailnotauthenticated": "Vaša imejl adresa još uvek nije potvrđena.\nImejl neće biti poslat ni u jednom od sledećih slučajeva.",
-       "noemailprefs": "Navedite imejl adresu u svojim podešavanjima za rad ovih mogućnosti.",
-       "emailconfirmlink": "Potvrdite svoju imejl adresu",
-       "invalidemailaddress": "Imejl adresa ne može biti prihvaćena jer je neispravnog oblika.\nUnesite ispravnu adresu ili ostavite prazno polje.",
-       "cannotchangeemail": "Na ovom vikiju ne možete promeniti imejl adresu naloga.",
+       "emailauthenticated": "Vaša imejl-adresa je potvrđena na dan $2 u $3 č.",
+       "emailnotauthenticated": "Vaša imejl-adresa još nije potvrđena.\nNijedan imejl neće da bude poslat ni u jednom od sledećih slučajeva.",
+       "noemailprefs": "Navedite imejl-adresu u svojim podešavanjima za osposobljavanje ovih mogućnosti.",
+       "emailconfirmlink": "Potvrdite svoju imejl-adresu",
+       "invalidemailaddress": "Imejl-adresa ne može da bude prihvaćena jer je u nevažećem obliku.\nUnesite ispravnu adresu ili ostavite prazno polje.",
+       "cannotchangeemail": "Imejl-adrese naloga ne mogu da se promene na ovom vikiju.",
        "emaildisabled": "Ovaj sajt ne može da šalje imejlove.",
        "accountcreated": "Nalog je otvoren",
        "accountcreatedtext": "Korisnički nalog [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|talk]]) je otvoren.",
        "createaccount-title": "Otvaranje korisničkog naloga za {{SITENAME}}",
-       "createaccount-text": "Neko je otvorio nalog s vašom imejl adresom na {{SITENAME}} ($4) pod imenom $2 i lozinkom $3.\nPrijavite se i promenite svoju lozinku.\n\nAko je ovo greška, zanemarite ovu poruku.",
-       "login-throttled": "Previše puta ste pokušali da se prijavite.\nMolimo vas da sačekate $1 pre nego što pokušate ponovo.",
+       "createaccount-text": "Neko je otvorio nalog sa vašom imejl-adresom na projektu {{SITENAME}} ($4) pod imenom „$2“ i sa lozinkom „$3“.\nOdmah trebate da se prijavite i promenite svoju lozinku.\n\nMožete da zanemarite ovu poruku, ako je ovaj nalog otvoren greškom.",
+       "login-throttled": "Previše puta ste pokušali da se prijavite.\nSačekajte $1 pre nego što pokušate ponovo.",
        "login-abort-generic": "Neuspešna prijava – prekinuto",
        "login-migrated-generic": "Vaš nalog je migriran i vaše korisničko više ne postoji na ovom vikiju.",
        "loginlanguagelabel": "Jezik: $1",
-       "suspicious-userlogout": "Vaš zahtev za odjavu je odbijen jer je poslat od strane neispravnog pregledača ili posrednika.",
-       "createacct-another-realname-tip": "Pravo ime nije obavezno.\nAko izaberete da ga unesete, ono će biti korišćeno za pripisivanje vašeg rada.",
+       "suspicious-userlogout": "Vaš zahtev za odjavu je odbijen jer izgleda da ga je poslao pokvareni pregledač ili keširani posrednik.",
+       "createacct-another-realname-tip": "Pravo ime je opcionalno.\nAko odaberete da ga navedete, biće korišćeno za pripisivanje vašeg rada.",
        "pt-login": "Prijavi me",
        "pt-login-button": "Prijavi me",
        "pt-login-continue-button": "Nastavi prijavljivanje",
        "pt-createaccount": "Otvori nalog",
        "pt-userlogout": "Odjavi me",
        "php-mail-error-unknown": "Nepoznata greška u funkciji PHP mail().",
-       "user-mail-no-addy": "Pokušali ste da pošaljete imejl bez imejl adrese.",
+       "user-mail-no-addy": "Pokušali ste da pošaljete imejl bez imejl-adrese.",
        "user-mail-no-body": "Pokušano slanje imejla s praznim ili nerazumno kratkim sadržajem.",
        "changepassword": "Promena lozinke",
        "resetpass_announce": "Da biste završili prijavu, podesite novu lozinku ovde.",
        "retypenew": "Potvrda lozinke:",
        "resetpass_submit": "Postavi lozinku i prijavi me",
        "changepassword-success": "Vaša lozinka je uspešno promenjena!",
-       "changepassword-throttled": "Previše puta ste pokušali da se prijavite.\nMolimo vas da sačekate $1 pre nego što pokušate ponovo.",
+       "changepassword-throttled": "Previše puta ste pokušali da se prijavite.\nSačekajte $1 pre nego što pokušate ponovo.",
        "botpasswords": "Lozinke botova",
        "botpasswords-disabled": "Lozinke botova su onemogućene.",
        "botpasswords-no-central-id": "Da bi ste koristili botovske lozinke, morate biti prijavljeni na središnji nalog.",
        "botpasswords-existing": "Postojeća lozinka bota",
        "botpasswords-createnew": "Napravi novu lozinku za bota",
-       "botpasswords-editexisting": "Izmeni postojeću lozinku za bota",
+       "botpasswords-editexisting": "Uredi postojeću lozinku bota",
        "botpasswords-label-needsreset": "(lozinku treba resetovati)",
        "botpasswords-label-appid": "Ime bota:",
        "botpasswords-label-create": "Napravi",
        "botpasswords-label-update": "Ažuriraj",
        "botpasswords-label-cancel": "Otkaži",
-       "botpasswords-label-delete": "Obriši",
+       "botpasswords-label-delete": "Izbriši",
        "botpasswords-label-resetpassword": "Resetuj lozinku",
        "botpasswords-label-grants": "Primenljive dozvole:",
        "botpasswords-label-grants-column": "Odobreno",
-       "botpasswords-bad-appid": "„$1” nije validan naziv bota.",
-       "botpasswords-insert-failed": "Neuspešno dodavanje bota \"$1\". Da li je već dodat?",
-       "botpasswords-update-failed": "Nije moguće ažurirati bota \"$1\". Da li je obrisan?",
+       "botpasswords-bad-appid": "Ime bota „$1” nije validno.",
+       "botpasswords-insert-failed": "Neuspelo dodavanje bota pod imenom „$1”. Možda je već dodat?",
+       "botpasswords-update-failed": "Neuspelo ažuriranje bota pod nazivom „$1”. Da nije izbrisan?",
        "botpasswords-created-title": "Napravljena lozinka bota",
        "botpasswords-created-body": "Lozinka za bota „$1” korisnika „$2” je napravljena.",
        "botpasswords-updated-title": "Lozinka bota promenjena",
        "botpasswords-updated-body": "Lozinka za bota „$1” korisnika „$2” je ažurirana.",
-       "botpasswords-deleted-title": "Obrisana lozinka bota",
-       "botpasswords-deleted-body": "Lozinka za bota „$1” korisnika „$2” je obrisana.",
+       "botpasswords-deleted-title": "Izbrisana lozinka bota",
+       "botpasswords-deleted-body": "Lozinka za bota „$1” {{GENDER:$2|korisnika|korisnice}} „$2” je izbrisana.",
        "botpasswords-no-provider": "BotPasswordsSessionProvider nije dostupan.",
        "botpasswords-restriction-failed": "Ne možete se prijaviti zbog ograničenja lozinki za botove.",
        "botpasswords-not-exist": "Korisnik „$1“ nema lozinku bota „$2“.",
-       "resetpass_forbidden": "Lozinka ne može biti promenjena",
-       "resetpass_forbidden-reason": "Lozinke nije moguće promeniti: $1",
+       "resetpass_forbidden": "Ne mogu da promenim lozinke",
+       "resetpass_forbidden-reason": "Ne mogu da promenim lozinke: $1",
        "resetpass-no-info": "Morate biti prijavljeni da biste pristupili ovoj stranici.",
        "resetpass-submit-loggedin": "Promeni lozinku",
        "resetpass-submit-cancel": "Otkaži",
-       "resetpass-wrong-oldpass": "Neispravna privremena ili trenutna lozinka.\nMožda ste već promenili lozinku ili ste zatražili novu privremenu lozinku.",
+       "resetpass-wrong-oldpass": "Nevažeća privremena ili aktuelna lozinka.\nMožda ste već promenili lozinku ili ste zahtevali novu privremenu lozinku.",
        "resetpass-recycled": "Uneli ste sadašnju lozinku, da biste promenili lozinku morate uneti novu.",
-       "resetpass-temp-emailed": "Prijavili ste se sa privremenim kôdom iz imejla.\nDa biste završili prijavljivanje morate postaviti novu lozinku ovde:",
+       "resetpass-temp-emailed": "Prijavili ste se sa privremenim kodom iz imejla.\nDa biste završili prijavljivanje morate postaviti novu lozinku ovde:",
        "resetpass-temp-password": "Privremena lozinka:",
-       "resetpass-abort-generic": "Promenu lozinke je sprečio dodatak.",
+       "resetpass-abort-generic": "Promenu lozinke je prekinuo dodatak.",
        "resetpass-expired": "Vaša lozinka je istekla. Postavite novu lozinku da biste se prijavili.",
        "resetpass-expired-soft": "Vaša lozinka je istekla i morate je promeniti. Postavite novu lozinku ili kliknite „{{int:authprovider-resetpass-skip-label}}“ da je promenite kasnije.",
-       "resetpass-validity-soft": "Vaša lozinka nije ispravna: $1\n\nMolimo izaberite novu ili kliknite „{{int:authprovider-resetpass-skip-label}}“ da je promenite kasnije.",
-       "passwordreset": "Obnavljanje lozinke",
+       "resetpass-validity-soft": "Vaša lozinka nije važeća: $1\n\nIzaberite novu odmah ili kliknite na „{{int:authprovider-resetpass-skip-label}}“ da je promenite kasnije.",
+       "passwordreset": "Resetovanje lozinke",
        "passwordreset-text-one": "Popunite ovaj obrazac da biste dobili privremenu lozinku na imejl.",
        "passwordreset-text-many": "{{PLURAL:$1|Ispunite jedno od polja kako biste dobili privremenu lozinku na imejl.}}",
-       "passwordreset-disabled": "Obnavljanje lozinke je onemogućeno na ovom vikiju.",
+       "passwordreset-disabled": "Resetovanje lozinke je onemogućeno na ovom vikiju.",
        "passwordreset-emaildisabled": "Imejl je onemogućen na ovom vikiju.",
        "passwordreset-username": "Korisničko ime:",
        "passwordreset-domain": "Domen:",
-       "passwordreset-email": "Imejl adresa:",
+       "passwordreset-email": "Imejl-adresa:",
        "passwordreset-emailtitle": "Detalji naloga na vikiju {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Neko (verovatno Vi, sa IP adrese $1) je zatražio novu lozinku na vikiju {{SITENAME}} ($4).\nSledeći {{PLURAL:$3|korisnički nalog je povezan|korisnički nalozi su povezani}} s ovom imejl adresom:\n\n$2\n\n{{PLURAL:$3|Privremena lozinka ističe|Privremene lozinke ističu}} za {{PLURAL:$5|jedan dan|$5 dana}}.\nPrijavite se i izaberite novu lozinku. Ako je neko drugi zahtevao ovu radnju ili ste se setili lozinke i ne želite da je menjate, zanemarite ovu poruku i nastavite koristiti staru lozinku.",
-       "passwordreset-emailtext-user": "{{GENDER:$1|Korisnik je zatražio|Korisnica je zatražila}} podsetnik o podacima za prijavu na vikiju {{SITENAME}} ($4).\nSledeći {{PLURAL:$3|korisnički nalog je povezan|korisnički nalozi su povezani}} s ovom imejl adresom:\n\n$2\n\n{{PLURAL:$3|Privremena lozinka ističe|Privremene lozinke ističu}} za {{PLURAL:$5|jedan dan|$5 dana}}.\nPrijavite se i izaberite novu lozinku. Ako je neko drugi zahtevao ovu radnju ili ste se setili lozinke i ne želite da je menjate, zanemarite ovu poruku.",
+       "passwordreset-emailtext-ip": "Neko (verovatno vi, sa IP adrese $1) zatražio je resetovanje vaše \nlozinke za projekat {{SITENAME}} ($4). Sledeći korisnički {{PLURAL:$3|nalog je povezan|nalozi su povezani}} \nsa ovom imejl adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena lozinka|Ove privremene lozinke}} će isteći za {{PLURAL:$5|jedan dan|$5 dana}}.\nOdmah trebate da se prijavite i odaberite novu lozinku. Ako je neko drugi napravio ovaj \nzahtev ili ste se setili svoje prvobitne lozinke, a ne \nželite da je promenite, možete da zanemarite ovu poruku i nastavite da koristite svoju staru \nlozinku.",
+       "passwordreset-emailtext-user": "{{GENDER:$1|Korisnik je zatražio|Korisnica je zatražila}} podsetnik o podacima za prijavu na vikiju {{SITENAME}} ($4).\nSledeći {{PLURAL:$3|korisnički nalog je povezan|korisnički nalozi su povezani}} sa ovom imejl-adresom:\n\n$2\n\n{{PLURAL:$3|Privremena lozinka ističe|Privremene lozinke ističu}} za {{PLURAL:$5|jedan dan|$5 dana}}.\nPrijavite se i izaberite novu lozinku. Ako je neko drugi zahtevao ovu radnju ili ste se setili lozinke i ne želite da je menjate, zanemarite ovu poruku.",
        "passwordreset-emailelement": "Korisničko ime: \n$1\n\nPrivremena lozinka: \n$2",
-       "passwordreset-emailsentemail": "Ako je ovo imejl adresa povezana sa Vašim nalogom, podsetnik o lozinci će biti poslat na imejl.",
-       "passwordreset-emailsentusername": "Ako ste naveli imejl adresu prilikom registracije, biće poslat imejl za resetovanje lozinke.",
+       "passwordreset-emailsentemail": "Ako je ova imejl-adresa povezana sa vašim nalogom, onda će imejl o resetovanju lozinke biti poslat.",
+       "passwordreset-emailsentusername": "Ako postoji imejl-adresa povezana sa ovim korisničkim imenom, onda će imejl o resetovanju lozinke biti poslat.",
        "passwordreset-nocaller": "Pozivalac se mora navesti",
        "passwordreset-nosuchcaller": "Pozivalac ne postoji: $1",
        "passwordreset-ignored": "Resetovanje lozinke nije uspelo. Možda poslužilac nije konfigurisan?",
-       "passwordreset-invalidemail": "Neispravna imejl adresa",
+       "passwordreset-invalidemail": "Nevažeća imejl-adresa",
        "passwordreset-nodata": "Korisničko ime i adresa e-pošte nisu navedeni",
-       "changeemail": "Promena ili uklanjanje imejl adrese",
-       "changeemail-header": "Popunite ovaj obrazac da bi ste promenili Vašu imejl adresu. Ako želi da uskratite pristup bilo kojoj imejl adresi Vašem nalogu, ostavite prazno polje za novu imejl adresu prilikom popunjavanje obrasca.",
+       "changeemail": "Promena ili uklanjanje imejl-adrese",
+       "changeemail-header": "Popunite ovaj obrazac da bi ste promenili vašu imejl-adresu. Ako biste želeli da uklonite povezanost bilo koje imejl-adrese sa vašeg naloga, ostavite prazno polje za novu imejl-adresu kada šaljete obrazac.",
        "changeemail-no-info": "Morate biti prijavljeni da biste pristupili ovoj stranici.",
-       "changeemail-oldemail": "Trenutna imejl adresa:",
-       "changeemail-newemail": "Nova imejl adresa:",
+       "changeemail-oldemail": "Aktuelna imejl-adresa:",
+       "changeemail-newemail": "Nova imejl-adresa:",
+       "changeemail-newemail-help": "Ovo polje bi trebalo da ostavite prazno ako želite da uklonite vašu imejl adresu. Nećete biti u mogućnosti da resetujete zaboravljenu lozinku i nećete primati mejlove od ovog vikija ako je imejl adresa uklonjena.",
        "changeemail-none": "(ništa)",
-       "changeemail-password": "Vaša lozinka:",
+       "changeemail-password": "Vaša lozinka za projekat {{SITENAME}}:",
        "changeemail-submit": "Promeni imejl",
        "changeemail-throttled": "Previše puta ste pokušali da se prijavite.\nMolimo vas da sačekate $1 pre nego što pokušate ponovo.",
-       "changeemail-nochange": "Unesite drugu imejl adresu.",
-       "resettokens": "Resetovanje žetona",
-       "resettokens-text": "Možete ponovo postaviti žetone koji će vam omogućiti pristup određenim privatnim podacima povezanim sa vašim nalogom ovde.\n\nTrebali biste to da uradite ako ih mimo volje podelite s nekim ili ako je vaš nalog ugrožen.",
+       "changeemail-nochange": "Unesite drugu imejl-adresu.",
+       "resettokens": "Resetovanje tokena",
+       "resettokens-text": "Možete ponovo postaviti žetone koji će vam omogućiti pristup određenim privatnim podacima povezanim sa vašim nalogom ovde.\n\nTrebali biste to da uradite ako ih mimo volje podelite sa nekim ili ako je vaš nalog ugrožen.",
        "resettokens-no-tokens": "Nema žetona za resetovanje.",
        "resettokens-tokens": "Žetoni:",
        "resettokens-token-label": "$1 (trenutna vrednost: $2)",
-       "resettokens-watchlist-token": "Žeton za veb dovod (Atom/RSS) [[Special:Watchlist|izmena na stranicama u vašem spisku nadgledanja]]",
+       "resettokens-watchlist-token": "Token za veb-fid (Atom/RSS) [[Special:Watchlist|promena na stranicama u vašem spisku nadgledanja]]",
        "resettokens-done": "Žetoni su resetovani",
        "resettokens-resetbutton": "Resetuj izabrane žetone",
        "bold_sample": "Podebljan tekst",
        "bold_tip": "Podebljan tekst",
        "italic_sample": "Iskošen tekst",
        "italic_tip": "Iskošen tekst",
-       "link_sample": "Naslov veze",
-       "link_tip": "Unutrašnja veza",
-       "extlink_sample": "http://www.example.com/ naslov veze",
-       "extlink_tip": "Spoljašnja veza (s prefiksom http://)",
+       "link_sample": "Naslov linka",
+       "link_tip": "Unutrašnji link",
+       "extlink_sample": "http://www.example.com/ naslov linka",
+       "extlink_tip": "Spoljašnji link (sa prefiksom http://)",
        "headline_sample": "Tekst naslova",
        "headline_tip": "Podnaslov (nivo 2)",
-       "nowiki_sample": "Ubacite neoblikovan tekst ovde",
+       "nowiki_sample": "Ovde umetnite neoblikovan tekst",
        "nowiki_tip": "Zanemari viki oblikovanje",
        "image_sample": "Primer.jpg",
        "image_tip": "Ugrađivanje datoteke",
        "media_sample": "Primer.ogg",
-       "media_tip": "Veza",
-       "sig_tip": "Vaš potpis sa trenutnim vremenom",
+       "media_tip": "Link do datoteke",
+       "sig_tip": "Vaš potpis sa vremenskom oznakom",
        "hr_tip": "Vodoravna linija (koristite retko)",
        "summary": "Opis izmene:",
        "subject": "Tema:",
        "minoredit": "Ovo je manja izmena",
        "watchthis": "Nadgledaj ovu stranicu",
        "savearticle": "Sačuvaj stranicu",
-       "savechanges": "Sačuvaj izmene",
+       "savechanges": "Sačuvaj promene",
        "publishpage": "Objavi stranicu",
-       "publishchanges": "Objavi izmene",
+       "publishchanges": "Objavi promene",
        "savearticle-start": "Sačuvaj stranicu...",
-       "savechanges-start": "Sačuvaj izmene...",
+       "savechanges-start": "Sačuvaj promene...",
        "publishpage-start": "Objavi stranicu...",
-       "publishchanges-start": "Objavi izmene...",
+       "publishchanges-start": "Objavi promene...",
        "preview": "Pretpregled",
        "showpreview": "Prikaži pretpregled",
-       "showdiff": "Prikaži izmene",
+       "showdiff": "Prikaži promene",
        "blankarticle": "<strong>Upozorenje:</strong> Stranica koju pravite je prazna.\nAko još jednom pritisnete „$1”, stranica će biti napravljena bez ikakvog sadržaja.",
-       "anoneditwarning": "<strong>Upozorenje:</strong> Niste prijavljeni. Ako objavite stranicu, Vaša IP adresa će biti javno vidljiva u njenoj istoriji izmena i drugde. Ako se <strong>[$1 prijavite]</strong> ili <strong>[$2 otvorite nalog]</strong>, pored ostalih pogodnosti koje dobijate Vaše izmene će biti pripisivane Vašem korisničkom imenu.",
-       "anonpreviewwarning": "<em>Niste prijavljeni. Ako objavite stranicu, Vaša IP adresa će biti javno vidljiva u njenoj istoriji izmena i drugde.</em>",
-       "missingsummary": "<strong>Podsetnik:</strong> Niste uneli opis izmene.\nAko ponovo kliknete na „$1”, Vaša izmena će biti sačuvana bez opisa.",
+       "anoneditwarning": "<strong>Upozorenje:</strong> Niste prijavljeni. Ako objavite stranicu, vaša IP adresa će biti javno vidljiva u njenoj istoriji izmena i drugde. Ako se <strong>[$1 prijavite]</strong> ili <strong>[$2 otvorite nalog]</strong>, pored ostalih pogodnosti koje dobijate vaše izmene će biti pripisivane vašem korisničkom imenu.",
+       "anonpreviewwarning": "<em>Niste prijavljeni. Ako objavite stranicu, vaša IP adresa će biti javno vidljiva u njenoj istoriji izmena i drugde.</em>",
+       "missingsummary": "<strong>Podsetnik:</strong> niste naveli opis izmene.\nAko ponovo kliknete na „$1”, vaša izmena će biti sačuvana bez njega.",
        "selfredirect": "<strong>Upozorenje:</strong> Preusmeravate ovu stranicu na nju samu.\nMožda vam je odredišna stranica za preusmerenje pogrešna ili uređujete pogrešnu stranicu.\nAko još jednom pritisnete „$1”, preusmerenje će svejedno biti napravljeno.",
        "missingcommenttext": "Molimo unesite komentar.",
        "missingcommentheader": "<strong>Napomena:</strong> Niste uneli naslov teme ovog komentara.\nAko ponovo kliknete na „$1”, izmena će biti sačuvana bez naslova.",
        "summary-preview": "Pregled opisa izmene:",
        "subject-preview": "Pregled teme:",
-       "previewerrortext": "Dogodila se greška prilikom prikazivanja vaših izmena.",
+       "previewerrortext": "Došlo je do greške pri pokušaju pregleda promena.",
        "blockedtitle": "Korisnik je blokiran",
-       "blockedtext": "<strong>Vaše korisničko ime ili IP adresa je blokirana.</strong>\n\nBlokiranje je {{GENDER:$4|izvršio|izvršila}} $1.\nRazlog je <em>$2</em>.\n\n* Početak blokiranja: $8\n* Istek blokiranja: $6\n* Blokirani: $7\n\nMožete da se obratite {{GENDER:$4|korisniku|korisnici}} $1 ili [[{{MediaWiki:Grouppage-sysop}}|administratoru]] radi diskusije o blokiranju.\nNe možete da koristite mogućnost „{{int:emailuser}}” osim ako ste uneli validnu imejl adresu u svojim [[Special:Preferences|podešavanjima]] naloga i niste blokirani od korišćenja iste.\nVaša trenutna IP adresa je $3, a ID blokiranja #$5.\nNavedite sve informacije odozgo pri stvaranju bilo kakvih upita.",
-       "autoblockedtext": "Vaša IP adresa je blokirana jer ju je upotrebljavao drugi korisnik, koga je {{GENDER:$4|blokirao|blokirala}} $1.\nRazlog:\n\n:<em>$2</em>\n\n* Datum blokiranja: $8\n* Blokiranje ističe: $6\n* Ime korisnika: $7\n\nObratite se {{GENDER:$4|korisniku|korisnici}} $1 ili [[{{MediaWiki:Grouppage-sysop}}|administratoru]] da razjasnite stvar.\n\nNe možete koristiti mogućnost „{{int:emailuser}}“ ako niste uneli ispravnu imejl adresu u [[Special:Preferences|podešavanjima]].\n\nVaša blokirana IP adresa je $3, a ID $5.\nNavedite sve podatke iznad pri stvaranju bilo kakvih upita.",
-       "blockednoreason": "razlog nije naveden",
+       "blockedtext": "<strong>Vaše korisničko ime ili IP adresa je blokirana.</strong>\n\nBlokiranje je {{GENDER:$4|izvršio|izvršila}} $1.\nRazlog je <em>$2</em>.\n\n* Početak blokiranja: $8\n* Istek blokiranja: $6\n* Blokirani: $7\n\nMožete da kontaktirate {{GENDER:$4|korisnika|korisnicu}} $1 ili drugog [[{{MediaWiki:Grouppage-sysop}}|administratora]] da biste razgovarali o blokiranju.\nNe možete da koristite mogućnost „{{int:emailuser}}” osim ako ste naveli validnu imejl adresu u svojim [[Special:Preferences|podešavanjima naloga]] i niste blokirani od korišćenja iste.\nVaša aktuelna IP adresa je $3, a ID blokade #$5.\nNavedite sve gornje detalje pri pravljenju bilo kakvih upita.",
+       "autoblockedtext": "Vaša IP adresa je automatski blokirana jer ju je koristio drugi korisnik, koga je {{GENDER:$4|blokirao|blokirala}} $1.\nRazlog:\n\n:<em>$2</em>\n\n* Početak blokade: $8\n* Kraj blokade: $6\n* Ime korisnika: $7\n\nMožete da kontaktirate {{GENDER:$4|korisnika|korisnicu}} $1 ili drugog [[{{MediaWiki:Grouppage-sysop}}|administratora]] da biste raspravljali o blokadi.\n\nZapamtite da ne možete da koristite mogućnost „{{int:emailuser}}“ osim ako ste naveli valjanu imejl adresu u svojim [[Special:Preferences|podešavanjima]].\n\nVaša aktuelna IP adresa je $3, a ID blokade $5.\nUključite sve gornje detalje pri pravljenju bilo kakvih upita.",
+       "blockednoreason": "nije naveden razlog",
        "whitelistedittext": "Za uređivanje stranice je potrebno da budete $1.",
        "confirmedittext": "Morate da potvrdite svoju imejl adresu pre uređivanja stranica.\nPostavite i potvrdite imejl adresu preko [[Special:Preferences|podešavanja]].",
        "nosuchsectiontitle": "Ne mogu da pronađem odeljak.",
-       "nosuchsectiontext": "Pokušali ste da uredite odeljak koji ne postoji.\nMožda je premešten ili obrisan dok ste pregledali stranicu.",
+       "nosuchsectiontext": "Pokušali ste da uredite odeljak koji ne postoji.\nMožda je premešten ili izbrisan dok ste pregledali stranicu.",
        "loginreqtitle": "Potrebna je prijava",
        "loginreqlink": "prijavljeni",
        "loginreqpagetext": "Morate biti $1 da biste videli druge stranice.",
        "newarticletext": "Došli ste na stranicu koja još ne postoji.\nDa biste je napravili, počnite da kucate u prozor ispod ovog teksta (pogledajte [$1 stranicu za pomoć]).\nAko ste ovde došli greškom, vratite se na prethodnu stranicu.",
        "anontalkpagetext": "----\n<em>Ovo je stranica za razgovor s anonimnim korisnikom koji još nema nalog ili ga ne koristi.</em>\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo ga prepoznali.\nTakvu adresu može deliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene primedbe, [[Special:CreateAccount|otvorite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbegli buduću zabunu s ostalim anonimnim korisnicima.",
        "noarticletext": "Na ovoj stranici trenutno nema teksta.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne izveštaje] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} napraviti ovu stranicu]</span>.",
-       "noarticletext-nopermission": "Na ovoj stranici trenutno nema teksta.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne dnevnike]</span>, ali nemate dozvolu da napravite ovu stranicu.",
-       "missing-revision": "Ne mogu da pronađem izmenu br. $1 na stranici pod nazivom „{{FULLPAGENAME}}“.\n\nOvo se obično dešava kada pratite zastarelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
+       "noarticletext-nopermission": "Trenutno nema teksta na ovoj stranici.\nMožete da [[Special:Search/{{PAGENAME}}|potražite ovaj naslov stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražite srodne evidencije]</span>, ali nemate dozvolu da napravite ovu stranicu.",
+       "missing-revision": "Izmena br. $1 na stranici pod imenom „{{FULLPAGENAME}}“ ne postoji.\n\nOvo se obično dešava kada pratite zastareli link do stranice koja je izbrisana.\nViše informacija možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
        "userpage-userdoesnotexist": "Korisnički nalog „<nowiki>$1</nowiki>“ nije otvoren.\nRazmislite da li zaista želite da napravite/uredite ovu stranicu.",
        "userpage-userdoesnotexist-view": "Korisnički nalog „$1“ nije otvoren.",
-       "blocked-notice-logextract": "Ovaj korisnik je trenutno blokiran.\nIzveštaj o poslednjem blokiranju možete pogledati ispod:",
-       "clearyourcache": "<strong>Napomena:</strong> Nakon čuvanja, možda ćete morati da očistite keš pregledača kako biste videli izmene.\n* <strong>Fajerfoks / Safari:</strong> Držite <em>Shift</em> i kliknite na <em>Osveži</em> ili pritisnite <em>Ctrl-F5</em> ili <em>Ctrl-R</em> (<em>⌘-R</em> na Meku)\n* <strong>Gugl kroum:</strong> Pritisnite <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> na Meku)\n* <strong>Internet eksplorer:</strong> Držite <em>Ctrl</em> i kliknite na <em>Osveži</em> ili pritisnite <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Idite na <em>Alatke → Podešavanja</em> (<em>Opera → Podešavanja</em> na Meku) i zatim <em>Privatnost i bezbednost → Očistite podatke o pregledima → Keširane slike i datoteke</em>.",
-       "usercssyoucanpreview": "<strong>Savet:<strong> korisitite dugme „{{int:showpreview}}“ da isprobate svoj novi CSS pre nego što ga sačuvate.",
-       "userjsyoucanpreview": "<strong>Savet:</strong> korisitite dugme „{{int:showpreview}}“ da isprobate svoj novi javaskript pre nego što ga sačuvate.",
+       "blocked-notice-logextract": "Ovaj korisnik je trenutno blokiran.\nPoslednji unos u evidenciji blokiranja je naveden ispod kao referenca:",
+       "clearyourcache": "<strong>Napomena:</strong> Nakon čuvanja, možda ćete morati da očistite keš pregledača kako biste videli promene.\n* <strong>Fajerfoks / Safari:</strong> Držite <em>Shift</em> i kliknite na <em>Osveži</em> ili pritisnite <em>Ctrl-F5</em> ili <em>Ctrl-R</em> (<em>⌘-R</em> na Meku)\n* <strong>Gugl kroum:</strong> Pritisnite <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> na Meku)\n* <strong>Internet eksplorer:</strong> Držite <em>Ctrl</em> i kliknite na <em>Osveži</em> ili pritisnite <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Idite na <em>Alatke → Podešavanja</em> (<em>Opera → Podešavanja</em> na Meku) i zatim <em>Privatnost i bezbednost → Očistite podatke o pregledima → Keširane slike i datoteke</em>.",
+       "usercssyoucanpreview": "<strong>Savet:<strong> Korisitite dugme „{{int:showpreview}}“ da isprobate svoj novi CSS pre nego što ga sačuvate.",
+       "userjsonyoucanpreview": "<strong>Savet:</strong> Koristite dugme \"{{int:showpreview}}\" da isprobate svoj novi JSON pre nego što ga sačuvate.",
+       "userjsyoucanpreview": "<strong>Savet:</strong> Korisitite dugme „{{int:showpreview}}“ da isprobate svoj novi javaskript pre nego što ga sačuvate.",
        "usercsspreview": "<strong>Ovo je samo pregled CSS-a.\nStranica još nije sačuvana!</strong>",
-       "userjspreview": "<strong>Ovo je samo pregled javaskripta.\nStranica još nije sačuvana!</strong>",
-       "sitecsspreview": "<strong>Ovo je samo pregled CSS-a.\nStranica još nije sačuvana!</strong>",
+       "userjsonpreview": "<strong>Zapamtite da samo testirate/pregledavate vašu korisničku JSON konfiguraciju.\nStranica još nije sačuvana!</strong>",
+       "userjspreview": "<strong>Zapamtite da samo testirate/pregledavate vaš korisnički javaskript.\nStranica još nije sačuvana!</strong>",
+       "sitecsspreview": "<strong>Zapamtite da je ovo samo pregled CSS-a.\nStranica još nije sačuvana!</strong>",
+       "sitejsonpreview": "<strong>Zapamtite da je ovo samo pregled JSON-a.\nStranica još nije sačuvana!</strong>",
        "sitejspreview": "<strong>Ovo je samo pregled javaskripta.\nStranica još nije sačuvana!</strong>",
        "userinvalidconfigtitle": "<strong>Upozorenje:</strong> ne postoji tema „$1“.\nPrilagođene stranice CSS, JSON i Javaskript počinju malim slovom, npr. {{ns:user}}:Foo/vector.css, a ne {{ns:user}}:Foo/Vector.css.",
        "updated": "(ažurirano)",
        "note": "<strong>Napomena:</strong>",
-       "previewnote": "<strong>Ne zaboravite da je ovo samo pretpregled.</strong>\nVaše izmene još nisu sačuvane!",
+       "previewnote": "<strong>Ne zaboravite da je ovo samo pretpregled.</strong>\nVaše promene još nisu sačuvane!",
        "continue-editing": "Idi na uređivački okvir",
        "previewconflict": "Ovaj pregled oslikava kako će izgledati tekst u tekstualnom okviru.",
-       "session_fail_preview": "Izvinjavamo se! Nismo mogli da obradimo Vašu izmenu zbog gubitka podataka sesije.\n\nMožda ste odjavljeni. <strong>Proverite da li ste prijavljeni i pokušajte ponovo</strong>.\nAko i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite, te proverite da li su na Vašem pretraživaču dozvoljeni kolačići sa ovog sajta.",
-       "session_fail_preview_html": "Nismo mogli da obradimo vašu izmenu zbog gubitka podataka sesije.\n\n<em>Budući da je na ovom vikiju omogućen unos HTML oznaka, pregled je sakriven kao mera predostrožnosti protiv napada preko javaskripta.</em>\n\n<strong>Ako ste pokušali da napravite pravu izmenu, pokušajte ponovo.<strong>\nAko i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite i proverite da li Vaš pregledač dozvoljava kolačiće sa ovog sajta.",
-       "token_suffix_mismatch": "<strong>Vaša izmena je odbačena jer je vaš pregledač ubacio znakove interpunkcije u novčić uređivanja.</strong>\nTo se ponekad događa kada se koristi neispravan posrednik.",
+       "session_fail_preview": "Izvinjavamo se! Nismo mogli da obradimo vašu izmenu zbog gubitka podataka sesije.\n\nMožda ste odjavljeni. <strong>Proverite da li ste prijavljeni i pokušajte ponovo</strong>.\nAko i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite, te proverite da li su na vašem pretraživaču dozvoljeni kolačići sa ovog sajta.",
+       "session_fail_preview_html": "Nismo mogli da obradimo vašu izmenu zbog gubitka podataka sesije.\n\n<em>Budući da je na ovom vikiju omogućen unos HTML oznaka, pregled je sakriven kao mera predostrožnosti protiv napada preko javaskripta.</em>\n\n<strong>Ako ste pokušali da napravite pravu izmenu, pokušajte ponovo.<strong>\nAko i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite i proverite da li vaš pregledač dozvoljava kolačiće sa ovog sajta.",
+       "token_suffix_mismatch": "<strong>Vaša izmena je odbijena jer je vaš klijent ubacio znakove interpunkcije u token uređivanja.</strong>\nIzmena je odbijena radi sprečavanja uništavanja teksta stranice.\nOvo se ponekad događa kada koristite problematični anonimni posrednik koji je zasnovan na vebu.",
        "edit_form_incomplete": "<strong>Neki delovi obrasca za uređivanje nisu stigli do servera. Proverite da li su vaše izmene nepromenjene i pokušajte ponovo.</strong>",
        "editing": "Uređujete $1",
        "creating": "Pravljenje stranice $1",
        "explainconflict": "Neko drugi je u međuvremenu promenio ovu stranicu.\nGornji okvir sadrži sadašnji tekst stranice.\nVaše izmene su prikazane u donjem okviru.\nMoraćete da unesete svoje promene u sadašnji tekst stranice.\n<strong>Samo</strong> će tekst u gornjem okviru za uređivanje biti sačuvan kada kliknete na „$1”.",
        "yourtext": "Vaš tekst",
        "storedversion": "Uskladištena izmena",
-       "editingold": "<strong>Upozorenje: uređujete zastarelu izmenu ove stranice.</strong>\nAko je sačuvate, sve novije izmene će biti izgubljene.",
+       "editingold": "<strong>Upozorenje: uređujete zastarelu izmenu ove stranice.</strong>\nAko je sačuvate, sve promene napravljene od ove izmene će biti izgubljene.",
        "unicode-support-fail": "Vaš pregledač ne podržava Unicode. On je neopohodan za uređivanje stranica, pa zato ne mogu sačuvati izmenu.",
        "yourdiff": "Razlike",
-       "copyrightwarning": "Imajte na umu da se svi doprinosi na ovom vikiju smatraju kao objavljeni pod licencom $2 (više na $1).\nAko ne želite da se vaši tekstovi menjaju i razmenjuju bez ograničenja, onda ih ne šaljite ovde.<br />\nIsto tako obećavate da ste Vi autor teksta, ili da ste ga umnožili s izvora koji je u javnom vlasništvu.\n<strong>Ne šaljite radove zaštićene autorskim pravima bez dozvole!</strong>",
+       "copyrightwarning": "Imajte na umu da se svi doprinosi na ovom vikiju smatraju kao objavljeni pod licencom $2 (više na $1).\nAko ne želite da se vaši tekstovi menjaju i razmenjuju bez ograničenja, onda ih ne šaljite ovde.<br />\nIsto tako obećavate da ste Vi autor teksta, ili da ste ga umnožili sa izvora koji je u javnom vlasništvu.\n<strong>Ne šaljite radove zaštićene autorskim pravima bez dozvole!</strong>",
        "copyrightwarning2": "Imajte na umu da se svi doprinosi na ovom vikiju mogu menjati, vraćati ili brisati od drugih korisnika.\nAko ne želite da se vaši tekstovi slobodno menjaju i raspodeljuju, ne šaljite ih ovde.<br />\nIsto tako obećavate da ste vi autor teksta, ili da ste ga umnožili s izvora koji je u javnom vlasništvu (više na $1).\n<strong>Ne šaljite radove zaštićene autorskim pravima bez dozvole!</strong>",
        "editpage-cannot-use-custom-model": "Model sadržaja ove stranice se ne može promeniti.",
        "longpageerror": "<strong>Greška: tekst koji ste uneli je veličine {{PLURAL:$1|jedan kilobajt|$1 kilobajta}}, što je veće od {{PLURAL:$2|dozvoljenog jednog kilobajta|dozvoljena $2 kilobajta|dozvoljenih $2 kilobajta}}.</strong>\nStranica ne može biti sačuvana.",
        "readonlywarning": "<strong>Upozorenje: baza podataka je zaključana radi održavanja, tako da trenutno nećete moći da sačuvate izmene.</strong>\nMožda biste želeli sačuvati tekst za kasnije u nekoj tekstualnoj datoteci.\n\nSistemski administrator je naveo sledeće objašnjenje: $1",
-       "protectedpagewarning": "<strong>Upozorenje: ova stranica je zaštićena, tako da samo administratori mogu da je menjaju.</strong>\nPoslednji zapis u dnevniku je prikazan ispod:",
-       "semiprotectedpagewarning": "<strong>Napomena:</strong> ova stranica je zaštićena, tako da samo registrovani korisnici mogu da je uređuju.\nPoslednji zapis u dnevniku je prikazan ispod kao referenca:",
-       "cascadeprotectedwarning": "<strong>Upozorenje:</strong> Ova stranica je zaštićena tako da je mogu uređivati samo korisnici sa [[Special:ListGroupRights|određenim pravima]] (administratori), jer je ista uključena u {{PLURAL:$1|sledeću stranicu koja je zaštićena|sledeće stranice koje su zaštićene}} „prenosivom” zaštitom:",
-       "titleprotectedwarning": "<strong>Upozorenje: ovu stranicu mogu napraviti samo korisnici [[Special:ListGroupRights|s određenim pravima]].</strong>\nPoslednji zapis u dnevniku je prikazan ispod:",
+       "protectedpagewarning": "<strong>Upozorenje: Ova stranica je zaštićena, tako da samo korisnici sa administratorskim ovlašćenjima mogu da je uređuju.</strong>\nNajnoviji unos u evidenciji je naveden ispod kao referenca:",
+       "semiprotectedpagewarning": "<strong>Napomena:</strong> Ova stranica je zaštićena, tako da samo automatski potvrđeni korisnici mogu da je uređuju.\nNajnoviji unos u evidenciji je naveden ispod kao referenca:",
+       "cascadeprotectedwarning": "<strong>Upozorenje:</strong> Ova stranica je zaštićena tako da samo korisnici sa [[Special:ListGroupRights|određenim pravima]] mogu da je uređuju, jer je uključena u {{PLURAL:$1|sledeću stranicu koja je zaštićena|sledeće stranice koje su zaštićene}} prenosivom zaštitom:",
+       "titleprotectedwarning": "<strong>Upozorenje: Ova stranica je zaštićena, tako da su potrebna [[Special:ListGroupRights|posebna prava]] da se ona napravi.</strong>\nNajnoviji unos u evidenciji je naveden ispod kao referenca:",
        "templatesused": "{{PLURAL:$1|Šablon koji se koristi|Šabloni koji se koriste}} na ovoj stranici:",
        "templatesusedpreview": "{{PLURAL:$1|Šablon|Šabloni}} u ovom pretpregledu:",
        "templatesusedsection": "{{PLURAL:$1|Šablon|Šabloni}} u ovom odeljku:",
        "sectioneditnotsupported-title": "Uređivanje odeljka nije podržano",
        "sectioneditnotsupported-text": "Uređivanje odeljka nije podržano na ovoj stranici.",
        "permissionserrors": "Greška u dozvoli",
-       "permissionserrorstext": "Nemate ovlašćenje za ovu radnju iz {{PLURAL:$1|1=sledećeg|sledećih}} razloga:",
-       "permissionserrorstext-withaction": "Nemate dozvolu za $2 iz {{PLURAL:$1|sledećeg|sledećih}} razloga:",
-       "contentmodelediterror": "Ne možete urediti ovu izmenu jer je njen model sadržaja <code>$1</code>, što se razlikuje od trenutnog modela sadržaja stranice <code>$2</code>.",
-       "recreate-moveddeleted-warn": "<strong>Upozorenje: ponovo pravite stranicu koja je prethodno obrisana.</strong>\n\nRazmotrite da li je prikladno da nastavite s uređivanjem ove stranice.\nOvde je navedena istorija brisanja i premeštanja s obrazloženjem:",
-       "moveddeleted-notice": "Ova stranica je obrisana.\nDnevnik brisanja, zaštite i premeštanja stranice nalazi se ispod.",
-       "moveddeleted-notice-recent": "Žao nam je, ova stranica je nedavno obrisana (u poslednjih 24 sata).\nIstorija njenog brisanja, zaštite i premeštanja nalazi se ispod:",
-       "log-fulllog": "Pogledaj celu istoriju",
+       "permissionserrorstext": "Nemate dozvolu za ovu radnju iz {{PLURAL:$1|sledećeg|sledećih}} razloga:",
+       "permissionserrorstext-withaction": "Nemate dozvolu da $2 iz {{PLURAL:$1|sledećeg|sledećih}} razloga:",
+       "contentmodelediterror": "Ne možete urediti ovu izmenu jer je njen model sadržaja <code>$1</code>, što se razlikuje od aktuelnog modela sadržaja stranice <code>$2</code>.",
+       "recreate-moveddeleted-warn": "<strong>Upozorenje: Ponovo pravite stranicu koja je prethodno izbrisana.</strong>\n\nRazmotrite da li je prikladno da nastavite sa uređivanjem ove stranice.\nOvde je navedena evidencija brisanja i premeštanja sa obrazloženjem:",
+       "moveddeleted-notice": "Ova stranica je izbrisana.\nEvidencija brisanja, zaštite i premeštanja stranice je navedena ispod kao referenca.",
+       "moveddeleted-notice-recent": "Nažalost, ova stranica je nedavno izbrisana (u poslednjih 24 sata).\nEvidencija brisanja, zaštite i premeštanja stranice navedena je ispod kao referenca:",
+       "log-fulllog": "Pogledaj celu evidenciju",
        "edit-hook-aborted": "Izmenu je prekinula kuka.\nNije dato nikakvo obrazloženje.",
-       "edit-gone-missing": "Ne mogu da ažuriram stranicu.\nIzgleda da je obrisana.",
+       "edit-gone-missing": "Ne mogu da ažuriram stranicu.\nIzgleda da je izbrisana.",
        "edit-conflict": "Sukob izmena.",
-       "edit-no-change": "Vaša izmena je zanemarena jer nije bilo nikakvih izmena u tekstu.",
+       "edit-no-change": "Vaša izmena je zanemarena jer nije bilo nikakvih promena u tekstu.",
        "postedit-confirmation-created": "Stranica je napravljena.",
        "postedit-confirmation-restored": "Stranica je vraćena.",
        "postedit-confirmation-saved": "Vaša izmena je sačuvana.",
        "edit-already-exists": "Ne mogu da napravim stranicu.\nIzgleda da ona već postoji.",
        "defaultmessagetext": "Podrazumevani tekst poruke",
        "content-failed-to-parse": "Ne mogu da raščlanim sadržaj tipa $2 za model $1: $3",
-       "invalid-content-data": "Neispravni podaci sadržaja",
+       "invalid-content-data": "Nevažeći podaci sadržaja",
        "content-not-allowed-here": "Sadržaj modela „$1“ nije dozvoljen na stranici [[$2]]",
        "editwarning-warning": "Ako napustite ovu stranicu, izgubićete sve izmene koje ste napravili. Ako ste prijavljeni, možete onemogućiti ovo upozorenje u svojim podešavanjima, u odeljku „{{int:prefs-editing}}“.",
        "editpage-invalidcontentmodel-title": "Model sadržaja nije podržan",
        "duplicate-args-warning": "<strong>Upozorenje:</strong> [[:$1]] poziva [[:$2]] sa više od jedne vrednosti za parametar „$3“. Samo poslednja navedena vrednost će biti korišćena.",
        "duplicate-args-category": "Stranice s dupliranim argumentima kod poziva šablona",
        "duplicate-args-category-desc": "Stranica sadrži pozive šablona koji koriste dvostruke argumente, kao što su <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ili <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
-       "expensive-parserfunction-warning": "<strong>Upozorenje:</strong> ova stranica sadrži previše poziva za raščlanjivanje.\n\nTrebalo bi da ima manje od $2 {{PLURAL:$2|poziv|poziva}}, a sada ima $1.",
+       "expensive-parserfunction-warning": "<strong>Upozorenje:</strong> Ova stranica sadrži previše poziva opterećujućih funkcija za raščlanjivanje.\n\nTrebalo bi da ima manje od $2 {{PLURAL:$2|poziv|poziva}}, a sada ima $1.",
        "expensive-parserfunction-category": "Stranice s previše poziva za raščlanjivanje",
        "post-expand-template-inclusion-warning": "<strong>Upozorenje:</strong> veličina obuhvaćenog šablona je prevelika.\nNeki šabloni neće biti obuhvaćeni.",
        "post-expand-template-inclusion-category": "Stranice gde su obuhvaćeni preveliki šabloni",
-       "post-expand-template-argument-warning": "'''Upozorenje:''' ova stranica sadrži najmanje jedan argument u šablonu koji ima preveliku veličinu.\nOvakve argumente bi trebalo izbegavati.",
+       "post-expand-template-argument-warning": "'''Upozorenje:''' Ova stranica sadrži najmanje jedan argument u šablonu koji ima preveliku veličinu.\nOvakvi argumenti trebaju da se izbegavaju.",
        "post-expand-template-argument-category": "Stranice koje sadrže izostavljene argumente u šablonu",
        "parser-template-loop-warning": "Otkrivena je petlja šablona: [[$1]]",
        "template-loop-category": "Stranice sa petljama šablona",
        "converter-manual-rule-error": "Pronađena je greška u pravilu za ručno pretvaranje jezika",
        "undo-success": "Izmena se može poništiti.\nProverite razlike ispod, pa sačuvajte izmene.",
        "undo-failure": "Ova izmena se ne može poništiti zbog sukoba izmena.",
-       "undo-norev": "Ne mogu da vratim izmenu jer ne postoji ili je obrisana.",
+       "undo-norev": "Ne mogu da vratim izmenu jer ne postoji ili je izbrisana.",
        "undo-nochange": "Izgleda da je izmena već poništena.",
-       "undo-summary": "Poništena izmena $1 {{GENDER:$2|korisnika|korisnice}} [[Special:Contribs/$2|$2]] ([[User talk:$2|razgovor]])",
+       "undo-summary": "Poništena izmena $1 {{GENDER:$2|korisnika|korisnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]])",
        "undo-summary-username-hidden": "Poništi izmenu $1 skrivenog korisnika",
        "cantcreateaccount-text": "Otvaranje naloga s ove IP adrese (<strong>$1</strong>) je blokirao/la [[User:$3|$3]].\n\nRazlog koji je naveo/la $3 je <em>$2</em>",
        "cantcreateaccount-range-text": "Otvaranje naloga sa IP adresa u rasponu <strong>$1</strong>, koji uključuje i vašu IP adresu (<strong>$4</strong>) je blokirao/la [[User:$3|$3]].\n\nRazlog koji je naveo/la $3 je <em>$2</em>",
-       "viewpagelogs": "Dnevnici ove stranice",
+       "viewpagelogs": "Evidencije ove stranice",
        "nohistory": "Ne postoji istorija izmena ove stranice.",
-       "currentrev": "Trenutna izmena",
-       "currentrev-asof": "Trenutna izmena na datum $2 u $3",
+       "currentrev": "Najnovija izmena",
+       "currentrev-asof": "Najnovija izmena na datum $2 u $3",
        "revisionasof": "Izmena na datum $2 u $3",
        "revision-info": "Izmena od $1 od strane {{GENDER:$6|korisnika $2|korisnice $2}}$7",
        "previousrevision": "← Starija izmena",
        "nextrevision": "Novija izmena →",
-       "currentrevisionlink": "Trenutna izmena",
+       "currentrevisionlink": "Najnovija izmena",
        "cur": "tren",
        "next": "sled",
        "last": "razl",
        "page_first": "prva",
        "page_last": "poslednja",
-       "histlegend": "Izbor razlika: izaberite kutijice izmena za upoređivanje i pritisnite enter ili dugme na dnu.<br />\nObjašnjenje: <strong>({{int:cur}})</strong> = razlika s trenutnom izmenom, <strong>({{int:last}})</strong> = razlika s prethodnom izmenom, <strong>{{int:minoreditletter}}</strong> = manja izmena",
+       "histlegend": "Izbor razlika: označite kutijice izmena za upoređivanje i pritisnite enter ili dugme na dnu.<br />\nObjašnjenje: <strong>({{int:cur}})</strong> = razlika sa najnovijom izmenom, <strong>({{int:last}})</strong> = razlika sa prethodnom izmenom, <strong>{{int:minoreditletter}}</strong> = manja izmena",
        "history-fieldset-title": "Pretraga izmena",
-       "history-show-deleted": "Samo obrisane izmene",
+       "history-show-deleted": "Samo izbrisane izmene",
        "histfirst": "najstarije",
        "histlast": "najnovije",
        "historysize": "({{PLURAL:$1|1 bajt|$1 bajta|$1 bajtova}})",
        "history-feed-title": "Istorija izmena",
        "history-feed-description": "Istorija izmena ove stranice na vikiju",
        "history-feed-item-nocomment": "$1 u $2",
-       "history-feed-empty": "Tražena stranica ne postoji.\nMoguće da je obrisana s vikija ili je preimenovana.\nPokušajte da [[Special:Search|pretražite viki]] za slične stranice.",
+       "history-feed-empty": "Tražena stranica ne postoji.\nMoguće da je izbrisana sa vikija ili je preimenovana.\nPokušajte da [[Special:Search|pretražite viki]] za relevantne nove stranice.",
        "history-edit-tags": "Uredi oznake izabranih izmena",
        "rev-deleted-comment": "(opis izmene uklonjen)",
        "rev-deleted-user": "(korisničko ime uklonjeno)",
        "rev-deleted-event": "(detalji unosa uklonjeni)",
        "rev-deleted-user-contribs": "[korisničko ime ili IP adresa je uklonjena – izmena je sakrivena sa spiska doprinosa]",
-       "rev-deleted-text-permission": "Izmena ove stranice je '''obrisana'''.\nDetalje možete videti u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].",
+       "rev-deleted-text-permission": "Izmena ove stranice je <strong>izbrisana</strong>.\nDetalje možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
        "rev-suppressed-text-permission": "Izmena ove stranice je <strong>sakrivena</strong>. Više detalja možete naći u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} istoriji sakrivanja].",
-       "rev-deleted-text-unhide": "Izmena ove stranice je '''obrisana'''.\nDetalje možete videti u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].\nIpak možete da [$1 vidite ovu izmenu] ako želite da nastavite.",
-       "rev-suppressed-text-unhide": "Izmena ove stranice je '''sakrivena'''.\nDetalje možete videti u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} istoriji sakrivanja].\nIpak možete da [$1 vidite ovu izmenu] ako želite da nastavite.",
+       "rev-deleted-text-unhide": "Izmena ove stranice je <strong>izbrisana</strong>.\nDetalje možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].\nIpak možete da [$1 pogledate ovu izmenu] ako želite da nastavite.",
+       "rev-suppressed-text-unhide": "Izmena ove stranice je <strong>sakrivena</strong>.\nDetalje možete da pronađete u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} evidenciji sakrivanja].\nIpak možete da [$1 pogledate ovu izmenu] ako želite da nastavite.",
        "rev-deleted-text-view": "Izmena ove stranice je '''obrisana'''.\nMožete je pogledati; više detalja možete naći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].",
-       "rev-suppressed-text-view": "Izmena ove stranice je '''sakrivena'''.\nMožete je pogledati; više detalja možete naći u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} istoriji sakrivanja].",
-       "rev-deleted-no-diff": "Ne možete videti ovu razliku jer je jedna od izmena '''obrisana'''.\nDetalji se nalaze u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].",
+       "rev-suppressed-text-view": "Izmena ove stranice je <strong>sakrivena</strong>.\nMožete je pogledati; detalje možete da pronađete u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} evidenciji sakrivanja].",
+       "rev-deleted-no-diff": "Ne možete da videte ovu razliku jer je jedna od izmena <strong>izbrisana</strong>.\nDetalji možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
        "rev-suppressed-no-diff": "Ne možete videti ovu razliku jer je jedna od izmena '''obrisana'''.",
-       "rev-deleted-unhide-diff": "Jedna od izmena u ovom pregledu razlika je '''obrisana'''.\nDetalji se nalaze u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].\nIpak možete da [$1 vidite ovu razliku] ako želite da nastavite.",
-       "rev-suppressed-unhide-diff": "Jedna od izmena ove razlike je '''sakrivena'''.\nDetalji se nalaze u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} istoriji sakrivanja].\nIpak možete da [$1 vidite ovu razliku] ako želite da nastavite.",
-       "rev-deleted-diff-view": "Jedna od izmena ove razlike je '''obrisana'''.\nIpak možete da vidite ovu razliku; više detalja možete naći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} istoriji brisanja].",
-       "rev-suppressed-diff-view": "Jedna od izmena ove razlike je '''sakrivena'''.\nIpak možete da vidite ovu razliku; više detalja možete naći u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} istoriji sakrivanja].",
+       "rev-deleted-unhide-diff": "Jedna od izmena u ovoj razlici je <strong>obrisana</strong>.\nDetalje možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].\nIpak možete da [$1 pogledate ovu razliku] ako želite da nastavite.",
+       "rev-suppressed-unhide-diff": "Jedna od izmena u ovoj razlici je <strong>sakrivena</strong>.\nViše informacija možete da pronađete u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} evidenciji sakrivanja].\nIpak možete da [$1 pogledate ovu razliku] ako želite da nastavite.",
+       "rev-deleted-diff-view": "Jedna od izmena u ovoj razlici je <strong>izbrisana</strong>.\nIpak možete da pogledate ovu razliku; detalje možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
+       "rev-suppressed-diff-view": "Jedna od izmena u ovoj razlici je <strong>sakrivena</strong>.\nIpak možete da pogledate ovu razliku; više informacija možete da pronađete u [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} evidenciji sakrivanja].",
        "rev-delundel": "promeni vidljivost",
        "rev-showdeleted": "prikaži",
-       "revisiondelete": "Obriši/vrati izmene",
-       "revdelete-nooldid-title": "Nema tražene izmene",
-       "revdelete-nooldid-text": "Niste izabrali odredišnu izmenu na kojoj treba da se izvrši ova funkcija, ta izmena ne postoji, ili pokušavate sakriti trenutnu izmenu.",
+       "revisiondelete": "Brisanje/vraćanje izmena",
+       "revdelete-nooldid-title": "Nevažeća odredišna izmena",
+       "revdelete-nooldid-text": "Niste naveli odredišnu izmenu na kojoj treba da se izvrši ova funkcija, ta izmena ne postoji, ili pokušavate da sakrijete aktuelnu izmenu.",
        "revdelete-no-file": "Tražena datoteka ne postoji.",
-       "revdelete-show-file-confirm": "Želite li da vidite obrisanu izmenu datoteke „<nowiki>$1</nowiki>“ od $2; $3?",
+       "revdelete-show-file-confirm": "Jeste li sigurni da želite da vidite izbrisanu izmenu datoteke „<nowiki>$1</nowiki>“ od $2; $3?",
        "revdelete-show-file-submit": "Da",
        "revdelete-selected-text": "{{PLURAL:$1|Izabrana izmena|Izabrane izmene|Izabranih izmena}} [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Izabrana verzija datoteke|Izabrane verzije datoteke}} [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Izabrana stavka u istoriji|Izabrane stavke u istoriji}}:",
        "revdelete-text-text": "Izbrisane izmene će i dalje biti vidljive u istoriji stranice, ali delovi njihovog sadržaja neće biti javno dostupni.",
        "revdelete-text-file": "Izbrisane verzije datoteke će i dalje biti vidljive u istoriji datoteke, ali delovi njihovog sadržaja neće biti javno dostupni.",
-       "logdelete-text": "Izbrisani unosi u dnevnicima će i dalje biti vidljivi u dnevnicima, ali delovi njihovog sadržaja neće biti javno dostupni.",
+       "logdelete-text": "Izbrisani događaji u evidencijama će se idalje pojavljivati u evidenciji, ali će delovi njihovog sadržaja biti nedostupni javnosti.",
        "revdelete-text-others": "Ostali administratori će i dalje moći da pristupe skrivenom sadržaju i vrate ga, osim ako se postave dodatna ograničenja.",
-       "revdelete-confirm": "Potvrdite da nameravate ovo uraditi, da razumete posledice i da to činite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
+       "revdelete-confirm": "Potvrdite da nameravate ovo uraditi, da razumete posledice i da to činite u skladu sa [[{{MediaWiki:Policy-url}}|pravilima]].",
        "revdelete-suppress-text": "Sakrivanje izmena bi trebalo koristiti <strong>samo</strong> u sledećim slučajevima:\n* zlonamerni ili pogrdni podaci\n* neprikladni lični podaci\n*: <em>kućna adresa i broj telefona, broj kreditne kartice, JMBG itd.</em>",
        "revdelete-legend": "Ograničenja vidljivosti",
        "revdelete-hide-text": "Tekst izmene",
        "revdelete-log": "Razlog:",
        "revdelete-submit": "Primeni na {{PLURAL:$1|izabranu izmenu|izabrane izmene}}",
        "revdelete-success": "Vidljivost izmene je ažurirana.",
-       "revdelete-failure": "'''Ne mogu da ažuriram vidljivost izmene:'''\n$1",
-       "logdelete-success": "Postavljena je vidljivost unosa u dnevniku.",
+       "revdelete-failure": "Ne mogu da ažuriram vidljivost izmene:\n$1",
+       "logdelete-success": "Postavljena je vidljivost unosa u evidenciji.",
        "logdelete-failure": "'''Ne mogu da postavim vidljivost istorije:'''\n$1",
        "revdel-restore": "promeni vidljivost",
        "pagehist": "Istorija stranice",
-       "deletedhist": "Obrisana istorija",
-       "revdelete-hide-current": "Greška pri sakrivanju stavke od $1, $2: ovo je trenutna izmena.\nNe može biti sakrivena.",
+       "deletedhist": "Izbrisana istorija",
+       "revdelete-hide-current": "Greška pri sakrivanju stavke od $1, $2: Ovo je aktuelna izmena.\nNe može da bude sakrivena.",
        "revdelete-show-no-access": "Greška pri prikazivanju stavke od $1, $2: označena je kao „ograničena“.\nNemate pristup do nje.",
        "revdelete-modify-no-access": "Greška pri menjanju stavke od $1, $2: označena je kao „ograničena“.\nNemate pristup do nje.",
        "revdelete-modify-missing": "Greška pri menjanju IB stavke $1: ona ne postoji u bazi podataka.",
        "revdelete-no-change": "<strong>Upozorenje:</strong> stavka od $1, $2 već poseduje zatražena podešavanja vidljivosti.",
-       "revdelete-concurrent-change": "Greška pri menjanju stavke od $1, $2: njeno stanje je u međuvremenu promenjeno od strane drugog korisnika.\nPogledajte istoriju.",
+       "revdelete-concurrent-change": "Greška pri menjanju stavke od $1, $2: njen status je u međuvremenu promenio drugi korisnik.\nProverite evidenciju.",
        "revdelete-only-restricted": "Greška pri sakrivanju stavke od $1, $2: ne možete sakriti stavke od administratora bez izbora drugih mogućnosti vidljivosti.",
        "revdelete-reason-dropdown": "*Uobičajeni razlozi za brisanje\n** Kršenje autorskog prava\n** Neprikladan komentar ili lični podaci\n** Neprikladno korisničko ime\n** Uvredljivi podaci",
        "revdelete-otherreason": "Drugi/dodatni razlog:",
        "revdelete-reasonotherlist": "Drugi razlog",
        "revdelete-edit-reasonlist": "Uredi razloge za brisanje",
        "revdelete-offender": "Autor izmene:",
-       "suppressionlog": "Dnevnik sakrivanja",
-       "suppressionlogtext": "Ispod se nalazi spisak brisanja i blokiranja koji uključuje sadržaj sakriven od administratora. Tekuće zabrane i blokiranja možete naći [[Special:BlockList|ovde]].",
-       "mergehistory": "Spoji istorije stranica",
-       "mergehistory-header": "Ova stranica vam omogućava da spojite izmene neke izvorne stranice u novu stranicu.\nZapamtite da će ova izmena ostaviti nepromenjen sadržaj istorije stranice.",
+       "suppressionlog": "Evidencija sakrivanja",
+       "suppressionlogtext": "Ispod se nalazi spisak brisanja i blokiranja koji uključuje sadržaj sakriven od administratora. Pogledajte [[Special:BlockList|spisak blokiranja]] za spisak aktuelnih operacija zabrana i blokiranja.",
+       "mergehistory": "Spajanje istorija stranice",
+       "mergehistory-header": "Ova stranica vam omogućava da spojite izmene neke izvorne stranice u novu stranicu.\nZapamtite da će ova promena ostaviti nepromenjen sadržaj istorije stranice.",
        "mergehistory-box": "Spoji izmene dve stranice:",
        "mergehistory-from": "Izvorna stranica:",
        "mergehistory-into": "Odredišna stranica:",
        "mergehistory-list": "Spojiva istorija izmena",
-       "mergehistory-merge": "Sledeće izmene stranice [[:$1]] mogu se spojiti sa [[:$2]].\nKoristite dugmiće u koloni da biste spojili izmene koje su napravljene pre navedenog vremena.\nKorišćenje navigacionih veza će poništiti ovu kolonu.",
+       "mergehistory-merge": "Sledeće izmene stranice [[:$1]] mogu se spojiti sa [[:$2]].\nKoristite dugmiće u koloni da biste spojili izmene koje su napravljene pre navedenog vremena.\nKorišćenje navigacionih linkova će poništiti ovu kolonu.",
        "mergehistory-go": "Prikaži izmene koje se mogu spojiti",
        "mergehistory-submit": "Spoji izmene",
        "mergehistory-empty": "Nema izmena za spajanje.",
        "mergehistory-done": "$3 {{PLURAL:$3|izmena stranice $1 je spojena|izmene stranice $1 su spojene|izmena stranice $1 je spojeno}} u [[:$2]].",
        "mergehistory-fail": "Ne mogu da spojim istorije. Proverite stranicu i vremenske parametre.",
-       "mergehistory-fail-bad-timestamp": "Vremenska oznaka nije ispravna.",
-       "mergehistory-fail-invalid-source": "Izvorna stranica nije ispravna.",
-       "mergehistory-fail-invalid-dest": "Odredišna stranica nije ispravna.",
+       "mergehistory-fail-bad-timestamp": "Vremenska oznaka je nevažeća.",
+       "mergehistory-fail-invalid-source": "Izvorna stranica nije validna.",
+       "mergehistory-fail-invalid-dest": "Odredišna stranica je nevažeća.",
        "mergehistory-fail-no-change": "Spajanje istorije nije spojilo nijednu izmenu. Proverite parametre stranice i vremena.",
        "mergehistory-fail-permission": "Nemate ovlašćenje za spajanje istorije.",
        "mergehistory-fail-self-merge": "Izvorna i odredišna stranica ne mogu biti iste.",
        "mergehistory-fail-timestamps-overlap": "Izvorne izmene se preklapaju ili dolaze nakon odredišnih izmena.",
-       "mergehistory-fail-toobig": "Nije moguće spojiti istorije jer više od $1 {{PLURAL:$1|izmene će biti premeštene|izmena će biti premešteno}}.",
+       "mergehistory-fail-toobig": "Ne mogu da izvršim spajanje istorije jer će više od $1 {{PLURAL:$1|izmene biti premeštene|izmena biti premešteno}}.",
        "mergehistory-no-source": "Izvorna stranica $1 ne postoji.",
        "mergehistory-no-destination": "Odredišna stranica $1 ne postoji.",
-       "mergehistory-invalid-source": "Izvorna stranica mora imati ispravan naslov.",
-       "mergehistory-invalid-destination": "Odredišna stranica mora imati ispravan naslov.",
+       "mergehistory-invalid-source": "Izvorna stranica mora imati validan naslov.",
+       "mergehistory-invalid-destination": "Odredišna stranica mora da ima važeći naslov.",
        "mergehistory-autocomment": "Stranica [[:$1]] je spojena u [[:$2]]",
        "mergehistory-comment": "Stranica [[:$1]] je spojena u [[:$2]]: $3",
        "mergehistory-same-destination": "Izvorna i odredišna stranica ne mogu biti iste",
        "mergehistory-reason": "Razlog:",
-       "mergelog": "Dnevnik spajanja",
+       "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
+       "mergelog": "Evidencija spajanja",
        "revertmerge": "rastavi",
        "mergelogpagetext": "Ispod je spisak najskorijih spajanja istorija dveju stranica.",
        "history-title": "Istorija izmena stranice „$1“",
        "showhideselectedversions": "Promeni vidljivost izabranih izmena",
        "editundo": "poništi",
        "diff-empty": "(nema razlike)",
-       "diff-multi-sameuser": "({{PLURAL:$1|Jedna međuizmena istog korisnika nije prikazana|$1 međuizmene istog korisnika nisu prikazane|$1 međuizmena istog korisnika nije prikazano}})",
+       "diff-multi-sameuser": "({{PLURAL:$1|Jedna međuizmena istog korisnika nije prikazana|$1 međuizmena istog korisnika nisu prikazane|$1 međuizmena istog korisnika nije prikazano}})",
        "diff-multi-otherusers": "({{PLURAL:$1|Jedna međuizmena|$1 međuizmene|$1 međuizmena}} od strane {{PLURAL:$2|još jednog korisnika nije prikazana|$2 korisnika nije prikazano}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Nije prikazana međuizmena|Nisu prikazane $1 međuizmene|Nije prikazano $1 međuizmena}} od više od $2 korisnika)",
-       "diff-paragraph-moved-tonew": "Odlomak je premešten. Kliknite da pređete na njegovo novo mesto.",
-       "diff-paragraph-moved-toold": "Odlomak je premešten. Kliknite da pređete na njegovo staro mesto.",
-       "difference-missing-revision": "Ne mogu da pronađem {{PLURAL:$2|jednu izmenu|$2 izmene|$2 izmena}} od ove razlike ($1).\n\nOvo se obično dešava kada pratite zastarelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
+       "diff-paragraph-moved-tonew": "Pasus je premešten. Kliknite da pređete na novu lokaciju.",
+       "diff-paragraph-moved-toold": "Pasus je premešten. Kliknite da pređete na staru lokaciju.",
+       "difference-missing-revision": "{{PLURAL:$2|Jedna izmena|$2 izmene}} ove razlike ($1) ne {{PLURAL:$2|postoji|postoje}}.\n\nOvo se obično dešava kada pratite zastareli link do stranice koja je izbrisana.\nDetalje možete da pronađete u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
        "searchresults": "Rezultati pretrage",
+       "search-filter-title-prefix-reset": "Pretraži sve stranice",
        "searchresults-title": "Rezultati pretrage za „$1“",
        "titlematches": "Naslov stranice odgovara",
        "textmatches": "Tekst stranice odgovara",
        "powersearch-togglelabel": "Izaberi:",
        "powersearch-toggleall": "Sve",
        "powersearch-togglenone": "Ništa",
-       "powersearch-remember": "Zapamti moj izbor za buduće pretrage",
+       "powersearch-remember": "Zapamti izbor za buduće pretrage",
        "search-external": "Spoljašnja pretraga",
        "searchdisabled": "Pretraga je onemogućena.\nU međuvremenu možete tražiti preko Gugla.\nUpamtite da njegovi popisi ovog vikija mogu biti zastareli.",
        "search-error": "Došlo je do greške prilikom pretrage: $1",
        "datedefault": "Svejedno",
        "prefs-labs": "Probne mogućnosti",
        "prefs-user-pages": "Korisničke stranice",
-       "prefs-personal": "Profil",
+       "prefs-personal": "Korisnički profil",
        "prefs-rc": "Skorašnje izmene",
        "prefs-watchlist": "Spisak nadgledanja",
        "prefs-editwatchlist": "Uređivanje spiska nadgledanja",
-       "prefs-editwatchlist-label": "Uređivanje spiska:",
-       "prefs-editwatchlist-edit": "uredi spisak",
-       "prefs-editwatchlist-raw": "uredi sirov spisak",
-       "prefs-editwatchlist-clear": "isprazni spisak",
+       "prefs-editwatchlist-label": "Uredi unose na spisku nadgledanja:",
+       "prefs-editwatchlist-edit": "pogledajte i uklonite naslove sa spiska nadgledanja",
+       "prefs-editwatchlist-raw": "uredi sirov spisak nadgledanja",
+       "prefs-editwatchlist-clear": "očisti spisak nadgledanja",
        "prefs-watchlist-days": "Broj dana u spisku nadgledanja:",
        "prefs-watchlist-days-max": "Najviše $1 {{PLURAL:$1|dan|dana|dana}}",
-       "prefs-watchlist-edits": "Najveći broj izmena prikazanih na spisku nadgledanja:",
+       "prefs-watchlist-edits": "Najveći broj promena prikazanih na spisku nadgledanja:",
        "prefs-watchlist-edits-max": "Najveći broj: 1000",
-       "prefs-watchlist-token": "Žeton spiska nadgledanja:",
+       "prefs-watchlist-token": "Token spiska nadgledanja:",
        "prefs-watchlist-managetokens": "Upravljaj žetonima",
-       "prefs-misc": "Druga podešavanja",
+       "prefs-misc": "Razno",
        "prefs-resetpass": "promeni lozinku",
-       "prefs-changeemail": "promeni ili ukloni imejl adresu",
-       "prefs-setemail": "postavi imejl adresu",
+       "prefs-changeemail": "promeni ili ukloni imejl-adresu",
+       "prefs-setemail": "postavi imejl-adresu",
        "prefs-email": "Opcije imejla",
        "prefs-rendering": "Izgled",
        "saveprefs": "Sačuvaj",
-       "restoreprefs": "Vrati sva podrazumevana podešavanja (u svim odeljcima)",
+       "restoreprefs": "Vrati sva podešavanja na podrazumevane vrednosti (u svim odeljcima)",
        "prefs-editing": "Uređivanje",
        "searchresultshead": "Pretraga",
-       "stub-threshold": "Prag za oblikovanje veze kao klice ($1):",
+       "stub-threshold": "Prag za oblikovanje linkova kao klice ($1):",
        "stub-threshold-sample-link": "primer",
        "stub-threshold-disabled": "onemogućeno",
        "recentchangesdays": "Broj dana u skorašnjim izmenama:",
        "recentchangesdays-max": "Najviše $1 {{PLURAL:$1|dan|dana}}",
-       "recentchangescount": "Podrazumevani broj izmena za prikaz u skorašnjim izmenama, istorijama stranica i dnevnicima:",
-       "prefs-help-recentchangescount": "Najveća broj: 1000",
-       "prefs-help-watchlist-token2": "Ovo je tajni ključ za veb-dovod Vašeg spiska nadgledanja. \nSvako ko zna ovaj ključ biće u mogućnosti da čita Vaš spisak nadgledanja, zato ga nemojte deliti. \nAko je potrebno, [[Special:ResetTokens|možete ga obnoviti]].",
+       "recentchangescount": "Podrazumevani broj izmena za prikaz u skorašnjim izmenama, istorijama stranica i evidencijama:",
+       "prefs-help-recentchangescount": "Najveći broj: 1000",
+       "prefs-help-watchlist-token2": "Ovo je tajni ključ za veb-fid vašeg spiska nadgledanja. \nSvako ko zna ovaj ključ biće u mogućnosti da čita vaš spisak nadgledanja, zato ga nemojte deliti. \nAko je potrebno, [[Special:ResetTokens|možete da ga resetujete]].",
        "savedprefs": "Vaša podešavanja su sačuvana.",
-       "savedrights": "Korisničke grupe za {{GENDER:$1|$1}} su sačuvane.",
+       "savedrights": "Korisničke grupe {{GENDER:$1|korisnika|korisnice}} $1 su sačuvane.",
        "timezonelegend": "Vremenska zona:",
        "localtime": "Lokalno vreme:",
        "timezoneuseserverdefault": "podrazumevane vrednosti ($1)",
        "prefs-files": "Datoteke",
        "prefs-custom-css": "prilagođeni CSS",
        "prefs-custom-json": "Prilagođeni JSON",
-       "prefs-custom-js": "prilagođeni Javaskript",
-       "prefs-common-config": "Deljeni CSS/JSON/Javaskript za sve teme:",
-       "prefs-reset-intro": "Možete koristiti ovu stranicu da poništite svoja podešavanja na podrazumevane vrednosti.\nOva radnja se ne može vratiti.",
+       "prefs-custom-js": "prilagođeni JavaScript",
+       "prefs-common-config": "Deljeni CSS/JSON/javaskript za sve teme:",
+       "prefs-reset-intro": "Možete koristiti ovu stranicu da ponovo postavite svoja podešavanja na podrazumevane vrednosti sajta.\nOvo se ne može opozvati.",
        "prefs-emailconfirm-label": "Potvrda imejla:",
        "youremail": "Imejl:",
        "username": "{{GENDER:$1|Korisničko ime}}:",
-       "prefs-memberingroups": "{{GENDER:$2|Član|Članica}} {{PLURAL:$1|grupe|grupâ}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Član|Članica}} {{PLURAL:$1|grupe|grupa}}:",
        "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (do $2)",
        "prefs-registration": "Vreme registracije:",
        "yourvariant": "Varijanta jezika:",
        "prefs-help-variant": "Željena varijanta ili pravopis za prikaz stranica sa sadržajem ovog vikija.",
        "yournick": "Novi potpis:",
-       "prefs-help-signature": "Komentari na stranicama za razgovor treba da budu potpisani sa „<nowiki>~~~~</nowiki>“ koje će biti pretvoreno u Vaš potpis s trenutnim vremenom.",
-       "badsig": "Potpis je neispravan.\nProverite oznake HTML.",
+       "prefs-help-signature": "Komentari na stranicama za razgovor treba da budu potpisani sa „<nowiki>~~~~</nowiki>“ koje će biti pretvoreno u vaš potpis i vremensku oznaku.",
+       "badsig": "Nevažeći sirov potpis.\nProverite HTML tagove.",
        "badsiglength": "Vaš potpis je predugačak.\nNe sme biti duži od $1 {{PLURAL:$1|znaka|znaka|znakova}}.",
        "yourgender": "Kako želite da se predstavite?",
-       "gender-unknown": "Kad Vas spominje, softver će koristiti rodno neutralne reči kad god je to moguće",
+       "gender-unknown": "Kad vas spominje, softver će koristiti rodno neutralne reči kad god je to moguće",
        "gender-male": "On uređuje viki stranice",
        "gender-female": "Ona uređuje viki stranice",
-       "prefs-help-gender": "Postavljanje ovog podešavanja je neobavezno.\nSoftver koristi datu vrednost da bi Vam se obratio i spomenuo Vas drugima koristeći odgovarajući gramatički rod.\nOva informacija će biti javna.",
+       "prefs-help-gender": "Postavljanje ovog podešavanja je opcionalno.\nSoftver koristi datu vrednost da bi vam se obratio i spomenuo vas drugima koristeći odgovarajući gramatički rod.\nOva informacija će biti javna.",
        "email": "Imejl",
-       "prefs-help-realname": "Pravo ime nije obavezno.\nAko izaberete da ga unesete, ono će biti korišćeno za pripisivanje vašeg rada.",
-       "prefs-help-email": "Imejl adresa nije obavezna, ali je potrebna za obnavljanje lozinke, ako je zaboravite.",
-       "prefs-help-email-others": "Takođe možete izabrati da dopustite drugima da Vas kontaktiraju preko imejla putem veze na Vašoj korisničkoj stranici ili stranici za razgovor.\nVaša imejl adresa neće biti prikazana drugim korisnicima koji Vas kontaktiraju.",
-       "prefs-help-email-required": "Potrebna je imejl adresa.",
+       "prefs-help-realname": "Pravo ime je opcionalno.\nAko je navedeno, biće korišćeno za pripisivanje vašeg rada.",
+       "prefs-help-email": "Imejl adresa je opcionalna, ali je potrebna za resetovanje lozinke, ako je zaboravite.",
+       "prefs-help-email-others": "Takođe možete izabrati da dopustite drugima da vas kontaktiraju preko imejla putem linka na vašoj korisničkoj stranici ili stranici za razgovor.\nVaša imejl adresa neće biti prikazana drugim korisnicima koji vas kontaktiraju.",
+       "prefs-help-email-required": "Imejl-adresa je neophodna.",
        "prefs-info": "Osnovne informacije",
        "prefs-i18n": "Internacionalizacija",
        "prefs-signature": "Potpis",
        "prefs-advancedwatchlist": "Napredne opcije",
        "prefs-displayrc": "Podešavanja prikaza",
        "prefs-displaywatchlist": "Podešavanja prikaza",
-       "prefs-tokenwatchlist": "Žeton",
+       "prefs-tokenwatchlist": "Token",
        "prefs-diffs": "Razlike",
        "prefs-help-prefershttps": "Ova podešavanja će stupiti na snagu pri sledećoj prijavi.",
-       "prefswarning-warning": "Promenili ste vaša podešavanja ali niste ih još sačuvali.\nAko ne pritisnete „$1“ vaša podešavanja će biti izgubljena.",
+       "prefswarning-warning": "Napravili ste promene u podešavanjima koje još uvek nisu sačuvane.\nAko napustite ovu stranicu bez klika na „$1“, podešavanja neće da budu ažurirana.",
        "prefs-tabs-navigation-hint": "Savet: možete koristiti tipke sa levom i desnom strelicom za kretanje kroz kartice.",
        "userrights": "Korisnička prava",
-       "userrights-lookup-user": "Izaberi korisnika",
+       "userrights-lookup-user": "Izbor korisnika",
        "userrights-user-editname": "Korisničko ime:",
        "editusergroup": "Učitaj korisničke grupe",
        "editinguser": "Menjate korisnička prava {{GENDER:$1|korisnika|korisnice}} <strong>[[User:$1|$1]]</strong> $2",
        "viewinguserrights": "Korisnička prava {{GENDER:$1|korisnika|korisnice}} <strong>[[User:$1|$1]]</strong> $2",
-       "userrights-editusergroup": "Promena {{GENDER:$1|korisničkih}} grupa",
-       "userrights-viewusergroup": "Pregled {{GENDER:$1|korisničkih}} grupa",
+       "userrights-editusergroup": "Uređivanje {{GENDER:$1|korisničkih}} grupa",
+       "userrights-viewusergroup": "Prikaz {{GENDER:$1|korisničkih}} grupa",
        "saveusergroups": "Sačuvaj {{GENDER:$1|korisničke}} grupe",
-       "userrights-groupsmember": "Član:",
-       "userrights-groupsmember-auto": "Podrazumevano član i:",
+       "userrights-groupsmember": "Član grupa:",
+       "userrights-groupsmember-auto": "{{GENDER:$2|Implicitan član|Implicitna članica}} grupa:",
+       "userrights-groupsmember-type": "$1",
        "userrights-groups-help": "Možete promeniti grupe kojima ovaj korisnik pripada:\n* Označen kvadratić označava da se korisnik nalazi u toj grupi.\n* Neoznačen kvadratić označava da se korisnik ne nalazi u toj grupi.\n* Zvezdica (*) označava da ne možete ukloniti tu grupu ako je dodate i obratno.\n* Taraba (#) označava da jedino možete odložiti vreme isteka članstva u toj grupi; ne možete ga ubrzati.",
        "userrights-reason": "Razlog:",
-       "userrights-no-interwiki": "Nemate ovlašćenja da menjate korisnička prava na drugim vikijima.",
+       "userrights-no-interwiki": "Nemate dozvolu da uređujete korisnička prava na drugim vikijima.",
        "userrights-nodatabase": "Baza podataka $1 ne postoji ili nije lokalna.",
        "userrights-changeable-col": "Grupe koje možete da promenite",
        "userrights-unchangeable-col": "Grupe koje ne možete da promenite",
        "userrights-irreversible-marker": "$1*",
+       "userrights-no-shorten-expiry-marker": "$1#",
        "userrights-expiry-current": "Ističe $1",
        "userrights-expiry-none": "Ne ističe",
        "userrights-expiry": "Ističe:",
        "userrights-expiry-existing": "Postojeće vreme isteka: $3, $2",
        "userrights-expiry-othertime": "Drugo vreme:",
        "userrights-expiry-options": "1 dan:1 day,1 nedelja:1 week,1 mesec:1 month,3 meseca:3 months,6 meseci:6 months,1 godina:1 year",
-       "userrights-invalid-expiry": "Vreme isticanja grupe „$1“ nije ispravno.",
+       "userrights-invalid-expiry": "Vreme isticanja grupe „$1“ je nevažeće.",
        "userrights-expiry-in-past": "Vreme isticanja grupe „$1“ je prošlo.",
        "userrights-cannot-shorten-expiry": "Ne možete ubrzati istek članstva u grupi „$1”. Samo korisnici sa dozvolom da dodaju ili uklone ovu grupu mogu da ubrzaju rok isteka.",
-       "userrights-conflict": "Sukob promena korisničkih prava! Molimo proverite vaše izmene.",
+       "userrights-conflict": "Sukob promena korisničkih prava! Pregledajte i proverite vaše promene.",
        "group": "Grupa:",
        "group-user": "Korisnici",
        "group-autoconfirmed": "Automatski potvrđeni korisnici",
        "group-bot": "Botovi",
        "group-sysop": "Administratori",
+       "group-interface-admin": "Administratori interfejsa",
        "group-bureaucrat": "Birokrate",
        "group-suppress": "Revizori",
        "group-all": "(svi)",
        "group-user-member": "{{GENDER:$1|korisnik|korisnica|korisnik}}",
        "group-autoconfirmed-member": "{{GENDER:$1|automatski potvrđen korisnik|automatski potvrđena korisnica}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
-       "group-sysop-member": "{{GENDER:$1|administrator|administratorka|administrator}}",
+       "group-sysop-member": "{{GENDER:$1|administrator|administratorka}}",
+       "group-interface-admin-member": "{{GENDER:$1|administrator interfejsa|administratorka interfejsa}}",
        "group-bureaucrat-member": "{{GENDER:$1|birokrata|birokratkinja}}",
        "group-suppress-member": "{{GENDER:$1|brisač izmena}}",
        "grouppage-user": "{{ns:project}}:Korisnici",
        "grouppage-autoconfirmed": "{{ns:project}}:Automatski potvrđeni korisnici",
        "grouppage-bot": "{{ns:project}}:Botovi",
        "grouppage-sysop": "{{ns:project}}:Administratori",
+       "grouppage-interface-admin": "{{ns:project}}:Administratori interfejsa",
        "grouppage-bureaucrat": "{{ns:project}}:Birokrate",
-       "grouppage-suppress": "{{ns:project}}:Revizor",
+       "grouppage-suppress": "{{ns:project}}:Brisači izmena",
        "right-read": "čitanje stranica",
        "right-edit": "uređivanje stranica",
        "right-createpage": "pravljenje stranica (izuzev stranica za razgovor)",
        "right-autocreateaccount": "Prijavite se automatski sa eksternim korisničkim nalogom",
        "right-minoredit": "označavanje izmena manjim",
        "right-move": "premeštanje stranica",
-       "right-move-subpages": "premeštanje stranica s njihovim podstranicama",
+       "right-move-subpages": "premeštanje stranica sa njihovim podstranicama",
        "right-move-rootuserpages": "premeštanje osnovnih korisničkih stranica",
        "right-move-categorypages": "premeštanje kategorija",
        "right-movefile": "premeštanje datoteka",
        "right-bot": "smatranje izmena kao automatski proces",
        "right-nominornewtalk": "neposedovanje manjih izmena na stranicama za razgovor otvara prozor za nove poruke",
        "right-apihighlimits": "korišćenje viših granica za upite iz API-ja",
-       "right-writeapi": "mogućnost pisanja API-ja",
+       "right-writeapi": "korišćenje API-ja za pisanje",
        "right-delete": "brisanje stranica",
-       "right-bigdelete": "brisanje stranica s velikom istorijom",
-       "right-deletelogentry": "brisanje i vraćanje određenih stavki u dnevniku",
+       "right-bigdelete": "brisanje stranica sa velikom istorijom",
+       "right-deletelogentry": "brisanje i vraćanje određenih unosa u evidenciji",
        "right-deleterevision": "brisanje i vraćanje određenih izmena stranica",
-       "right-deletedhistory": "pregledanje obrisanih stavki istorije bez povezanog teksta",
-       "right-deletedtext": "pregledanje obrisanog teksta i izmena između obrisanih izmena",
-       "right-browsearchive": "pretraga obrisanih stranica",
-       "right-undelete": "vraćanje obrisanih stranica",
+       "right-deletedhistory": "pregledanje izbrisanih stavki istorije bez povezanog teksta",
+       "right-deletedtext": "pregledanje izbrisanog teksta i promena između izbrisanih izmena",
+       "right-browsearchive": "pretraga izbrisanih stranica",
+       "right-undelete": "vraćanje izbrisanih stranica",
        "right-suppressrevision": "pregledanje, skrivanje i vraćanje određenih izmena stranica od svih korisnika",
        "right-viewsuppressed": "pregledanje izmena skrivenih od svih korisnika",
-       "right-suppressionlog": "pregledanje privatnih dnevnika",
+       "right-suppressionlog": "pregledanje privatnih evidencija",
        "right-block": "blokiranje daljih izmena drugih korisnika",
        "right-blockemail": "blokiranje korisnika da šalju imejl",
        "right-hideuser": "blokiranje korisničkog imena i njegovo sakrivanje od javnosti",
-       "right-ipblock-exempt": "zaobilaženje blokiranja IP adrese, automatska blokiranja i blokiranja opsega",
+       "right-ipblock-exempt": "zaobilaženje IP blokada, autoblokada i blokada opsega",
        "right-unblockself": "deblokiranje samog sebe",
-       "right-protect": "menjanje stepena zaštite i uređivanje stranica pod prenosivom zaštitom",
+       "right-protect": "menjanje nivoa zaštite i uređivanje stranica pod prenosivom zaštitom",
        "right-editprotected": "uređivanje stranica pod zaštitom „{{int:protect-level-sysop}}“",
        "right-editsemiprotected": "uređivanje stranica pod zaštitom „{{int:protect-level-autoconfirmed}}“",
        "right-editcontentmodel": "menjanje modela sadržaja stranice",
        "right-editmyuserjs": "uređivanje sopstvenih JavaScript datoteka",
        "right-viewmywatchlist": "pregled sopstvenog spiska nadgledanja",
        "right-editmywatchlist": "uređivanje sopstvenog spiska nadgledanja; neke preduzete radnje će svejedno dodati stranice na spisak i bez ovog prava",
-       "right-viewmyprivateinfo": "pregled svojih ličnih podataka (npr. imejl adresu, pravo ime)",
-       "right-editmyprivateinfo": "uređivanje sopstvenih ličnih podataka (npr. imejl adrese, pravog imena)",
+       "right-viewmyprivateinfo": "pregled svojih privatnih podataka (npr. imejl-adresu, pravo ime)",
+       "right-editmyprivateinfo": "uređivanje sopstvenih privatnih podataka (npr. imejl-adrese, pravog imena)",
        "right-editmyoptions": "uređivanje sopstvenih podešavanja",
        "right-rollback": "brzo vraćanje izmena poslednjeg korisnika koji je menjao određenu stranicu",
        "right-markbotedits": "označavanje vraćenih izmena kao izmene bota",
        "right-userrights": "uređivanje svih korisničkih prava",
        "right-userrights-interwiki": "uređivanje korisničkih prava na drugim vikijima",
        "right-siteadmin": "zaključavanje i otključavanje baze podataka",
-       "right-override-export-depth": "izvoz stranica uključujući i povazene stranice do dubine od pet veza",
+       "right-override-export-depth": "izvoz stranica uključujući i povazene stranice do dubine od pet linkova",
        "right-sendemail": "slanje imejla drugim korisnicima",
        "right-managechangetags": "pravljenje i (de)aktiviranje [[Special:Tags|oznaka]]",
-       "right-applychangetags": "primenjivanje [[Special:Tags|oznaka]] na nečije izmene",
-       "right-changetags": "dodavanje i uklanjanje raznih [[Special:Tags|oznaka]] na pojedinačnim izmenama i unosima u dnevnicima",
+       "right-applychangetags": "primenjivanje [[Special:Tags|oznaka]] na nečije promene",
+       "right-changetags": "dodavanje i uklanjanje raznih [[Special:Tags|oznaka]] na pojedinačnim izmenama i unosima u evidencijama",
        "right-deletechangetags": "brisanje [[Special:Tags|oznaka]] iz baze podataka",
        "grant-generic": "Skup prava „$1“",
        "grant-group-page-interaction": "Uređivanje stranica",
        "grant-group-high-volume": "Izvršavanje velikog broja radnji",
        "grant-group-customization": "Prilagođavanje i podešavanja",
        "grant-group-administration": "Izvršavanje administrativnih radnji",
-       "grant-group-private-information": "Pristupanje Vašim ličnim podacima",
+       "grant-group-private-information": "Pristupanje vašim privatnim podacima",
        "grant-group-other": "Razne aktivnosti",
        "grant-blockusers": "Blokiranje i deblokiranje korisnika",
        "grant-createaccount": "Otvaranje naloga",
        "grant-createeditmovepage": "Pravljenje, uređivanje i premeštanje stranica",
-       "grant-delete": "Brisanje stranica, izmena i unosa u dnevnicima",
-       "grant-editinterface": "Uređivanje Medijaviki imenskog prostora i korisničkih CSS/JSON/Javaskript stranica",
+       "grant-delete": "Brisanje stranica, izmena i unosa u evidencijama",
+       "grant-editinterface": "Uređivanje imenskog prostora Medijaviki i JSON-a sajta/korisnika",
        "grant-editmycssjs": "Uređivanje vašeg CSS/JSON/Javaskripta",
-       "grant-editmyoptions": "Uređivanje Vaših podešavanja",
+       "grant-editmyoptions": "Uređivanje vaših korisničkih podešavanja",
        "grant-editmywatchlist": "Uređivanje vašeg spiska nadgledanja",
        "grant-editpage": "Uređivanje postojećih stranica",
        "grant-editprotected": "Uređivanje zaštićenih stranica",
        "grant-highvolume": "Masovno uređivanje",
        "grant-oversight": "Skrivanje korisnika i izmena",
-       "grant-patrol": "Patroliranje izmena",
+       "grant-patrol": "Patroliranje promena na stranicama",
        "grant-privateinfo": "Pristupi privatnim informacijama",
        "grant-protect": "Zaključavanje i otključavanje stranica",
-       "grant-rollback": "Vraćanje izmena",
+       "grant-rollback": "Vraćanje promena na stranicama",
        "grant-sendemail": "Slanje imejlova drugim korisnicima",
        "grant-uploadeditmovefile": "Otpremanje, zamena i premeštanje datoteka",
        "grant-uploadfile": "Otpremanje novih datoteka",
        "grant-basic": "Osnovna prava",
-       "grant-viewdeleted": "Pregled obrisanih stranica i datoteka",
+       "grant-viewdeleted": "Pregled izbrisanih stranica i datoteka",
        "grant-viewmywatchlist": "Pregled vašeg spisak nadgledanja",
-       "grant-viewrestrictedlogs": "Pregledanje ograničenih unosa u dnevniku",
-       "newuserlogpage": "Dnevnik novih korisnika",
-       "newuserlogpagetext": "Ovo je dnevnik novih korisnika.",
-       "rightslog": "Dnevnik korisničkih prava",
-       "rightslogtext": "Ovo je dnevnik izmena korisničkih prava.",
-       "action-read": "čitanje ove stranice",
-       "action-edit": "uređivanje ove stranice",
-       "action-createpage": "pravljenje stranica",
-       "action-createtalk": "pravljenje stranica za razgovor",
-       "action-createaccount": "otvaranje ovog korisničkog naloga",
-       "action-autocreateaccount": "automatsko pravljenje ovog spoljašnjeg korisničkog naloga",
-       "action-history": "gledanje istorije ove stranice",
-       "action-minoredit": "označavanje ove izmene kao manje",
-       "action-move": "premeštanje ove stranice",
-       "action-move-subpages": "premeštanje ove stranice i njenih podstranica",
-       "action-move-rootuserpages": "premeštanje osnovnih korisničkih stranica",
-       "action-move-categorypages": "premeštanje kategorija",
-       "action-movefile": "premeštanje ove datoteke",
-       "action-upload": "otpremi ovu datoteku",
-       "action-reupload": "zamenjivanje postojeće datoteke",
-       "action-reupload-shared": "postavljanje ove datoteke na zajedničko skladište",
-       "action-upload_by_url": "otpremanje ove datoteke preko veb-adrese",
-       "action-writeapi": "pisanje API-ja",
-       "action-delete": "brisanje ove stranice",
-       "action-deleterevision": "brisanje izmena",
-       "action-deletelogentry": "birsanje unosa u dnevnicima",
-       "action-deletedhistory": "pregledanje obrisane istorije stranice",
-       "action-deletedtext": "pregled obrisanog teksta izmene",
-       "action-browsearchive": "pretraživanje obrisanih stranica",
-       "action-undelete": "vraćanje stranica",
-       "action-suppressrevision": "pregledanje i vraćanje sakrivenih izmena",
-       "action-suppressionlog": "pregledanje ove privatne istorije",
-       "action-block": "blokiranje daljih izmena ovog korisnika",
-       "action-protect": "menjanje stepena zaštite ove stranice",
-       "action-rollback": "brzo vraćanje izmena poslednjeg korisnika koji je menjao određenu stranicu",
-       "action-import": "uvoženje stranica iz drugih vikija",
-       "action-importupload": "uvoženje stranica iz otpremljene datoteke",
-       "action-patrol": "označavanje tuđih izmena patroliranim",
-       "action-autopatrol": "označavanje sopstvenih izmena patroliranim",
-       "action-unwatchedpages": "pregledanje spiska nenadgledanih stranica",
-       "action-mergehistory": "spajanje istorije ove stranice",
-       "action-userrights": "uređivanje svih korisničkih prava",
-       "action-userrights-interwiki": "uređivanje korisničkih prava na drugim vikijima",
-       "action-siteadmin": "zaključavanje ili otključavanje baze podataka",
-       "action-sendemail": "slanje imejlova",
-       "action-editmyoptions": "uređivanje Vaših podešavanja",
-       "action-editmywatchlist": "izmenu sopstvenog spisak nadgledanja",
-       "action-viewmywatchlist": "pregled vašeg spisak nadgledanja",
-       "action-viewmyprivateinfo": "pregledanje vaših ličnih podataka",
-       "action-editmyprivateinfo": "uređivanje vaših ličnih podataka",
-       "action-editcontentmodel": "menjanje modela sadržaja stranice",
-       "action-managechangetags": "pravljenje i (de)aktiviranje oznaka",
-       "action-applychangetags": "dodavanje oznaka na vaše izmene",
-       "action-changetags": "dodavanje i uklanjanje raznih oznaka na pojedinačnim izmenama i unosima u dnevnicima",
-       "action-deletechangetags": "Obriši oznake iz baze podataka",
-       "action-purge": "čišćenje privremene memorije ove stranice",
-       "nchanges": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
+       "grant-viewrestrictedlogs": "Pregledanje ograničenih unosa u evidenciji",
+       "newuserlogpage": "Evidencija novih korisnika",
+       "newuserlogpagetext": "Ovo je evidencija o registraciji novih korisnika.",
+       "rightslog": "Evidencija korisničkih prava",
+       "rightslogtext": "Ovo je evidencija promena korisničkih prava.",
+       "action-read": "čitate ovu stranicu",
+       "action-edit": "uređujete ovu stranicu",
+       "action-createpage": "napravite ovu stranicu",
+       "action-createtalk": "napravite ovu stranicu za razgovor",
+       "action-createaccount": "napravite ovaj korisnički nalog",
+       "action-autocreateaccount": "automatski napravite ovaj spoljašnji korisnički nalog",
+       "action-history": "gledate istoriju ove stranice",
+       "action-minoredit": "označite ovu izmenu kao manju",
+       "action-move": "premestite ovu stranicu",
+       "action-move-subpages": "premestite ovu stranicu i njene podstranice",
+       "action-move-rootuserpages": "premeštate osnovne korisničke stranice",
+       "action-move-categorypages": "premeštate kategorije",
+       "action-movefile": "premestite ovu datoteku",
+       "action-upload": "otpremite ovu datoteku",
+       "action-reupload": "zamenjujete ovu postojeću datoteku",
+       "action-reupload-shared": "premostite ovu datoteku sa zajedničkog skladišta",
+       "action-upload_by_url": "otpremite ovu datoteku putem URL-a",
+       "action-writeapi": "koristite API za pisanje",
+       "action-delete": "izbrišete ovu stranicu",
+       "action-deleterevision": "brišete izmene",
+       "action-deletelogentry": "brišete unose u evidencijama",
+       "action-deletedhistory": "pregledate izbrisanu istoriju stranice",
+       "action-deletedtext": "pregledate izbrisani tekst izmene",
+       "action-browsearchive": "pretražujete izbrisane stranice",
+       "action-undelete": "vraćate stranice",
+       "action-suppressrevision": "pregledate i vraćate sakrivene izmene",
+       "action-suppressionlog": "pregledate ovu privatnu evidencije",
+       "action-block": "blokirate uređivanje ovom korisniku",
+       "action-protect": "promenite nivoe zaštite ove stranice",
+       "action-rollback": "brzo vratite izmene poslednjeg korisnika koji je uređivao određenu stranicu",
+       "action-import": "uvozite stranice iz drugog vikija",
+       "action-importupload": "uvozite stranice putem otpremanja datoteke",
+       "action-patrol": "označite tuđe izmene kao patrolirane",
+       "action-autopatrol": "označite sopstvene izmene kao patrolirane",
+       "action-unwatchedpages": "pregledate spisak nenadgledanih stranica",
+       "action-mergehistory": "spajate istoriju ove stranice",
+       "action-userrights": "uređujete sva korisnička prava",
+       "action-userrights-interwiki": "uređujete korisnička prava korisnika na drugim vikijima",
+       "action-siteadmin": "zaključavate ili otključavate bazu podataka",
+       "action-sendemail": "šaljete imejlove",
+       "action-editmyoptions": "uređujete sopstvena podešavanja",
+       "action-editmywatchlist": "uređujete sopstveni spisak nadgledanja",
+       "action-viewmywatchlist": "pregledate sopstveni spisak nadgledanja",
+       "action-viewmyprivateinfo": "pregledate sopstvene lične informacije",
+       "action-editmyprivateinfo": "uređujete sopstvene privatne informacije",
+       "action-editcontentmodel": "uređujete model sadržaja stranice",
+       "action-managechangetags": "pravite i (de)aktivirate oznake",
+       "action-applychangetags": "dodate oznake uz sopstvene promene",
+       "action-changetags": "dodate i uklonite razne oznake na pojedinačnim izmenama i unosima u evidencijama",
+       "action-deletechangetags": "brišete oznake iz baze podataka",
+       "action-purge": "osvežite ovu stranicu",
+       "nchanges": "$1 {{PLURAL:$1|promena|promene|promena}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|izmena od vaše poslednje posete}}",
        "enhancedrc-history": "istorija",
        "recentchanges": "Skorašnje izmene",
        "recentchanges-legend": "Opcije skorašnjih izmena",
-       "recentchanges-summary": "Pratite skorašnje izmene na ovoj stranici.",
-       "recentchanges-noresult": "Nema izmena tokom datog perioda a koje odgovaraju ovim kriterijumima.",
+       "recentchanges-summary": "Pratite nedavne promene na ovoj stranici.",
+       "recentchanges-noresult": "Nema promena tokom datog perioda a koje odgovaraju ovim kriterijumima.",
        "recentchanges-timeout": "Ova pretraga je istekla. Možda želite da pokušate drugačije parametre pretrage.",
        "recentchanges-network": "Zbog tehničkog problema ne mogu da učitam rezultate. Pokušajte da osvežite stranicu.",
-       "recentchanges-notargetpage": "Unesite naziv stranice kako biste videli srodne izmene.",
-       "recentchanges-feed-description": "Pratite skorašnje izmene uz pomoć ovog dovoda.",
+       "recentchanges-notargetpage": "Unesite ime stranice iznad da biste videli promene srodne s ovom stranicom",
+       "recentchanges-feed-description": "Pratite najskorije promene na vikiju u ovom fidu.",
        "recentchanges-label-newpage": "Ovom izmenom je napravljena nova stranica",
        "recentchanges-label-minor": "Ovo je manja izmena",
        "recentchanges-label-bot": "Ovu izmenu je napravio bot",
        "rcfilters-activefilters-show-tooltip": "Prikažite područje aktivnih filtera",
        "rcfilters-advancedfilters": "Napredni filteri",
        "rcfilters-limit-title": "Broj izmena za prikaz",
-       "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|izmena|izmene|izmena}}, $2",
+       "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|promena|promene|promena}}, $2",
        "rcfilters-date-popup-title": "Vremenski period za pretragu",
-       "rcfilters-days-title": "Skorašnji dani",
+       "rcfilters-days-title": "Nedavni dani",
        "rcfilters-hours-title": "Skorašnji sati",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|dan|dana}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|sat|sata}}",
        "rcfilters-highlighted-filters-list": "Istaknuto: $1",
        "rcfilters-quickfilters": "Sačuvani filteri",
        "rcfilters-quickfilters-placeholder-title": "Još nema sačuvanih filtera",
-       "rcfilters-quickfilters-placeholder-description": "Da biste sačuvali svoja podešavanja filtera i ponovo ih upotrebljavali kasnije, kliknite na ikonu za oznaku u području aktivnih filtera — ispod.",
+       "rcfilters-quickfilters-placeholder-description": "Da biste sačuvali svoja podešavanja filtera i ponovo ih upotrebljavali kasnije, kliknite na ikonu za obeležavanje u području aktivnih filtera — ispod.",
        "rcfilters-savedqueries-defaultlabel": "Sačuvani filteri",
        "rcfilters-savedqueries-rename": "Preimenuj",
        "rcfilters-savedqueries-setdefault": "Postavi kao podrazumevano",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Napravi podrazumevani filter",
        "rcfilters-savedqueries-cancel-label": "Otkaži",
        "rcfilters-savedqueries-add-new-title": "Sačuvajte trenutna podešavanja filtera",
-       "rcfilters-savedqueries-already-saved": "Ovi filteri su već sačuvani. Izmenite Vaša podešavanja da biste napravili nove sačuvane filtere.",
+       "rcfilters-savedqueries-already-saved": "Ovi filteri su već sačuvani. Promenite svoja podešavanja da biste napravili nove sačuvane filtere.",
        "rcfilters-restore-default-filters": "Vrati podrazumevane filtere",
        "rcfilters-clear-all-filters": "Uklonite sve filtere",
-       "rcfilters-show-new-changes": "Najnovije izmene",
-       "rcfilters-search-placeholder": "Filtrirajte izmene (koristite meni ili pretragu za ime filtera)",
-       "rcfilters-invalid-filter": "Neispravan filter",
+       "rcfilters-show-new-changes": "Najnovije promene",
+       "rcfilters-search-placeholder": "Filtrirajte promene (koristite meni ili pretragu za ime filtera)",
+       "rcfilters-invalid-filter": "Nevažeći filter",
        "rcfilters-empty-filter": "Nema aktivnih filtera. Svi doprinosi su prikazani.",
        "rcfilters-filterlist-title": "Filteri",
        "rcfilters-filterlist-whatsthis": "Kako ovo funkcioniše?",
        "rcfilters-state-message-subset": "Ovaj filter nema efekta jer su njegovi rezultati uključeni sa onima {{PLURAL:$2|sledećeg, šireg filtera|sledećih, širih filtera}} (pokušajte sa označavanjem da biste ih raspoznali): $1",
        "rcfilters-state-message-fullcoverage": "Odabir svih filtera u grupi je isto kao i odabir nijednog, tako da ovaj filter nema efekta. Grupa uključuje: $1",
        "rcfilters-filtergroup-authorship": "Autorstvo doprinosa",
-       "rcfilters-filter-editsbyself-label": "Vaše izmene",
-       "rcfilters-filter-editsbyself-description": "Vaši doprinosi.",
-       "rcfilters-filter-editsbyother-label": "Izmene drugih",
-       "rcfilters-filter-editsbyother-description": "Sve izmene osim Vaših.",
+       "rcfilters-filter-editsbyself-label": "Vaše promene",
+       "rcfilters-filter-editsbyself-description": "Vaši sopstveni doprinosi.",
+       "rcfilters-filter-editsbyother-label": "Promene drugih",
+       "rcfilters-filter-editsbyother-description": "Sve promene osim vaših.",
        "rcfilters-filtergroup-userExpLevel": "Korisnička registracija i iskustvo",
        "rcfilters-filter-user-experience-level-registered-label": "Registrovani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni urednici.",
        "rcfilters-filter-major-description": "Izmene koje nisu označene kao manje.",
        "rcfilters-filtergroup-watchlist": "Stranice na spisku nadgledanja",
        "rcfilters-filter-watchlist-watched-label": "Na spisku nadgledanja",
-       "rcfilters-filter-watchlist-watched-description": "Izmene stranica na Vašem spisku nadgledanja.",
-       "rcfilters-filter-watchlist-watchednew-label": "Nove izmene na spisku nadgledanja",
-       "rcfilters-filter-watchlist-watchednew-description": "Izmene stranica na spisku nadgledanja koje niste posetili od kada su napravljene izmene.",
+       "rcfilters-filter-watchlist-watched-description": "Promene stranica na vašem spisku nadgledanja.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nove promene na spisku nadgledanja",
+       "rcfilters-filter-watchlist-watchednew-description": "Promene stranica na spisku nadgledanja koje niste posetili od kada su promene napravljene.",
        "rcfilters-filter-watchlist-notwatched-label": "Nije na spisku nadgledanja",
-       "rcfilters-filter-watchlist-notwatched-description": "Sve osim izmena stranica na Vašem spisku nadgledanja.",
+       "rcfilters-filter-watchlist-notwatched-description": "Sve osim promena stranica na vašem spisku nadgledanja.",
        "rcfilters-filtergroup-watchlistactivity": "Stanje na spisku nadgledanja",
-       "rcfilters-filter-watchlistactivity-unseen-label": "Nepogledane izmene",
-       "rcfilters-filter-watchlistactivity-unseen-description": "Izmene stranica koje niste posetili od kada su napravljene izmene.",
-       "rcfilters-filter-watchlistactivity-seen-label": "Pogledane izmene",
-       "rcfilters-filter-watchlistactivity-seen-description": "Izmene stranica koje ste posetili od kada su napravljene izmene.",
-       "rcfilters-filtergroup-changetype": "Tip izmene",
+       "rcfilters-filter-watchlistactivity-unseen-label": "Nepogledane promene",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Promene na stranicama koje niste posetili od kada su promene napravljene.",
+       "rcfilters-filter-watchlistactivity-seen-label": "Pogledane promene",
+       "rcfilters-filter-watchlistactivity-seen-description": "Promene na stranicama koje ste posetili od kada su promene napravljene.",
+       "rcfilters-filtergroup-changetype": "Tip promene",
        "rcfilters-filter-pageedits-label": "Izmene stranica",
        "rcfilters-filter-pageedits-description": "Izmene viki sadržaja, rasprava, opisa kategorija…",
        "rcfilters-filter-newpages-label": "Pravljenje stranica",
        "rcfilters-filter-newpages-description": "Izmene kojima se prave nove stranice.",
-       "rcfilters-filter-categorization-label": "Izmene kategorija",
+       "rcfilters-filter-categorization-label": "Promene kategorija",
        "rcfilters-filter-categorization-description": "Zapisi o stranicama dodatim ili uklonjenim iz kategorija.",
-       "rcfilters-filter-logactions-label": "Zabeležene radnje",
-       "rcfilters-filter-logactions-description": "Administrativne radnje, pravljenje naloga, brisanje stranica, otpremanja…",
-       "rcfilters-hideminor-conflicts-typeofchange-global": "Filter za „manje” izmene je u sukobu sa jednim ili više filtera tipa izmena, zato što određeni tipovi izmena ne mogu da se označe kao „manje”. Sukobljeni filteri su označeni u području Aktivni filteri, iznad.",
-       "rcfilters-hideminor-conflicts-typeofchange": "Određeni tipovi izmena ne mogu da se označe kao „manje”, tako da je ovaj filter u sukobu sa sledećim filterima tipa izmena: $1",
+       "rcfilters-filter-logactions-label": "Evidentirane radnje",
+       "rcfilters-filter-logactions-description": "Administrativne radnje, otvaranje naloga, brisanje stranica, otpremanja…",
+       "rcfilters-hideminor-conflicts-typeofchange-global": "Filter za „manje” izmene je u sukobu sa jednim ili više filtera tipa promena, zato što određeni tipovi promena ne mogu da se označe kao „manje”. Sukobljeni filteri su označeni u području Aktivni filteri, iznad.",
+       "rcfilters-hideminor-conflicts-typeofchange": "Određeni tipovi promena ne mogu da se označe kao „manje”, tako da je ovaj filter u sukobu sa sledećim filterima tipa promena: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ovaj filter tipa izmene je u sukobu sa filterom za „manje” izmene. Određeni tipovi izmena ne mogu da se označe kao „manje”.",
-       "rcfilters-filtergroup-lastRevision": "Poslednje izmene",
-       "rcfilters-filter-lastrevision-label": "Poslednja izmena",
-       "rcfilters-filter-lastrevision-description": "Samo najnovija izmena na stranici.",
-       "rcfilters-filter-previousrevision-label": "Nije poslednja izmena",
-       "rcfilters-filter-previousrevision-description": "Sve izmene koje nisu „poslednje izmene”.",
-       "rcfilters-filter-excluded": "Izostavljeno",
+       "rcfilters-filtergroup-lastRevision": "Najnovije izmene",
+       "rcfilters-filter-lastrevision-label": "Najnovija izmena",
+       "rcfilters-filter-lastrevision-description": "Samo najnovija promena na stranici.",
+       "rcfilters-filter-previousrevision-label": "Nije najnovija izmena",
+       "rcfilters-filter-previousrevision-description": "Sve promene koje nisu „poslednje izmene”.",
+       "rcfilters-filter-excluded": "Izuzeto",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:nije</strong> $1",
-       "rcfilters-exclude-button-off": "Izostavi označeno",
-       "rcfilters-exclude-button-on": "Izostavi odabrano",
+       "rcfilters-exclude-button-off": "Izuzmi izabrano",
+       "rcfilters-exclude-button-on": "Izuzmi izabrano",
        "rcfilters-view-tags": "Označene izmene",
        "rcfilters-view-namespaces-tooltip": "Filtrirajte rezultate prema imenskom prostoru",
        "rcfilters-view-tags-tooltip": "Filtrirajte rezultate prema oznaci izmene",
        "rcfilters-view-tags-help-icon-tooltip": "Saznajte više o označenim izmenama",
        "rcfilters-liveupdates-button": "Ažuriraj uživo",
        "rcfilters-liveupdates-button-title-on": "Isključite ažuriranja uživo",
-       "rcfilters-liveupdates-button-title-off": "Prikažite nove izmene uživo",
-       "rcfilters-watchlist-markseen-button": "Označi sve izmene kao pogledane",
+       "rcfilters-liveupdates-button-title-off": "Prikažite nove promene uživo",
+       "rcfilters-watchlist-markseen-button": "Označi sve promene kao pogledane",
        "rcfilters-watchlist-edit-watchlist-button": "Promeni spisak nadgledanih stranica",
-       "rcfilters-watchlist-showupdated": "Izmene stranica koje niste posetili od kada je izmena izvršena su <strong>podebljane</strong>, sa ispunjenim oznakama.",
+       "rcfilters-watchlist-showupdated": "Promene na stranicama koje niste posetili od kada je izmena izvršena su <strong>podebljane</strong>, s ispunjenim oznakama.",
        "rcfilters-preference-label": "Sakrij poboljšanu verziju skorašnjih izmena",
        "rcfilters-preference-help": "Poništava redizajn interfejsa iz 2017. i sve alatke dodate tada i posle.",
        "rcfilters-watchlist-preference-label": "Sakrij poboljšanu verziju spiska nadgledanja",
-       "rcfilters-filter-showlinkedfrom-label": "Prikaži izmene na stranicama sa kojih dolaze veze",
+       "rcfilters-watchlist-preference-help": "Uklanja redizajn interfejsa iz 2017. godine i sve alatke dodate tada i od tada.",
+       "rcfilters-filter-showlinkedfrom-label": "Prikaži promene na stranicama sa kojih dolaze veze",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Stranice sa kojih dolaze veze do</strong> izabrane stranice",
-       "rcfilters-filter-showlinkedto-label": "Prikaži izmene na stranicama ka kojima vode veze",
+       "rcfilters-filter-showlinkedto-label": "Prikaži promene na stranicama ka kojima vode veze",
        "rcfilters-filter-showlinkedto-option-label": "<strong>Stranice ka kojima vode veze sa</strong> izabrane stranice",
        "rcfilters-target-page-placeholder": "Unesite ime stranice (ili kategorije)",
-       "rcnotefrom": "Ispod {{PLURAL:$5|je izmena|su izmene}} od <strong>$3, $4</strong> (do <strong>$1</strong> prikazano).",
-       "rclistfromreset": "Resetuj odabir datuma",
-       "rclistfrom": "Prikaži nove izmene počev od $2, $3",
+       "rcnotefrom": "Ispod {{PLURAL:$5|je promena|su promene}} od <strong>$3, $4</strong> (do <strong>$1</strong> prikazano).",
+       "rclistfromreset": "Resetuj izbor datuma",
+       "rclistfrom": "Prikaži nove promene počev od $2, $3",
        "rcshowhideminor": "$1 manje izmene",
        "rcshowhideminor-show": "Prikaži",
        "rcshowhideminor-hide": "Sakrij",
        "rcshowhidecategorization": "$1 kategorizaciju stranica",
        "rcshowhidecategorization-show": "Prikaži",
        "rcshowhidecategorization-hide": "Sakrij",
-       "rclinks": "Prikaži poslednjih $1 izmena {{PLURAL:$2|prethodni dan|u poslednja $2 dana|u poslednjih $2 dana}}",
+       "rclinks": "Prikaži poslednjih $1 promena {{PLURAL:$2|prethodni dan|u poslednja $2 dana|u poslednjih $2 dana}}",
        "diff": "razl",
        "hist": "ist",
        "hide": "Sakrij",
        "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|korisnik nadgleda|korisnika nadgledaju|korisnika nadgledaju}}]",
        "rc-change-size": "$1",
-       "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} posle izmene",
+       "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} posle promene",
        "newsectionsummary": "/* $1 */ novi odeljak",
        "rc-enhanced-expand": "Prikaži detalje",
        "rc-enhanced-hide": "Sakrij detalje",
        "rc-old-title": "prvobitno napravljeno kao „$1“",
-       "recentchangeslinked": "Srodne izmene",
+       "recentchangeslinked": "Srodne promene",
        "recentchangeslinked-feed": "Srodne izmene",
-       "recentchangeslinked-toolbox": "Srodne izmene",
-       "recentchangeslinked-title": "Srodne izmene sa „$1“",
+       "recentchangeslinked-toolbox": "Srodne promene",
+       "recentchangeslinked-title": "Izmene srodne sa „$1“",
        "recentchangeslinked-summary": "Unesite ime stranice da biste videli promene na stranicama koje su povezane sa ili sa te stranice. (Da biste videli članove kategorije, unesite {{ns:category}}:Ime kategorije). Promene na stranicama koje su na [[Special:Watchlist|Vašem spisku nadgledanja]] su <strong>podebljane</strong>.",
        "recentchangeslinked-page": "Naziv stranice:",
-       "recentchangeslinked-to": "Prikaži izmene stranica koje su povezane s datom stranicom",
+       "recentchangeslinked-to": "Prikaži promene na stranicama koje su povezane s datom stranicom",
        "recentchanges-page-added-to-category": "[[:$1]] je dodata u kategoriju",
        "recentchanges-page-added-to-category-bundled": "[[:$1]] je dodana u kategoriju, [[Special:WhatLinksHere/$1|ova stranica je povezana sa drugim stranicama]]",
        "recentchanges-page-removed-from-category": "[[:$1]] je uklonjena iz kategorije",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] je uklonjena iz kategorije, [[Special:WhatLinksHere/$1|ova stranica je povezana sa drugim stranicama]]",
-       "autochange-username": "Medijaviki automatska izmena",
+       "autochange-username": "Automatska promena Medijavikija",
        "upload": "Otpremanje datoteke",
        "uploadbtn": "Otpremi datoteku",
        "reuploaddesc": "Nazad na obrazac za otpremanje",
        "upload_directory_missing": "Fascikla za slanje ($1) nedostaje i server je ne može napraviti.",
        "upload_directory_read_only": "Server ne može da piše po fascikli za slanje ($1).",
        "uploaderror": "Greška pri otpremanju",
-       "upload-recreate-warning": "'''Upozorenje: datoteka s tim nazivom je obrisana ili premeštena.'''\n\nIstorija brisanja i premeštanja se nalazi ispod:",
-       "uploadtext": "Koristite obrazac ispod da biste otpremili datoteke.\nZa pregled ili pretragu postojećih datoteka, pogledajte [[Special:FileList|spisak otpremljenih datoteka]], ponovna otpremanja su navedena u [[Special:Log/upload|dnevniku otpremanja]], a brisanja u [[Special:Log/delete|dnevniku brisanja]].\n\nDatoteku dodajete na željenu stranicu koristeći sledeće obrasce:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Slika.jpg]]</nowiki></code>''' za verziju slike u punoj veličini\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Slika.png|200p|mini|levo|opis]]</nowiki></code>''' za verziju slike s veličinom od 200 piksela koja je prikazana u zasebnom okviru, zajedno s opisom.\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Datoteka.ogg]]</nowiki></code>''' za direktno povezivanje s datotekom bez njenog prikazivanja",
+       "upload-recreate-warning": "<strong>Upozorenje: Datoteka sa tim imenom je izbrisana ili premeštena.</strong>\n\nEvidencija brisanja i premeštanja stranice navedena je ispod sa obrazloženjem:",
+       "uploadtext": "Koristite obrazac ispod da biste otpremili datoteke.\nZa pregled ili pretragu postojećih datoteka, pogledajte [[Special:FileList|spisak otpremljenih datoteka]], ponovna otpremanja su navedena u [[Special:Log/upload|evidenciji otpremanja]], a brisanja u [[Special:Log/delete|evidenciji brisanja]].\n\nDatoteku dodajete na željenu stranicu koristeći sledeće obrasce:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Slika.jpg]]</nowiki></code>''' za verziju slike u punoj veličini\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Slika.png|200p|mini|levo|opis]]</nowiki></code>''' za verziju slike s veličinom od 200 piksela koja je prikazana u zasebnom okviru, zajedno s opisom.\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Datoteka.ogg]]</nowiki></code>''' za direktno povezivanje s datotekom bez njenog prikazivanja",
        "upload-permitted": "Dozvoljeni {{PLURAL:$2|tip|tipovi}} datoteka: $1.",
        "upload-preferred": "Preporučeni {{PLURAL:$2|tip|tipovi}} datoteka: $1.",
        "upload-prohibited": "Zabranjeni {{PLURAL:$2|tip|tipovi}} datoteka: $1.",
-       "uploadlogpage": "Dnevnik otpremanja",
-       "uploadlogpagetext": "Ispod je spisak skorašnjih slanja.\nPogledajte [[Special:NewFiles|galeriju novih datoteka]] za lepši pregled.",
+       "uploadlogpage": "Evidencija otpremanja",
+       "uploadlogpagetext": "Ispod je spisak nedavnih otpremanja.\nPogledajte [[Special:NewFiles|galeriju novih datoteka]] za lepši pregled.",
        "filename": "Naziv datoteke",
-       "filedesc": "Opis",
-       "fileuploadsummary": "Opis:",
-       "filereuploadsummary": "Izmene datoteke:",
+       "filedesc": "Opis izmene",
+       "fileuploadsummary": "Opis izmene:",
+       "filereuploadsummary": "Promene datoteke:",
        "filestatus": "Status autorskog prava:",
        "filesource": "Izvor:",
        "ignorewarning": "Zanemari upozorenja i sačuvaj datoteku",
        "ignorewarnings": "Zanemari sva upozorenja",
        "minlength1": "Naziv datoteke mora imati barem jedan znak.",
-       "illegalfilename": "Datoteka „$1“ sadrži znakove koji nisu dozvoljeni u nazivima stranica.\nPromenite naziv datoteke i ponovo je pošaljite.",
+       "illegalfilename": "Ime datoteke „$1“ sadrži znakove koji nisu dozvoljeni u naslovima stranica.\nPreimenujte datoteku i pokušate da je ponovo otpremite.",
        "filename-toolong": "Nazivi datoteka mogu imati najviše 240 bajtova.",
-       "badfilename": "Naziv datoteke je promenjen u „$1“.",
-       "filetype-mime-mismatch": "Ekstenzija „.$1“ ne odgovara prepoznatoj vrsti MIME datoteke ($2).",
+       "badfilename": "Ime datoteke je promenjeno u „$1“.",
+       "filetype-mime-mismatch": "Proširenje datoteke „.$1“ ne odgovara prepoznatom tipu MIME datoteke ($2).",
        "filetype-badmime": "Datoteke MIME tipa „$1“ nije dozvoljeno slati.",
-       "filetype-bad-ie-mime": "Ova datoteka se ne može poslati zato što bi je Internet eksplorer uočio kao „$1“, a to je zabranjena i opasna vrsta datoteke.",
-       "filetype-unwanted-type": "„.$1“ je nepoželjna vrsta datoteke.\n{{PLURAL:$3|Poželjna vrsta datoteke je|Poželjne vrste datoteka su}} $2.",
-       "filetype-banned-type": "'''„.$1“''' {{PLURAL:$4|je zabranjena vrsta datoteke|su zabranjene vrste datoteka}}.\n{{PLURAL:$3|Dozvoljena vrsta datoteke je|Dozvoljene vrste datoteka su}} $2.",
-       "filetype-missing": "Ova datoteka nema ekstenziju (npr. „.jpg“).",
+       "filetype-bad-ie-mime": "Ne mogu da otpremim ovu datoteku jer bi je Internet eksplorer prepoznao kao „$1“, što je nedozvoljen i potencijalno opasan tip datoteke.",
+       "filetype-unwanted-type": "<strong>„.$1“</strong> je nepoželjan tip datoteke.\n{{PLURAL:$3|Poželjan tip datoteke je|Poželjni tipovi datoteka su}} $2.",
+       "filetype-banned-type": "<strong>„.$1“</strong> {{PLURAL:$4|nije dopušten tip datoteke|nisu dopušteni tipovi datoteka}}.\n{{PLURAL:$3|Dozvoljen tip datoteke je|Dozvoljeni tipovi datoteka su}} $2.",
+       "filetype-missing": "Ova datoteka nema proširenje (npr. „.jpg“).",
        "empty-file": "Poslata datoteka je prazna.",
        "file-too-large": "Poslata datoteka je prevelika.",
        "filename-tooshort": "Naziv datoteke je prekratak.",
-       "filetype-banned": "Vrsta datoteke je zabranjena.",
+       "filetype-banned": "Ovaj tip datoteke je zabranjen.",
        "verification-error": "Ova datoteka nije prošla proveru.",
-       "hookaborted": "Izmena je odbačena od kuke za proširenja.",
+       "hookaborted": "Izmenu koju ste pokušali da napravite je prekinuo dodatak.",
        "illegal-filename": "Naziv datoteke je zabranjen.",
        "overwrite": "Zamenjivanje postojeće datoteke je zabranjeno.",
        "unknown-error": "Došlo je do nepoznate greške.",
        "large-file": "Preporučljivo je da datoteke ne budu veće od $1; ova datoteka je $2.",
        "largefileserver": "Ova datoteka prelazi ograničenje veličine.",
        "emptyfile": "Datoteka koju ste poslali je prazna.\nUzrok može biti greška u nazivu datoteke.\nProverite da li zaista želite da je pošaljete.",
-       "windows-nonascii-filename": "Ovaj viki ne podržava nazive datoteka s posebnim znacima.",
-       "fileexists": "Datoteka s ovim nazivom već postoji. Pogledajte <strong>[[:$1]]</strong> ako niste sigurni da li želite da je promenite.\n[[$1|thumb]]",
+       "windows-nonascii-filename": "Ovaj viki ne podržava imena datoteka sa posebnim znacima.",
+       "fileexists": "Datoteka s ovim imenom već postoji. Pogledajte <strong>[[:$1]]</strong> ako niste sigurni da li želite da je promenite.\n[[$1|thumb]]",
        "filepageexists": "Stranica s opisom ove datoteke je već napravljena ovde <strong>[[:$1]]</strong>, iako datoteka ne postoji.\nOpis koji ste naveli se neće pojaviti na stranici s opisom.\nDa bi se vaš opis ovde našao, potrebno je da ga ručno izmenite.\n[[$1|thumb]]",
        "fileexists-extension": "Datoteka sa sličnim nazivom već postoji: [[$2|thumb]]\n* Naziv datoteke koju šaljete: <strong>[[:$1]]</strong>\n* Naziv postojeće datoteke: <strong>[[:$2]]</strong>\nDa li želite da koristite prepoznatljivije ime?",
-       "fileexists-thumbnail-yes": "Izgleda da je datoteka umanjeno izdanje slike ''(thumbnail)''.\n[[$1|thumb]]\nProverite datoteku <strong>[[:$1]]</strong>.\nAko je proverena datoteka ista slika originalne veličine, nije potrebno slati dodatnu sliku.",
-       "file-thumbnail-no": "Datoteka počinje sa <strong>$1</strong>.\nIzgleda da se radi o umanjenoj slici ''(thumbnail)''.\nUkoliko imate ovu sliku u punoj veličini, pošaljite je, a ako nemate, promenite naziv datoteke.",
+       "fileexists-thumbnail-yes": "Izgleda da je datoteka slika umanjene veličine <em>(sličica)</em>.\n[[$1|thumb]]\nProverite datoteku <strong>[[:$1]]</strong>.\nAko je proverena datoteka ista slika prvobitne veličine, nije potrebno otpremati dodatnu.",
+       "file-thumbnail-no": "Ime datoteke počinje sa <strong>$1</strong>.\nIzgleda da se radi o slici umanjene veličine <em>(sličica)</em>.\nAko imate ovu sliku u punoj rezoluciji, otpremite je, u protivnom, promenite ime datoteke.",
        "fileexists-forbidden": "Datoteka s ovim nazivom već postoji i ne može se zameniti.\nAko i dalje želite da pošaljete datoteku, vratite se i izaberite drugi naziv.\n[[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Datoteka s ovim nazivom već postoji u zajedničkoj ostavi.\nVratite se i pošaljite datoteku s drugim nazivom.\n[[File:$1|thumb|center|$1]]",
-       "fileexists-no-change": "Datoteka je duplikat trenutne verzije <strong>[[:$1]]</strong>.",
+       "fileexists-shared-forbidden": "Datoteka sa ovim imenom već postoji u zajedničkoj ostavi.\nAko još uvek želite da otpremite datoteku, vratite se i koristite novo ime.\n[[File:$1|thumb|center|$1]]",
+       "fileexists-no-change": "Datoteka je duplikat aktuelne verzije <strong>[[:$1]]</strong>.",
        "fileexists-duplicate-version": "Datoteka je duplikat {{PLURAL:$2|stare verzije|starih verzija}} <strong>[[:$1]]</strong>.",
        "file-exists-duplicate": "Ovo je duplikat {{PLURAL:$1|sledeće datoteke|sledećih datoteka}}:",
-       "file-deleted-duplicate": "Datoteka istovetna ovoj ([[:$1]]) je prethodno obrisana.\nPogledajte istoriju brisanja pre ponovnog slanja.",
-       "file-deleted-duplicate-notitle": "Datoteka identična ovoj prethodno je obrisana i ime joj je sakriveno.\nTrebali biste pitati nekoga ko može videti podatke skrivenih datoteka da pregleda situaciju pre nego što ponovo otpremite datoteku.",
+       "file-deleted-duplicate": "Datoteka koja je identična ovoj ([[:$1]]) je ranije bila izbrisana.\nTrebate da proverite istoriju brisanja te datoteke pre nego što nastavite sa njenim ponovnim optremanjem.",
+       "file-deleted-duplicate-notitle": "Datoteka koja je identična ovoj ranije je izbrisana i ime joj je sakriveno.\nTrebate da pitate nekoga ko može videti podatke skrivenih datoteka da pregleda situaciju pre nego što ponovo otpremite datoteku.",
        "uploadwarning": "Upozorenje pri otpremanju",
        "uploadwarning-text": "Izmenite opis datoteke i pokušajte ponovo.",
        "uploadwarning-text-nostash": "Re-otpremite datoteku, izmenite opis ispod i pokušajte ponovo.",
        "copyuploaddisabled": "Otpremanje putem veb-adrese je onemogućeno.",
        "uploaddisabledtext": "Otpremanje datoteka je onemogućeno.",
        "php-uploaddisabledtext": "Otpremanje datoteka je onemogućeno u PHP-u.\nProverite podešavanja file_uploads.",
-       "uploadscripted": "Datoteka sadrži HTML ili skriptni kôd koji može biti pogrešno protumačen od strane pregledača.",
+       "uploadscripted": "Datoteka sadrži HTML ili skriptni kod koji može biti pogrešno protumačen od strane pregledača.",
        "upload-scripted-pi-callback": "Datoteka koja sadrži instrukcije za obradu XML stilskog oblika se ne može otpremiti.",
        "upload-scripted-dtd": "Nije moguće otpremanje SVG datoteka koje sadrže nestandardnu DTD deklaraciju.",
        "uploaded-script-svg": "Pronađen skriptni elemenat „$1“ u postavljenoj SVG datoteci.",
        "uploaded-href-unsafe-target-svg": "Pronađen href sa nesigurnim podacima: URI odredište <code>&lt;$1 $2=\"$3\"&gt;</code> u postavljenoj SVG datoteci.",
        "uploaded-animate-svg": "Pronađena „animate“ oznaka koja možda menja href koristeći se „from“ atributom <code>&lt;$1 $2=\"$3\"&gt;</code> u postavljenoj SVG datoteci.",
        "uploadscriptednamespace": "Ova SVG datoteka sadrži pogrešan imenski prostor „<nowiki>$1</nowiki>“",
-       "uploadinvalidxml": "Nije moguće raščlaniti XML otpremljene datoteke.",
+       "uploadinvalidxml": "Ne mogu da raščlanim XML u otpremljenoj datoteci.",
        "uploadvirus": "Datoteka sadrži virus!\nDetalji: $1",
        "uploadjava": "Datoteka je formata ZIP koji sadrži java .class element.\nSlanje java datoteka nije dozvoljeno jer one mogu izazvati zaobilaženje sigurnosnih ograničenja.",
        "upload-source": "Izvorna datoteka",
        "upload-description": "Opis datoteke",
        "upload-options": "Opcije otpremanja",
        "watchthisupload": "Nadgledaj ovu datoteku",
-       "filewasdeleted": "Datoteka s ovim nazivom je ranije poslata, ali je obrisana.\nProverite $1 pre nego što nastavite s ponovnim slanjem.",
+       "filewasdeleted": "Datoteka sa ovim imenom je ranije optremljena i nakon toga izbrisana.\nTrebate da proverite $1 pre nego što nastavite sa njenim ponovnim optremanjem.",
+       "filename-thumb-name": "Ovo izgleda kao naziv sličice. Molimo vas da ne otpremate sličice na isti viki. U suprotnom, molimo vas, popravite ime datoteke tako da je korisnije i nema prefiks sličice.",
        "filename-bad-prefix": "Naziv datoteke koju šaljete počinje sa <strong>„$1“</strong>, a njega obično dodeljuju digitalni fotoaparati.\nIzaberite naziv datoteke koji opisuje njen sadržaj.",
        "filename-prefix-blacklist": " #<!-- ostavite ovaj red onakvim kakav jeste --> <pre>\n# Sintaksa je sledeća:\n#   * Sve od tarabe pa do kraja reda je komentar\n#   * Svaki red označava prefiks tipičnih naziva datoteka koje dodeljivaju digitalni aparati\nCIMG # Kasio\nDSC_ # Nikon\nDSCF # Fudži\nDSCN # Nikon\nDUW # neki mobilni telefoni\nIMG # opšte\nJD # Dženoptik\nMGP # Pentaks\nPICT # razno\n #</pre> <!-- ostavite ovaj red onakvim kakav jeste -->",
-       "upload-proto-error": "Neispravan protokol",
+       "upload-proto-error": "Nevažeći protokol",
        "upload-proto-error-text": "Slanje sa spoljne lokacije zahteva adresu koja počinje sa <code>http://</code> ili <code>ftp://</code>.",
        "upload-file-error": "Unutrašnja greška",
        "upload-file-error-text": "Došlo je do unutrašnje greške pri otvaranju privremene datoteke na serveru.\nKontaktirajte [[Special:ListUsers/sysop|administratora]].",
        "upload-misc-error": "Nepoznata greška pri slanju datoteke",
-       "upload-misc-error-text": "Nepoznata greška pri slanju datoteke.\nProverite da li je adresa ispravna i pokušajte ponovo.\nAko se problem ne reši, kontaktirajte [[Special:ListUsers/sysop|administratora]].",
+       "upload-misc-error-text": "Nepoznata greška pri otpremanju datoteke.\nProverite da li je adresa validna i pokušajte ponovo.\nAko se problem ne reši, kontaktirajte [[Special:ListUsers/sysop|administratora]].",
        "upload-too-many-redirects": "Adresa sadrži previše preusmerenja",
        "upload-http-error": "Došlo je do HTTP greške: $1",
        "upload-copy-upload-invalid-domain": "Primerci otpremanja nisu dostupni na ovom domenu.",
        "upload-dialog-button-upload": "Otpremi",
        "upload-form-label-infoform-title": "Detalji",
        "upload-form-label-infoform-name": "Naziv",
+       "upload-form-label-infoform-name-tooltip": "Jedinstveni opisni naslov za datoteku, koji će služiti kao ime datoteke. Možete koristiti čist jezik sa razmacima. Ne uključujte proširenje datoteke.",
        "upload-form-label-infoform-description": "Opis",
        "upload-form-label-usage-title": "Upotrebe",
        "upload-form-label-usage-filename": "Naziv datoteke",
        "upload-form-label-own-work": "Ovo je moje sopstveno delo",
        "upload-form-label-infoform-categories": "Kategorije",
        "upload-form-label-infoform-date": "Datum",
+       "upload-form-label-own-work-message-generic-local": "Ja potvrđujem da otpremam ovu datoteku poštujući uslove korišćenja usluge i licenciranje na {{SITENAME}}.",
+       "upload-form-label-not-own-work-message-generic-local": "Ako niste u mogućnosti da otpremite ovu datoteku pod uslovima {{SITENAME}}, molimo vas da zatvorite ovaj dijalog i pokušate drugom metodom.",
        "upload-form-label-not-own-work-local-generic-local": "Takođe možete pokušati [[Special:Upload|podrazumevanu stranicu za otpremanje]].",
        "backend-fail-stream": "Ne mogu da emitujem datoteku $1.",
        "backend-fail-backup": "Ne mogu da napravim rezervu datoteke $1.",
        "backend-fail-notexists": "Datoteka $1 ne postoji.",
        "backend-fail-hashes": "Ne mogu da dobijem disperzije datoteke za upoređivanje.",
        "backend-fail-notsame": "Već postoji neistovetna datoteka – $1.",
-       "backend-fail-invalidpath": "$1 nije ispravna putanja za skladištenje.",
-       "backend-fail-delete": "Ne mogu da obrišem datoteku „$1”.",
+       "backend-fail-invalidpath": "$1 nije važeća putanja za skladištenje.",
+       "backend-fail-delete": "Ne mogu da izbrišem datoteku „$1”.",
        "backend-fail-describe": "Ne mogu da promenim metapodatke za datoteku „$1“.",
        "backend-fail-alreadyexists": "Datoteka $1 već postoji.",
        "backend-fail-store": "Ne mogu da smestim datoteku $1 u $2.",
        "backend-fail-read": "Ne mogu da pročitam datoteku $1.",
        "backend-fail-create": "Ne mogu da zapišem datoteku $1.",
        "backend-fail-maxsize": "Ne mogu da zapišem datoteku $1 jer je veća od {{PLURAL:$2|$2 bajta|$2 bajta|$2 bajtova}}.",
-       "backend-fail-readonly": "Skladišna osnova „$1“ trenutno ne može da se zapisuje. Navedeni razlog glasi: <em>$2</em>",
+       "backend-fail-readonly": "Skladišna osnova „$1“ je trenutno samo za čitanje. Navedeni razlog je: <em>$2</em>",
        "backend-fail-synced": "Datoteka „$1“ je nedosledna između unutrašnjih skladišnih osnova",
        "backend-fail-connect": "Ne mogu da se povežem sa skladišnom osnovom „$1“.",
        "backend-fail-internal": "Došlo je do nepoznate greške u skladišnoj osnovi „$1“.",
        "filejournal-fail-dbquery": "Ne mogu da ažuriram novinarsku bazu za skladišnu osnovu „$1“.",
        "lockmanager-notlocked": "Ne mogu da otključam „$1“ jer nije zaključan.",
        "lockmanager-fail-closelock": "Ne mogu da zatvorim katanac za „$1“.",
-       "lockmanager-fail-deletelock": "Ne mogu da obrišem katanac za „$1“.",
+       "lockmanager-fail-deletelock": "Ne mogu da izbrišem katanac za „$1“.",
        "lockmanager-fail-acquirelock": "Ne mogu da se zaključam za „$1“.",
-       "lockmanager-fail-openlock": "Ne mogu da otvorim katanac za „$1“. Uverite se da je Vaš direktorijum za otpremanje ispravno konfigurisan i da Vaš veb-server ima dozvolu da piše u tom direktorijumu. Pogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory za više informacija.",
+       "lockmanager-fail-openlock": "Ne mogu da otvorim katanac za „$1“. Uverite se da je vaš direktorijum za otpremanje ispravno konfigurisan i da vaš veb-server ima dozvolu da piše u tom direktorijumu. Pogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory za više informacija.",
        "lockmanager-fail-releaselock": "Ne mogu da oslobodim katanac za „$1“.",
        "lockmanager-fail-db-bucket": "Ne mogu da kontaktiram s dovoljno katanaca u kanti $1.",
        "lockmanager-fail-db-release": "Ne mogu da oslobodim katance u bazi $1.",
        "zip-wrong-format": "Navedena datoteka nije formata ZIP.",
        "zip-bad": "Datoteka je oštećena ili je nečitljiva ZIP datoteka.\nBezbednosna provera ne može da se izvrši kako treba.",
        "zip-unsupported": "Datoteka je formata ZIP koji koristi mogućnosti koje ne podržava Medijaviki.\nBezbednosna provera ne može da se izvrši kako treba.",
-       "uploadstash": "Tajno skladište",
+       "uploadstash": "Otpremanje niza datoteka",
        "uploadstash-summary": "Ova stranica pruža pristup datotekama koje su otpremljene ili se otpremaju, ali još nisu objavljene. Ove datoteke nisu vidljive nikome, osim korisniku koji ih je otpremio.",
        "uploadstash-clear": "Očisti sakrivene datoteke",
        "uploadstash-nofiles": "Nemate sakrivene datoteke.",
        "uploadstash-badtoken": "Izvršavanje ove radnje nije uspelo, razlog tome može biti istek vremena za uređivanje. Pokušajte ponovo.",
        "uploadstash-errclear": "Čišćenje datoteka nije uspelo.",
        "uploadstash-refresh": "Osveži spisak datoteka",
-       "uploadstash-thumbnail": "pogledaj minijaturu",
+       "uploadstash-thumbnail": "pogledaj sličicu",
        "uploadstash-exception": "Ne mogu sačuvati datoteku u skladište ($1): „$2“.",
        "uploadstash-bad-path": "Putanja ne postoji.",
-       "uploadstash-bad-path-invalid": "Putanja nije ispravna.",
+       "uploadstash-bad-path-invalid": "Putanja nije validna.",
        "uploadstash-bad-path-unknown-type": "Nepoznat tip „$1“.",
        "uploadstash-bad-path-unrecognized-thumb-name": "Neprepoznato ime minijature.",
        "uploadstash-bad-path-bad-format": "Ključ „$1“ nije u odgovarajućem obliku.",
-       "uploadstash-file-not-found-no-thumb": "Ne mogu dobiti minijaturu.",
+       "uploadstash-file-not-found": "Ključ „$1” nije pronađen u skladištu.",
+       "uploadstash-file-not-found-no-thumb": "Ne mogu da pribavim sličicu.",
        "uploadstash-file-not-found-no-local-path": "Nema lokalne putanje za umanjenu stavku.",
-       "uploadstash-file-not-found-no-object": "Ne mogu napraviti lokalni datotečni objekat za minijaturu.",
+       "uploadstash-file-not-found-no-object": "Ne mogu da napravim lokalni datotečni objekat za sličicu.",
        "uploadstash-file-not-found-no-remote-thumb": "Dobavljanje minijature nije uspelo: $1\nAdresa = $2",
-       "uploadstash-file-not-found-missing-content-type": "Nedostaje zaglavlje za vrstu sadržaja.",
+       "uploadstash-file-not-found-missing-content-type": "Nedostaje zaglavlje za tip sadržaja.",
        "uploadstash-file-not-found-not-exists": "Ne mogu naći putanju ili ovo nije obična datoteka.",
        "uploadstash-file-too-large": "Ne mogu poslužiti datoteku veću od $1 {{PLURAL:$1|bajta|bajtova}}",
        "uploadstash-not-logged-in": "Niko nije prijavljen. Datoteke moraju pripadati korisnicima.",
-       "uploadstash-wrong-owner": "Ova datoteka ($1) ne pripada trenutnom korisniku.",
+       "uploadstash-wrong-owner": "Ova datoteka ($1) ne pripada aktuelnom korisniku.",
        "uploadstash-no-such-key": "Nema takvog ključa ($1). Ne mogu ukloniti.",
-       "uploadstash-no-extension": "Nema traženog dodatka.",
+       "uploadstash-no-extension": "Dodatak je prazan.",
        "uploadstash-zero-length": "Datoteka je prazna",
-       "invalid-chunk-offset": "Neispravna polazna tačka",
+       "invalid-chunk-offset": "Nevažeća polazna tačka",
        "img-auth-accessdenied": "Pristup je odbijen",
        "img-auth-nopathinfo": "Nedostaje PATH_INFO.\nVaš server nije podešen da prosleđuje ovakve podatke.\nMožda je zasnovan na CGI-ju koji ne podržava img_auth.\nPogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization?uselang=sr-ec.",
-       "img-auth-notindir": "Zahtevana putanja nije u podešenoj fascikli za otpremanje.",
-       "img-auth-badtitle": "Ne mogu da stvorim ispravan naslov za „$1“.",
+       "img-auth-notindir": "Tražena putanja nije u podešenom direktorijumu za otpremanje.",
+       "img-auth-badtitle": "Ne mogu da sastavim važeći naslov iz „$1“.",
        "img-auth-nologinnWL": "Niste prijavljeni i „$1” nije na spisku dozvoljenih.",
        "img-auth-nofile": "Datoteka „$1“ ne postoji.",
        "img-auth-isdir": "Pokušavate da pristupite fascikli „$1“.\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Učitavam „$1“...",
        "img-auth-public": "Svrha img_auth.php je da prosleđuje datoteke iz privatnih vikija.\nOvaj viki je postavljen kao javni.\nRadi sigurnosti, img_auth.php je onemogućen.",
        "img-auth-noread": "Korisnik nema pristup za čitanje „$1“.",
-       "http-invalid-url": "Neispravna adresa: $1",
+       "http-invalid-url": "Nevažeći URL: $1",
        "http-invalid-scheme": "Adrese sa šemom „$1“ nisu podržane.",
        "http-request-error": "HTTP zahtev nije prošao zbog nepoznate greške.",
        "http-read-error": "HTTP greška pri čitanju.",
        "http-timed-out": "Zahtev HTTP je istekao.",
        "http-curl-error": "Greška pri otvaranju adrese: $1",
        "http-bad-status": "Došlo je do problema tokom zahteva HTTP: $1 $2",
+       "http-internal-error": "HTTP interna greška.",
        "upload-curl-error6": "Ne mogu da pristupim adresi",
-       "upload-curl-error6-text": "Ne mogu da pristupim navedenoj adresi.\nProverite da li je adresa ispravna i dostupna.",
+       "upload-curl-error6-text": "Ne mogu da pristupim navedenom URL-u.\nProverite da li je URL ispravan i dostupan.",
        "upload-curl-error28": "Otpremanje je isteklo",
        "upload-curl-error28-text": "Server ne odgovara na upit.\nProverite da li sajt radi, malo osačekajte i pokušajte ponovo.\nProbajte kasnije kada bude manje opterećenje.",
        "license": "Licenca:",
        "nolicense": "Nije izabrano",
        "licenses-edit": "Uredi izbor licenci",
        "license-nopreview": "(pregled nije dostupan)",
-       "upload_source_url": "(vaša izabrana datoteka od ispravnih i javno dostupnih adresa)",
-       "upload_source_file": "(vaša odabrana datoteka sa vašeg računara)",
-       "listfiles-delete": "obriši",
+       "upload_source_url": "(vaša izabrana datoteka od važećih, javno dostupnih adresa)",
+       "upload_source_file": "(vaša odabrana datoteka sa računara)",
+       "listfiles-delete": "izbriši",
        "listfiles-summary": "Ova posebna stranica prikazuje sve otpremljene datoteke.",
        "listfiles_search_for": "Naziv datoteke:",
        "listfiles-userdoesnotexist": "Korisnički nalog „$1“ nije otvoren.",
        "imgfile": "datoteka",
        "listfiles": "Spisak datoteka",
-       "listfiles_thumb": "Minijatura",
+       "listfiles_thumb": "Sličica",
        "listfiles_date": "Datum",
        "listfiles_name": "Naziv",
        "listfiles_user": "Korisnik",
        "listfiles_description": "Opis",
        "listfiles_count": "Verzije",
        "listfiles-show-all": "Obuhvati stare verzije datoteka",
-       "listfiles-latestversion": "Trenutna verzija",
+       "listfiles-latestversion": "Aktuelna verzija",
        "listfiles-latestversion-yes": "Da",
        "listfiles-latestversion-no": "Ne",
        "file-anchor-link": "Datoteka",
        "filehist": "Istorija datoteke",
-       "filehist-help": "Kliknite na datum/vreme da vidite tadašnju verziju datoteke.",
-       "filehist-deleteall": "obriši sve",
-       "filehist-deleteone": "obriši",
+       "filehist-help": "Kliknite na datum/vreme da biste videli tadašnju verziju datoteke.",
+       "filehist-deleteall": "izbriši sve",
+       "filehist-deleteone": "izbriši",
        "filehist-revert": "vrati",
-       "filehist-current": "trenutno",
+       "filehist-current": "aktuelna",
        "filehist-datetime": "Datum/vreme",
-       "filehist-thumb": "Minijatura",
+       "filehist-thumb": "Sličica",
        "filehist-thumbtext": "Minijatura za verziju na dan $1",
-       "filehist-nothumb": "Nema umanjenog prikaza",
+       "filehist-nothumb": "Bez sličice",
        "filehist-user": "Korisnik",
        "filehist-dimensions": "Dimenzije",
        "filehist-filesize": "Veličina datoteke",
        "filehist-comment": "Komentar",
        "imagelinks": "Upotreba datoteke",
        "linkstoimage": "{{PLURAL:$1|Sledeća stranica koristi|$1 sledeće stranice koriste|$1 sledećih stranica koristi}} ovu datoteku:",
-       "linkstoimage-more": "Više od $1 {{PLURAL:$1|stranica|stranice|stranica}} je povezano s ovom datotekom.\nSledeći spisak prikazuje samo {{PLURAL:$1|prvu stranicu povezanu|prve $1 stranice povezane|prvih $1 stranica povezanih}} s ovom datotekom.\nDostupan je i [[Special:WhatLinksHere/$2|potpuni spisak]].",
+       "linkstoimage-more": "Više od $1 {{PLURAL:$1|stranica koristi|stranice koriste|stranica koristi}} ovu datoteku.\nSledeći spisak prikazuje {{PLURAL:$1|prvu stranicu koja koristi|prve $1 stranice koje koriste|prvih $1 stranica koje koriste}} samo ovu datoteku.\nDostupan je i [[Special:WhatLinksHere/$2|potpuni spisak]].",
        "nolinkstoimage": "Nema stranica koje koriste ovu datoteku.",
-       "morelinkstoimage": "Pogledajte [[Special:WhatLinksHere/$1|više veza]] do ove datoteke.",
+       "morelinkstoimage": "Pogledajte [[Special:WhatLinksHere/$1|više linkova]] do ove datoteke.",
        "linkstoimage-redirect": "$1 (preusmerenje datoteke) $2",
        "duplicatesoffile": "{{PLURAL:$1|Sledeća datoteka je duplikat|Sledeće $1 datoteke su duplikati|Sledećih $1 datoteka su duplikati}} ove datoteke ([[Special:FileDuplicateSearch/$2|detaljnije]]):",
        "sharedupload": "Ova datoteka se nalazi na $1 i može se koristiti i na drugim projektima.",
        "sharedupload-desc-edit": "Ova datoteka se nalazi na $1 i može da se koristi na drugim projektima.\nNjen opis možete da izmenite na [$2 odgovarajućoj stranici].",
        "sharedupload-desc-create": "Ova datoteka se nalazi na $1 i može da se koristi na drugim projektima.\nNjen opis možete da izmenite na [$2 odgovarajućoj stranici].",
        "filepage-nofile": "Ne postoji datoteka s ovim nazivom.",
-       "filepage-nofile-link": "Ne postoji datoteka s ovim nazivom, ali je možete [$1 poslati].",
+       "filepage-nofile-link": "Ne postoji datoteka sa ovim imenom, ali je možete [$1 opremiti].",
        "uploadnewversion-linktext": "Otpremi novu verziju ove datoteke",
        "shared-repo-from": "iz $1",
        "shared-repo": "zajedničko skladište",
        "upload-disallowed-here": "Ne možete da zamenite ovu datoteku.",
        "filerevert": "Vrati $1",
        "filerevert-legend": "Vrati datoteku",
-       "filerevert-intro": "Vraćate datoteku '''[[Media:$1|$1]]''' na [$4 izdanje od $2; $3].",
+       "filerevert-intro": "Vraćate datoteku <strong>[[Media:$1|$1]]</strong> na [$4 verziju od $2; $3].",
        "filerevert-comment": "Razlog:",
        "filerevert-defaultcomment": "Vraćeno na verziju od $2, $1 ($3)",
        "filerevert-submit": "Vrati",
-       "filerevert-success": "Datoteka '''[[Media:$1|$1]]''' je vraćena na [$4 izdanje od $2; $3].",
-       "filerevert-badversion": "Ne postoji ranije lokalno izdanje datoteke s navedenim vremenskim podacima.",
-       "filerevert-identical": "Trenutna izmena datoteke indentična je izabranoj.",
-       "filedelete": "Obriši $1",
-       "filedelete-legend": "Obriši datoteku",
+       "filerevert-success": "Datoteka <strong>[[Media:$1|$1]]</strong> je vraćena na [$4 verziju od $2; $3].",
+       "filerevert-badversion": "Ne postoji ranija lokalna verzija ove datoteke sa navedenom vremenskom oznakom.",
+       "filerevert-identical": "Aktuelna verzija datoteke je indentična izabranoj.",
+       "filedelete": "Brisanje datoteke/stranice $1",
+       "filedelete-legend": "Izbriši datoteku",
        "filedelete-intro": "Brišete datoteku '''[[Media:$1|$1]]''' zajedno s njenom istorijom.",
        "filedelete-intro-old": "Brišete verziju datoteke '''[[Media:$1|$1]]''' od [$4 $2; $3].",
        "filedelete-comment": "Razlog:",
-       "filedelete-submit": "Obriši",
-       "filedelete-success": "Datoteka '''$1''' je obrisana.",
-       "filedelete-success-old": "Izdanje '''[[Media:$1|$1]]''' od $2, $3 je obrisano.",
+       "filedelete-submit": "Izbriši",
+       "filedelete-success": "Datoteka <strong>$1</strong> je izbrisana.",
+       "filedelete-success-old": "Verzija datoteke <strong>[[Media:$1|$1]]</strong> od $2, $3 je izbrisana.",
        "filedelete-nofile": "Datoteka '''$1''' ne postoji.",
-       "filedelete-nofile-old": "Ne postoji arhivirano izdanje datoteke '''$1''' s navedenim osobinama.",
+       "filedelete-nofile-old": "Ne postoji arhivirana verzija datoteke <strong>$1</strong> sa navedenim osobinama.",
        "filedelete-otherreason": "Drugi/dodatni razlog:",
        "filedelete-reason-otherlist": "Drugi razlog",
        "filedelete-reason-dropdown": "*Najčešći razlozi brisanja\n** Kršenje autorskih prava\n** Duplikati datoteka",
        "filedelete-edit-reasonlist": "Uredi razloge brisanja",
        "filedelete-maintenance": "Brisanje i vraćanje datoteka je privremeno onemogućeno zbog održavanja.",
-       "filedelete-maintenance-title": "Ne mogu da obrišem datoteku",
+       "filedelete-maintenance-title": "Ne mogu da izbrišem datoteku",
        "mimesearch": "MIME pretraga",
        "mimesearch-summary": "Ova stranica omogućava filtriranje datoteka prema njihovim MIME tipovima.\nUlazni podaci: contenttype/subtype ili contenttype/*, npr. <code>image/jpeg</code>.",
-       "mimetype": "MIME vrsta:",
+       "mimetype": "MIME tip:",
        "download": "preuzmi",
        "unwatchedpages": "Nenadgledane stranice",
        "listredirects": "Spisak preusmerenja",
-       "listduplicatedfiles": "Spisak dupliranih datoteka",
+       "listduplicatedfiles": "Spisak datoteka sa duplikatima",
        "listduplicatedfiles-summary": "Ovo je spisak datoteka koje su duplikat nekih drugih datoteka. Samo lokalne datoteke su prikazane.",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] ima [[$3|{{PLURAL:$2|jedan duplikat|$2 duplikata}}]].",
        "unusedtemplates": "Nekorišćeni šabloni",
        "unusedtemplatestext": "Ova stranica navodi sve stranice u imenskom prostoru {{ns:template}} koje nisu uključene ni na jednoj drugoj stranici.\nPre brisanja proverite da li druge stranice vode do tih šablona.",
-       "unusedtemplateswlh": "ostale veze",
+       "unusedtemplateswlh": "ostali linkovi",
        "randompage": "Slučajna stranica",
        "randompage-nopages": "Nema stranica u {{PLURAL:$2|sledećem imenskom prostoru|sledećim imenskim prostorima}}: $1.",
        "randomincategory": "Slučajna stranica u kategoriji",
        "statistics-header-users": "Korisnici",
        "statistics-header-hooks": "Ostalo",
        "statistics-articles": "Stranice sa sadržajem",
-       "statistics-pages": "Stranica",
+       "statistics-pages": "Stranice",
        "statistics-pages-desc": "Sve stranice na vikiju, uključujući stranice za razgovor, preusmerenja itd.",
-       "statistics-files": "Broj poslatih datoteka",
+       "statistics-files": "Otpremljene datoteke",
        "statistics-edits": "Broj izmena stranica otkad postoji {{SITENAME}}",
        "statistics-edits-average": "Prosečan broj izmena po stranici",
        "statistics-users": "Registrovani korisnici",
        "pageswithprop-prophidden-long": "sakriveno dugo tekstualno svojstvo ($1)",
        "pageswithprop-prophidden-binary": "sakriveno dugo binarno svojstvo ($1)",
        "doubleredirects": "Dvostruka preusmerenja",
-       "doubleredirectstext": "Ova stranica prikazuje stranice koje preusmeravaju na druga preusmerenja.\nSvaki red sadrži veze prema prvom i drugom preusmerenju, kao i odredišnu stranicu drugog preusmerenja koja je obično „pravi“ članak na koga prvo preusmerenje treba da upućuje.\n<del>Precrtani</del> unosi su već rešeni.",
+       "doubleredirectstext": "Ova stranica prikazuje stranice koje preusmeravaju na druga preusmerenja.\nSvaki red sadrži linkove prema prvom i drugom preusmerenju, kao i odredišnu stranicu drugog preusmerenja koja je obično „pravi“ članak na koga prvo preusmerenje treba da upućuje.\n<del>Precrtani</del> unosi su već rešeni.",
        "double-redirect-fixed-move": "[[$1]] je premešten.\nAutomatski je ažurirano i sada preusmerava na [[$2]].",
        "double-redirect-fixed-maintenance": "Automatski ispravlja dvostruka preusmerenja iz [[$1]] u [[$2]] kao deo održavanja",
        "double-redirect-fixer": "Ispravljač preusmerenja",
        "brokenredirects": "Pokvarena preusmerenja",
-       "brokenredirectstext": "Sledeća preusmerenja upućuju na nepostojeće stranice:",
+       "brokenredirectstext": "Sledeća preusmerenja vode na nepostojeće stranice:",
        "brokenredirects-edit": "uredi",
-       "brokenredirects-delete": "obriši",
-       "withoutinterwiki": "Stranice bez jezičkih veza",
-       "withoutinterwiki-summary": "Sledeće stranice nisu povezane s drugim jezicima.",
+       "brokenredirects-delete": "izbriši",
+       "withoutinterwiki": "Stranice bez jezičkih linkova",
+       "withoutinterwiki-summary": "Sledeće stranice nemaju linkove prema verzijama na drugim jezicima.",
        "withoutinterwiki-legend": "Prefiks",
        "withoutinterwiki-submit": "Prikaži",
-       "fewestrevisions": "Stranice s najmanje izmena",
+       "fewestrevisions": "Stranice sa najmanje izmena",
        "nbytes": "$1 {{PLURAL:$1|bajt|bajta|bajtova}}",
        "ncategories": "$1 {{PLURAL:$1|kategorija|kategorije|kategorija}}",
        "ninterwikis": "$1 {{PLURAL:$1|međuviki|međuvikija|međuvikija}}",
-       "nlinks": "$1 {{PLURAL:$1|veza|veze|veza}}",
+       "nlinks": "$1 {{PLURAL:$1|link|linka|linkova}}",
        "nmembers": "$1 {{PLURAL:$1|član|člana|članova}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|član|člana|članova}}",
        "nrevisions": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
        "unusedimages": "Nekorišćene datoteke",
        "wantedcategories": "Tražene kategorije",
        "wantedpages": "Tražene stranice",
-       "wantedpages-summary": "Spisak nepostojećih stranica sa najviše veza do njih, na ovom spisku se ne nalaze stranice do kojih vode preusmerenja. Za spisak pokvarenih preusmerenja pogledajte [[{{#special:BrokenRedirects}}|spisak pokvarenih preusmerenja]].",
-       "wantedpages-badtitle": "Neispravan naslov u setu rezultata: $1",
+       "wantedpages-summary": "Spisak nepostojećih stranica sa najviše linkova do njih, na ovom spisku se ne nalaze stranice do kojih vode preusmerenja. Za spisak pokvarenih preusmerenja pogledajte [[{{#special:BrokenRedirects}}|spisak pokvarenih preusmerenja]].",
+       "wantedpages-badtitle": "Nevalidan naslov u skupu rezultata: $1",
        "wantedfiles": "Tražene datoteke",
        "wantedfiletext-cat": "Sledeće datoteke se koriste, ali ne postoje. Datoteke iz drugih riznica mogu biti navedene iako ne postoje. Takve datoteke će biti <del>poništene</del> sa spiska. Pored toga, stranice koje sadrže nepostojeće datoteke se nalaze [[:$1|ovde]].",
        "wantedfiletext-nocat": "Sledeće datoteke se koriste, ali ne postoje. Datoteke iz drugih riznica mogu biti navedene iako ne postoje. Takve datoteke će biti <del>poništene</del> sa spiska.",
        "wantedfiletext-nocat-noforeign": "Sledeće datoteke se koriste, ali ne postoje.",
        "wantedtemplates": "Traženi šabloni",
-       "mostlinked": "Stranice s najviše veza",
-       "mostlinkedcategories": "Kategorije s najviše veza",
-       "mostlinkedtemplates": "Stranice s najviše veza",
-       "mostcategories": "Stranice s najviše kategorija",
-       "mostimages": "Datoteke s najviše veza",
+       "mostlinked": "Stranice sa najviše linkova",
+       "mostlinkedcategories": "Kategorije sa najviše linkova",
+       "mostlinkedtemplates": "Stranice sa najviše linkova",
+       "mostcategories": "Stranice sa najviše kategorija",
+       "mostimages": "Datoteke sa najviše linkova",
        "mostinterwikis": "Stranice sa najviše međuvikija",
-       "mostrevisions": "Stranice s najviše izmena",
+       "mostrevisions": "Stranice sa najviše izmena",
        "prefixindex": "Sve stranice sa prefiksom",
        "prefixindex-namespace": "Sve stranice s predmetkom (imenski prostor $1)",
        "prefixindex-submit": "Prikaži",
        "shortpages": "Kratke stranice",
        "longpages": "Dugačke stranice",
        "deadendpages": "Ćorsokaci",
-       "deadendpagestext": "Sledeće stranice nemaju veze do drugih stranica na ovom vikiju.",
+       "deadendpagestext": "Sledeće stranice nemaju linkove do drugih stranica na ovom vikiju.",
        "protectedpages": "Zaštićene stranice",
        "protectedpages-filters": "Filteri:",
        "protectedpages-indef": "Samo neograničene zaštite",
-       "protectedpages-summary": "Na ovoj stranici se nalazi spisak trenutno zaštićenih stranica. Za spisak zaštićenih naslova vidi [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
+       "protectedpages-summary": "Na ovoj stranici se nalazi spisak postojećih stranica koje su trenutno zaštićene. Za spisak naslova koji su zaštićeni od pravljenja, pogledajte [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "protectedpages-cascade": "Samo prenosive zaštite",
        "protectedpages-noredirect": "Sakrij preusmerenja",
        "protectedpagesempty": "Nema zaštićenih stranica s ovim parametrima.",
-       "protectedpages-timestamp": "Vreme i datum",
+       "protectedpages-timestamp": "Vremenska oznaka",
        "protectedpages-page": "Stranica",
        "protectedpages-expiry": "Ističe",
        "protectedpages-performer": "Zaštitio",
-       "protectedpages-params": "Nivo zaštite",
+       "protectedpages-params": "Parametri zaštite",
        "protectedpages-reason": "Razlog",
        "protectedpages-submit": "Prikaži stranice",
        "protectedpages-unknown-timestamp": "nema",
        "protectedpages-unknown-performer": "nema",
        "protectedtitles": "Zaštićeni naslovi",
-       "protectedtitles-summary": "Na ovoj stranici se nalazi spisak trenutno zaštićenih naslova. Za spisak trenutno zaštićenih stranica vidi [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
+       "protectedtitles-summary": "Na ovoj stranici se nalaze naslovi koji su trenutno zaštićeni od pravljenja. Za spisak postojećih stranica koje su zaštićene, pogledajte [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
        "protectedtitlesempty": "Nema zaštićenih naslova s ovim parametrima.",
        "protectedtitles-submit": "Prikaži naslove",
        "listusers": "Spisak korisnika",
        "apisandbox-dynamic-parameters-add-placeholder": "Naziv parametra",
        "apisandbox-dynamic-error-exists": "Parametar pod nazivom \"$1\" već postoji.",
        "apisandbox-deprecated-parameters": "Zastareli parametri",
-       "apisandbox-fetch-token": "Automatski popuni token",
+       "apisandbox-fetch-token": "Automatski ispuni token",
        "apisandbox-add-multi": "Dodaj",
-       "apisandbox-submit-invalid-fields-title": "Neka polja nisu ispravna",
+       "apisandbox-submit-invalid-fields-title": "Neka polja nisu validna",
        "apisandbox-submit-invalid-fields-message": "Molimo Vas popravite označena polja i pokušajte ponovo.",
        "apisandbox-results": "Rezultati",
-       "apisandbox-sending-request": "Slanje API zahteva...",
+       "apisandbox-sending-request": "Šaljem API zahtev…",
        "apisandbox-loading-results": "Prijem API rezultata...",
        "apisandbox-results-error": "Došlo je do greške prilikom učitavanja rezultata API upita: $1.",
        "apisandbox-request-selectformat-label": "Prikaži sahtevane podatke kao:",
        "apisandbox-request-format-json-label": "JSON",
        "apisandbox-request-json-label": "Zatražite JSON:",
        "apisandbox-request-time": "Vreme za izvršavanje zahtjeva: {{PLURAL:$1|$1 milisekunda|$1 milisekunde|$1 milisekundi}}",
-       "apisandbox-results-fixtoken": "Ispravi žeton i pošalji ponovo",
-       "apisandbox-results-fixtoken-fail": "Nisam uspeo da dobijem žeton „$1“.",
-       "apisandbox-alert-page": "Polja na stranici su neispravna.",
-       "apisandbox-alert-field": "Vrednost ovog polja je neispravna.",
+       "apisandbox-results-fixtoken": "Ispravi token i pošalji ponovo",
+       "apisandbox-results-fixtoken-fail": "Neuspelo dobijanje „$1“ tokena.",
+       "apisandbox-alert-page": "Polja na stranici nisu važeća.",
+       "apisandbox-alert-field": "Vrednost ovog polja nije važeća.",
        "apisandbox-continue": "Nastavi",
        "apisandbox-continue-clear": "Očisti",
        "apisandbox-param-limit": "Unesite <kbd>max</kbd> da bi ste koristili najveće ograničenje.",
        "booksources-search-legend": "Pretraži štampane izvore",
        "booksources-isbn": "ISBN:",
        "booksources-search": "Pretraži",
-       "booksources-text": "Ispod se nalazi spisak veza ka sajtovima koji se bave prodajom novih i polovnih knjiga, a koji bi mogli imati dodatne podatke o knjigama koje tražite:",
-       "booksources-invalid-isbn": "Navedeni ISBN broj nije ispravan. Proverite da nije došlo do greške pri umnožavanju iz prvobitnog izvora.",
-       "magiclink-tracking-rfc": "Stranice s magičnim RFC vezama",
-       "magiclink-tracking-pmid": "Stranice s magičnim PMID vezama",
-       "magiclink-tracking-isbn": "Stranice sa ISBN magičnim vezama",
+       "booksources-text": "Ispod se nalazi spisak linkova ka sajtovima koji se bave prodajom novih i polovnih knjiga, a koji bi mogli imati dodatne podatke o knjigama koje tražite:",
+       "booksources-invalid-isbn": "Navedeni ISBN broj nije validan. Proverite da nije došlo do greške pri kopiranju iz prvobitnog izvora.",
+       "magiclink-tracking-rfc": "Stranice sa magičnim RFC linkovima",
+       "magiclink-tracking-pmid": "Stranice sa magičnim PMID linkovima",
+       "magiclink-tracking-isbn": "Stranice sa ISBN magičnim linkovima",
        "specialloguserlabel": "Izvršilac:",
        "speciallogtitlelabel": "Cilj (naslov ili {{ns:user}}:korisničko ime):",
-       "log": "Dnevnici",
+       "log": "Evidencije",
        "logeventslist-submit": "Prikaži",
-       "logeventslist-more-filters": "Prikaz dodatnih dnevnika:",
-       "all-logs-page": "Svi javni dnevnici",
-       "alllogstext": "Skupni prikaz svih dostupnih istorija ovog vikija.\nMožete suziti prikaz odabirući vrstu istorije, korisničkog imena ili tražene stranice.",
-       "logempty": "Nema pronađenih unosa u dnevniku.",
+       "logeventslist-more-filters": "Prikaz dodatnih evidencija:",
+       "logeventslist-patrol-log": "Evidencija patroliranja",
+       "logeventslist-tag-log": "Evidencija oznaka",
+       "all-logs-page": "Sve javne evidencije",
+       "alllogstext": "Skupni prikaz svih dostupnih evidencija sa ovog vikija.\nMožete suziti prikaz izabiranjem tipa evidencije, korisničkog imena (osetljivo na mala i velika slova) ili tražene stranice (takođe osetljivo na mala i velika slova).",
+       "logempty": "Nema pronađenih unosa u evidenciji.",
        "log-title-wildcard": "Pretraži naslove koji počinju sa ovim tekstom",
-       "showhideselectedlogentries": "Prikaži/sakrij izabrane događaje",
-       "log-edit-tags": "Uredi oznake izabranih unosa u dnevnicima",
+       "showhideselectedlogentries": "Promeni vidljivost izabranih unosa u evidenciji",
+       "log-edit-tags": "Uredi oznake izabranih unosa u evidencijama",
        "checkbox-select": "Izaberi: $1",
        "checkbox-all": "Sve",
        "checkbox-none": "Ništa",
        "allinnamespace": "Sve stranice (imenski prostor $1)",
        "allpagessubmit": "Idi",
        "allpagesprefix": "Prikaži stranice s prefiksom:",
-       "allpagesbadtitle": "Navedeni naziv stranice nije ispravan ili sadrži međujezički ili međuviki prefiks.\nMožda sadrži znakove koji se ne mogu koristiti u naslovima.",
+       "allpagesbadtitle": "Navedeni naziv stranice nije validan ili sadrži međujezički ili međuviki prefiks.\nMožda sadrži jedan ili više znakova koji se ne mogu koristiti u naslovima.",
        "allpages-bad-ns": "{{SITENAME}} nema imenski prostor „$1“.",
        "allpages-hide-redirects": "Sakrij preusmerenja",
        "cachedspecial-viewing-cached-ttl": "Gledate keširanu verziju ove stranice, koja može biti stara i do $1.",
-       "cachedspecial-viewing-cached-ts": "Gledate keširanu verziju ove stranice, koja može da se razlikuje od trenutne.",
+       "cachedspecial-viewing-cached-ts": "Gledate keširanu verziju ove stranice, koja možda nije potpuno aktuelna.",
        "cachedspecial-refresh-now": "Pogledaj najnoviju.",
        "categories": "Kategorije",
        "categories-submit": "Prikaži",
        "categoriespagetext": "{{PLURAL:$1|1=Sledeća kategorija sadrži|Sledeće kategorije sadrže}} stranice ili datoteke.\n[[Special:UnusedCategories|Nekorišćene kategorije]] nisu prikazane ovde.\nPogledajte i [[Special:WantedCategories|tražene kategorije]].",
        "categoriesfrom": "Prikaži kategorije počev od:",
-       "deletedcontributions": "Obrisani korisnički doprinosi",
-       "deletedcontributions-title": "Obrisani korisnički doprinosi",
+       "deletedcontributions": "Izbrisani korisnički doprinosi",
+       "deletedcontributions-title": "Izbrisani korisnički doprinosi",
        "sp-deletedcontributions-contribs": "doprinosi",
-       "linksearch": "Pretraga spoljašnjih veza",
+       "linksearch": "Pretraga spoljašnjih linkova",
        "linksearch-pat": "Obrazac pretrage:",
        "linksearch-ns": "Imenski prostor:",
        "linksearch-ok": "Pretraži",
        "linksearch-text": "Mogu se koristiti džokeri poput „*.wikipedia.org“.\nPotreban je najviši domen, kao „*.org“.<br />\n{{PLURAL:$2|1=Podržan protokol|Podržani protokoli}}: $1 (zadaje http:// ako ne navedete protokol).",
-       "linksearch-line": "$1 veza u $2",
+       "linksearch-line": "$1 vodi sa $2",
        "linksearch-error": "Džokeri se mogu pojaviti samo na početku adrese.",
        "listusersfrom": "Prikaži korisnike počev od:",
        "listusers-submit": "Prikaži",
        "listgrants": "Dozvole",
        "listgrants-grant": "Dozvola",
        "listgrants-rights": "Prava",
-       "trackingcategories": "Medijaviki kategorije",
+       "listgrants-grant-display": "$1 <code>($2)</code>",
+       "trackingcategories": "Kategorije za praćenje",
        "trackingcategories-summary": "Ova posebna stranica je spisak kategorija koje su deo Medijavikija, one se automatski ažuriraju i njihovi nazivi se mogu menjati uređivanjem sistemskih poruka u imenskom prostoru {{ns:8}}.",
-       "trackingcategories-msg": "Praćenje kategorije",
+       "trackingcategories-msg": "Kategorije za praćenje",
        "trackingcategories-name": "Ime poruke",
        "trackingcategories-desc": "Koje stranice se nalaze u kategoriji",
        "restricted-displaytitle-ignored": "Stranice sa zanemarenim naslovima za prikaz",
        "noindex-category-desc": "Stranice koje u sebi imaju magičnu reč <code><nowiki>__NOINDEX__</nowiki></code>.",
        "index-category-desc": "Stranice koje u sebi imaju magičnu reč <code><nowiki>__INDEX__</nowiki></code> i samim tim su indeksirane od strane robota.",
-       "broken-file-category-desc": "Stranice koje imaju veze do nepostojećih datoteka.",
+       "broken-file-category-desc": "Stranica sadrži pokvareni link do datoteke (link za ugrađivanje datoteke kada ona ne postoji).",
        "hidden-category-category-desc": "Kategorije koje u sebi imaju magičnu reč <code><nowiki>__HIDDENCAT__</nowiki></code> i samim tim se ne prikazuju u odeljku za kategorije na stranicama.",
        "trackingcategories-nodesc": "Opis nije dostupan.",
        "trackingcategories-disabled": "Kategorija je onemogućena",
        "mailnologin": "Nema adrese za slanje",
-       "mailnologintext": "Morate biti [[Special:UserLogin|prijavljeni]] i imati ispravan imejl adresu u [[Special:Preferences|podešavanjima]] da biste slali imejlove drugim korisnicima.",
+       "mailnologintext": "Morate biti [[Special:UserLogin|prijavljeni]] i imati valjanu imejl adresu u [[Special:Preferences|podešavanjima]] da biste slali imejlove drugim korisnicima.",
        "emailuser": "Pošalji imejl ovom korisniku/ci",
        "emailuser-title-target": "Slanje imejla {{GENDER:$1|korisniku|korisnici}}",
        "emailuser-title-notarget": "Slanje imejla korisniku",
        "defemailsubject": "{{SITENAME}} — Imejl od {{GENDER:$1|korisnika|korisnice}} „$1”",
        "usermaildisabled": "Korisnički imejl je onemogućen",
        "usermaildisabledtext": "Ne možete da šaljete imejlove drugim korisnicima na ovom vikiju",
-       "noemailtitle": "Nema imejl adrese",
-       "noemailtext": "Ovaj korisnik nije naveo ispravnu imejl adresu.",
+       "noemailtitle": "Nema imejl-adrese",
+       "noemailtext": "Ovaj korisnik nije naveo važeću imejl-adresu.",
        "nowikiemailtext": "Ovaj korisnik je odlučio da ne prima imejlove od drugih korisnika.",
-       "emailnotarget": "Nepostojeće ili neispravno korisničko ime primaoca.",
+       "emailnotarget": "Nepostojeće ili navažeće korisničko ime primaoca.",
        "emailtarget": "Unos korisničkog imena primaoca",
        "emailusername": "Korisničko ime:",
        "emailusernamesubmit": "Pošalji",
-       "email-legend": "Pošalji imejl drugom korisniku",
+       "email-legend": "Slanje imejla drugom korisniku projekta {{SITENAME}}",
        "emailfrom": "Od:",
        "emailto": "Za:",
        "emailsubject": "Naslov:",
        "emailmessage": "Poruka:",
        "emailsend": "Pošalji",
        "emailccme": "Pošalji mi kopiju poruke na moj imejl.",
-       "emailccsubject": "Kopija vaše poruke korisniku $1: $2",
+       "emailccsubject": "Kopija poruke korisniku/ci $1: $2",
        "emailsent": "Imejl je poslat",
        "emailsenttext": "Vaša imejl poruka je poslata.",
        "emailuserfooter": "Ovaj imejl je {{GENDER:$1|poslao|poslala}} $1 {{GENDER:$2|korisniku|korisnici}} $2 pomoću opcije „{{int:emailuser}}“ na vikiju {{SITENAME}}. Ako odgovorite na ovaj imejl, {{GENDER:$2|Vaš}} imejl će biti neposredno prosleđen ka {{GENDER:$1|prvobitnom pošiljaocu}}, čime ćete {{GENDER:$2|mu|joj}} otkriti {{GENDER:$2|svoju}} imejl adresu.",
        "watchlist": "Spisak nadgledanja",
        "mywatchlist": "Spisak nadgledanja",
        "watchlistfor2": "Za $1 $2",
-       "nowatchlist": "Vaš spisak nadgledanja je prazan.",
+       "nowatchlist": "Nemate ništa na svom spisku nadgledanja.",
        "watchlistanontext": "Morate biti prijavljeni da biste gledali i uređivali stavke na vašem spisku nadgledanja.",
        "watchnologin": "Niste prijavljeni",
        "addwatch": "Dodaj na spisak nadgledanja",
-       "addedwatchtext": "Stranica „[[:$1]]“ i njena stranica za razgovor je dodata na Vaš [[Special:Watchlist|spisak nadgledanja]].",
-       "addedwatchtext-talk": "Stranica „[[:$1]]” i njena pridružena stranica je dodata na Vaš [[Special:Watchlist|spisak nadgledanja]]",
-       "addedwatchtext-short": "Stranica „$1“ je dodata na Vaš spisak nadgledanja.",
+       "addedwatchtext": "Stranica „[[:$1]]“ i njena stranica za razgovor je dodata na vaš [[Special:Watchlist|spisak nadgledanja]].",
+       "addedwatchtext-talk": "Stranica „[[:$1]]” i njena pridružena stranica je dodata na vaš [[Special:Watchlist|spisak nadgledanja]]",
+       "addedwatchtext-short": "Stranica „$1“ je dodata na vaš spisak nadgledanja.",
        "removewatch": "Ukloni sa spiska nadgledanja",
-       "removedwatchtext": "Stranica „[[:$1]]“ i njena stranica za razgovor je uklonjena sa Vašeg [[Special:Watchlist|spiska nadgledanja]].",
-       "removedwatchtext-short": "Stranica „$1“ je uklonjena s vašeg spiska nadgledanja.",
+       "removedwatchtext": "Stranica „[[:$1]]“ i njena stranica za razgovor je uklonjena sa vašeg [[Special:Watchlist|spiska nadgledanja]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" i njegove povezane stranice su uklonjene sa vašeg [[Special:Watchlist|spiska nadgledanja]].",
+       "removedwatchtext-short": "Stranica „$1“ je uklonjena sa vašeg spiska nadgledanja.",
        "watch": "Nadgledaj",
        "watchthispage": "Nadgledaj ovu stranicu",
        "unwatch": "Prekini nadgledanje",
        "unwatchthispage": "Prekini nadgledanje",
        "notanarticle": "Nije stranica sa sadržajem",
-       "notvisiblerev": "Izmena je obrisana",
-       "watchlist-details": "Na Vašem spisku nadgledanja {{PLURAL:$1|je $1 stranica|su $1 stranice|je $1 stranica}} (plus stranice za razgovor).",
+       "notvisiblerev": "Poslednja izmena drugog korisnika je izbrisana.",
+       "watchlist-details": "Imate {{PLURAL:$1|$1 stranicu|$1 stranice|$1 stranica}} na svom spisku nadgledanja (plus stranice za razgovor).",
        "wlheader-enotif": "Obaveštenje imejlom je omogućeno.",
-       "wlheader-showupdated": "Stranice koje su izmenjene otkad ste ih poslednji put posetili su <strong>podebljane</strong>.",
-       "wlnote": "Ispod {{PLURAL:$1|je poslednja izmena|su poslednje <strong>$1</strong> izmene|je poslednjih <strong>$1</strong> izmena}} u {{PLURAL:$2|prethodnom satu|prethodna <strong>$2</strong> sata|prethodnih <strong>$2</strong> sati}}, zaključno sa $3, $4.",
+       "wlheader-showupdated": "Stranice koje su promenjene otkad ste ih poslednji put posetili su <strong>podebljane</strong>.",
+       "wlnote": "Ispod {{PLURAL:$1|je poslednja promena|su poslednje <strong>$1</strong> promene|je poslednjih <strong>$1</strong> promena}} u {{PLURAL:$2|prethodnom satu|prethodna <strong>$2</strong> sata|prethodnih <strong>$2</strong> sati}}, zaključno sa $3, $4.",
        "wlshowlast": "Prikaži poslednjih $1 sati, $2 dana",
        "watchlist-hide": "Sakrij",
        "watchlist-submit": "Prikaži",
        "enotif_subject_restored": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|vratio je|vratila je|vratio je}} $2",
        "enotif_subject_changed": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|promenio|promenila}} je $2",
        "enotif_body_intro_deleted": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|obrisao|obrisala}} je $2 dana $PAGEEDITDATE Pogledajte $3.",
-       "enotif_body_intro_created": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|napravio|napravila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na $3.",
-       "enotif_body_intro_moved": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|premestio|premestila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na  $3.",
-       "enotif_body_intro_restored": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|vratio|vratila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na $3.",
-       "enotif_body_intro_changed": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|promenio|promenila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na $3.",
-       "enotif_lastvisited": "Za sve izmene od vaše poslednje posete, pogledajte $1.",
-       "enotif_lastdiff": "Da vidite ovu izmenu, pogledajte $1.",
+       "enotif_body_intro_created": "Stranicu $1 na projektu {{SITENAME}} je {{GENDER:$2|napravio korisnik|napravila korisnica}} $2 na datum $PAGEEDITDATE Aktuelna izmena se nalazi na $3.",
+       "enotif_body_intro_moved": "Stranicu $1 na {{SITENAME}} je {{GENDER:$2|premestio korisnik|premestila korisnica}} $2 na datum $PAGEEDITDATE Aktuelna izmena se nalazi na $3.",
+       "enotif_body_intro_restored": "Stranicu $1 na projektu {{SITENAME}} je {{GENDER:$2|vratio korisnik|vratila korisnica}} $2 na datum $PAGEEDITDATE Aktuelna izmena se nalazi na $3.",
+       "enotif_body_intro_changed": "Stranicu $1 na projektu {{SITENAME}} je {{GENDER:$2|promenio korisnik|promenila korisnica}} $2 na datum $PAGEEDITDATE Aktuelna izmena se nalazi na $3.",
+       "enotif_lastvisited": "Za sve promene od poslednje posete, pogledajte $1.",
+       "enotif_lastdiff": "Da biste videli ovu promenu, pogledajte $1.",
        "enotif_anon_editor": "anoniman korisnik $1",
-       "enotif_body": "Poštovani $WATCHINGUSERNAME,\n \t\n$PAGEINTRO $NEWPAGE\n\nOpis: $PAGESUMMARY $PAGEMINOREDIT\n\nKontakt:\nmejl: $PAGEEDITOR_EMAIL\nviki: $PAGEEDITOR_WIKI\n\nNeće biti drugih obaveštenja u slučaju daljih izmena ukoliko ne posetite ovu stranicu kada ste prijavljeni.\nMožete i da poništite podešavanja obaveštenja za sve stranice u vašem spisku nadgledanja.\n\nSrdačan pozdrav, {{SITENAME}}\n\n--\nDa biste promenili podešavanja imejl obaveštenja, posetite\n{{canonicalurl:{{#special:Preferences}}}}\n\nDa biste promenili podešavanja spiska nadgledanja, posetite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nDa biste uklonili ovu stranicu sa spiska nadgledanja, posetite\n$UNWATCHURL\n\nPodrška i dalja pomoć:\n$HELPPAGE",
+       "enotif_body": "Poštovani $WATCHINGUSERNAME,\n \t\n$PAGEINTRO $NEWPAGE\n\nRezime uređivača: $PAGESUMMARY $PAGEMINOREDIT\n\nKontakt:\nmejl: $PAGEEDITOR_EMAIL\nviki: $PAGEEDITOR_WIKI\n\nNeće biti drugih obaveštenja u slučaju daljih izmena ukoliko ne posetite ovu stranicu kada ste prijavljeni.\nMožete i da poništite podešavanja obaveštenja za sve stranice u vašem spisku nadgledanja.\n\nSrdačan pozdrav, {{SITENAME}}\n\n--\nDa biste promenili podešavanja imejl obaveštenja, posetite\n{{canonicalurl:{{#special:Preferences}}}}\n\nDa biste promenili podešavanja spiska nadgledanja, posetite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nDa biste uklonili ovu stranicu sa spiska nadgledanja, posetite\n$UNWATCHURL\n\nPodrška i dalja pomoć:\n$HELPPAGE",
        "enotif_minoredit": "Ovo je manja izmena",
        "created": "napravljena",
        "changed": "izmenjena",
-       "deletepage": "Obriši stranicu",
+       "deletepage": "Izbriši stranicu",
        "confirm": "Potvrdi",
        "excontent": "sadržaj je bio: „$1“",
        "excontentauthor": "sadržaj je bio: „$1“, a jedini urednik „[[Special:Contributions/$2|$2]]“ ([[User talk:$2|razgovor]])",
        "exbeforeblank": "sadržaj pre brisanja je bio: „$1“",
        "delete-confirm": "Brisanje stranice „$1“",
-       "delete-legend": "Obriši",
-       "historywarning": "<strong>Upozorenje:</strong> stranica koju želite da obrišete ima istoriju sa $1 {{PLURAL:$1|izmenom|izmene|izmena}}:",
+       "delete-legend": "Brisanje",
+       "historywarning": "<strong>Upozorenje:</strong> Stranica koju želite da izbrišete ima istoriju sa $1 {{PLURAL:$1|revizijom|izmene|izmena}}:",
        "historyaction-submit": "Prikaži",
-       "confirmdeletetext": "Upravo ćete obrisati stranicu, uključujući i njenu istoriju.\nPotvrdite svoju nameru, da razumete posledice i da ovo radite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
+       "confirmdeletetext": "Upravo ćete izbrisati stranicu, uključujući i njenu istoriju.\nPotvrdite svoju nameru, da razumete posledice i da ovo radite u skladu sa [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Radnja je završena",
        "actionfailed": "Radnja nije uspela",
-       "deletedtext": "Stranica „$1“ je obrisana.\nPogledajte ''$2'' za više detalja.",
-       "dellogpage": "Dnevnik brisanja",
-       "dellogpagetext": "Ispod je spisak poslednjih brisanja.",
-       "deletionlog": "dnevnik brisanja",
+       "deletedtext": "Stranica „$1“ je izbrisana.\nPogledajte $2 za zapis nedavnih brisanja.",
+       "dellogpage": "Evidencija brisanja",
+       "dellogpagetext": "Ispod je spisak nedavnih brisanja.",
+       "deletionlog": "evidencija brisanja",
+       "log-name-create": "Evidencija pravljenja stranica",
+       "log-description-create": "Ispod je spisak nedavnih pravljenja stranica.",
        "logentry-create-create": "$1 je {{GENDER:$2|napravio|napravila}} stranicu $3",
        "reverted": "Vraćeno na raniju izmenu",
        "deletecomment": "Razlog:",
        "deleteotherreason": "Drugi/dodatni razlog:",
        "deletereasonotherlist": "Drugi razlog",
-       "deletereason-dropdown": "*Najčešći razlozi za brisanje\n** Spam\n** Zahtev autora\n** Kršenje autorskih prava\n** Vandalizam",
+       "deletereason-dropdown": "* Uobičajeni razlozi za brisanje\n** Nepoželjan sadržaj\n** Vandalizam\n** Kršenje autorskih prava\n** Zahtev autora\n** Pokvareno preusmerenje",
        "delete-edit-reasonlist": "Uredi razloge brisanja",
-       "delete-toobig": "Ova stranica ima veliku istoriju, preko $1 {{PLURAL:$1|izmene|izmene|izmena}}.\nBrisanje takvih stranica je ograničeno da bi se sprečilo slučajno opterećenje servera.",
-       "delete-warning-toobig": "Ova stranica ima veliku istoriju, preko $1 {{PLURAL:$1|izmene|izmene|izmena}}.\nNjeno brisanje može poremetiti bazu podataka, stoga postupajte s oprezom.",
-       "deleteprotected": "Ne možete obrisati ovu stranicu zato što je zaštićena.",
+       "delete-toobig": "Ova stranica ima veliku istoriju izmena, preko $1 {{PLURAL:$1|izmena|izmene|izmena}}.\nBrisanje takvih stranica je ograničeno da bi se sprečilo slučajno opterećenje servera.",
+       "delete-warning-toobig": "Ova stranica ima veliku istoriju izmena, preko $1 {{PLURAL:$1|izmena|izmene|izmena}}.\nNjeno brisanje može da poremeti bazu podataka, stoga postupajte s oprezom.",
+       "deleteprotected": "Ne možete da izbrišete ovu stranicu jer je zaštićena.",
        "deleting-backlinks-warning": "<strong>Upozorenje:</strong> brišete stranicu koja je uključena u [[Special:WhatLinksHere/{{FULLPAGENAME}}|druge stranice]] ili druge stranice vode na nju.",
-       "deleting-subpages-warning": "<strong>Pažnja:</strong> Stranicu koju želite obrisati ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstranicu|$1 podstranice|$1 podstranica|51=preko 50 podstranica}}]].",
+       "deleting-subpages-warning": "<strong>Upozorenje:</strong> Stranica koju želite izbrisati ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstranicu|$1 podstranice|$1 podstranica|51=preko 50 podstranica}}]].",
        "rollback": "Vrati izmene",
        "rollbacklink": "vrati",
        "rollbacklinkcount": "vrati $1 {{PLURAL:$1|izmenu|izmene|izmena}}",
        "rollbacklinkcount-morethan": "vrati više od $1 {{PLURAL:$1|izmene|izmene|izmena}}",
-       "rollbackfailed": "Neuspešno vraćanje",
+       "rollbackfailed": "Vraćanje nije uspelo",
        "rollback-missingparam": "Nedostaje potreban parametar na zahtevu.",
-       "rollback-missingrevision": "Ne mogu učitati podatke o izmeni.",
+       "rollback-missingrevision": "Ne mogu da učitam podatke o izmeni.",
        "cantrollback": "Ne mogu da vratim izmenu.\nPoslednji autor je ujedno i jedini.",
        "alreadyrolled": "Vraćanje poslednje izmene stranice [[:$1]] od strane {{GENDER:$2|korisnika|korisnice|korisnika}} [[User:$2|$2]] ([[User talk:$2|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) nije uspelo; neko drugi je u međuvremenu izmenio ili vratio stranicu.\n\nPoslednju izmenu je {{GENDER:$3|napravio|napravila|napravio}} [[User:$3|$3]] ([[User talk:$3|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
-       "editcomment": "Opis izmene: <em>$1</em>.",
-       "revertpage": "Vraćene izmene {{GENDER:$2|korisnika|korisnice}} [[Special:Contribs/$2|$2]] ([[User talk:$2|razgovor]]) na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
-       "revertpage-nouser": "Izmene skrivenog korisnika su vraćene na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
-       "rollback-success": "Izmene {{GENDER:$1|korisnika|korisnice}} {{GENDER:$3|$1}} su vraćene na poslednju izmenu {{GENDER:$2|korisnika|korisnice}} {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Vraćene izmene korisnika $1;\nvraćeno na poslednju izmenu korisnika $2. [$3 Prikaži izmene]",
+       "editcomment": "Rezime izmene je bio: <em>$1</em>.",
+       "revertpage": "Vraćene izmene {{GENDER:$2|korisnika|korisnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]) na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
+       "revertpage-nouser": "Vraćene izmene skrivenog korisnika na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
+       "rollback-success": "Vraćene izmene {{GENDER:$1|korisnika|korisnice}} {{GENDER:$3|$1}}  na poslednju izmenu {{GENDER:$2|korisnika|korisnice}} {{GENDER:$4|$2}}.",
+       "rollback-success-notify": "Vraćene izmene korisnika $1;\nvraćeno na poslednju izmenu korisnika $2. [$3 Prikaži promene]",
        "sessionfailure-title": "Sesija je okončana",
        "sessionfailure": "Izgleda da postoji problem s vašom sesijom;\nova radnja je otkazana da bi se izbegla zloupotreba.\nMolimo, ponovo pošaljite obrazac.",
        "changecontentmodel": "Promena modela sadržaja stranice",
        "changecontentmodel-submit": "Promeni",
        "changecontentmodel-success-title": "Model sadržaja je promenjen",
        "changecontentmodel-success-text": "Model sadržaja stranice [[:$1]] je promenjen.",
-       "changecontentmodel-cannot-convert": "Model sadržaja stranice [[:$1]] se ne može pretvoriti u vrstu $2.",
+       "changecontentmodel-cannot-convert": "Model sadržaja stranice [[:$1]] se ne može konvertovati u tip $2.",
        "changecontentmodel-nodirectediting": "Model sadržaja $1 ne podržava izravno uređivanje",
        "changecontentmodel-emptymodels-title": "Nema dostupnih modela sadržaja",
-       "changecontentmodel-emptymodels-text": "Model sadržaja stranice [[:$1]] se ne može pretvoriti ni u jednu drugu vrstu.",
-       "log-name-contentmodel": "Dnevnik promene modela sadržaja",
+       "changecontentmodel-emptymodels-text": "Model sadržaja stranice [[:$1]] se ne može konvertovati ni u jedan drugi tip.",
+       "log-name-contentmodel": "Evidencija promene modela sadržaja",
        "log-description-contentmodel": "Ova stranica prikazuje izmene u modelima sadržaja stranica i stranice koje su napravljene sa modelom sadržaja koji se razlikuje od podrazumevanog.",
        "logentry-contentmodel-new": "$1 je {{GENDER:$2|napravio|napravila}} stranicu $3 s nestandardnim modelom sadržaja „$5“",
        "logentry-contentmodel-change": "$1 je {{GENDER:$2|promenio|promenila}} model sadržaja stranice $3 iz „$4“ u „$5“",
        "logentry-contentmodel-change-revertlink": "vrati",
        "logentry-contentmodel-change-revert": "vrati",
-       "protectlogpage": "Dnevnik zaštite",
+       "protectlogpage": "Evidencija zaštite",
        "protectlogtext": "Ispod je spisak zaštićenih stranica.\nPogledajte [[Special:ProtectedPages|spisak zaštićenih stranica]] za više detalja.",
        "protectedarticle": "je {{GENDER:|zaštitio|zaštitila}} stranicu „[[$1]]“",
-       "modifiedarticleprotection": "je {{GENDER:|promenio|promenila}} stepen zaštite stranice „[[$1]]“",
+       "modifiedarticleprotection": "je {{GENDER:|promenio|promenila}} nivo zaštite stranice „[[$1]]“",
        "unprotectedarticle": "je skinuo zaštitu sa stranice „[[$1]]“",
        "movedarticleprotection": "je premestio podešavanja zaštite sa „[[$2]]“ na „[[$1]]“",
        "protectedarticle-comment": "{{GENDER:$2|Zaštićena}} stranica [[$1]]",
-       "modifiedarticleprotection-comment": "{{GENDER:$2|Promenjen}} nivo zaštite [[$1]]",
+       "modifiedarticleprotection-comment": "je {{GENDER:$2|promenio|promenila}} nivo zaštite stranice „[[$1]]”",
        "unprotectedarticle-comment": "{{GENDER:$2|Skinuta}} zaštita sa [[$1]]",
-       "protect-title": "Stepen zaštite za „$1“",
-       "protect-title-notallowed": "Pregled stepena zaštite za „$1“",
+       "protect-title": "Promena nivoa zaštite stranice „$1“",
+       "protect-title-notallowed": "Pregled nivoa zaštite stranice „$1“",
        "prot_1movedto2": "je premestio [[$1]] na [[$2]]",
        "protect-badnamespace-title": "Nezaštitljiv imenski prostor",
        "protect-badnamespace-text": "Stranice u ovom imenskom prostoru se ne mogu zaštititi.",
-       "protect-norestrictiontypes-text": "Ova stranica se ne može zaštititi jer nema dostupnih vrsta ograničenja.",
+       "protect-norestrictiontypes-text": "Ova stranica se ne može zaštititi jer nema dostupnih tipova ograničenja.",
        "protect-norestrictiontypes-title": "Nezaštitljiva strana",
        "protect-legend": "Podešavanja zaštite",
        "protectcomment": "Razlog:",
        "protectexpiry": "Ističe:",
-       "protect_expiry_invalid": "Vreme isteka je neispravno.",
-       "protect_expiry_old": "Vreme isteka je starije od trenutnog vremena.",
+       "protect_expiry_invalid": "Vreme isteka je nevažeće.",
+       "protect_expiry_old": "Vreme isteka je u prošlosti.",
        "protect-unchain-permissions": "Otključaj daljnja podešavanja zaštite",
-       "protect-text": "Ovde možete da pogledate i promenite stepen zaštite za stranicu '''$1'''.",
-       "protect-locked-blocked": "Ne možete menjati stepene zaštite dok ste blokirani.\nOvo su trenutna podešavanja stranice '''$1''':",
-       "protect-locked-dblock": "Stepeni zaštite se ne mogu menjati jer je aktivna baza podataka zaključana.\nOvo su podešavanja stranice '''$1''':",
-       "protect-locked-access": "Nemate ovlašćenja za menjanje stepena zaštite stranice.\nOvo su trenutna podešavanja stranice '''$1''':",
-       "protect-cascadeon": "Ova stranica je trenutno zaštićena jer se nalazi na {{PLURAL:$1|stranici koja ima|stranicama koje imaju}} prenosivu zaštitu.\nMožete da promenite stepen zaštite, ali to neće uticati na prenosivu zaštitu.",
+       "protect-text": "Ovde možete da pogledate i promenite nivo zaštite stranice <strong>$1</strong>.",
+       "protect-locked-blocked": "Ne možete da menjate nivoe zaštite dok ste blokirani.\nOvo su aktuelna podešavanja stranice '''$1''':",
+       "protect-locked-dblock": "Nivoi zaštite se ne mogu menjati jer je aktivna baza podataka zaključana.\nOvo su aktuelna podešavanja stranice '''$1''':",
+       "protect-locked-access": "Vaš nalog nema dozvolu da menja nivoe zaštite stranice.\nOvo su aktuelna podešavanja stranice '''$1''':",
+       "protect-cascadeon": "Ova stranica je trenutno zaštićena jer je uključena u {{PLURAL:$1|sledeću stranicu koja ima|sledeće stranice koje imaju}} uključenu prenosivu zaštitu.\nPromene nivoa zaštite ove stranice neće da utiču na prenosivu zaštitu.",
        "protect-default": "Dopušteno svim korisnicima",
        "protect-fallback": "Dozvoljeno samo korisnicima sa dozvolom „$1“",
        "protect-level-autoconfirmed": "Dopušteno samo automatski potvrđenim korisnicima",
        "protect-level-sysop": "Dopušteno samo administratorima",
+       "protect-summary-desc": "[$1=$2] ($3)",
        "protect-summary-cascade": "prenosiva zaštita",
        "protect-expiring": "ističe $1 (UTC)",
        "protect-expiring-local": "ističe $1",
        "protect-expiry-indefinite": "neodređeno",
-       "protect-cascade": "Zaštiti sve stranice koje su uključene u ovu (prenosiva zaštita)",
-       "protect-cantedit": "Ne možete menjati stepene zaštite ove stranice jer nemate ovlašćenja za uređivanje.",
+       "protect-cascade": "Zaštiti stranice koje su uključene u ovu (prenosiva zaštita)",
+       "protect-cantedit": "Ne možete da menjate nivo zaštite ove stranice jer nemate dozvolu da je uređujete.",
        "protect-othertime": "Drugo vreme:",
        "protect-othertime-op": "drugo vreme",
        "protect-existing-expiry": "Postojeće vreme isteka: $2 u $3",
        "protect-edit-reasonlist": "Uredi razloge zaštićivanja",
        "protect-expiry-options": "1 sat:1 hour,1 dan:1 day,1 nedelja:1 week,2 nedelje:2 weeks,1 mesec:1 month,3 meseca:3 months,6 meseci:6 months,1 godina:1 year,trajno:infinite",
        "restriction-type": "Dozvola:",
-       "restriction-level": "Nivo zaštite:",
+       "restriction-level": "Nivo ograničenja:",
        "minimum-size": "Najmanja veličina",
        "maximum-size": "Najveća veličina:",
        "pagesize": "(bajtovi)",
        "restriction-level-sysop": "potpuno zaštićeno",
        "restriction-level-autoconfirmed": "poluzaštićeno",
        "restriction-level-all": "svi nivoi",
-       "undelete": "Prikaz obrisanih stranica",
-       "undeletepage": "Pregled i vraćanje obrisanih stranica",
-       "undeletepagetitle": "'''Sledeći sadržaj se sastoji od obrisanih izmena stranice [[:$1|$1]]'''.",
-       "viewdeletedpage": "Prikaz obrisanih stranica",
-       "undeletepagetext": "{{PLURAL:$1|Sledeća stranica je obrisana, ali je još u arhivi i može biti vraćena|Sledeće $1 stranice su obrisane, ali su još u arhivi i mogu biti vraćene|Sledećih $1 stranica je obrisano, ali su još u arhivi i mogu biti vraćene}}.\nArhiva se povremeno čisti od ovakvih stranica.",
+       "undelete": "Pregled izbrisanih stranica",
+       "undeletepage": "Pregled i vraćanje izbrisanih stranica",
+       "undeletepagetitle": "<strong>Sledeći sadržaj se sastoji od izbrisanih izmena stranice [[:$1|$1]]</strong>.",
+       "viewdeletedpage": "Pregled izbrisanih stranica",
+       "undeletepagetext": "{{PLURAL:$1|Sledeća stranica je izbrisana, ali je još u arhivi i može biti vraćena|Sledeće $1 stranice su izbrisane, ali su još u arhivi i mogu biti vraćene|Sledećih $1 stranica je izbrisano, ali su još u arhivi i mogu biti vraćene}}.\nArhiva se povremeno čisti od ovakvih stranica.",
        "undelete-fieldset-title": "Vraćanje izmena",
-       "undeleteextrahelp": "Da biste vratili celu istoriju stranice, ostavite sve kućice neoznačene i kliknite na dugme '''''{{int:undeletebtn}}'''''.\nAko želite da vratite određene izmene, označite ih i kliknite na '''''{{int:undeletebtn}}'''''.",
-       "undeleterevisions": "{{PLURAL:$1|Izmena}} obrisano: $1",
+       "undeleteextrahelp": "Da biste vratili celu istoriju stranice, ostavite sve kućice neoznačene i kliknite na dugme <strong><em>{{int:undeletebtn}}</em></strong>.\nAko želite da vratite određene izmene, označite ih i kliknite na <strong><em>{{int:undeletebtn}}</em></strong>.",
+       "undeleterevisions": "{{PLURAL:$1|Izbrisana je|Izbrisane su|Izbrisano je}} $1 {{PLURAL:$1|izmena|izmene|izmena}}",
        "undeletehistory": "Ako vratite stranicu, sve izmene će biti vraćene njenoj istoriji.\nAko je u međuvremenu napravljena nova stranica s istim nazivom, vraćene izmene će se pojaviti u njenoj ranijoj istoriji.",
-       "undeleterevdel": "Vraćanje neće biti izvršeno ako je rezultat toga delimično brisanje poslednje izmene.\nU takvim slučajevima morate isključiti ili otkriti najnovije obrisane izmene.",
-       "undeletehistorynoadmin": "Ova stranica je obrisana.\nRazlog za brisanje se nalazi ispod, zajedno s detaljima o korisniku koji je izmenio ovu stranicu pre brisanja.\nTekst obrisanih izmena je dostupan samo administratorima.",
-       "undelete-revision": "Obrisana izmena stranice $1 (dana $4; $5) od strane {{GENDER:$3|korisnika|korisnice|korisnika}} $3:",
-       "undeleterevision-missing": "Neispravna ili nepostojeća izmena.\nMožda ste uneli pogrešnu vezu, ili je izmena vraćena ili uklonjena iz arhive.",
+       "undeleterevdel": "Vraćanje neće biti izvršeno ako je rezultat toga delimično brisanje poslednje izmene.\nU takvim slučajevima morate isključiti ili otkriti najnovije izbrisane izmene.",
+       "undeletehistorynoadmin": "Ova stranica je izbrisana.\nRazlog za brisanje se nalazi ispod, zajedno sa detaljima o korisniku koji je uredio ovu stranicu pre brisanja.\nTekst izbrisanih izmena je dostupan samo administratorima.",
+       "undelete-revision": "Izbrisana izmena stranice $1 (dana $4; $5) od strane {{GENDER:$3|korisnika|korisnice}} $3:",
+       "undeleterevision-missing": "Nevažeća ili nedostajuća izmena.\nMožda ste uneli loš link ili je izmena vraćena ili uklonjena iz arhive.",
        "undeleterevision-duplicate-revid": "Ne mogu vratiti {{PLURAL:$1|izmenu|$1 izmene|$1 izmena}} jer se {{PLURAL:$1|njen|njihov}} <code>rev_id</code> već koristi.",
        "undelete-nodiff": "Prethodne izmene nisu pronađene.",
        "undeletebtn": "Vrati",
        "undeleteinvert": "Obrni izbor",
        "undeletecomment": "Razlog:",
        "cannotundelete": "Vraćanje jedne ili svih nije uspelo:\n$1",
-       "undeletedpage": "<strong>Stranica $1 je vraćena</strong>\n\nPogledajte [[Special:Log/delete|dnevnik brisanja]] za zapise o skorašnjim brisanjima i vraćanjima.",
-       "undelete-header": "Pogledajte [[Special:Log/delete|istorijat brisanja]] za nedavno obrisane stranice.",
-       "undelete-search-title": "Pretraga obrisanih stranica",
-       "undelete-search-box": "Pretraži obrisane stranice",
+       "undeletedpage": "<strong>Stranica $1 je vraćena</strong>\n\nPogledajte [[Special:Log/delete|evidenciju brisanja]] za zapise o nedavnim brisanjima i vraćanjima.",
+       "undelete-header": "Pogledajte [[Special:Log/delete|evidenciju brisanja]] za nedavno izbrisane stranice.",
+       "undelete-search-title": "Pretraga izbrisanih stranica",
+       "undelete-search-box": "Pretraga izbrisanih stranica",
        "undelete-search-prefix": "Prikaži stranice koje počinju sa:",
        "undelete-search-full": "Prikaži naslove koji sadrže:",
        "undelete-search-submit": "Pretraži",
-       "undelete-no-results": "Odgovarajuća stranica u dnevniku brisanja nije pronađena.",
-       "undelete-filename-mismatch": "Ne mogu da vratim izmenu datoteke od $1: naziv datoteke se ne poklapa",
+       "undelete-no-results": "Nije pronađena odgovarajuća stranica u arhivi brisanja.",
+       "undelete-filename-mismatch": "Ne mogu da vratim izmenu datoteke od $1: naziv datoteke se ne poklapa.",
        "undelete-bad-store-key": "Ne mogu da vratim izmenu datoteke od $1: datoteka je nedostajala pre brisanja.",
        "undelete-cleanup-error": "Greška pri brisanju nekorišćene arhive „$1“.",
        "undelete-missing-filearchive": "Ne mogu da vratim arhivu s IB $1 jer se ona ne nalazi u bazi podataka.\nMožda je već bila vraćena.",
-       "undelete-error": "Došlo je do greške pri vraćanju obrisane stranice",
+       "undelete-error": "Došlo je do greške pri vraćanju izbrisane stranice",
        "undelete-error-short": "Greška pri vraćanju datoteke: $1",
        "undelete-error-long": "Došlo je do greške pri vraćanju datoteke:\n\n$1",
-       "undelete-show-file-confirm": "Želite li da vidite obrisanu izmenu datoteke „<nowiki>$1</nowiki>“ od $2; $3?",
+       "undelete-show-file-confirm": "Jeste li sigurni da želite da pogledate izbrisanu izmenu datoteke „<nowiki>$1</nowiki>“ od $2 u $3?",
        "undelete-show-file-submit": "Da",
+       "undelete-revision-row2": "$1 ($2) $3 . . $4 $5 $6 $7 $8",
        "namespace": "Imenski prostor:",
        "invert": "Obrni izbor",
-       "tooltip-invert": "Označite ovu kutijucu da biste sakrili izmene stranica u izabranom imenskom prostoru (i povezanim imenskim prostorima, ako je označeno)",
-       "tooltip-whatlinkshere-invert": "Označite ovu kutijicu za sakrivanje veza sa stranica u izabranom imenskom prostoru.",
+       "tooltip-invert": "Označite ovu kutijucu da biste sakrili promene na stranicana u izabranom imenskom prostoru (i povezanim imenskim prostorima, ako je označeno)",
+       "tooltip-whatlinkshere-invert": "Označite ovu kutijicu za sakrivanje linkova sa stranica u izabranom imenskom prostoru.",
        "namespace_association": "Povezani imenski prostor",
        "tooltip-namespace_association": "Označite ovu kutijicu da biste uključili i razgovor ili imenski prostor teme koja je povezana sa izabranim imenskim prostorom",
        "blanknamespace": "(glavni)",
-       "contributions": "{{GENDER:$1|Korisnički}} doprinosi",
+       "contributions": "Doprinosi {{GENDER:$1|korisnika|korisnice}}",
        "contributions-title": "Doprinosi {{GENDER:$1|korisnika|korisnice}} $1",
        "mycontris": "Doprinosi",
        "anoncontribs": "Doprinosi",
        "contribsub2": "Za {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Korisnički nalog „$1“ nije otvoren.",
-       "nocontribs": "Nema izmena koje odgovaraju navedenim kriterijumima.",
-       "uctop": "(trenutna)",
+       "nocontribs": "Nisu pronađene promene koje odgovaraju ovim kriterijumima.",
+       "uctop": "(aktuelna)",
        "month": "od meseca (i ranije):",
        "year": "od godine (i ranije):",
-       "sp-contributions-newbies": "Prikaži samo doprinose novih korisnika",
+       "date": "Od datuma (i ranije):",
+       "sp-contributions-newbies": "Prikaži samo doprinose novih naloga",
        "sp-contributions-newbies-sub": "Za nove korisnike",
        "sp-contributions-newbies-title": "Doprinosi novih korisnika",
-       "sp-contributions-blocklog": "dnevnik blokiranja",
-       "sp-contributions-suppresslog": "obrisani {{GENDER:$1|korisnički}} doprinosi",
-       "sp-contributions-deleted": "obrisani {{GENDER:$1|doprinosi}}",
+       "sp-contributions-blocklog": "evidencija blokiranja",
+       "sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
+       "sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
        "sp-contributions-uploads": "otpremanja",
-       "sp-contributions-logs": "dnevnici",
+       "sp-contributions-logs": "evidencije",
        "sp-contributions-talk": "razgovor",
-       "sp-contributions-userrights": "upravljanje pravima {{GENDER:$1|korisnika|korisnice|korisnika}}",
-       "sp-contributions-blocked-notice": "Ovaj korisnik je trenutno blokiran. \nIspod su navedeni poslednji zapisi u dnevniku blokiranja:",
-       "sp-contributions-blocked-notice-anon": "Ova IP adresa je trenutno blokirana.\nIspod su navedeni poslednji zapisi u dnevniku blokiranja:",
+       "sp-contributions-userrights": "upravljanje pravima {{GENDER:$1|korisnika|korisnice}}",
+       "sp-contributions-blocked-notice": "Ovaj korisnik je trenutno blokiran. \nPoslednji unos u evidenciji blokiranja je naveden ispod kao referenca:",
+       "sp-contributions-blocked-notice-anon": "Ova IP adresa je trenutno blokirana.\nPoslednji unos u evidenciji blokiranja je naveden ispod kao referenca:",
        "sp-contributions-search": "Pretraga doprinosa",
        "sp-contributions-username": "IP adresa ili korisničko ime:",
-       "sp-contributions-toponly": "Samo najnovije izmene",
+       "sp-contributions-toponly": "Prikaži samo izmene koje su najnovije izmene",
        "sp-contributions-newonly": "Samo izmene kojima su napravljene nove stranice",
        "sp-contributions-hideminor": "Sakrij manje izmene",
        "sp-contributions-submit": "Pretraži",
        "whatlinkshere": "Šta vodi ovde",
-       "whatlinkshere-title": "Stranice koje su povezane sa „$1”",
+       "whatlinkshere-title": "Stranice koje vode na stranicu „$1”",
        "whatlinkshere-page": "Stranica:",
-       "linkshere": "Sledeće stranice imaju vezu do <strong>$1</strong>:",
+       "linkshere": "Sledeće stranice vode na stranicu <strong>$2</strong>:",
        "nolinkshere": "Nijedna stranica nije povezana sa: <strong>$2</strong>.",
-       "nolinkshere-ns": "Nijedna stranica ne vodi do '''$2''' u izabranom imenskom prostoru.",
+       "nolinkshere-ns": "Nijedna stranica ne vodi na stranicu <strong>$2</strong> u izabranom imenskom prostoru.",
        "isredirect": "preusmerenje",
        "istemplate": "uključivanje",
-       "isimage": "veza do datoteke",
+       "isimage": "link do datoteke",
        "whatlinkshere-prev": "{{PLURAL:$1|prethodni|prethodna $1|prethodnih $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|sledeći|sledeća $1|sledećih $1}}",
-       "whatlinkshere-links": "← veze",
+       "whatlinkshere-links": "← linkovi",
        "whatlinkshere-hideredirs": "$1 preusmerenja",
        "whatlinkshere-hidetrans": "$1 uključivanja",
-       "whatlinkshere-hidelinks": "$1 veze",
-       "whatlinkshere-hideimages": "$1 veze do datoteke",
+       "whatlinkshere-hidelinks": "$1 linkove",
+       "whatlinkshere-hideimages": "$1 linkova do datoteke",
        "whatlinkshere-filters": "Filteri",
        "whatlinkshere-submit": "Idi",
        "autoblockid": "Automatsko blokiranje #$1",
-       "block": "Blokiraj korisnika",
+       "block": "Blokiranje korisnika",
        "unblock": "Deblokiranje korisnika",
-       "blockip": "Blokiraj {{GENDER:$1|korisnika|korisnicu}}",
+       "blockip": "Blokiranje {{GENDER:$1|korisnika|korisnice}}",
        "blockiptext": "Koristite donji obrazac da biste zabranili pristup za pisanje s određene IP adrese ili korisničkog imena.\nOvo bi trebalo da vršite samo radi sprečavanja vandalizma, u skladu sa [[{{MediaWiki:Policy-url}}|smernicama]].\nIzaberite konkretan razlog ispod (primer: navođenje konkretnih stranica koje su vandalizovane). Možete blokirati opsege IP adresa pomoću [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR] sintakse, najveći dozvoljeni opseg za IPv4 je /$1 odnosno /$2 za IPv6.",
        "ipaddressorusername": "IP adresa ili korisničko ime:",
        "ipbexpiry": "Ističe:",
        "ipbreason": "Razlog:",
-       "ipbreason-dropdown": "*Najčešći razlozi za blokiranje\n** Unošenje lažnih informacija\n** Uklanjanje sadržaja sa stranica\n** Postavljanje veza do spoljašnjih sajtova\n** Unošenje besmislica u stranice\n** Nepristojno ponašanje\n** Upotreba više naloga\n** Neprihvatljivo korisničko ime",
-       "ipb-hardblock": "Onemogući prijavljenim korisnicima da uređuju s ove IP adrese",
+       "ipbreason-dropdown": "*Najčešći razlozi za blokiranje\n** Umetanje lažnih informacija\n** Uklanjanje sadržaja sa stranica\n** Dodavanje nepoželjnih linkova do spoljašnjih sajtova\n** Unošenje besmislica/grafita u stranice\n** Nepristojno ponašanje\n** Upotreba više naloga\n** Neprihvatljivo korisničko ime",
+       "ipb-hardblock": "Spreči prijavljene korisnike da uređuju s ove IP adrese",
        "ipbcreateaccount": "Onemogući otvaranje naloga",
        "ipbemailban": "Spreči korisnika da šalje imejlove",
        "ipbenableautoblock": "Automatski blokiraj poslednju IP adresu ovog korisnika i sve daljnje adrese s kojih pokuša da uređuje",
        "ipbhidename": "Sakrij korisničko ime sa izmena i spiskova",
        "ipbwatchuser": "Nadgledaj korisničke stranice i stranice za razgovor ovog korisnika",
        "ipb-disableusertalk": "Onemogući korisniku da uređuje svoju stranicu za razgovor",
-       "ipb-change-block": "Ponovo blokiraj korisnika s ovim postavkama",
+       "ipb-change-block": "Ponovno blokiraj korisnika s ovim podešavanjima",
        "ipb-confirm": "Potvrdi blokiranje",
-       "badipaddress": "Neispravna IP adresa",
+       "badipaddress": "Nevažeća IP adresa",
        "blockipsuccesssub": "Blokiranje je uspelo",
-       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] je {{GENDER:$1|blokiran|blokirana|blokiran}}.<br />\nBlokiranja možete da pogledate [[Special:BlockList|ovde]].",
+       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] je {{GENDER:$1|blokiran|blokirana}}.<br />\nPogledajte [[Special:BlockList|spisak]] za pregled blokada.",
        "ipb-blockingself": "Ovom radnjom ćete blokirati sebe! Jeste li sigurni da to želite?",
        "ipb-confirmhideuser": "Upravo ćete blokirati korisnika s uključenom mogućnošću „sakrij korisnika“. Ovim će korisničko ime biti sakriveno u svim spiskovima i izveštajima. Želite li to da uradite?",
        "ipb-confirmaction": "Ako ste sigurni da želite nastaviti označite polje „{{int:ipb-confirm}}“ na dnu stranice.",
        "ipb-blocklist": "Pogledaj postojeća blokiranja",
        "ipb-blocklist-contribs": "Doprinosi za {{GENDER:$1|$1}}",
        "ipb-blocklist-duration-left": "preostalo: $1",
-       "unblockip": "Deblokiraj korisnika",
-       "unblockiptext": "Koristite obrazac ispod da biste vratili pravo pisanja blokiranoj IP adresi ili korisničkom imenu.",
+       "unblockip": "Deblokiranje korisnika",
+       "unblockiptext": "Koristite donji obrazac da biste vratili pravo pisanja ranije blokiranoj IP adresi ili korisničkom imenu.",
        "ipusubmit": "Ukloni ovu blokadu",
        "unblocked": "[[User:$1|$1]] je deblokiran",
        "unblocked-range": "$1 je deblokiran",
        "ipblocklist-legend": "Pronalaženje blokiranog korisnika",
        "blocklist-userblocks": "Sakrij blokiranja naloga",
        "blocklist-tempblocks": "Sakrij privremena blokiranja",
-       "blocklist-addressblocks": "Sakrij pojedinačna blokiranja IP adrese",
+       "blocklist-addressblocks": "Sakrij pojedinačne blokade IP-a",
        "blocklist-rangeblocks": "Sakrij blokiranja opsega",
-       "blocklist-timestamp": "Vreme i datum",
+       "blocklist-timestamp": "Vremenska oznaka",
        "blocklist-target": "Korisnik",
        "blocklist-expiry": "Ističe",
        "blocklist-by": "Blokirao",
        "change-blocklink": "promeni blokadu",
        "contribslink": "doprinosi",
        "emaillink": "pošalji imejl",
-       "autoblocker": "Automatski ste blokirani jer delite IP adresu s korisnikom/com [[User:$1|$1]].\nRazlog blokiranja: „$2“",
-       "blocklogpage": "Dnevnik blokiranja",
+       "autoblocker": "Automatski ste blokirani jer delite IP adresu s korisnikom/com [[User:$1|$1]].\nRazlog blokiranja korisnika/ce $1 je „$2“",
+       "blocklogpage": "Evidencija blokiranja",
        "blocklog-showlog": "{{GENDER:$1|Ovaj korisnik je ranije blokiran|Ova korisnica je ranije blokirana}}.\nIstorija blokiranja se nalazi ispod:",
        "blocklog-showsuppresslog": "{{GENDER:$1|Ovaj korisnik je ranije blokiran i sakriven|Ova korisnica je ranije blokirana i sakrivena}}.\nIstorija sakrivanja se nalazi ispod:",
        "blocklogentry": "je blokirao [[$1]] sa vremenom isticanja od $2 $3",
        "reblock-logentry": "{{GENDER:|je promenio|je promenila}} podešavanja za blokiranje {{GENDER:$1|korisnika|korisnice}} [[$1]] sa vremenom isteka od $2 ($3)",
-       "blocklogtext": "Ovo je dnevnik blokiranja i deblokiranja korisnika.\nAutomatski blokirane IP adrese nisu navedene.\nTekuće zabrane i blokiranja možete naći [[Special:BlockList|ovde]].",
+       "blocklogtext": "Ovo je evidencija radnji blokiranja i deblokiranja korisnika.\nAutomatski blokirane IP adrese nisu navedene.\nPogledajte [[Special:BlockList|spisak blokiranja]] za spisak aktuelnih operacija zabrana i blokiranja.",
        "unblocklogentry": "je deblokirao $1",
        "block-log-flags-anononly": "samo anonimni korisnici",
        "block-log-flags-nocreate": "onemogućeno otvaranje naloga",
        "block-log-flags-nousertalk": "zabranjeno uređivanje sopstvene stranice za razgovor",
        "block-log-flags-angry-autoblock": "prošireno automatsko blokiranje je omogućeno",
        "block-log-flags-hiddenname": "korisničko ime je sakriveno",
-       "range_block_disabled": "Administratorska mogućnost za blokiranje raspona IP adresa je onemogućena.",
-       "ipb_expiry_invalid": "Vreme isteka je neispravno.",
+       "range_block_disabled": "Administratorska mogućnost za pravljenje opsega blokade je onemogućena.",
+       "ipb_expiry_invalid": "Vreme isteka nije važeće.",
        "ipb_expiry_old": "Vreme isteka je u prošlosti.",
        "ipb_expiry_temp": "Sakrivene blokade korisnika moraju biti trajne.",
        "ipb_hide_invalid": "Ne mogu da potisnem ovaj nalog; ima više od {{PLURAL:$1|jedne izmene|$1 izmena}}.",
        "ipb-otherblocks-header": "{{PLURAL:$1|Druge blokade}}",
        "unblock-hideuser": "Ne možete deblokirati ovog korisnika jer je njegovo korisničko ime sakriveno.",
        "ipb_cant_unblock": "Greška: blokada $1 ne postoji. Možda je korisnik deblokiran.",
-       "ipb_blocked_as_range": "Greška: IP adresa $1 nije direktno blokirana i ne može da se deblokira.\nOna je blokirana kao deo blokade $2, koja može biti deblokirana.",
-       "ip_range_invalid": "Neispravan raspon IP adresa.",
-       "ip_range_toolarge": "Opsežna blokiranja veća od /$1 nisu dozvoljena.",
-       "ip_range_toolow": "IP-opsezi nisu dozvoljeni.",
+       "ipb_blocked_as_range": "Greška: IP adresa $1 nije direktno blokirana i ne može da se deblokira.\nOna je blokirana kao deo blokade $2, koja može da se deblokira.",
+       "ip_range_invalid": "Nevažeći opseg IP adrese.",
+       "ip_range_toolarge": "Opsezi blokiranja veći od /$1 nisu dozvoljeni.",
+       "ip_range_toolow": "IP opsezi nisu dozvoljeni.",
        "proxyblocker": "Bloker posrednika",
        "proxyblockreason": "Vaša IP adresa je blokirana jer predstavlja otvoreni posrednik.\nObratite se vašem dobavljaču internet usluga ili tehničku podršku i obavestite ih o ovom ozbiljnom bezbednosnom problemu.",
        "sorbs": "DNSBL",
        "sorbsreason": "Vaša IP adresa je navedena kao otvoreni posrednik u DNSBL-u koji koristi {{SITENAME}}.",
        "sorbs_create_account_reason": "Vaša IP adresa je navedena kao otvoreni posrednik u DNSBL-u koji koristi {{SITENAME}}.\nNe možete da otvorite nalog.",
-       "cant-see-hidden-user": "Član kome želite da zabranite pristup je već blokiran i sakriven.\nS obzirom na to da nemate prava za sakrivanje korisnika, ne možete da vidite niti izmenite zabranu.",
+       "softblockrangesreason": "Anonimni doprinosi nisu dozvoljeni sa vaše IP adrese ($1). Molimo vas da se prijavite.",
+       "cant-see-hidden-user": "Korisnik kojeg pokušavate da blokirate je već blokiran i sakriven.\nS obzirom na to da nemate prava za sakrivanje korisnika, ne možete da pogledate niti uredite korisničku blokadu.",
        "ipbblocked": "Ne možete zabraniti ili vratiti pristup drugim korisnicima jer ste i sami blokirani",
        "ipbnounblockself": "Nije vam dozvoljeno da deblokirate sebe",
        "lockdb": "Zaključavanje baze podataka",
        "lockedbyandtime": "(od $1 dana $2 u $3)",
        "move-page": "Premeštanje „$1”",
        "move-page-legend": "Premeštanje stranice",
-       "movepagetext": "Donji obrazac će preimenovati stranicu, premeštajući celu istoriju na novo ime.\nStari naslov postaće preusmerenje na novi.\nMožete ažurirati preusmerenja koja vode do izvornog naslova;\npogledajte [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|pokvarena]] preusmerenja.\nNa vama je odgovornost da veze i dalje idu tamo gde treba.\n\nStranica <strong>neće</strong> biti premeštena ako već postoji stranica s tim imenom (osim ako je prazna, sadrži preusmerenje ili nema istoriju izmena).\nTo znači da možete vratiti stranicu na prethodno ime ako pogrešite, ali ne možete ''prepisati'' postojeću.\n\n<strong>Napomena:</strong>\nOvo može predstavljati drastičnu i neočekivanu izmenu za popularnu stranicu;\ndobro razmislite o posledicama pre nego što nastavite.",
-       "movepagetext-noredirectfixer": "Donji obrazac će preimenovati stranicu, premeštajući celu istoriju na novo ime.\nStari naslov postaće preusmerenje na novi.\nPogledajte [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|pokvarena]] preusmerenja.\nNa vama je odgovornost da veze i dalje idu tamo gde treba.\n\nStranica <strong>neće</strong> biti premeštena ako već postoji stranica s tim imenom (osim ako je prazna, sadrži preusmerenje ili nema istoriju izmena).\nTo znači da možete vratiti stranicu na prethodno ime ako pogrešite, ali ne možete ''prepisati'' postojeću.\n\n<strong>Napomena:</strong>\nOvo može predstavljati drastičnu i neočekivanu izmenu za popularnu stranicu;\ndobro razmislite o posledicama pre nego što nastavite.",
+       "movepagetext": "Donji obrazac će preimenovati stranicu, premeštajući celu istoriju na novo ime.\nStari naslov postaće preusmerenje na novi.\nMožete ažurirati preusmerenja koja vode do izvornog naslova;\npogledajte [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|pokvarena]] preusmerenja.\nNa vama je odgovornost da linkovi i dalje idu tamo gde treba.\n\nStranica <strong>neće</strong> biti premeštena ako već postoji stranica s tim imenom (osim ako je prazna, sadrži preusmerenje ili nema istoriju izmena).\nTo znači da možete vratiti stranicu na prethodno ime ako pogrešite, ali ne možete ''prepisati'' postojeću.\n\n<strong>Napomena:</strong>\nOvo može predstavljati drastičnu i neočekivanu izmenu za popularnu stranicu;\ndobro razmislite o posledicama pre nego što nastavite.",
+       "movepagetext-noredirectfixer": "Donji obrazac će preimenovati stranicu, premeštajući celu istoriju na novo ime.\nStari naslov postaće preusmerenje na novi.\nPogledajte [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|pokvarena]] preusmerenja.\nNa vama je odgovornost da linkovi i dalje idu tamo gde treba.\n\nStranica <strong>neće</strong> biti premeštena ako već postoji stranica s tim imenom (osim ako je prazna, sadrži preusmerenje ili nema istoriju izmena).\nTo znači da možete vratiti stranicu na prethodno ime ako pogrešite, ali ne možete ''prepisati'' postojeću.\n\n<strong>Napomena:</strong>\nOvo može predstavljati drastičnu i neočekivanu izmenu za popularnu stranicu;\ndobro razmislite o posledicama pre nego što nastavite.",
        "movepagetalktext": "Ako ste označili ovaj kvadratić, odgovarajuća stranica za razgovor biće automatski premeštena na novi naslov, osim ako već postoji stranica za razgovor sa istim naslovom.\n\nU tom slučaju, moraćete ručno da je premestite ili spojite, ako ima potrebe za tim.",
        "moveuserpage-warning": "'''Upozorenje:''' na putu ste da premestite korisničku stranicu. Imajte u vidu da će samo stranica biti premeštena, a sam korisnik ''neće'' biti preimenovan.",
        "movecategorypage-warning": "<strong>Upozorenje:</strong> premeštate stranicu kategorije. Imajte na umu da će samo stranica biti premeštena i da sve stranice u staroj kategoriji <em>neće</em> biti rekategorisane u novu kategoriju.",
        "movenologintext": "Morate da budete registrovani i [[Special:UserLogin|prijavljeni]] da biste premeštali stranice.",
        "movenotallowed": "Nemate dozvolu da premeštate stranice.",
        "movenotallowedfile": "Nemate dozvolu da premeštate datoteke.",
-       "cant-move-user-page": "Nemate dozvolu za premeštanje osnovnih korisničkih stranica (osim podstranica).",
-       "cant-move-to-user-page": "Nemate dozvolu za premeštanje stranice na vašu korisničku stranicu (osim na korisničku podstranicu).",
+       "cant-move-user-page": "Nemate dozvolu da premeštate korisničke stranice (osim podstranica).",
+       "cant-move-to-user-page": "Nemate dozvolu da premestite stranicu na korisničku stranicu (osim na korisničku podstranicu).",
        "cant-move-category-page": "Nemate dozvolu da premeštate stranice kategorija.",
        "cant-move-to-category-page": "Nemate dozvolu da premestite stranicu na stranicu kategorije.",
        "cant-move-subpages": "Nemate dozvolu da premeštate podstranice.",
        "movepage-moved": "'''„$1“ je premeštena na „$2“'''",
        "movepage-moved-redirect": "Preusmerenje je napravljeno.",
        "movepage-moved-noredirect": "Stvaranje preusmerenja je onemogućeno.",
-       "articleexists": "Stranica s tim imenom već postoji, ili je ime neispravno.\nIzaberite drugo ime.",
-       "cantmove-titleprotected": "Ne možete da premestite stranicu na to mesto jer je željeni naslov zaštićen od stvaranja",
+       "articleexists": "Stranica sa tim imenom već postoji ili ime koje ste odabrali nije važeće.\nOdaberite drugo.",
+       "cantmove-titleprotected": "Ne možete da premestite stranicu na ovu lokaciju jer je pravljenje novog naslova zaštićeno.",
        "movetalk": "Premesti i stranicu za razgovor",
        "move-subpages": "Premesti i podstranice (do $1)",
        "move-talk-subpages": "Premesti podstranice stranice za razgovor (do $1)",
        "movepage-page-moved": "Stranica $1 je premeštena na $2.",
        "movepage-page-unmoved": "Stranica $1 ne može da se premesti na $2.",
        "movepage-max-pages": "Najviše $1 {{PLURAL:$1|stranica je premeštena|stranice su premeštene|stranica je premešteno}} i više ne može da bude automatski premešteno.",
-       "movelogpage": "Dnevnik premeštanja",
+       "movelogpage": "Evidencija premeštanja",
        "movelogpagetext": "Ispod se nalazi spisak premeštanja stranica.",
        "movesubpage": "{{PLURAL:$1|Podstranica|Podstranice}}",
        "movesubpagetext": "Ova stranica ima $1 {{PLURAL:$1|podstranicu prikazanu|podstranice prikazane|podstranica prikazanih}} ispod.",
        "movenosubpage": "Ova stranica nema podstrana.",
        "movereason": "Razlog:",
        "revertmove": "vrati",
-       "delete_and_move_text": "Odredišna stranica „[[:$1]]“ već postoji. \nŽelite li da je obrišete da biste oslobodili mesto za premeštanje?",
-       "delete_and_move_confirm": "Da, obriši stranicu",
-       "delete_and_move_reason": "Obrisano da se oslobodi mesto za premeštanje iz „[[$1]]“",
+       "delete_and_move_text": "Odredišna stranica „[[:$1]]“ već postoji. \nŽelite li da je izbrišete da biste oslobodili mesto za premeštanje?",
+       "delete_and_move_confirm": "Da, izbriši stranicu",
+       "delete_and_move_reason": "Izbrisano da se oslobodi mesto za premeštanje iz „[[$1]]“",
        "selfmove": "Naslov je istovetan;\nne možete premestiti stranicu preko same sebe.",
        "immobile-source-namespace": "Ne mogu premestiti stranice u imenski prostor „$1“.",
        "immobile-target-namespace": "Ne mogu premestiti stranice u imenski prostor „$1“.",
-       "immobile-target-namespace-iw": "Međuviki veza nije ispravno odredište za premeštanje stranice.",
+       "immobile-target-namespace-iw": "Međuviki link nije važeće odredište za premeštanje stranice.",
        "immobile-source-page": "Ova stranica se ne može premestiti.",
        "immobile-target-page": "Ne mogu da premestim na željeni naslov.",
        "bad-target-model": "Željeno odredište koristi drugačiji model sadržaja. Ne mogu da pretvorim iz $1 u $2.",
        "imagenocrossnamespace": "Datoteka se ne može premestiti u imenski prostor koji ne pripada datotekama.",
        "nonfile-cannot-move-to-file": "Ne-datoteke ne možete premestiti u imenski prostor za datoteke",
-       "imagetypemismatch": "Ekstenzija nove datoteke se ne poklapa s njenom vrstom",
-       "imageinvalidfilename": "Ciljani naziv datoteke je neispravan",
+       "imagetypemismatch": "Proširenje nove datoteke se ne poklapa s njenim tipom.",
+       "imageinvalidfilename": "Ciljano ime datoteke je nevažeće",
        "fix-double-redirects": "Ažurirajte sva preusmerenja koja vode do prvobitnog naslova",
        "move-leave-redirect": "Ostavi preusmerenje",
-       "protectedpagemovewarning": "'''Upozorenje:''' ova stranica je zaštićena, tako da samo korisnici s administratorskim ovlašćenjima mogu da je premeste.\nZa više informacija, poslednji zapis u dnevniku izmena je prikazan ispod:",
-       "semiprotectedpagemovewarning": "<strong>Napomena:</strong> Ova stranica je zaštićena, tako da samo registrovani korisnici mogu da je premeste.\nPoslednji zapis u dnevniku izmena prikazan je ispod kao referenca:",
+       "protectedpagemovewarning": "'''Upozorenje:''' Ova stranica je zaštićena, tako da samo korisnici sa administratorskim ovlašćenjima mogu da je premeste.\nNajnoviji unos u evidenciji je naveden ispod kao referenca:",
+       "semiprotectedpagemovewarning": "<strong>Napomena:</strong> Ova stranica je zaštićena, tako da samo automatski potvrđeni korisnici mogu da je premeste.\nNajnoviji unos u evidenciji je naveden ispod kao referenca:",
        "move-over-sharedrepo": "[[:$1]] se nalazi na deljenom skladištu. Ako premestite datoteku na ovaj naslov, to će zameniti deljenu datoteku.",
        "file-exists-sharedrepo": "Navedeni naziv datoteke se već koristi u deljenom skladištu.\nIzaberite drugi naziv.",
        "export": "Izvoz stranica",
-       "exporttext": "Možete izvesti tekst i istoriju izmena određene stranice ili grupe stranica u formatu XML.\nOvo onda može biti uvezeno u drugi viki koji koristi Medijaviki softver preko [[Special:Import|stranice za uvoz]].\n\nDa biste izvezli stranice, unesite nazive u okviru ispod, s jednim naslovom po redu, i izaberite da li želite tekuću izmenu i sve ostale, ili samo tekuću izmenu s podacima o poslednjoj izmeni.\n\nU drugom slučaju, možete koristiti i vezu, na primer [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] za stranicu [[{{MediaWiki:Mainpage}}]].",
+       "exporttext": "Možete da izvezete tekst i istoriju izmena određene stranice ili skupa stranica uklljenih u XML formatu.\nOvo onda može da bude uvezeno u drugi viki koji koristi Medijaviki softver preko [[Special:Import|stranice za uvoz]].\n\nDa biste izvezli stranice, unesite nazive u okviru ispod, s jednim naslovom po redu, i izaberite da li želite aktuelnu izmenu i sve ostale, ili samo aktuelnu izmenu s podacima o poslednjoj izmeni.\n\nU drugom slučaju, možete koristiti i link, na primer [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] za stranicu [[{{MediaWiki:Mainpage}}]].",
        "exportall": "Izvezi sve stranice",
-       "exportcuronly": "Uključi samo tekuću izmenu, ne celu istoriju",
+       "exportcuronly": "Uključi samo aktuelnu izmenu, ne celu istoriju",
        "exportnohistory": "----\n'''Napomena:''' izvoz pune istorije stranica preko ovog obrasca je onemogućeno iz tehničkih razloga.",
        "exportlistauthors": "Uključi celokupan spisak doprinosilaca za svaku stranicu",
        "export-submit": "Izvezi",
        "allmessages": "Sistemske poruke",
        "allmessagesname": "Naziv",
        "allmessagesdefault": "Podrazumevani tekst",
-       "allmessagescurrent": "Trenutni tekst poruke",
+       "allmessagescurrent": "Aktuelni tekst poruke",
        "allmessagestext": "Ovo je spisak sistemskih poruka dostupnih u imenskom prostoru „Medijaviki“.\nPosetite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Medijaviki lokalizaciju] i [https://translatewiki.net translatewiki.net] ako želite da doprinesete opštoj lokalizaciji Medijavikija.",
        "allmessagesnotsupportedDB": "Ova stranica ne može da se koristi jer je '''$wgUseDatabaseMessages''' onemogućen.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter-translate": "Prevedi",
        "thumbnail-more": "Povećajte",
        "filemissing": "Nedostaje datoteka",
-       "thumbnail_error": "Greška pri stvaranju minijature: $1",
+       "thumbnail_error": "Greška pri pravljenju sličice: $1",
        "thumbnail_error_remote": "Poruka o grešci iz $1:\n$2",
-       "djvu_page_error": "DjVu stranica je nedostupna",
+       "djvu_page_error": "DjVu stranica je van opsega",
        "djvu_no_xml": "Ne mogu da preuzmem XML za DjVu datoteku.",
-       "thumbnail-temp-create": "Ne mogu da napravim privremenu datoteku minijature",
+       "thumbnail-temp-create": "Ne mogu da napravim privremenu datoteku za sličicu",
        "thumbnail-dest-create": "Ne mogu da sačuvam minijaturu u odredištu",
-       "thumbnail_invalid_params": "Neispravni parametri za minijaturu",
+       "thumbnail_invalid_params": "Nevažeći parametri sličice",
        "thumbnail_toobigimagearea": "Datoteka sa veličinama većim od $1",
        "thumbnail_dest_directory": "Ne mogu da napravim odredišnu fasciklu",
-       "thumbnail_image-type": "Vrsta slike nije podržana",
+       "thumbnail_image-type": "Tip slike nije podržan",
        "thumbnail_gd-library": "Nedovršena podešavanja grafičke biblioteke: nedostaje funkcija $1",
        "thumbnail_image-size-zero": "Izgleda da je veličina datoteke nula.",
        "thumbnail_image-missing": "Datoteka nedostaje: $1",
-       "thumbnail_image-failure-limit": "Bilo je previše skorašnjih neuspešnih pokušaja ($1 ili više) renderovanja ove minijature. Pokušajte ponovo kasnije.",
+       "thumbnail_image-failure-limit": "Bilo je previše nedavnih neuspelih pokušaja ($1 ili više) renderovanja ove sličice. Pokušajte ponovo kasnije.",
        "import": "Uvoz stranica",
        "importinterwiki": "Uvoz sa drugog vikija",
-       "import-interwiki-text": "Izaberite viki i naslov stranice za uvoz.\nDatumi i imena urednika će biti sačuvani.\nSve radnje pri uvozu s drugih vikija su zabeležene u [[Special:Log/import|dnevniku uvoza]].",
+       "import-interwiki-text": "Izaberite viki i naslov stranice za uvoz.\nDatumi izmena i imena urednika će biti sačuvani.\nSve radnje pri uvozu s drugih vikija su evidentirane u [[Special:Log/import|evidenciji uvoza]].",
        "import-interwiki-sourcewiki": "Izvorna viki:",
        "import-interwiki-sourcepage": "Izvorna stranica:",
-       "import-interwiki-history": "Kopiraj sve verzije istorije za ovu stranicu",
+       "import-interwiki-history": "Kopiraj sve izmene istorije za ovu stranicu",
        "import-interwiki-templates": "Uključi sve šablone",
        "import-interwiki-submit": "Uvezi",
        "import-mapping-default": "Isto kao i izvorne stranice",
        "import-mapping-subpage": "Uvezi kao podstranice sledeće stranice:",
        "import-upload-filename": "Naziv datoteke:",
        "import-upload-username-prefix": "Međuviki prefiks:",
+       "import-assign-known-users": "Dodeljivanje izmena lokalnim korisnicima gde imenovani korisnik postoji lokalno",
        "import-comment": "Komentar:",
-       "importtext": "Izvezite datoteku s izvornog vikija koristeći [[Special:Export|izvoz]].\nSačuvajte je na računar i pošaljite ovde.",
+       "importtext": "Izvezite datoteku sa izvornog vikija koristeći [[Special:Export|alat za izvoz]].\nSačuvajte je na računar i optremite ovde.",
        "importstart": "Uvozim stranice…",
        "import-revision-count": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
        "importnopages": "Nema stranica za uvoz.",
        "imported-log-entries": "{{PLURAL:$1|Uvezena je $1 stavka izveštaja|Uvezene su $1 stavke izveštaja|Uvezeno je $1 stavki izveštaja}}.",
        "importfailed": "Neuspešan uvoz: <nowiki>$1</nowiki>",
-       "importunknownsource": "Nepoznata vrsta za uvoz",
+       "importunknownsource": "Nepoznat izvorni tip uvoza",
        "importnoprefix": "Nije naveden međuviki prefiks",
        "importcantopen": "Ne mogu da otvorim datoteku za uvoz.",
-       "importbadinterwiki": "Neispravna međuviki veza",
+       "importbadinterwiki": "Loš međuviki link",
        "importsuccess": "Uvoženje je završeno!",
        "importnosources": "Nije određen nijedan izvor za uvoz, tako da je otpremanje istorije onemogućeno.",
        "importnofile": "Uvozna datoteka nije poslata.",
        "importuploaderrortemp": "Ne mogu da pošaljem datoteku za uvoz.\nNedostaje privremena fascikla.",
        "import-parse-failure": "Pogrešno raščlanjivanje XML-a.",
        "import-noarticle": "Nema stranice za uvoz!",
-       "import-nonewrevisions": "Izmene nisu uvezene (sve su već bile ili prisutne ili preskočene zbog grešaka).",
+       "import-nonewrevisions": "Nijedna izmena nije uvezena (sve su već prisutne ili su preskočene zbog grešaka).",
        "xml-error-string": "$1 u redu $2, kolona $3 (bajt $4): $5",
        "import-upload": "Otpremanje XML podataka",
-       "import-token-mismatch": "Gubitak podataka o sesiji.\n\nMožda ste odjavljeni. '''Molimo Vas proverite da li ste još uvek prijavljeni i pokušajte ponovo'''.\n\nAko i dalje ne radi, pokušajte se [[Special:UserLogout|odjaviti]] i ponovo prijaviti i proverite da li Vaš veb-prtraživač dozvoljava kolačiće sa ovog sajta.",
+       "import-token-mismatch": "Gubitak podataka o sesiji.\n\nMožda ste odjavljeni. '''Molimo Vas proverite da li ste još uvek prijavljeni i pokušajte ponovo'''.\n\nAko i dalje ne radi, pokušajte se [[Special:UserLogout|odjaviti]] i ponovo prijaviti i proverite da li vaš veb-pretraživač dozvoljava kolačiće sa ovog sajta.",
        "import-invalid-interwiki": "Ne mogu da uvozim s navedenog vikija.",
        "import-error-edit": "Stranica „$1“ nije uvezena jer vam nije dozvoljeno da je uređujete.",
        "import-error-create": "Stranica „$1“ nije uvezena jer vam nije dozvoljeno da je napravite.",
        "import-error-interwiki": "Ne mogu da uvezem stranicu „$1“ jer je njen naziv rezervisan za spoljno povezivanje (međuviki).",
        "import-error-special": "Ne mogu da uvezem stranicu „$1“ jer ona pripada posebnom imenskom prostoru koje ne prihvata stranice.",
-       "import-error-invalid": "Ne mogu da uvezem stranicu „$1“ jer je njen naziv neispravan.",
-       "import-error-unserialize": "Verzija $2 stranice $1 ne može biti pročitana/uvezena. Zapisano je da verzija koristi $3 tip sadržaja u $4 formatu.",
+       "import-error-invalid": "Stranica „$1“ nije uvezena jer je ime pod kojim se treba uvosti nevažeće na ovom vikiju.",
+       "import-error-unserialize": "Ne mogu da deserijalizujem izmenu $2 stranice $1. Zapisano je da izmena koristi $3 model sadržaja u $4 formatu.",
        "import-options-wrong": "{{PLURAL:$2|Pogrešna opcija|Pogrešne opcije}}: <nowiki>$1</nowiki>",
-       "import-rootpage-invalid": "Navedena osnovna stranica ima neispravan naslov.",
+       "import-rootpage-invalid": "Navedena osnovna stranica ima nevažeći naslov.",
        "import-rootpage-nosubpage": "Imenski prostor „$1“ osnovne stranice ne dozvoljava podstranice.",
-       "importlogpage": "Dnevnik uvoza",
+       "importlogpage": "Evidencija uvoza",
        "importlogpagetext": "Administrativni uvozi stranica s istorijama izmena s drugih vikija.",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|izmena uvezena|izmene uvezene|izmena uvezeno}}",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|izmena uvezena|izmene uvezene|izmena uvezeno}} iz $2",
-       "javascripttest": "Testiranje javaskripta",
+       "javascripttest": "Testiranje javasktipta",
        "javascripttest-pagetext-unknownaction": "Nepoznata radnja „$1“.",
        "javascripttest-qunit-intro": "Pogledajte [$1 dokumentaciju za testiranje] na mediawiki.org.",
        "tooltip-pt-userpage": "{{GENDER:|Vaša}} korisnička stranica",
        "tooltip-pt-watchlist": "Spisak stranica koje nadgledate",
        "tooltip-pt-mycontris": "Spisak {{GENDER:|Vaših}} doprinosa",
        "tooltip-pt-anoncontribs": "Spisak izmena napravljenih sa ove IP adrese",
-       "tooltip-pt-login": "Predlažemo Vam da se prijavite, iako to nije obavezno",
+       "tooltip-pt-login": "Predlažemo vam da se prijavite, iako to nije obavezno",
        "tooltip-pt-login-private": "Morate da se prijavite da biste koristili ovaj Viki",
        "tooltip-pt-logout": "Odjavite se",
-       "tooltip-pt-createaccount": "Predlažemo Vam da otvorite nalog i prijavite se, iako to nije obavezno",
+       "tooltip-pt-createaccount": "Predlažemo vam da otvorite nalog i prijavite se, iako to nije obavezno",
        "tooltip-ca-talk": "Razgovor o stranici sa sadržajem",
        "tooltip-ca-edit": "Uredite ovu stranicu",
        "tooltip-ca-addsection": "Započnite novi odeljak",
-       "tooltip-ca-viewsource": "Ova stranica je zaključana. \nMožete da pogledate njen izvorni kod",
+       "tooltip-ca-viewsource": "Ova stranica je zaključana. \nMožete da pogledate njen izvornik",
        "tooltip-ca-history": "Prethodne izmene ove stranice",
        "tooltip-ca-protect": "Zaštitite ovu stranicu",
        "tooltip-ca-unprotect": "Promeni zaštitu ove stranice",
-       "tooltip-ca-delete": "Obrišite ovu stranicu",
-       "tooltip-ca-undelete": "Vrati izmene napravljene na ovoj stranici pre nego što bude obrisana",
+       "tooltip-ca-delete": "Izbrišite ovu stranicu",
+       "tooltip-ca-undelete": "Vrati izmene koje su načinjene na ovoj stranici pre brisanja stranice",
        "tooltip-ca-move": "Premesti ovu stranicu",
        "tooltip-ca-watch": "Dodajte ovu stranicu na svoj spisak nadgledanja",
        "tooltip-ca-unwatch": "Uklonite ovu stranicu sa spiska nadgledanja",
        "tooltip-n-mainpage-description": "Posetite glavnu stranu",
        "tooltip-n-portal": "O projektu, šta možete da radite i gde da pronađete stvari",
        "tooltip-n-currentevents": "Pronađite dodatne informacije o aktuelnostima",
-       "tooltip-n-recentchanges": "Spisak skorašnjih izmena na vikiju",
+       "tooltip-n-recentchanges": "Spisak nedavnih promena na vikiju",
        "tooltip-n-randompage": "Učitajte slučajnu stranicu",
-       "tooltip-n-help": "Mesto gde možete da naučite nešto",
+       "tooltip-n-help": "Mesto gde možete nešto da naučite",
        "tooltip-t-whatlinkshere": "Spisak svih viki stranica koje vode ovde",
-       "tooltip-t-recentchangeslinked": "Skorašnje izmene na stranicama koje su povezane sa ovom stranicom",
-       "tooltip-feed-rss": "RSS dovod ove stranice",
-       "tooltip-feed-atom": "Atom dovod ove stranice",
+       "tooltip-t-recentchangeslinked": "Nedavne promene na stranicama koje su povezane s ovom stranicom",
+       "tooltip-feed-rss": "RSS fid za ovu stranicu",
+       "tooltip-feed-atom": "Atom fid za ovu stranicu",
        "tooltip-t-contributions": "Spisak doprinosa {{GENDER:$1|ovog korisnika|ove korisnice|ovog korisnika}}",
        "tooltip-t-emailuser": "Pošaljite imejl {{GENDER:$1|ovom korisniku|ovoj korisnici}}",
        "tooltip-t-info": "Više informacija o ovoj stranici",
        "tooltip-t-upload": "Otpremite datoteke",
        "tooltip-t-specialpages": "Spisak svih posebnih stranica",
        "tooltip-t-print": "Verzija ove stranice za štampanje",
-       "tooltip-t-permalink": "Trajna veza ka ovoj izmeni stranice",
+       "tooltip-t-permalink": "Trajni link ka ovoj izmeni stranice",
        "tooltip-ca-nstab-main": "Pogledajte stranicu sa sadržajem",
        "tooltip-ca-nstab-user": "Pogledajte korisničku stranicu",
        "tooltip-ca-nstab-media": "Pogledajte medijsku stranicu",
        "tooltip-ca-nstab-help": "Pogledajte stranicu za pomoć",
        "tooltip-ca-nstab-category": "Pogledajte stranicu kategorije",
        "tooltip-minoredit": "Označite ovu izmenu kao manju",
-       "tooltip-save": "Sačuvajte svoje izmene",
+       "tooltip-save": "Sačuvajte svoje promene",
        "tooltip-publish": "Objavite svoje izmene",
-       "tooltip-preview": "Pregledajte svoje izmene. Koristite ovo dugme pre čuvanja.",
-       "tooltip-diff": "Pogledajte koje izmene ste napravili na tekstu",
-       "tooltip-compareselectedversions": "Pogledajte razlike između dve izabrane izmene ove stranice.",
+       "tooltip-preview": "Pregledajte svoje promene. Koristite ovo dugme pre čuvanja.",
+       "tooltip-diff": "Pogledajte koje promene ste napravili na tekstu",
+       "tooltip-compareselectedversions": "Pogledajte razlike između dve izabrane izmene ove stranice",
        "tooltip-watch": "Dodajte ovu stranicu na svoj spisak nadgledanja",
        "tooltip-watchlistedit-normal-submit": "Uklonite naslove",
        "tooltip-watchlistedit-raw-submit": "Ažuriraj spisak",
-       "tooltip-recreate": "Ponovo napravite stranicu iako je obrisana",
+       "tooltip-recreate": "Ponovo napravite stranicu iako je već izbrisana",
        "tooltip-upload": "Započnite otpremanje",
        "tooltip-rollback": "„Vrati“ vraća izmene poslednjeg doprinosioca ove stranice jednim klikom",
-       "tooltip-undo": "„Poništi” vraća ovu izmenu i otvara obrazac za uređivanje u pretpreglednom modu. Dozvoljava dodavanje razloga u opisu izmene.",
+       "tooltip-undo": "„Poništi” vraća ovu izmenu i otvara obrazac za uređivanje u pretpreglednom modu. Dozvoljava dodavanje razloga u rezimeu.",
        "tooltip-preferences-save": "Sačuvaj podešavanja",
        "tooltip-summary": "Unesite kratak opis",
        "interlanguage-link-title": "$1 — $2",
        "print.css": "/* CSS postavljen ovde će uticati na izdanje za štampu */",
        "noscript.css": "/* CSS postavljen ovde će uticati na sve korisnike kojima je onemogućen javaskript */",
        "group-autoconfirmed.css": "/* CSS postavljen ovde će uticati na samopotvrđene korisnike */",
+       "group-user.css": "/* CSS postavljen ovde će uticati samo na registrovane korisnike */",
        "group-bot.css": "/* CSS postavljen ovde će uticati samo na botove */",
        "group-sysop.css": "/* CSS postavljen ovde će uticati samo na sistemske operatore */",
        "group-bureaucrat.css": "/* CSS postavljen ovde će uticati samo na birokrate */",
+       "common.json": "/* JSON postavljen ovde će se koristiti za sve korisnike pri otvaranju svake stranice. */",
        "common.js": "/* Javaskript postavljen ovde će se koristiti za sve korisnike pri otvaranju svake stranice. */",
        "group-autoconfirmed.js": "/* Javaskript postavljen ovde će se učitati za samopotvrđene korisnike */",
+       "group-user.js": "/* Javaskript postavljen ovde će se učitati za registrovane korisnike */",
        "group-bot.js": "/* Javaskript postavljen ovde će se učitati samo za botove */",
-       "group-sysop.js": "/* Javaskript postavljen ovde će se učitati samo za sistemske operatore */",
+       "group-sysop.js": "/* JavaScript postavljen ovde će se učitati samo za sistemske operatore */",
        "group-bureaucrat.js": "/* Javaskript postavljen ovde će se učitati samo za birokrate */",
        "anonymous": "Anonimni {{PLURAL:$1|korisnik|korisnici}} projekta {{SITENAME}}",
        "siteuser": "{{SITENAME}} korisnik $1",
        "creditspage": "Autori stranice",
        "nocredits": "Ne postoje podaci o autoru ove stranice.",
        "spamprotectiontitle": "Filter za zaštitu od nepoželjnih poruka",
-       "spamprotectiontext": "Filtera protiv neželjenih poruka je blokirao čuvanje ove stranice.\nOvo je verovatno izazvano vezom do spoljašnjeg sajta koji se nalazi na crnom spisku.",
+       "spamprotectiontext": "Filtera protiv neželjenih poruka je blokirao čuvanje ove stranice.\nOvo je verovatno izazvano linkom do spoljašnjeg sajta koji se nalazi na crnom spisku.",
        "spamprotectionmatch": "Sledeći tekst je aktivirao naš filter za neželjene poruke: $1",
        "spambot_username": "Čišćenje nepoželjnih poruka u Medijavikiji",
-       "spam_reverting": "Vraćam na poslednju izmenu koja ne sadrži veze do $1",
-       "spam_blanking": "Sve izmene sadrže veze do $1. Čistim",
-       "spam_deleting": "Sve izmene sadrže veze do $1. Brišem",
-       "simpleantispam-label": "Anti-spam provera. \n<strong>Ne</strong> popunjavaj ovo unutra!",
+       "spam_reverting": "Vraćam na poslednju izmenu koja ne sadrži linkove do $1",
+       "spam_blanking": "Sve izmene sadrže linkove do $1. Praznim",
+       "spam_deleting": "Sve izmene sadrže linkove do $1. Brišem",
+       "simpleantispam-label": "Provera protiv neželjenog sadržaja. \n<strong>Ne</strong> popunjavajte ovo!",
        "pageinfo-title": "Informacije za „$1“",
-       "pageinfo-not-current": "Nažalost, nemoguće je pribaviti ove podatke za starije izmene.",
+       "pageinfo-not-current": "Nažalost, nemoguće je navesti ove infomacije za starije izmene.",
        "pageinfo-header-basic": "Osnovne informacije",
        "pageinfo-header-edits": "Istorija izmena",
        "pageinfo-header-restrictions": "Zaštita stranice",
        "pageinfo-watchers": "Broj nadgledača stranice",
        "pageinfo-visiting-watchers": "Broj nadgledača stranice koji su posetili skorašnje izmene",
        "pageinfo-few-watchers": "Manje od $1 {{PLURAL:$1|nadgledača}}",
+       "pageinfo-few-visiting-watchers": "Moguće je da postoji korisnik koji prati i posećuje nedavne promene",
        "pageinfo-redirects-name": "Broj preusmerenja na ovu stranicu",
        "pageinfo-redirects-value": "$1",
        "pageinfo-subpages-name": "Broj podstranica ove stranice",
        "pageinfo-lasttime": "Datum poslednje izmene",
        "pageinfo-edits": "Broj izmena",
        "pageinfo-authors": "Broj zasebnih autora",
-       "pageinfo-recent-edits": "Broj skorašnjih izmena (u poslednjih $1)",
+       "pageinfo-recent-edits": "Broj nedavnih promena (u poslednjih $1)",
        "pageinfo-recent-authors": "Broj skorašnjih zasebnih autora",
        "pageinfo-magic-words": "{{PLURAL:$1|Magična reč|Magične reči}} ($1)",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Sakrivena kategorija|Sakrivene kategorije}} ($1)",
        "markedaspatrolled": "Označeno kao patrolirano",
        "markedaspatrolledtext": "Izabrana izmena stranice [[:$1]] označena je kao patrolirana.",
        "rcpatroldisabled": "Patroliranje skorašnjih izmena je onemogućeno",
-       "rcpatroldisabledtext": "Patroliranje skorašnjih izmena je onemogućeno.",
+       "rcpatroldisabledtext": "Mogućnost patroliranja skorašnjih izmena je aktuelno onemogućena.",
        "markedaspatrollederror": "Ne mogu da označim kao patrolirano.",
-       "markedaspatrollederrortext": "Morate izabrati izmenu da biste je označili kao patroliranu.",
-       "markedaspatrollederror-noautopatrol": "Ne možete da označite svoje izmene kao patrolirane.",
+       "markedaspatrollederrortext": "Morate navesti izmenu da biste je označili kao patroliranu.",
+       "markedaspatrollederror-noautopatrol": "Ne možete da označite svoje promene kao patrolirane.",
        "markedaspatrollednotify": "Ova izmena na stranici „$1” označena je kao patrolirana.",
        "markedaspatrollederrornotify": "Označavanje ove izmene patroliranom nije uspelo.",
-       "patrol-log-page": "Dnevnik patroliranja",
-       "patrol-log-header": "Ovo je dnevnik patroliranih izmena.",
+       "patrol-log-page": "Evidencija patroliranja",
+       "patrol-log-header": "Ovo je evidencija patroliranih izmena.",
        "confirm-markpatrolled-button": "U redu",
-       "confirm-markpatrolled-top": "Označiti izmenu $3 stranice $2 patroliranom?",
-       "deletedrevision": "Obrisana stara izmena $1.",
+       "confirm-markpatrolled-top": "Označiti izmenu $3 stranice $2 kao patroliranu?",
+       "deletedrevision": "Izbrisana stara izmena $1.",
        "filedeleteerror-short": "Greška pri brisanju datoteke: $1",
        "filedeleteerror-long": "Došlo je do grešaka pri brisanju datoteke:\n\n$1",
-       "filedelete-missing": "Datoteka „$1“ se ne može obrisati jer ne postoji.",
+       "filedelete-missing": "Ne mogu da izbrišem datoteku „$1“ jer ne postoji.",
        "filedelete-old-unregistered": "Navedena izmena datoteke „$1“ ne postoji u bazi podataka.",
        "filedelete-current-unregistered": "Navedena datoteka „$1“ ne postoji u bazi podataka.",
        "filedelete-archive-read-only": "Server ne može da piše po skladišnoj fascikli ($1).",
        "previousdiff": "← Starija izmena",
        "nextdiff": "Novija izmena →",
-       "mediawarning": "<strong>Upozorenje:</strong> ova vrsta datoteke može sadržati štetan kôd.\nAko ga pokrenete, Vaš računar može biti ugrožen.",
+       "mediawarning": "<strong>Upozorenje:</strong> ovaj tip datoteke može da sadrži štetan kod.\nNjegovim izvršavanjem možete da ugrozite vaš sistem.",
        "imagemaxsize": "Ograničenje veličine slike:<br /><em>(na stranicama za opis datoteka)</em>",
-       "thumbsize": "Veličina minijature:",
+       "thumbsize": "Veličina sličice:",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|stranica|stranice|stranica}}",
        "file-info": "veličina datoteke: $1, MIME tip: $2",
        "file-info-size": "$1 × $2 piksela, veličina datoteke: $3, MIME tip: $4",
-       "file-info-size-pages": "$1 × $2 piksela, veličina: $3, MIME vrsta: $4, $5 {{PLURAL:$5|stranica|stranice|stranica}}",
+       "file-info-size-pages": "$1 × $2 piksela, veličina: $3, MIME tip: $4, $5 {{PLURAL:$5|stranica|stranice|stranica}}",
        "file-nohires": "Veća rezolucija nije dostupna.",
        "svg-long-desc": "SVG datoteka, nominalno $1 × $2 piksela, veličina: $3",
        "svg-long-desc-animated": "Animirana SVG datoteka, nominalno: $1 × $2 piksela, veličina: $3",
-       "svg-long-error": "Neispravna SVG datoteka: $1",
-       "show-big-image": "Izvorna datoteka",
+       "svg-long-error": "Nevažeća SVG datoteka: $1",
+       "show-big-image": "Prvobitna datoteka",
        "show-big-image-preview": "Veličina ovog prikaza: $1.",
        "show-big-image-preview-differ": "Veličina $3 pregleda za ovu $2 datoteku je $1.",
        "show-big-image-other": "$2 {{PLURAL:$2|druga rezolucija|druge rezolucije|drugih rezolucija}}: $1.",
        "file-info-png-looped": "petlja",
        "file-info-png-repeat": "ponovljeno $1 {{PLURAL:$1|put|puta|puta}}",
        "file-info-png-frames": "$1 {{PLURAL:$1|kadar|kadra|kadrova}}",
-       "file-no-thumb-animation": "'''Napomena: zbog tehničkih ograničenja, minijature ove datoteke se neće animirati.'''",
+       "file-no-thumb-animation": "<strong>Napomena: Zbog tehničkih ograničenja, sličice ove datoteke neće da se animiraju.</strong>",
        "file-no-thumb-animation-gif": "'''Napomena: zbog tehničkih ograničenja, minijature GIF slika visoke rezolucije kao što je ova neće se animirati.'''",
        "newimages": "Galerija novih datoteka",
        "imagelisttext": "Ispod je spisak od '''$1''' {{PLURAL:$1|datoteke|datoteke|datoteka}} poređanih $2.",
        "newimages-legend": "Filter",
        "newimages-label": "Naziv datoteke (ili njen deo):",
        "newimages-user": "IP adresa ili korisničko ime",
-       "newimages-newbies": "Prikaži samo doprinose novih korisnika",
-       "newimages-showbots": "Prikaži datoteke koje su poslali botovi",
+       "newimages-newbies": "Prikaži samo doprinose novih naloga",
+       "newimages-showbots": "Prikaži otpremanja botova",
        "newimages-hidepatrolled": "Sakrij patrolirana otpremanja",
-       "newimages-mediatype": "Vrsta datoteke:",
+       "newimages-mediatype": "Tip datoteke:",
        "noimages": "Nema ništa.",
-       "gallery-slideshow-toggle": "minijature",
+       "gallery-slideshow-toggle": "sličice",
        "ilsubmit": "Pretraži",
        "bydate": "po datumu",
        "sp-newimages-showfrom": "prikaži nove datoteke počevši od $1, $2",
        "saturday-at": "u subotu u $1",
        "sunday-at": "u nedelju u $1",
        "yesterday-at": "Juče u $1",
-       "bad_image_list": "Format je sledeći:\n\nRazmatraju se samo nabrajanja (redovi koji počinju sa zvezdicom).\nPrva veza u redu mora da bude veza do neispravne datoteke.\nSve daljnje veze u istom redu smatraju se izuzecima.",
+       "bad_image_list": "Format je sledeći:\n\nRazmatraju se samo nabrajanja (redovi koji počinju sa zvezdicom).\nPrvi link u redu mora da bude link do neispravne datoteke.\nSvi daljnji linkovi u istom redu smatraju se izuzecima.",
        "variantname-zh-hans": "hans",
        "variantname-zh-hant": "hant",
        "variantname-zh-cn": "cn",
        "variantname-shi-tfng": "shi-Tfng",
        "variantname-shi-latn": "shi-Latn",
        "variantname-shi": "shi",
+       "variantname-uz": "uz",
+       "variantname-uz-latn": "uz-Latn",
+       "variantname-uz-cyrl": "uz-Cyrl",
+       "variantname-crh": "crh",
+       "variantname-crh-latn": "crh-Latn",
+       "variantname-crh-cyrl": "crh-Cyrl",
        "metadata": "Metapodaci",
        "metadata-help": "Ova datoteka sadrži dodatne podatke, koji verovatno dolaze od digitalnog fotoaparata ili skenera korišćenog za digitalizaciju.\nAko je prvobitno stanje datoteke promenjeno, moguće je da neki detalji ne opisuju izmenjenu datoteku u potpunosti.",
        "metadata-expand": "Prikaži detalje",
        "exif-ycbcrsubsampling": "Odnos veličine Y prema C",
        "exif-ycbcrpositioning": "Položaj Y i C",
        "exif-xresolution": "Vodoravna rezolucija",
-       "exif-yresolution": "Uspravna rezolucija",
-       "exif-stripoffsets": "Mesto podataka",
+       "exif-yresolution": "Vertikalna rezolucija",
+       "exif-stripoffsets": "Lokacija podataka slike",
        "exif-rowsperstrip": "Broj redova po liniji",
        "exif-stripbytecounts": "Bajtova po sažetom bloku",
        "exif-jpeginterchangeformat": "Početak JPEG pregleda",
        "exif-primarychromaticities": "Hromatičnost osnovnih boja",
        "exif-ycbcrcoefficients": "Matrični koeficijenti transformacije bojnog prostora",
        "exif-referenceblackwhite": "Uputne vrednosti para bele i crne tačke",
-       "exif-datetime": "Datum i vreme poslednje izmene datoteke",
+       "exif-datetime": "Datum i vreme poslednje promene datoteke",
        "exif-imagedescription": "Naziv slike",
        "exif-make": "Proizvođač kamere",
        "exif-model": "Model kamere",
        "exif-software": "Korišćeni softver",
        "exif-artist": "Autor",
        "exif-copyright": "Nosilac autorskih prava",
-       "exif-exifversion": "Exif izdanje",
-       "exif-flashpixversion": "Podržano izdanje FlashPix-a",
+       "exif-exifversion": "Exif verzija",
+       "exif-flashpixversion": "Podržana verzija FlashPix-a",
        "exif-colorspace": "Prostor boje",
        "exif-componentsconfiguration": "Značenje svakog dela",
        "exif-compressedbitsperpixel": "Režim sažimanja slike",
        "exif-focalplaneresolutionunit": "Jedinica za rezoluciju fokusne ravni",
        "exif-subjectlocation": "Položaj objekta",
        "exif-exposureindex": "Popis ekspozicije",
-       "exif-sensingmethod": "Vrsta senzora",
+       "exif-sensingmethod": "Način senzora",
        "exif-filesource": "Izvorna datoteka",
-       "exif-scenetype": "Vrsta scene",
+       "exif-scenetype": "Tip scene",
        "exif-customrendered": "Prilagođena obrada slika",
        "exif-exposuremode": "Režim ekspozicije",
        "exif-whitebalance": "Bela ravnoteža",
        "exif-digitalzoomratio": "Odnos digitalnog uveličanja",
        "exif-focallengthin35mmfilm": "Žarišna daljina za film od 35 mm",
-       "exif-scenecapturetype": "Vrsta snimanja scena",
+       "exif-scenecapturetype": "Tip snimanja scena",
        "exif-gaincontrol": "Kontrola scene",
        "exif-contrast": "Kontrast",
        "exif-saturation": "Zasićenost",
        "exif-devicesettingdescription": "Opis postavki uređaja",
        "exif-subjectdistancerange": "Opseg udaljenosti objekta",
        "exif-imageuniqueid": "Naznaka slike",
-       "exif-gpsversionid": "Izdanje GPS oznake",
+       "exif-gpsversionid": "Verzija GPS oznake",
        "exif-gpslatituderef": "Severna ili južna širina",
        "exif-gpslatitude": "Širina",
        "exif-gpslongituderef": "Istočna ili zapadna dužina",
        "exif-keywords": "Ključne reči",
        "exif-worldregioncreated": "Oblast sveta gde je slikana fotografija",
        "exif-countrycreated": "Zemlja gde je slikana fotografija",
-       "exif-countrycodecreated": "Kôd zemlje gde je slika napravljena",
+       "exif-countrycodecreated": "Kod zemlje gde je slika napravljena",
        "exif-provinceorstatecreated": "Pokrajina ili država gde je slikana fotografija",
        "exif-citycreated": "Grad gde je slikana fotografija",
        "exif-sublocationcreated": "Oblast grada gde je slikana fotografija",
        "exif-worldregiondest": "Prikazana oblast sveta",
        "exif-countrydest": "Prikazana zemlja",
-       "exif-countrycodedest": "Kôd prikazane zemlje",
+       "exif-countrycodedest": "Kod prikazane zemlje",
        "exif-provinceorstatedest": "Prikazana pokrajina ili država",
        "exif-citydest": "Prikazani grad",
        "exif-sublocationdest": "Prikazana oblast grada",
        "exif-urgency": "Hitnost",
        "exif-fixtureidentifier": "Naziv rubrike",
        "exif-locationdest": "Prikazana lokacija",
-       "exif-locationdestcode": "Kôd prikazanog mesta",
+       "exif-locationdestcode": "Kôd prikazane lokacije",
        "exif-objectcycle": "Doba dana za koji je medij namenjen",
        "exif-contact": "Podaci za kontakt",
        "exif-writer": "Pisac",
        "exif-languagecode": "Jezik",
-       "exif-iimversion": "IIM izdanje",
+       "exif-iimversion": "IIM verzija",
        "exif-iimcategory": "Kategorija",
        "exif-iimsupplementalcategory": "Dopunske kategorije",
        "exif-datetimeexpires": "Ne koristi nakon",
        "exif-datetimereleased": "Objavljeno",
-       "exif-originaltransmissionref": "Izvorni prenos kôda lokacije",
+       "exif-originaltransmissionref": "Prvobitni kod lokacije prenosa",
        "exif-identifier": "Naznaka",
        "exif-lens": "Korišćeni objektiv",
        "exif-serialnumber": "Serijski broj kamere",
        "exif-originaldocumentid": "Jedinstveni ID izvornog dokumenta",
        "exif-licenseurl": "Adresa licence za autorska prava",
        "exif-morepermissionsurl": "Rezervni podaci o licenciranju",
-       "exif-attributionurl": "Pri ponovnom korišćenju ovog rada, koristite vezu do",
+       "exif-attributionurl": "Pri ponovnom korišćenju ovog rada, koristite link do",
        "exif-preferredattributionname": "Pri ponovnom korišćenju ovog rada, postavite zasluge",
        "exif-pngfilecomment": "Komentar na datoteku PNG",
        "exif-disclaimer": "Odricanje odgovornosti",
        "exif-contentwarning": "Upozorenje o sadržaju",
        "exif-giffilecomment": "Komentar na datoteku GIF",
-       "exif-intellectualgenre": "Vrsta stavke",
-       "exif-subjectnewscode": "Kôd predmeta",
-       "exif-scenecode": "IPTC kôd scene",
+       "exif-intellectualgenre": "Tip stavke",
+       "exif-subjectnewscode": "Kod predmeta",
+       "exif-scenecode": "IPTC kod scene",
        "exif-event": "Prikazani događaj",
        "exif-organisationinimage": "Prikazana organizacija",
        "exif-personinimage": "Prikazana osoba",
        "exif-photometricinterpretation-1": "Crno-belo (crna je 0)",
        "exif-photometricinterpretation-2": "RGB",
        "exif-photometricinterpretation-3": "Paleta",
+       "exif-photometricinterpretation-4": "Maska transparentnosti",
        "exif-photometricinterpretation-6": "YCbCr",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
        "exif-unknowndate": "Nepoznat datum",
        "exif-orientation-1": "Normalno",
        "exif-orientation-2": "Obrnuto po horizontali",
        "exif-componentsconfiguration-4": "R",
        "exif-componentsconfiguration-5": "G",
        "exif-componentsconfiguration-6": "B",
-       "exif-exposureprogram-0": "Neodređeno",
+       "exif-exposureprogram-0": "Nije određen",
        "exif-exposureprogram-1": "Ručno",
        "exif-exposureprogram-2": "Normalan program",
        "exif-exposureprogram-3": "Prioritet otvora blende",
        "exif-flash-function-1": "Nema funkcije za blic",
        "exif-flash-redeye-1": "režim ispravke crvenih očiju",
        "exif-focalplaneresolutionunit-2": "inči",
-       "exif-sensingmethod-1": "Neodređeno",
+       "exif-sensingmethod-1": "Nedefinisan",
        "exif-sensingmethod-2": "Jednokristalni matrični senzor",
        "exif-sensingmethod-3": "Dvokristalni matrični senzor",
        "exif-sensingmethod-4": "Trokristalni matrični senzor",
        "exif-dc-relation": "Srodni mediji",
        "exif-dc-rights": "Prava",
        "exif-dc-source": "Izvor medija",
-       "exif-dc-type": "Vrsta medija",
+       "exif-dc-type": "Tip medija",
        "exif-rating-rejected": "Odbijeno",
        "exif-isospeedratings-overflow": "Veće od 65535",
        "exif-maxaperturevalue-value": "$1 APEX (f/$2)",
        "exif-urgency-other": "Prilagođeni prioritet ($1)",
        "namespacesall": "svi",
        "monthsall": "sve",
-       "confirmemail": "Potvrda imejl adrese",
-       "confirmemail_noemail": "Niste uneli ispravnu imejl adresu u [[Special:Preferences|podešavanjima]].",
-       "confirmemail_text": "{{SITENAME}} zahteva da potvrdite imejl adresu pre nego što počnete da koristite mogućnosti imejla.\nKliknite na dugme ispod za slanje poruke na vašu adresu.\nU poruci će se nalaziti veza s potvrdnim kôdom;\nunesite je u pregledač da biste potvrdili da je vaša imejl adresa ispravna.",
-       "confirmemail_pending": "Potvrdni kôd vam je već poslat. Ako ste upravo otvorili nalog, onda verovatno treba da sačekate nekoliko minuta da pristigne, pre nego što ponovo zatražite novi kôd.",
-       "confirmemail_send": "Pošalji potvrdni kôd",
+       "confirmemail": "Potvrda imejl-adrese",
+       "confirmemail_noemail": "Niste postavili važeću imejl-adresu u [[Special:Preferences|korisničkim podešavanjima]].",
+       "confirmemail_text": "{{SITENAME}} zahteva da potvrdite imejl adresu pre nego što počnete da koristite mogućnosti imejla.\nKliknite na dugme ispod za slanje poruke na vašu adresu.\nU poruci će se nalaziti link sa potvrdnim kodom;\nunesite je u pregledač da biste potvrdili da je vaša imejl adresa važeća.",
+       "confirmemail_pending": "Kod za potvrdu vam je već poslat imejlom.\nAko ste nedavno otvorili nalog, možda treba da sačekate nekoliko minuta da pristigne pre nego što ponovo zatražite novi kod.",
+       "confirmemail_send": "Pošalji kod za potvrdu",
        "confirmemail_sent": "Potvrdna poruka je poslata.",
-       "confirmemail_oncreate": "Poslat je potvrdni kôd na vašu imejl adresu.\nOvaj kôd nije potreban za prijavljivanje, ali vam treba da biste uključili mogućnosti imejla na vikiju.",
+       "confirmemail_oncreate": "Poslat je kod za potvrdu na vašu imejl adresu.\nOvaj kod nije potreban za prijavljivanje, ali vam treba da biste uključili mogućnosti imejla na vikiju.",
        "confirmemail_sendfailed": "{{SITENAME}} ne može da pošalje imejl potvrdu.\nProverite da li je imejl adresa pravilno napisana.\n\nGreška: $1",
-       "confirmemail_invalid": "Potvrdni kod je neispravan. Verovatno je istekao.",
-       "confirmemail_needlogin": "Morate biti $1 da biste potvrdili imejl adresu.",
-       "confirmemail_success": "Vaša imejl adresa je potvrđena.\nSada možete da se [[Special:UserLogin|prijavite]] i uživate u vikiju.",
-       "confirmemail_loggedin": "Vaša imejl adresa je sada potvrđena.",
-       "confirmemail_subject": "{{SITENAME}} – potvrda imejl adrese",
-       "confirmemail_body": "Neko, verovatno vi, sa IP adrese $1,\notvorio je nalog „$2“ sa ovom imejl adresom na vikiju {{SITENAME}}.\n\nDa potvrdite da ovaj nalog stvarno pripada vama i da aktivirate\nmogućnosti imejla na vikiju {{SITENAME}}, otvorite ovu vezu u pregledaču:\n\n$3\n\nUkoliko nalog *ne* pripada vama, pratite vezu\nda otkažete potvrdu imejl adrese:\n\n$5\n\nOvaj potvrdni kod ističe u $4.",
-       "confirmemail_body_changed": "Neko, verovatno vi, sa IP adrese $1,\npromenio je imejl adresu naloga „$2“ u ovu adresu na vikiju {{SITENAME}}.\n\nDa biste potvrdili da ovaj nalog stvarno pripada vama i ponovo aktivirali mogućnosti imejla, otvorite sledeću vezu u pregledaču:\n\n$3\n\nAko nalog *ne* pripada vama, pratite sledeću vezu da otkažete potvrdu imejl adrese:\n\n$5\n\nOvaj potvrdni kod ističe $6 u $7",
-       "confirmemail_body_set": "Neko, verovatno vi, sa IP adrese $1,\npromenio je imejl adresu naloga „$2“ u ovu adresu na {{SITENAME}}.\n\nDa bismo potvrdili da ovaj nalog stvarno pripada vama i ponovo aktivirali\nmogućnosti imejla na {{SITENAME}}, otvorite sledeću vezu u pregledaču:\n\n$3\n\nAko nalog *ne* pripada vama, pratite sledeću vezu da otkažete potvrdu imejl adrese:\n\n$5\n\nOvaj potvrdni kod ističe $4.",
+       "confirmemail_invalid": "Nevažeći kod za potvrdu.\nKod je možda istekao.",
+       "confirmemail_needlogin": "Morate biti $1 da biste potvrdili svoju imejl-adresu.",
+       "confirmemail_success": "Vaša imejl-adresa je potvrđena.\nSada možete da se [[Special:UserLogin|prijavite]] i uživate u vikiju.",
+       "confirmemail_loggedin": "Vaša imejl-adresa je sada potvrđena.",
+       "confirmemail_subject": "{{SITENAME}} – potvrda imejl-adrese",
+       "confirmemail_body": "Neko, verovatno Vi, sa IP adrese $1,\nregistrovao je nalog „$2“ sa ovom imejl adresom na projektu {{SITENAME}}.\n\nDa biste potvrdili da ovaj nalog stvarno pripada vama i aktivirali mogućnosti imejla na projektu {{SITENAME}}, otvorite ovaj link u pregledaču:\n\n$3\n\nAko vi *niste* registrovali nalog, pratite ovaj link\nda biste otkazali potvrdu imejl adrese:\n\n$5\n\nOvaj kod za potvrdu ističe u $4.",
+       "confirmemail_body_changed": "Neko, verovatno Vi, s IP adrese $1,\npromenio je imejl adresu naloga „$2“ u ovu adresu na projektu {{SITENAME}}.\n\nDa biste potvrdili da ovaj nalog stvarno pripada vama i ponovo aktivirali mogućnosti imejla, otvorite sledeći link u pregledaču:\n\n$3\n\nAko nalog *ne* pripada vama, pratite sledeći link da otkažete potvrdu imejl adrese:\n\n$5\n\nOvaj kod za potvrdu ističe $6 u $7",
+       "confirmemail_body_set": "Neko, verovatno Vi, s IP adrese $1,\npromenio je imejl adresu naloga „$2“ u ovu adresu na {{SITENAME}}.\n\nDa bismo potvrdili da ovaj nalog stvarno pripada vama i ponovo aktivirali\nmogućnosti imejla na {{SITENAME}}, otvorite sledeći link u pregledaču:\n\n$3\n\nAko nalog *ne* pripada vama, pratite sledeći link da otkažete potvrdu imejl adrese:\n\n$5\n\nOvaj kod za potvrdu ističe $4.",
        "confirmemail_invalidated": "Potvrda imejl adrese je otkazana",
        "invalidateemail": "Otkazivanje potvrde imejla",
+       "notificationemail_subject_changed": "Registrovana imejl adresa na projektu {{SITENAME}} je promenjena",
+       "notificationemail_subject_removed": "Registrovana imejl adresa na projektu {{SITENAME}} je uklonjena",
        "notificationemail_body_changed": "Neko, verovatno Vi je promenio imejl adresu naloga iz $2“ u „$3“ sa IP adrese $1 na sajtu {{SITENAME}}.\n\nAko ovo niste bili Vi, odmah obavestite administratore sajta.",
-       "notificationemail_body_removed": "Neko, verovatno Vi sa IP adrese $1 je uklonio imejl adresu za nalog „$2“ na {{SITENAME}}.\n\n\nAko ovo niste bili Vi, odmah obavestite administratore sajta.",
+       "notificationemail_body_removed": "Neko, verovatno Vi, s IP adrese $1, \nuklonio je imejl adresu za nalog „$2“ na {{SITENAME}}.\n\nAko ovo niste bili Vi, kontaktirajte administratore sajta odmah.",
        "scarytranscludedisabled": "[Međuviki uključivanje šablona je onemogućeno]",
        "scarytranscludefailed": "[Dobavljanje šablona za $1 nije uspelo]",
        "scarytranscludefailed-httpstatus": "[Ne mogu da preuzmem šablon $1: HTTP $2]",
        "scarytranscludetoolong": "[URL adresa je predugačka]",
-       "deletedwhileediting": "<strong>Upozorenje</strong>: ova stranica je obrisana nakon što ste počeli s uređivanjem!",
+       "deletedwhileediting": "<strong>Upozorenje</strong>: Ova stranica je izbrisana nakon što ste počeli sa uređivanjem!",
        "confirmrecreate": "{{GENDER:$1|Korisnik|Korisnica}} [[User:$1|$1]] ([[User talk:$1|razgovor]]) je {{GENDER:$1|obrisao|obrisala}} ovu stranicu nakon što ste počeli da je uređujete iz sledećeg razloga:\n: <em>$2</em>\nPotvrdite da stvarno želite da napravite stranicu.",
        "confirmrecreate-noreason": "{{GENDER:$1|Korisnik|Korisnica}} [[User:$1|$1]] ([[User talk:$1|razgovor]]) je {{GENDER:$1|obrisao|obrisala}} ovu stranicu nakon što ste počeli da je uređujete. Potvrdite da stvarno želite da ponovo napravite ovu stranicu.",
        "recreate": "Ponovo napravi",
        "unit-pixel": "p",
        "confirm-purge-title": "Osveži ovu stranicu",
        "confirm_purge_button": "U redu",
-       "confirm-purge-top": "Očistiti privremenu memoriju ove stranice?",
-       "confirm-purge-bottom": "Ova radnja čisti privremenu memoriju i prikazuje najnoviju izmenu.",
+       "confirm-purge-top": "Očistiti keš ove stranice?",
+       "confirm-purge-bottom": "Osvežavanje stranice čisti keš i nameće najnoviju izmenu.",
        "confirm-watch-button": "U redu",
        "confirm-watch-top": "Dodati ovu stranicu u spisak nadgledanja?",
        "confirm-unwatch-button": "U redu",
        "confirm-unwatch-top": "Ukloniti ovu stranicu sa spiska nadgledanja?",
        "confirm-rollback-button": "U redu",
        "confirm-rollback-top": "Vrati izmene na ovoj stranici?",
+       "confirm-mcrundo-title": "Poništavanje promene",
+       "mcrundofailed": "Poništavanje nije uspelo",
+       "mcrundo-missingparam": "Nedostaje potreban parametar na zahtevu.",
+       "mcrundo-changed": "Stranica je promenjena dok ste gledali razliku. Pregledajte novu promenu.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "ellipsis": "…",
        "percent": "$1%",
        "parentheses": "($1)",
+       "brackets": "[$1]",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "← prethodna stranica",
        "imgmultipagenext": "sledeća stranica →",
        "imgmultigo": "Idi!",
        "imgmultigoto": "Idi na stranicu $1",
+       "img-lang-opt": "$2 ($1)",
        "img-lang-default": "(podrazumevani jezik)",
-       "img-lang-info": "Prikaži ovu sliku na $1. $2",
+       "img-lang-info": "Renderuj ovu sliku u $1. $2",
        "img-lang-go": "Idi",
        "ascending_abbrev": "rast.",
        "descending_abbrev": "opad.",
        "size-kilobytes": "$1 kB",
        "size-megabytes": "$1 MB",
        "size-gigabytes": "$1 GB",
-       "lag-warn-normal": "Izmene novije od $1 {{PLURAL:$1|sekunde|sekunde|sekundi}} neće biti prikazane.",
-       "lag-warn-high": "Zbog preopterećenja baze podataka, izmene novije od $1 {{PLURAL:$1|1=sekunde|sekunde|sekundi}} neće biti prikazane.",
+       "size-terabytes": "$1 TB",
+       "size-petabytes": "$1 PB",
+       "size-exabytes": "$1 EB",
+       "size-zetabytes": "$1 ZB",
+       "size-yottabytes": "$1 YB",
+       "size-pixel": "$1 {{PLURAL:$1|piksel|piksela}}",
+       "size-kilopixel": "$1 KP",
+       "size-megapixel": "$1 MP",
+       "size-gigapixel": "$1 GP",
+       "size-terapixel": "$1 TP",
+       "size-petapixel": "$1 PP",
+       "size-exapixel": "$1 EP",
+       "size-zetapixel": "$1 ZP",
+       "size-yottapixel": "$1 YP",
+       "bitrate-bits": "$1 bps",
+       "bitrate-kilobits": "$1 kbps",
+       "bitrate-megabits": "$1 Mbps",
+       "bitrate-gigabits": "$1 Gbps",
+       "bitrate-terabits": "$1 Tbps",
+       "bitrate-petabits": "$1 Pbps",
+       "bitrate-exabits": "$1 Ebps",
+       "bitrate-zetabits": "$1 Zbps",
+       "bitrate-yottabits": "$1 Ybps",
+       "lag-warn-normal": "Promene novije od $1 {{PLURAL:$1|sekunde|sekunde|sekundi}} neće biti prikazane.",
+       "lag-warn-high": "Zbog preopterećenja baze podataka, promene novije od $1 {{PLURAL:$1|1=sekunde|sekunde|sekundi}} neće biti prikazane.",
        "watchlistedit-normal-title": "Uređivanje spiska nadgledanja",
        "watchlistedit-normal-legend": "Uklanjanje naslova sa spiska nadgledanja",
        "watchlistedit-normal-explain": "Naslovi na vašem spisku nadgledanja su prikazani ispod.\nDa biste uklonili naslov, označite kvadratić do njega i kliknite na „{{int:Watchlistedit-normal-submit}}“.\nMožete i da [[Special:EditWatchlist/raw|uredite sirov spisak]].",
        "watchlistedit-normal-submit": "Ukloni naslove",
        "watchlistedit-normal-done": "{{PLURAL:$1|1=Jedna stranica je uklonjena|$1 stranice su uklonjene|$1 stranica je uklonjeno}} s vašeg spiska nadgledanja:",
-       "watchlistedit-raw-title": "Izmeni sirov spisak nadgledanja",
-       "watchlistedit-raw-legend": "Izmeni sirov spisak nadgledanja",
+       "watchlistedit-raw-title": "Uredi sirov spisak nadgledanja",
+       "watchlistedit-raw-legend": "Uredi sirov spisak nadgledanja",
        "watchlistedit-raw-explain": "Naslovi sa spiska nadgledanja su prikazani ispod i mogu se uređivati dodavanjem ili uklanjanjem stavki sa spiska;\njedan naslov po redu.\nKada završite, kliknite na „{{int:Watchlistedit-raw-submit}}“.\nMožete da [[Special:EditWatchlist|koristite i običan uređivač]].",
        "watchlistedit-raw-titles": "Naslovi:",
        "watchlistedit-raw-submit": "Ažuriraj spisak",
        "watchlistedit-raw-done": "Vaš spisak nadgledanja je ažuriran.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1=Dodat je jedan naslov|Dodata su $1 naslova|Dodato je $1 naslova}}:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 naslov je uklonjen|Uklonjena su $1 naslova|Uklonjeno je $1 naslova}}:",
-       "watchlistedit-clear-title": "Pražnjenje spiska nadgledanja",
-       "watchlistedit-clear-legend": "Isprazni spisak nadgledanja",
-       "watchlistedit-clear-explain": "Svi naslovi će biti uklonjeni iz vašeg spiska nadgledanja.",
+       "watchlistedit-clear-title": "Čišćenje spiska nadgledanja",
+       "watchlistedit-clear-legend": "Čišćenje spiska nadgledanja",
+       "watchlistedit-clear-explain": "Svi naslovi će biti uklonjeni iz spiska nadgledanja",
        "watchlistedit-clear-titles": "Naslovi:",
-       "watchlistedit-clear-submit": "Isprazni spisak nadgledanja (Ovo je nepovratno!)",
-       "watchlistedit-clear-done": "Vaš spisak nadgledanja je ispražnjen.",
+       "watchlistedit-clear-submit": "Očisti spisak nadgledanja (Ovo je nepovratno!)",
+       "watchlistedit-clear-done": "Vaš spisak nadgledanja je očišćen.",
+       "watchlistedit-clear-jobqueue": "Vaš spisak nadgledanja će biti očišćen. Ovo može potrajati neko vreme!",
        "watchlistedit-clear-removed": "{{PLURAL:$1|1 naslov je uklonjen|$1 naslova su uklonjena|$1 naslova je uklonjeno}}:",
        "watchlistedit-too-many": "Ima previše stranica za prikaz ovde.",
-       "watchlisttools-clear": "isprazni spisak nadgledanja",
-       "watchlisttools-view": "prikaži srodne izmene",
-       "watchlisttools-edit": "prikaži i uredi spisak nadgledanja",
-       "watchlisttools-raw": "izmeni sirov spisak nadgledanja",
+       "watchlisttools-clear": "očisti spisak nadgledanja",
+       "watchlisttools-view": "pogledaj relevantne promene",
+       "watchlisttools-edit": "pogledaj i uredi spisak nadgledanja",
+       "watchlisttools-raw": "uredi sirov spisak nadgledanja",
        "iranian-calendar-m1": "Farvardin",
        "iranian-calendar-m2": "Ordibehešt",
        "iranian-calendar-m3": "Hordad",
        "duplicate-displaytitle": "<strong>Upozorenje:</strong> naslov za prikaz „$2“ zameniće postojeći „$1“.",
        "restricted-displaytitle": "<strong>Upozorenje:</strong> Naslov za prikaz „$1” je ignorisan pošto nije ekvivalentan stvarnom naslovu stranice.",
        "version": "Verzija",
-       "version-extensions": "Instalirana proširenja",
+       "version-extensions": "Instalirani dodaci",
        "version-skins": "Instalirane teme",
        "version-specialpages": "Posebne stranice",
        "version-parserhooks": "Kuke raščlanjivača",
        "version-other": "Drugo",
        "version-mediahandlers": "Rukovodioci medijima",
        "version-hooks": "Kuke",
-       "version-parser-extensiontags": "Oznake",
+       "version-parser-extensiontags": "Oznake dodatka raščlanjivača",
        "version-parser-function-hooks": "Kuke",
        "version-hook-name": "Naziv kuke",
        "version-hook-subscribedby": "Prijavljeno od",
        "version-no-ext-name": "[nema imena]",
        "version-license": "Medijaviki licenca",
        "version-ext-license": "Licenca",
-       "version-ext-colheader-name": "Ekstenzija",
+       "version-ext-colheader-name": "Dodatak",
        "version-skin-colheader-name": "Tema",
-       "version-ext-colheader-version": "Izdanje",
+       "version-ext-colheader-version": "Verzija",
        "version-ext-colheader-license": "Licenca",
        "version-ext-colheader-description": "Opis",
        "version-ext-colheader-credits": "Autori",
        "version-license-title": "Licenca za $1",
-       "version-license-not-found": "Za ovu ekstenziju nije nađena informacija o licenci.",
+       "version-license-not-found": "Za ovaj dodatak nije pronađena informacija o licenci.",
        "version-credits-title": "Zasluge za $1",
-       "version-credits-not-found": "Za ovu ekstenziju nije nađena informacija o zaslugama.",
+       "version-credits-not-found": "Za ovaj dodatak nije pronađena informacija o zaslugama.",
        "version-poweredby-credits": "Ovaj viki pokreće '''[https://www.mediawiki.org/ Medijaviki]''', autorska prava © 2001-$1 $2.",
        "version-poweredby-others": "ostali",
        "version-poweredby-translators": "translatewiki.net prevodioci",
        "version-license-info": "Medijaviki je slobodan softver možete ga redistribuirati i/ili modifikovati pod uslovima GNU-ove opšte javne licence verzija 2 ili svake sledeće koju objavi Zadužbina za slobodan softver.\n\nMedijaviki se redistribuira u nadi da će biti od koristi, ali <em>BEZ IKAKVE GARANCIJE</em> čak i bez <strong>PODRAZUMEVANE GARANCIJE FUNKCIONALNOSTI</strong> ili <strong>PRIKLADNOSTI ZA ODREĐENEU NAMENU</strong>. Pogledajte GNU-ovu opštu javnu licencu za više informacija.\n\nTrebalo bi da ste dobili [{{SERVER}}{{SCRIPTPATH}}/COPYING primerak GNU-ove opšte javne licence] zajedno sa ovim programom. Ako niste, pišite na Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA ili [//www.gnu.org/licenses/old-licenses/gpl-2.0.html pročitajte ovde].",
        "version-software": "Instalirani softver",
        "version-software-product": "Proizvod",
-       "version-software-version": "Izdanje",
+       "version-software-version": "Verzija",
        "version-entrypoints": "Adrese ulazne tačke",
        "version-entrypoints-header-entrypoint": "Ulazna tačka",
        "version-entrypoints-header-url": "Adresa",
+       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Article path]",
+       "version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath Script path]",
        "version-libraries": "Instalirane biblioteke",
        "version-libraries-library": "Biblioteka",
        "version-libraries-version": "Verzija",
        "version-libraries-license": "Licenca",
        "version-libraries-description": "Opis",
        "version-libraries-authors": "Autori",
-       "redirect": "Preusmerenje na datoteku, korisnika, stranicu, izmenu ili dnevnik (ID)",
+       "redirect": "Preusmerenje na datoteku, korisnika, stranicu, izmenu ili evidenciju (ID)",
        "redirect-summary": "Ova posebna stranica preusmerava do datoteke (s datim imenom datoteke), stranice (s datim ID-om izmene ili ID-om stranice), korisničke stranice (s datim numeričkim korisničkim ID-om), ili unosa u dnevniku (s datim dnevničkim ID-om). Upotreba: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Idi",
        "redirect-lookup": "Tip vrednosti:",
        "redirect-value": "Vrednost:",
        "redirect-user": "Korisnički ID",
        "redirect-page": "ID stranice",
-       "redirect-revision": "Izmena stranice",
+       "redirect-revision": "Revizija stranice",
        "redirect-file": "Naziv datoteke",
-       "redirect-logid": "ID dnevnika",
+       "redirect-logid": "ID evidencije",
        "redirect-not-exists": "Vrednost nije pronađena",
        "fileduplicatesearch": "Pretraga duplikata datoteka",
        "fileduplicatesearch-summary": "Pretraga dupliranih datoteka prema heš vrednosti.",
        "specialpages-group-maintenance": "Izveštaji održavanja",
        "specialpages-group-other": "Ostale posebne stranice",
        "specialpages-group-login": "Prijava / registracija",
-       "specialpages-group-changes": "Skorašnje izmene i dnevnici",
+       "specialpages-group-changes": "Nedavne promene i evidencije",
        "specialpages-group-media": "Izveštaji o multimedijalnom sadržaju i otpremanja",
        "specialpages-group-users": "Korisnici i korisnička prava",
        "specialpages-group-highuse": "Najčešće korišćene stranice",
        "specialpages-group-developer": "Programerske alatke",
        "blankpage": "Prazna stranica",
        "intentionallyblankpage": "Ova stranica je namerno ostavljena praznom.",
-       "external_image_whitelist": " #Ostavite ovaj red onakvim kakav jeste<pre>\n#Ispod dodajte odlomke regularnih izraza (samo deo koji se nalazi između //)\n#Oni će biti upoređeni s adresama spoljašnjih slika\n#One koje se poklapaju biće prikazane kao slike, a preostale kao veze do slika\n#Redovi koji počinju s tarabom se smatraju komentarima\n#Svi unosi su osetljivi na mala i velika slova\n\n#Dodajte sve odlomke regularnih izraza iznad ovog reda. Ovaj red ne dirajte</pre>",
-       "tags": "Važeće oznake izmena",
-       "tag-filter": "Filter za [[Special:Tags|oznake]]:",
+       "external_image_whitelist": " #Ostavite ovaj red onakvim kakav jeste<pre>\n#Ispod dodajte odlomke regularnih izraza (samo deo koji se nalazi između //)\n#Oni će biti upoređeni s adresama spoljašnjih slika\n#One koje se poklapaju biće prikazane kao slike, a preostale kao linkovi do slika\n#Redovi koji počinju s tarabom se smatraju komentarima\n#Svi unosi su osetljivi na mala i velika slova\n\n#Dodajte sve odlomke regularnih izraza iznad ovog reda. Ovaj red ne dirajte</pre>",
+       "tags": "Važeće oznake promena",
+       "tag-filter": "Filter [[Special:Tags|oznaka]]:",
        "tag-filter-submit": "Filtriraj",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|oznaka|oznake}}]]: $2)",
        "tag-mw-contentmodelchange": "promena modela sadržaja",
-       "tag-mw-contentmodelchange-description": "Izmene koje menjaju model sadržaja stranice",
+       "tag-mw-contentmodelchange-description": "Izmene koje [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel menjaju model sadržaja] stranice",
        "tag-mw-new-redirect": "novo preusmerenje",
        "tag-mw-new-redirect-description": "Izmene kojima je napravljeno novo preusmerenje ili je stranica izmenjena da bude preusmerenje",
        "tag-mw-removed-redirect": "uklonjeno preusmerenje",
        "tags-title": "Oznake",
        "tags-intro": "Na ovoj stranici je naveden spisak oznaka s kojima program može da označi izmene i njegovo značenje.",
        "tags-tag": "Naziv oznake",
-       "tags-display-header": "Izgled na spiskovima izmena",
+       "tags-display-header": "Izgled na spiskovima promena",
        "tags-description-header": "Opis značenja",
        "tags-source-header": "Izvor",
        "tags-active-header": "Aktivna?",
-       "tags-hitcount-header": "Označene izmene",
+       "tags-hitcount-header": "Označene promene",
        "tags-actions-header": "Radnje",
        "tags-active-yes": "Da",
        "tags-active-no": "Ne",
        "tags-source-manual": "Ručno je dodaju korisnici i botovi",
        "tags-source-none": "Van upotrebe",
        "tags-edit": "uredi",
-       "tags-delete": "obriši",
+       "tags-delete": "izbriši",
        "tags-activate": "aktiviraj",
        "tags-deactivate": "deaktiviraj",
-       "tags-hitcount": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
-       "tags-manage-no-permission": "Nemate dozvolu da menjate oznake.",
-       "tags-create-heading": "Nova oznaka",
+       "tags-hitcount": "$1 {{PLURAL:$1|promena|promene|promena}}",
+       "tags-manage-no-permission": "Nemate dozvolu da upravljate promenama oznaka.",
+       "tags-manage-blocked": "Ne možete da menjate oznake promena dok {{GENDER:$1|ste}} blokirani.",
+       "tags-create-heading": "Pravljenje nove oznake",
        "tags-create-explanation": "Po podrazumevanim podešavanjima nove oznake moći će da koriste korisnici i botovi.",
        "tags-create-tag-name": "Naziv oznake:",
        "tags-create-reason": "Razlog:",
        "tags-create-submit": "Napravi",
-       "tags-create-no-name": "Morate navesti naziv oznake.",
+       "tags-create-no-name": "Morate da navedete ime oznake.",
+       "tags-create-invalid-chars": "Imena oznaka ne smeju sadržati (<code>,</code>), (<code>|</code>) ili (<code>/</code>).",
+       "tags-create-invalid-title-chars": "Imena oznaka ne smeju sadržati karaktere koji se ne mogu koristiti u naslovima stranica.",
        "tags-create-already-exists": "Oznaka „$1“ već postoji.",
        "tags-create-warnings-below": "Pravite novu oznaku, želite li da nastavite?",
        "tags-delete-title": "Brisanje oznaka",
        "tags-delete-explanation-initial": "Brišete oznaku „$1“ iz baze podataka.",
-       "tags-delete-explanation-warning": "Ova radnja je <strong>nepovratna</strong> i <strong>ne može se poništiti</strong>, čak ni administratori baze podataka je ne mogu poništiti. Budite sigurni da je ovo oznaka koju želite obrisati.",
+       "tags-delete-explanation-warning": "Ova radnja je <strong>nepovratna</strong> i <strong>ne može da se poništi</strong>. Ovo ne mogu da urade čak ni administratori baze podataka. Budite sigurni da je ovo oznaka koju želite izbrisati.",
        "tags-delete-reason": "Razlog:",
-       "tags-delete-submit": "Nepovratno obriši ovu oznaku",
+       "tags-delete-submit": "Nepovratno izbriši ovu oznaku",
+       "tags-delete-not-allowed": "Oznake koje su definisane ekstenzijom ne mogu se izbrisati osim ako ih ekstenzija ne dozvoljava.",
        "tags-delete-not-found": "Oznaka „$1“ ne postoji.",
-       "tags-delete-too-many-uses": "Oznaka „$1” je primenjena na više od $2 {{PLURAL:$2|izmene|izmena}}, što znači da se ne može obrisati.",
-       "tags-delete-no-permission": "Nemate dozvolu da brišete oznake za izmenu.",
+       "tags-delete-too-many-uses": "Oznaka „$1” je primenjena na više od $2 {{PLURAL:$2|izmene|izmena}}, što znači da se ne može izbrisati.",
+       "tags-delete-no-permission": "Nemate dozvolu da brišete oznake promena.",
        "tags-activate-title": "Aktiviranje oznaka",
        "tags-activate-question": "Aktivirate oznaku „$1“.",
        "tags-activate-reason": "Razlog:",
        "tags-deactivate-reason": "Razlog:",
        "tags-deactivate-not-allowed": "Nije moguće deaktivirati oznaku „$1“.",
        "tags-deactivate-submit": "Dekativiraj",
-       "tags-update-no-permission": "Nemate dozvolu za dodavanje ili uklanjanje oznake izmena iz zasebnih izmena ili unosa u dnevniku.",
+       "tags-apply-no-permission": "Nemate dozvolu da primenite oznake promena zajedno sa svojim promenama.",
+       "tags-apply-blocked": "Ne možete da primenite oznake tagova zajedno sa vašim promenama sve dok ste blokirani.",
+       "tags-update-no-permission": "Nemate dozvolu da dodate ili uklonite oznake promena iz pojedinačnih izmena ili unosa u evidenciji.",
        "tags-update-blocked": "Ne možete dodavati niti uklanjati oznake izmena dok {{GENDER:$1|ste}} blokirani.",
        "tags-update-add-not-allowed-one": "Nije dozvoljeno da se oznaka „$1” dodaje ručno.",
        "tags-edit-title": "Uredi oznake",
        "tags-edit-manage-link": "Upravljaj oznakama",
+       "tags-edit-revision-selected": "{{PLURAL:$1|Izabrana izmena|Izabrane izmene}} stranice [[:$2]]:",
+       "tags-edit-revision-legend": "Dodajte ili uklonite oznake sa {{PLURAL:$1|ove izmene|svih $1 izmena}}",
        "tags-edit-existing-tags": "Postojeće oznake:",
        "tags-edit-existing-tags-none": "<em>Nema</em>",
        "tags-edit-new-tags": "Nove oznake:",
        "tags-edit-chosen-placeholder": "Izaberi neke oznake",
        "tags-edit-chosen-no-results": "Odgovarajuće oznake nisu pronađene",
        "tags-edit-reason": "Razlog:",
-       "tags-edit-success": "Izmene su primenjene.",
+       "tags-edit-revision-submit": "Primeni promene {{PLURAL:$1|ovoj izmeni|$1 izmenama}}",
+       "tags-edit-success": "Promene su primenjene.",
        "tags-edit-failure": "Ne mogu da primenim izmene:\n$1",
-       "tags-edit-nooldid-title": "Neispravna odredišna izmena",
+       "tags-edit-nooldid-title": "Nevažeća odredišna izmena",
+       "tags-edit-nooldid-text": "Niste odredili bilo koju ciljanu izmenu na kojoj će se izvršiti ova funkcija ili ako navedena izmena ne postoji.",
        "tags-edit-none-selected": "Izaberite bar jednu oznaku koju treba dodati ili ukloniti.",
        "comparepages": "Upoređivanje stranica",
        "compare-page1": "Stranica 1",
        "compare-page2": "Stranica 2",
-       "compare-rev1": "Izmena 1",
+       "compare-rev1": "Revizija 1",
        "compare-rev2": "Izmena 2",
        "compare-submit": "Uporedi",
-       "compare-invalid-title": "Navedeni naslov je neispravan.",
+       "compare-invalid-title": "Naslov koji ste naveli je nevažeći.",
        "compare-title-not-exists": "Navedeni naslov ne postoji.",
-       "compare-revision-not-exists": "Navedena izmena ne postoji.",
+       "compare-revision-not-exists": "Revizija koju ste naveli ne postoji.",
        "diff-form": "Razlike",
-       "diff-form-oldid": "ID stare izmene (neobavezno)",
+       "diff-form-oldid": "ID stare izmene (opcionalno)",
        "diff-form-revid": "ID izmene ili razlike",
        "diff-form-submit": "Prikaži razlike",
-       "permanentlink": "Trajna veza",
+       "permanentlink": "Trajni link",
        "permanentlink-revid": "ID izmene",
        "permanentlink-submit": "Idi na izmenu",
        "dberr-problems": "Došlo je do tehničkih problema.",
        "dberr-usegoogle": "U međuvremenu, pokušajte da pretražite pomoću Gugla.",
        "dberr-outofdate": "Imajte na umu da njihovi primerci našeg sadržaja mogu biti zastareli.",
        "dberr-cachederror": "Ovo je privremeno memorisan primerak strane koji možda nije ažuran.",
-       "htmlform-invalid-input": "Pronađeni su problemi u vašem unosu",
-       "htmlform-select-badoption": "Navedena vrednost nije ispravna opcija.",
+       "htmlform-invalid-input": "Postoje problemi sa vašim unosom.",
+       "htmlform-select-badoption": "Vrednost koju ste naveli nije validna opcija.",
        "htmlform-int-invalid": "Navedena vrednost nije celi broj.",
        "htmlform-float-invalid": "Navedena vrednost nije broj.",
        "htmlform-int-toolow": "Navedena vrednost je ispod minimuma od $1",
        "htmlform-int-toohigh": "Navedena vrednost je iznad maksimuma od $1",
        "htmlform-required": "Ova vrednost je obavezna.",
        "htmlform-submit": "Postavi",
-       "htmlform-reset": "Vrati izmene",
+       "htmlform-reset": "Vrati promene",
        "htmlform-selectorother-other": "Drugo",
        "htmlform-no": "Ne",
        "htmlform-yes": "Da",
        "htmlform-date-placeholder": "GGGG-MM-DD",
        "htmlform-time-placeholder": "ČČ:MM:SS",
        "htmlform-datetime-placeholder": "GGGG-MM-DD ČČ:MM:SS",
+       "htmlform-date-invalid": "Vrednost koju ste naveli nije prepoznati datum. Pokušajte da koristite format GGGG-MM-DD.",
+       "htmlform-time-invalid": "Vrednost koju ste naveli nije prepoznato vreme. Pokušajte da koristite format ČČ:MM:SS.",
+       "htmlform-datetime-invalid": "Vrednost koju ste naveli nije prepoznati datum i vreme. Pokušajte da koristite format GGGG-MM-DD ČČ:MM:SS.",
+       "htmlform-date-toolow": "Vrednost koju ste naveli je pre najranijeg dozvoljenog datuma – $1.",
+       "htmlform-date-toohigh": "Vrednost koju ste naveli je posle krajnjeg dozvoljenog datuma – $1.",
+       "htmlform-time-toolow": "Vrednost koju ste naveli je pre najranijeg dozvoljenog vremena – $1.",
+       "htmlform-time-toohigh": "Vrednost koju ste naveli je poslednje dozvoljeno vreme od $1.",
+       "htmlform-datetime-toolow": "Vrednost koju ste naveli je najraniji datum i vreme od $1.",
+       "htmlform-datetime-toohigh": "Vrednost koju ste naveli je najnoviji datum i vreme od $1.",
        "htmlform-title-badnamespace": "[[:$1]] nije u imenskom prostoru „{{ns:$2}}“.",
        "htmlform-title-not-creatable": "Stranica „$1“ se ne može napraviti",
        "htmlform-title-not-exists": "$1 ne postoji.",
        "htmlform-user-not-exists": "<strong>$1</strong> ne postoji.",
-       "htmlform-user-not-valid": "<strong>$1</strong> nije ispravno korisničko ime.",
+       "htmlform-user-not-valid": "<strong>$1</strong> nije validno korisničko ime.",
        "logentry-delete-delete": "$1 je {{GENDER:$2|obrisao|obrisala}} stranicu $3",
        "logentry-delete-delete_redir": "$1 je {{GENDER:$2|obrisao|obrisala}} preusmerenje $3 prepisivanjem",
        "logentry-delete-restore": "$1 je {{GENDER:$2|vratio|vratila}} stranicu $3 ($4)",
        "logentry-delete-restore-nocount": "$1 je {{GENDER:$2|vratio|vratila}} stranicu $3",
        "restore-count-revisions": "{{PLURAL:$1|1 izmena|$1 izmene|$1 izmena}}",
        "restore-count-files": "{{PLURAL:$1|1 datoteka|$1 datoteke|$1 datoteka}}",
-       "logentry-delete-event": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|1=događaja|$5 događaja}} u dnevniku $3: $4",
-       "logentry-delete-revision": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|1=jedne izmene|$5 izmene|$5 izmena}} na stranici $3: $4",
-       "logentry-delete-event-legacy": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost događaja u dnevniku $3",
+       "logentry-delete-event": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|događaja|$5 događaja}} u evidenciji na stranici „$3”: $4",
+       "logentry-delete-revision": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|izmene|$5 izmene|$5 izmena}} na stranici $3: $4",
+       "logentry-delete-event-legacy": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost događaja u evidenciji na stranici „$3”",
        "logentry-delete-revision-legacy": "$1 je {{GENDER:$2|promenio|promenila}} vidljivost izmena na stranici $3",
        "logentry-suppress-delete": "$1 je {{GENDER:$2|potisnuo|potisnula}} stranicu $3",
-       "logentry-suppress-event": "$1 je tajno {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|događaja|$5 događaja}} u dnevniku $3: $4",
+       "logentry-suppress-event": "$1 je tajno {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|događaja|$5 događaja}} u evidenciji na stranici „$3”: $4",
        "logentry-suppress-revision": "$1 je tajno {{GENDER:$2|promenio|promenila}} vidljivost {{PLURAL:$5|izmene|$5 izmena}} na stranici $3: $4",
-       "logentry-suppress-event-legacy": "$1 je potajno {{GENDER:$2|promenio|promenila}} vidljivost događaja u dnevniku $3",
+       "logentry-suppress-event-legacy": "$1 je potajno {{GENDER:$2|promenio|promenila}} vidljivost događaja u evidenciji na stranici „$3”",
        "logentry-suppress-revision-legacy": "$1 je tajno {{GENDER:$2|promenio|promenila}} vidljivost izmena na stranici $3",
        "revdelete-content-hid": "sadržaj je sakriven",
        "revdelete-summary-hid": "opis izmene je sakriven",
        "logentry-import-upload": "$1 je {{GENDER:$2|uvezao|uvezla}} $3 otpremanjem datoteke",
        "logentry-import-upload-details": "$1 je {{GENDER:$2|uvezao|uvezla}} $3 otpremanjem datoteke ($4 {{PLURAL:$4|izmena|izmene|izmena}})",
        "logentry-import-interwiki": "$1 je {{GENDER:$2|uvezao|uvezla}} $3 s drugog vikija",
-       "logentry-import-interwiki-details": "$1 je {{GENDER:$2|uvezao|uvezla}} $3 iz $5 ($4 {{PLURAL:$4|1=izmena|izmene|izmena}})",
+       "logentry-import-interwiki-details": "$1 je {{GENDER:$2|uvezao|uvezla}} $3 iz $5 ($4 {{PLURAL:$4|izmena|izmene|izmena}})",
        "logentry-merge-merge": "$1 je {{GENDER:$2|spojio|spojila}} $3 u $4 (sve do izmene $5)",
        "logentry-move-move": "$1 je {{GENDER:$2|premestio|premestila}} stranicu $3 na $4",
        "logentry-move-move-noredirect": "$1 je {{GENDER:$2|premestio|premestila}} stranicu $3 na $4 bez ostavljanja preusmerenja",
        "logentry-newusers-newusers": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog",
        "logentry-newusers-create": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog",
        "logentry-newusers-create2": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog $3",
-       "logentry-newusers-byemail": "$1 je {{GENDER:$2|napravio|napravila}} korisnički nalog $3 i lozinka je poslata na imejl",
-       "logentry-newusers-autocreate": "Korisnički nalog $1 je automatski {{GENDER:$2|otvoren}}",
+       "logentry-newusers-byemail": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog $3 i lozinka je poslata na imejl",
+       "logentry-newusers-autocreate": "$1 je automatski {{GENDER:$2|otvorio|otvorila}} korisnički nalog",
        "logentry-protect-move_prot": "$1 je {{GENDER:$2|premestio|premestila}} podešavanja zaštite sa $4 na $3",
        "logentry-protect-unprotect": "$1 je {{GENDER:$2|skinuo|skinula}} zaštitu sa stranice $3",
        "logentry-protect-protect": "$1 je {{GENDER:$2|zaštitio|zaštitila}} $3 $4",
        "logentry-protect-protect-cascade": "$1 je {{GENDER:$2|zaštitio|zaštitila}} $3 $4 [prenosiva zaštita]",
-       "logentry-protect-modify": "$1 je {{GENDER:$2|promenio|promenila}} stepen zaštite za $3 $4",
-       "logentry-protect-modify-cascade": "$1 je {{GENDER:$2|promenio|promenila}} stepen zaštite za $3 $4 [prenosiva zaštita]",
+       "logentry-protect-modify": "$1 je {{GENDER:$2|promenio|promenila}} nivo zaštite stranice „$3” $4",
+       "logentry-protect-modify-cascade": "$1 je {{GENDER:$2|promenio|promenila}} nivo zaštite stranice „$3” $4 [prenosiva zaštita]",
        "logentry-rights-rights": "$1 je {{GENDER:$2|promenio|promenila}} članstvo grupe za {{GENDER:$6|$3}} iz $4 u $5",
        "logentry-rights-rights-legacy": "$1 je {{GENDER:$2|promenio|promenila}} članstvo grupe za $3",
        "logentry-rights-autopromote": "$1 je automatski {{GENDER:$2|unapređen|unapređena}} iz $4 u $5",
        "logentry-upload-upload": "$1 je {{GENDER:$2|otpremio|otpremila}} $3",
-       "logentry-upload-overwrite": "$1 je {{GENDER:$2|otpremio|otpremila}} novu verziju $3",
+       "logentry-upload-overwrite": "$1 je {{GENDER:$2|otpremio|otpremila}} novu verziju datoteke $3",
        "logentry-upload-revert": "$1 je {{GENDER:$2|otpremio|otpremila}} $3",
-       "log-name-managetags": "Dnevnik uređivanja oznaka",
-       "log-description-managetags": "Ovaj dnevnik sadrži spisak izmena u vezi [[Special:Tags|oznaka]]. Dnevnik sadrži samo radnje izvršene od strane administratora, unosi za oznake napravljene ili obrisane od strane viki softvera se ne nalaze u ovom dnevniku.",
+       "log-name-managetags": "Evidencija upravljanja oznakama",
+       "log-description-managetags": "Na ovoj stranici se nalazi spisak izmena u vezi [[Special:Tags|oznaka]]. Evidencija sadrži samo radnje koje su ručno izvršili administratori; unosi za oznake koje je napravio ili izbrisao viki softvera se ne nalaze u ovoj evidenciji.",
        "logentry-managetags-create": "$1 je {{GENDER:$2|napravio|napravila}} oznaku „$4“",
-       "logentry-managetags-delete": "$1 je {{GENDER:$2|obrisao|obrisala}} oznaku „$4“ (uklonjena je iz $5 {{PLURAL:$5|izmene ili dnevnika|izmena i/ili dnevnika}})",
+       "logentry-managetags-delete": "$1 je {{GENDER:$2|obrisao|obrisala}} oznaku „$4“ (uklonjena je iz $5 {{PLURAL:$5|izmene ili unosa u evidenciji|izmena i/ili unosa u evidenciji}})",
        "logentry-managetags-activate": "$1 je {{GENDER:$2|aktivirao|aktivirala}} oznaku „$4“ za upotrebu od strane korisnika i botova",
        "logentry-managetags-deactivate": "$1 je {{GENDER:$2|deaktivirao|deaktivirala}} oznaku „$4“ za upotrebu od strane korisnika i botova",
-       "log-name-tag": "Dnevnik oznaka",
-       "log-description-tag": "Ovaj dnevnik prikazuje dodavanje/uklanjanje [[Special:Tags|oznaka]] na pojedinačne izmene ili unose u dnevnicima. Ovaj dnevnik ne prikazuje označavanje kada su ona deo uređivanja, brisanja ili neke druge radnje.",
+       "log-name-tag": "Evidencija oznaka",
+       "log-description-tag": "Ova stranica prikazuje kada su korisnici dodali/uklonili [[Special:Tags|oznake]] s pojedinačnih izmena ili unosa u evidencijama. Evidencija ne prikazuje radnje označavanja kada su se dogodile prilikom uređivanja, brisanja ili slične radnje.",
        "rightsnone": "(nema)",
        "rightslogentry-temporary-group": "$1 (privremeno, do $2)",
-       "feedback-adding": "Dodajem povratnu informaciju na stranicu…",
+       "feedback-adding": "Dodajem povratne informacije na stranicu…",
        "feedback-back": "Nazad",
-       "feedback-bugcheck": "Odlično! Proverite da li je greška [$1 poznata od pre].",
+       "feedback-bugcheck": "Odlično! Proverite da se ne radi o nekoj [$1 poznatoj grešci].",
        "feedback-bugnew": "Provereno. Prijavi novu grešku",
        "feedback-bugornote": "Ako ste spremni da detaljno opišete tehnički problem, onda [$1 prijavite grešku].\nU suprotnom, poslužite se jednostavnim obrascem ispod. Vaš komentar će stajati na stranici „[$3 $2]“, zajedno s korisničkim imenom i pregledačem koji koristite.",
        "feedback-cancel": "Otkaži",
-       "feedback-close": "Urađeno",
-       "feedback-external-bug-report-button": "Prijavi grešku",
-       "feedback-dialog-title": "Slanje povratne informacije",
+       "feedback-close": "Gotovo",
+       "feedback-external-bug-report-button": "Arhiviraj tehnički zadatak",
+       "feedback-dialog-title": "Slanje povratnih informacija",
        "feedback-error1": "Greška: neprepoznat rezultat od API-ja",
        "feedback-error2": "Greška: uređivanje nije uspelo",
        "feedback-error3": "Greška: nema odgovora od API-ja",
+       "feedback-error4": "Greška: ne mogu da postavim povratne informacije na dati naslov",
        "feedback-message": "Poruka:",
-       "feedback-subject": "Naslov:",
+       "feedback-subject": "Tema:",
        "feedback-submit": "Pošalji",
        "feedback-termsofuse": "Prihvatam da pošaljem povratne informacije u skladu sa uslovima korišćenja.",
        "feedback-thanks": "Hvala! Vaša povratna informacija je postavljena na stranicu „[$2 $1]“.",
        "feedback-thanks-title": "Hvala vam!",
        "feedback-useragent": "Korisnički agent:",
        "searchsuggest-search": "Pretraga",
-       "searchsuggest-containing": "sadrži...",
-       "api-error-badtoken": "Unutrašnja greška: neispravan žeton.",
-       "api-error-emptypage": "Stvaranje novih praznih stranica nije dozvoljeno.",
+       "searchsuggest-containing": "sadrži",
+       "api-error-badtoken": "Unutrašnja greška: loš token.",
+       "api-error-emptypage": "Pravljenje novih praznih stranica nije dozvoljeno.",
        "api-error-publishfailed": "Unutrašnja greška: server nije uspeo da objavi privremenu datoteku.",
-       "api-error-stashfailed": "Unutrašnja greška: server ne može da sačuva privremenu datoteku.",
+       "api-error-stashfailed": "Unutrašnja greška: server nije uspeo da smesti privremenu datoteku.",
        "api-error-unknown-warning": "Nepoznato upozorenje: „$1”.",
-       "api-error-unknownerror": "Nepoznata greÅ¡ka: â\80\9e$1â\80\9c.",
+       "api-error-unknownerror": "Nepoznata greÅ¡ka: â\80\9e$1â\80\9d.",
        "duration-seconds": "$1 {{PLURAL:$1|sekund|sekunda|sekundi}}",
-       "duration-minutes": "$1 {{PLURAL:$1|minut|minuta|minuta}}",
+       "duration-minutes": "$1 {{PLURAL:$1|minut|minuta}}",
        "duration-hours": "$1 {{PLURAL:$1|sat|sata|sati}}",
-       "duration-days": "$1 {{PLURAL:$1|dan|dana|dana}}",
+       "duration-days": "$1 {{PLURAL:$1|dan|dana}}",
        "duration-weeks": "$1 {{PLURAL:$1|nedelja|nedelje|nedelja}}",
        "duration-years": "$1 {{PLURAL:$1|godina|godine|godina}}",
        "duration-decades": "$1 {{PLURAL:$1|decenija|decenije|decenija}}",
        "duration-centuries": "$1 {{PLURAL:$1|vek|veka|vekova}}",
-       "duration-millennia": "$1 {{PLURAL:$1|milenijum|milenijuma|milenijuma}}",
-       "rotate-comment": "Slika je rotirana za $1° u smeru kazaljke na satu",
+       "duration-millennia": "$1 {{PLURAL:$1|milenijum|milenijuma}}",
+       "rotate-comment": "Slika je rotirana za $1 {{PLURAL:$1|stepen|stepena|stepeni}} u smeru kazaljke na satu",
        "limitreport-title": "Podaci profilisanja analizatora:",
-       "limitreport-cputime": "Vreme korišćenja CPU",
+       "limitreport-cputime": "Vreme korišćenja CPU-a",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|sekund|sekunda|sekundi}}",
        "limitreport-walltime": "Korišćenje u realnom vremenu",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|sekund|sekunda|sekundi}}",
        "limitreport-ppvisitednodes": "Broj predprocesiranih posećenih nodova",
+       "limitreport-ppvisitednodes-value": "$1/$2",
        "limitreport-ppgeneratednodes": "Broj predprocesiranih generisanih nodova",
+       "limitreport-ppgeneratednodes-value": "$1/$2",
        "limitreport-postexpandincludesize": "Uključena veličina nakon proširenja",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|bajt|bajta|bajtova}}",
        "limitreport-templateargumentsize": "Veličina argumenata šablona",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|bajt|bajta|bajtova}}",
        "limitreport-expansiondepth": "Najveća dubina proširenja",
+       "limitreport-expansiondepth-value": "$1/$2",
        "limitreport-expensivefunctioncount": "Broj „skupih” funkcija analizatora",
+       "limitreport-expensivefunctioncount-value": "$1/$2",
        "limitreport-unstrip-depth": "Unstrip dubina rekurzije",
+       "limitreport-unstrip-depth-value": "$1/$2",
        "limitreport-unstrip-size": "Unstrip veličina nakon proširenja",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|bajt|bajta|bajtova}}",
        "expandtemplates": "Proširavanje šablona",
        "expand_templates_intro": "Ova posebna stranica uzima vikitekst i menja sve šablone u njemu rekurzivno.\nTakođe menja funkcije parsera kao što je <code><nowiki>{{</nowiki>#language:…}}</code> i promenljive kao što je <code><nowiki>{{</nowiki>CURRENTDAY}}</code>. \nZapravo praktično sve što se nalazi između vitičastih zagrada.",
-       "expand_templates_title": "Naziv konteksta; za {{STRANICA}} itd.:",
+       "expand_templates_title": "Naslov konteksta, za {{FULLPAGENAME}} itd.:",
        "expand_templates_input": "Unos vikiteksta:",
        "expand_templates_output": "Rezultat",
        "expand_templates_xml_output": "XML izlaz",
        "expand_templates_ok": "U redu",
        "expand_templates_remove_comments": "Ukloni komentare",
        "expand_templates_remove_nowiki": "Poništava efekat <nowiki> tagova u prikazu članaka",
-       "expand_templates_generate_xml": "Prikaži XML stablo",
+       "expand_templates_generate_xml": "Prikaži XML stablo za raščlanjivanje",
        "expand_templates_generate_rawhtml": "Prikaži sirov HTML",
        "expand_templates_preview": "Pretpregled",
+       "expand_templates_input_missing": "Morate da obezbedite barem neki ulazni vikitekst.",
        "pagelanguage": "Promena jezika stranice",
        "pagelang-name": "Stranica",
        "pagelang-language": "Jezik",
        "pagelang-select-lang": "Izaberi jezik",
        "pagelang-reason": "Razlog",
        "pagelang-submit": "Pošalji",
-       "pagelang-nonexistent-page": "Stranica $1 ne postoji.",
-       "pagelang-unchanged-language": "Stranica $1  je već postavljena na jezik $2.",
-       "pagelang-db-failed": "Baza podataka nije uspela promeniti jezik stranice.",
+       "pagelang-nonexistent-page": "Stranica „$1” ne postoji.",
+       "pagelang-unchanged-language": "Stranica „$1” je već postavljena na jezik $2.",
+       "pagelang-unchanged-language-default": "Stranica $1 je već podešena na podrazumevani jezik vikija.",
+       "pagelang-db-failed": "Baza podataka nije uspela da promeni jezik stranice.",
        "right-pagelang": "menjanje jezika stranice",
-       "action-pagelang": "promenu jezika stranice",
-       "log-name-pagelang": "Dnevnik promene jezika",
-       "log-description-pagelang": "Ovo je dnevnik izmena u jezicima stranica.",
-       "logentry-pagelang-pagelang": "$1 je {{GENDER:$2|promenio|promenila}} jezik stranice $3 iz $4 u $5.",
+       "action-pagelang": "promenite jezik stranice",
+       "log-name-pagelang": "Evidencija promene jezika",
+       "log-description-pagelang": "Ovo je evidencija promena u jezicima stranica.",
+       "logentry-pagelang-pagelang": "$1 je {{GENDER:$2|promenio|promenila}} jezik stranice „$3” iz $4 u $5.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (omogućena)",
+       "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>onemogućena</strong>)",
        "mediastatistics": "Statistika medija",
-       "mediastatistics-summary": "Statistike o tipovima poslatih datoteka. Ovde su uračunate samo najnovije verzije datoteka. Stare ili obrisane verzije nisu uračunate.",
+       "mediastatistics-summary": "Statistike o tipovima otpremljenih datoteka. Ovde su uračunate samo najskorije verzije datoteka. Stare ili izbrisane verzije nisu uračunate.",
+       "mediastatistics-nfiles": "$1 ($2%)",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 bajt|$1 bajta|$1 bajtova}} ($2; $3%)",
        "mediastatistics-bytespertype": "Ukupna veličina datoteke ovog odeljka: {{PLURAL:$1|$1 bajt|$1 bajta|$1 bajtova}} ($2; $3%).",
        "mediastatistics-allbytes": "Ukupna veličina svih datoteka: {{PLURAL:$1|$1 bajt|$1 bajta|$1 bajtova}} ($2).",
        "mediastatistics-table-mimetype": "MIME tip",
-       "mediastatistics-table-extensions": "Moguće ekstenzije",
+       "mediastatistics-table-extensions": "Mogući dodaci",
        "mediastatistics-table-count": "Broj datoteka",
-       "mediastatistics-table-totalbytes": "Ukupna veličina",
+       "mediastatistics-table-totalbytes": "Kombinovana veličina",
        "mediastatistics-header-unknown": "Nepoznato",
        "mediastatistics-header-bitmap": "Bitmap slike",
        "mediastatistics-header-drawing": "Crteži (vektorske slike)",
-       "mediastatistics-header-audio": "Audio",
-       "mediastatistics-header-video": "Video",
+       "mediastatistics-header-audio": "Zvuk",
+       "mediastatistics-header-video": "Videi",
+       "mediastatistics-header-multimedia": "Obogaćeni mediji",
        "mediastatistics-header-office": "Kancelarija",
        "mediastatistics-header-text": "Tekstualne",
        "mediastatistics-header-executable": "Izvršne",
-       "mediastatistics-header-archive": "Kompresovane",
+       "mediastatistics-header-archive": "Kompresovani formati",
+       "mediastatistics-header-3d": "3D",
        "mediastatistics-header-total": "Sve datoteke",
        "json-warn-trailing-comma": "$1 {{PLURAL:$1|prateća tačka je uklonjena|prateće tačke su uklonjene|pratećih tački je uklonjeno}} iz JSON-a",
        "json-error-unknown": "Dogodio se problem s JSON-om. Greška: $1",
        "json-error-depth": "Prekoračena je najveća dubina",
-       "json-error-state-mismatch": "Nevalidan ili pokvareni JSON",
+       "json-error-state-mismatch": "Nevažeći ili pokvareni JSON",
        "json-error-ctrl-char": "Greška kontrolnog simbola, moguće je da je neispravno enkodiran",
        "json-error-syntax": "Greška u sintaksi",
        "json-error-utf8": "Malformirani UTF-8 znaci, moguće je da su neispravno enkodirani",
        "json-error-recursion": "Jedna ili više rekurzivnih referenci u vrednosti koju treba enkodirati.",
        "json-error-inf-or-nan": "Jedna ili više NAN ili INF vrednosti u vrednosti koju treba enkodirati",
-       "json-error-unsupported-type": "Data je vrednos vrste koja se ne može enkodirati",
-       "headline-anchor-title": "Veza do ovog odeljka",
+       "json-error-unsupported-type": "Data je vrednost tipa koja se ne može enkodirati",
+       "headline-anchor-title": "Link do ovog odeljka",
        "special-characters-group-latin": "Latinica",
        "special-characters-group-latinextended": "Proširena latinica",
-       "special-characters-group-ipa": "IPA",
+       "special-characters-group-ipa": "MFA",
        "special-characters-group-symbols": "Simboli",
        "special-characters-group-greek": "Grčki",
        "special-characters-group-greekextended": "Prošireni grčki",
        "special-characters-group-cyrillic": "Ćirilica",
        "special-characters-group-arabic": "Arapski",
        "special-characters-group-arabicextended": "Prošireni arapski",
-       "special-characters-group-persian": "persijski",
+       "special-characters-group-persian": "Persijski",
        "special-characters-group-hebrew": "Hebrejski",
        "special-characters-group-bangla": "Bengalski",
        "special-characters-group-tamil": "Tamilski",
        "special-characters-group-khmer": "Kmerski",
        "special-characters-group-canadianaboriginal": "Kanadski aboridžinski",
        "special-characters-title-endash": "crtica",
-       "special-characters-title-emdash": "duga crtica",
-       "special-characters-title-minus": "minus",
+       "special-characters-title-emdash": "duga crta",
+       "special-characters-title-minus": "znak za minus",
        "mw-widgets-dateinput-no-date": "Datum nije izabran",
        "mw-widgets-dateinput-placeholder-day": "GGGG-MM-DD",
        "mw-widgets-dateinput-placeholder-month": "GGGG-MM",
-       "mw-widgets-mediasearch-input-placeholder": "Pretražite datoteke",
-       "mw-widgets-mediasearch-noresults": "Nema rezultata.",
+       "mw-widgets-mediasearch-input-placeholder": "Pretražite medije",
+       "mw-widgets-mediasearch-noresults": "Rezultati nisu pronađeni.",
        "mw-widgets-titleinput-description-new-page": "stranica još uvek ne postoji",
        "mw-widgets-titleinput-description-redirect": "preusmerava na $1",
-       "mw-widgets-categoryselector-add-category-placeholder": "Dodaj kategoriju...",
-       "mw-widgets-usersmultiselect-placeholder": "Dodaj još...",
+       "mw-widgets-categoryselector-add-category-placeholder": "Dodajte kategoriju…",
+       "mw-widgets-usersmultiselect-placeholder": "Dodajte još…",
        "date-range-from": "Od datuma:",
        "date-range-to": "Do datuma:",
+       "sessionmanager-tie": "Ne možete da kombinujete više tipova potvrde identiteta: $1.",
        "sessionprovider-generic": "$1 sesije",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesije sa kolačićima",
-       "sessionprovider-nocookies": "Kolačići su možda onemogućeni. Uverite se da su kolačići omogućeni i počnite ponovo.",
+       "sessionprovider-nocookies": "Kolačići su možda onemogućeni. Uverite se da imate kolačiće omogućene i počnite ponovo.",
        "randomrootpage": "Slučajna korenska stranica",
        "log-action-filter-block": "Tip blokiranja:",
        "log-action-filter-contentmodel": "Tip promene modela sadržaja:",
        "log-action-filter-delete": "Tip brisanja:",
        "log-action-filter-import": "Tip uvoza:",
-       "log-action-filter-managetags": "Tip uređivanja oznaka:",
+       "log-action-filter-managetags": "Tip radnje upravljanja oznakama:",
        "log-action-filter-move": "Tip premeštanja:",
-       "log-action-filter-newusers": "Tip novog naloga:",
+       "log-action-filter-newusers": "Tip otvaranja naloga:",
        "log-action-filter-patrol": "Tip patroliranja:",
-       "log-action-filter-protect": "Tip zaključavanja:",
+       "log-action-filter-protect": "Tip zaštite:",
        "log-action-filter-rights": "Tip promene korisničkih prava:",
-       "log-action-filter-suppress": "Vrsta skrivanja:",
+       "log-action-filter-suppress": "Tip skrivanja:",
        "log-action-filter-upload": "Tip otpremanja:",
        "log-action-filter-all": "Sve",
        "log-action-filter-block-block": "blokiranje",
        "log-action-filter-block-reblock": "izmena blokiranja",
        "log-action-filter-block-unblock": "deblokiranje",
-       "log-action-filter-contentmodel-change": "Izmena modela sadržaja",
-       "log-action-filter-contentmodel-new": "Nova stranica s nestandardnim modelom sadržaja",
+       "log-action-filter-contentmodel-change": "Promena modela sadržaja",
+       "log-action-filter-contentmodel-new": "Pravljenje stranice sa nestandardnim modelom sadržaja",
        "log-action-filter-delete-delete": "brisanje stranice",
        "log-action-filter-delete-delete_redir": "presnimavanje preusmerenja",
        "log-action-filter-delete-restore": "vraćanje stranice",
-       "log-action-filter-delete-event": "brisanje unosa u dnevnicima",
-       "log-action-filter-delete-revision": "brisanje izmene",
+       "log-action-filter-delete-event": "brisanje evidencije",
+       "log-action-filter-delete-revision": "brisanje izmena",
        "log-action-filter-import-interwiki": "Međuviki uvoz",
        "log-action-filter-import-upload": "Uvoz postavljanjem XML-a",
-       "log-action-filter-managetags-create": "nova oznaka",
+       "log-action-filter-managetags-create": "pravljenje oznake",
        "log-action-filter-managetags-delete": "brisanje oznake",
        "log-action-filter-managetags-activate": "aktiviranje oznake",
        "log-action-filter-managetags-deactivate": "deaktiviranje oznake",
        "log-action-filter-newusers-create": "otvorio anoniman korisnik",
        "log-action-filter-newusers-create2": "otvorio registrovan korisnik",
        "log-action-filter-newusers-autocreate": "automatski otvoren",
+       "log-action-filter-newusers-byemail": "otvaranje lozinkom poslanom na imejlu",
        "log-action-filter-patrol-patrol": "ručno",
        "log-action-filter-patrol-autopatrol": "automatsko",
        "log-action-filter-protect-protect": "zaključavanje",
        "log-action-filter-protect-move_prot": "premeštanje zaštite",
        "log-action-filter-rights-rights": "ručno",
        "log-action-filter-rights-autopromote": "automatski",
-       "log-action-filter-suppress-event": "Skrivanje unosa u dnevniku",
-       "log-action-filter-suppress-revision": "Skrivanje izmene",
+       "log-action-filter-suppress-event": "Skrivanje unosa u evidenciji",
+       "log-action-filter-suppress-revision": "skrivanje izmena",
        "log-action-filter-suppress-delete": "Skrivanje stranice",
        "log-action-filter-suppress-block": "Skrivanje korisnika blokiranjem",
        "log-action-filter-suppress-reblock": "Skrivanje korisnika ponovnim blokiranjem",
        "log-action-filter-upload-upload": "novo otpremanje",
        "log-action-filter-upload-overwrite": "promena postojećeg",
-       "authmanager-authn-not-in-progress": "Autentifikacija nije u toku ili je došlo do gubitka podataka o sesiji. Počnite ispočetka.",
+       "authmanager-authn-not-in-progress": "Potvrda identiteta nije u toku ili je došlo do gubitka podataka o sesiji. Počnite ispočetka.",
        "authmanager-authn-no-primary": "Ne mogu da proverim pružene akreditive.",
        "authmanager-authn-no-local-user": "Pruženi akreditivi nisu povezani ni sa jednim korisnikom na ovom vikiju.",
-       "authmanager-authn-no-local-user-link": "Pruženi su ispravni akreditivi, ali nisu povezani ni s jednim korisnikom na ovom vikiju. Prijavite se na neki drugi način ili napravite novi korisnički nalog, što će Vam dati mogućnost da povežete prethodne akreditive na novi nalog.",
+       "authmanager-authn-no-local-user-link": "Pruženi su važeći akreditivi, ali nisu povezani ni s jednim korisnikom na ovom vikiju. Prijavite se na neki drugi način ili napravite novi korisnički nalog, što će vam dati mogućnost da povežete prethodne akreditive na novi nalog.",
        "authmanager-authn-autocreate-failed": "Ne mogu da automatski napravim lokalni nalog: $1",
        "authmanager-change-not-supported": "Ne mogu da promenim pružene akreditive jer ih ništa ne bi koristilo.",
-       "authmanager-create-disabled": "Onemogućeno pravljenje naloga.",
+       "authmanager-create-disabled": "Otvaranje naloga je onemogućeno.",
        "authmanager-create-from-login": "Popunite polja da biste napravili nalog.",
-       "authmanager-create-not-in-progress": "Pravljenje naloga nije u toku ili su podaci o sesiji izgubljeni. Počnite ispočetka.",
-       "authmanager-create-no-primary": "Ne mogu da iskoristim pružene akreditive za pravljenje naloga.",
+       "authmanager-create-not-in-progress": "Otvaranje naloga nije u toku ili su podaci o sesiji izgubljeni. Počnite ponovo ispočetka.",
+       "authmanager-create-no-primary": "Ne mogu da iskoristim pružene akreditive za otvaranje naloga.",
        "authmanager-link-no-primary": "Ne mogu da iskoristim pružene akreditive za spajanje naloga.",
        "authmanager-link-not-in-progress": "Spajanje naloga nije u toku ili je došlo do gubitka podataka o sesiji. Počnite ispočetka.",
        "authmanager-authplugin-setpass-failed-title": "Neuspešna promena lozinke",
-       "authmanager-authplugin-setpass-failed-message": "Dodatak za autentifikaciju je odbio promenu lozinke.",
-       "authmanager-authplugin-create-fail": "Dodatak za autentifikaciju je odbio pravljenje naloga.",
-       "authmanager-authplugin-setpass-denied": "Dodatak za autentifikaciju ne dozvoljava menjanje loziku.",
-       "authmanager-authplugin-setpass-bad-domain": "Neispravan domen.",
-       "authmanager-autocreate-noperm": "Automatsko pravljenje naloga nije dozvoljeno.",
+       "authmanager-authplugin-setpass-failed-message": "Dodatak za potvrdu identiteta je odbio promenu lozinke.",
+       "authmanager-authplugin-create-fail": "Dodatak za potvrdu identiteta je odbio otvaranje naloga.",
+       "authmanager-authplugin-setpass-denied": "Dodatak za potvrdu identiteta ne dozvoljava menjanje loziku.",
+       "authmanager-authplugin-setpass-bad-domain": "Nevažeći domen.",
+       "authmanager-autocreate-noperm": "Automatsko otvaranje naloga nije dozvoljeno.",
+       "authmanager-autocreate-exception": "Automatsko kreiranje naloga je privremeno onemogućeno zbog prethodnih grešaka.",
        "authmanager-userdoesnotexist": "Korisnički nalog „$1“ nije otvoren.",
-       "authmanager-username-help": "Korisničko ime za autentifikaciju.",
-       "authmanager-password-help": "Lozinka za autentifikaciju.",
-       "authmanager-domain-help": "Domen za spoljašnju autentifikaciju.",
+       "authmanager-username-help": "Korisničko ime za potvrdu identiteta.",
+       "authmanager-password-help": "Lozinka za potvrdu identiteta.",
+       "authmanager-domain-help": "Domen za spoljašnju potvrdu identiteta.",
        "authmanager-retype-help": "Ponovite lozinku da bi ste potvrdili.",
        "authmanager-email-label": "Imejl",
-       "authmanager-email-help": "Imejl adresa",
+       "authmanager-email-help": "Imejl-adresa",
        "authmanager-realname-label": "Pravo ime",
        "authmanager-realname-help": "Pravo ime korisnika",
-       "authmanager-provider-password": "Autentifikacija lozinkom",
-       "authmanager-provider-password-domain": "Autentifikacija lozinkom i domenom",
+       "authmanager-provider-password": "Potvrda identiteta lozinkom",
+       "authmanager-provider-password-domain": "Potvrda identiteta lozinkom i domenom",
        "authmanager-provider-temporarypassword": "Privremena lozinka",
        "authprovider-confirmlink-option": "$1 ($2)",
        "authprovider-confirmlink-request-label": "Računi koji se trebaju povezati",
        "authprovider-confirmlink-success-line": "$1: Uspešno povezano.",
+       "authprovider-confirmlink-failed-line": "$1: $2",
        "authprovider-confirmlink-failed": "Ne mogu da povežem nalog u potpunosti: $1",
-       "authprovider-confirmlink-ok-help": "Nastavite nakon prikazivanja poruka za neuspešno povezivanje.",
+       "authprovider-confirmlink-ok-help": "Nastavite nakon prikazivanja poruka za neuspelo povezivanje.",
        "authprovider-resetpass-skip-label": "Preskoči",
        "authprovider-resetpass-skip-help": "Preskočite resetovanje lozinke.",
-       "authform-nosession-login": "Autentifikacija je uspela, ali Vaš pregledač ne može da „zapamti” da ste prijavljeni.\n\n$1",
-       "authform-nosession-signup": "Nalog je napravljen, ali Vaš pregledač ne može da „zapamti” da ste prijavljeni.\n\n$1",
-       "authform-newtoken": "Nedostaje žeton. $1",
-       "authform-notoken": "Nedostaje žeton",
-       "authform-wrongtoken": "Pogrešan žeton",
+       "authform-nosession-login": "Potvrda identiteta je uspela, ali vaš pregledač ne može da „zapamti” da ste prijavljeni.\n\n$1",
+       "authform-nosession-signup": "Nalog je otvoren, ali vaš pregledač ne može da „zapamti” da ste prijavljeni.\n\n$1",
+       "authform-newtoken": "Nedostaje token. $1",
+       "authform-notoken": "Nedostaje token",
+       "authform-wrongtoken": "Pogrešan token",
        "specialpage-securitylevel-not-allowed-title": "Nije dozvoljeno",
-       "specialpage-securitylevel-not-allowed": "Žao nam je, nije Vam dozvoljeno da koristite ovu stranicu jer ne mogu da potvrdim Vaš identitet.",
-       "authpage-cannot-login": "Ne mogu započeti prijavu.",
-       "authpage-cannot-login-continue": "Ne mogu da nastavim prijavljivanje. Vaša sesija je najverovatnije istekla.",
-       "authpage-cannot-create": "Ne mogu započeti stvaranje naloga.",
-       "authpage-cannot-link": "Ne mogu započeti spajanje naloga.",
+       "specialpage-securitylevel-not-allowed": "Žao nam je, nije vam dozvoljeno da koristite ovu stranicu jer ne mogu da potvrdim vaš identitet.",
+       "authpage-cannot-login": "Ne mogu da započnem prijavu.",
+       "authpage-cannot-login-continue": "Ne mogu da nastavim sa prijavom. Vaša sesija je najverovatnije istekla.",
+       "authpage-cannot-create": "Ne mogu da započnem otvaranje naloga.",
+       "authpage-cannot-create-continue": "Ne mogu da nastavim kreiranje naloga. Vaša sesija je najverovatnije istekla.",
+       "authpage-cannot-link": "Ne mogu da započnem povezivanje naloga.",
+       "authpage-cannot-link-continue": "Ne mogu nastaviti povezivanje naloga. Vaša sesija je najverovatnije istekla.",
        "cannotauth-not-allowed-title": "Pristup je odbijen",
-       "cannotauth-not-allowed": "Nije Vam dozvoljeno da koristite ovu stranicu",
+       "cannotauth-not-allowed": "Nije vam dozvoljeno da koristite ovu stranicu",
        "changecredentials": "Promena akreditiva",
        "changecredentials-submit": "Promeni",
-       "changecredentials-invalidsubpage": "„$1“ nije ispravna vrsta akreditiva.",
+       "changecredentials-invalidsubpage": "„$1“ nije važeći tip akreditiva.",
        "changecredentials-success": "Vaši akreditivi su promenjeni.",
        "removecredentials": "Uklanjanje akreditiva",
        "removecredentials-submit": "Uklanjanje akreditiva",
-       "removecredentials-invalidsubpage": "„$1“ nije ispravna vrsta akreditiva.",
+       "removecredentials-invalidsubpage": "„$1“ nije važeći tip akreditiva.",
        "removecredentials-success": "Vaši akreditivi su uklonjeni.",
-       "credentialsform-provider": "Vrsta akreditiva:",
+       "credentialsform-provider": "Tip akreditiva:",
        "credentialsform-account": "Naziv naloga:",
        "cannotlink-no-provider-title": "Nema naloga za povezivanje",
        "cannotlink-no-provider": "Nema naloga za povezivanje.",
-       "linkaccounts": "Poveži naloge",
+       "linkaccounts": "Spajanje naloga",
        "linkaccounts-success-text": "Nalog je povezan.",
        "linkaccounts-submit": "Poveži naloge",
-       "unlinkaccounts": "Objedini naloge",
+       "unlinkaccounts": "Razdvajanje naloga",
        "unlinkaccounts-success": "Nalog je objedinjen.",
+       "authenticationdatachange-ignored": "Promena podataka autenifikacije nije obrađena. Možda nijedan provajder nije konfigurisan?",
        "userjsispublic": "Napomena: JavaScript podstranice ne bi trebale sadržavati poverljive informacije budući da su vidljive drugim korisnicima.",
+       "userjsonispublic": "Napomena: JSON podstranice ne bi trebale sadržavati poverljive informacije budući da su vidljive drugim korisnicima.",
        "usercssispublic": "Napomena: CSS podstranice ne bi trebale sadržavati poverljive informacije budući da su vidljive drugim korisnicima.",
-       "restrictionsfield-badip": "Neispravna IP adresa ili opseg: $1",
-       "restrictionsfield-label": "Dozvoljeni IP-opsezi:",
+       "restrictionsfield-badip": "Nevažeća IP adresa ili opseg: $1",
+       "restrictionsfield-label": "Dozvoljeni IP opsezi:",
        "edit-error-short": "Greška: $1",
        "edit-error-long": "Greške:\n\n$1",
        "revid": "izmena $1",
        "pageid": "ID stranice: $1",
        "rawhtml-notallowed": "&lt;html&gt; tagovi ne mogu da se koriste van normalnih stranica.",
        "gotointerwiki": "Napuštanje projekta {{SITENAME}}",
-       "gotointerwiki-invalid": "Odabrani naslov je nevalidan.",
+       "gotointerwiki-invalid": "Navedeni naslov je nevalidan.",
        "gotointerwiki-external": "Upravo ćete da napustite projekat {{SITENAME}} da biste na zasebnom veb-sajtu posetili [[$2]].\n\n'''[$1 Produži na $1]'''",
        "undelete-cantedit": "Ne možete povratiti ovu stranicu jer nemate dozvolu da je uređujete.",
        "undelete-cantcreate": "Ne možete povratiti ovu stranicu jer nema postojeće stranice sa ovim imenom i nemate dozvolu da napravite ovu stranicu.",
        "pagedata-title": "Podaci stranice",
        "pagedata-not-acceptable": "Nije pronađen odgovarajući oblik. Podržane MIME-vrste: $1",
-       "pagedata-bad-title": "Nevalidan naslov: $1."
+       "pagedata-bad-title": "Nevalidan naslov: $1.",
+       "unregistered-user-config": "Iz bezbedonosnih razloga JavaScript, CSS i JSON korisničke podstranice ne mogu biti učitane za neregistrovane korisnike.",
+       "passwordpolicies": "Pravila za lozinke",
+       "passwordpolicies-summary": "Ovo je lista efikasnih smernica za lozinke za korisničke grupe definisane na ovom vikiju.",
+       "passwordpolicies-group": "Grupa",
+       "passwordpolicies-policies": "Pravila",
+       "passwordpolicies-policy-display": "<span class=\"passwordpolicies-policy\">$1 <code>($2)</code></span>",
+       "passwordpolicies-policy-minimalpasswordlength": "Lozinka mora da ima najmanje {{PLURAL:$1|jedan znak|$1 znaka|$1 znakova}}",
+       "passwordpolicies-policy-minimumpasswordlengthtologin": "Lozinka mora sadržati najmanje $1 {{PLURAL:$1|karakter|karaktera}} da bi ste mogli da se prijavite.",
+       "passwordpolicies-policy-passwordcannotmatchusername": "Lozinka ne može da bude ista kao korisničko ime",
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "Lozinka se ne može podudarati sa lozinkama na crnoj listi",
+       "passwordpolicies-policy-maximalpasswordlength": "Lozinka mora da bude kraća od $1 {{PLURAL:$1|znaka|znakova}}",
+       "passwordpolicies-policy-passwordcannotbepopular": "Lozinka ne može da bude {{PLURAL:$1|popularna lozinka|na spisku $1 popularnih lozinki}}"
 }
index 2b44968..f95b824 100644 (file)
        "cascadeprotected": "Ta zajta je chrōniōnŏ ôd edycyje, skuli tego co je ôna wkludzōnŏ do {{PLURAL:$1|nastympujōncyj zajty, kerŏ ôstała ôchrōniōnŏ|nastympujōncych zajtach, kere ôstały ôchrōniōne}} ze załōnczōnōm ôpcyjōm erbowaniŏ:\n$2",
        "namespaceprotected": "Ńy mosz uprowńyń, coby sprowjać zajty we raumje mjan '''$1'''.",
        "customcssprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty, bo na ńij sům uosobiste sztalowańo inkszego użytkowńika.",
+       "customjsonprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty, bo na ńij sům uosobiste sztalowańo inkszego użytkowńika.",
        "customjsprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty, bo na ńij sům uosobiste sztalowańo inkszego użytkowńika.",
        "mycustomcssprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty CSS.",
+       "mycustomjsonprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty JSON.",
        "mycustomjsprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty JavaScript.",
        "myprivateinfoprotected": "Ńy mosz uprowńyń coby sprowjić swoje prywatne dane.",
        "mypreferencesprotected": "Ńy mosz uprowńyń coby sprowjić swoje sztalowańo.",
index fd2c5d3..cfd4c2b 100644 (file)
        "loginlanguagelabel": "ಬಾಸೆ: $1",
        "pt-login": "ಲಾಗ್ ಇನ್",
        "pt-login-button": "ಲಾಗಿನ್ ಆಲೆ",
+       "pt-login-continue-button": "ಲಾಗಿನ್ ಅದ್ ಮುಂದುವರಿಲೆ",
        "pt-createaccount": "ಪೊಸ ಖಾತೆ ಸುರು ಮಲ್ಪುಲೆ",
        "pt-userlogout": "ಲಾಗ್ ಔಟ್",
        "changepassword": "ಪ್ರವೇಶಪದೊನ್ ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
        "savechanges": "ಬದಲಾವನೆನ್ ಒರಿಪಾಲೆ",
        "publishpage": "ಪುಟೋನು ಪ್ರಕಟಿಸಲೇ",
        "publishchanges": "ಬದಲಾವನೆನ್ ತೋಜಾಲೆ",
+       "savearticle-start": "ಪುಟೊನು ಒರಿಪಾಲೆ",
+       "savechanges-start": "ಬದಲಾವನೆನ್ ಒರಿಪಾಲೆ",
+       "publishpage-start": "ಪುಟೋನು ಪ್ರಕಟಿಸಲೇ...",
+       "publishchanges-start": "ಬದಲಾವನೆನ್ ತೋಜಾಲೆ...",
        "preview": "ಮುನ್ನೋಟ",
        "showpreview": "ಮುನ್ನೋಟೊ ತೋಜಾವು",
        "showdiff": "ಬದಲಾವಣೆಲೆನ್ ತೋಜಾವ್",
        "anoneditwarning": "<strong>ಜಾಗ್‍ರ್ತೆ:</strong> ಈರ್ ಇತ್ತೆ ಲಾಗ್ ಇನ್ ಆತಿಜರ್. ಈರ್ ಸಂಪೊಲಿತರ್ಂಡ ಈರೆನ ಐ.ಪಿ. ಎಡ್ರೆಸ್ ಮಾಂತೆರೆಗ್ಲಾ ತೆರಿವುಂಡು. ಒಂಜೇಲೆ <strong>[$1 ಲಾಗಿನ್ ಆಯರ್ಂದಾಂಡ]</strong> ಅತ್ತಂಡ <strong>[$2 ಒಂಜಿ ಅಕೌಂಟ್ ಮಲ್ತರ್ಂಡ]</strong>, ಈರ್ ಸಂಪೊಲ್ತಿನೆತ್ತ ಶ್ರೇಯೊ (ಕ್ರೆಡಿಟ್) ಬೊಕ್ಕ ಬೇತೆ ಲಾಬೊಲು ಇರೆನ ಸದಸ್ಯೆರೆ ಪುದರ್‍ಗ್ ಸೇರುಂಡು.",
        "anonpreviewwarning": "ಈರ್ ಇತ್ತೆ ಲಾಗ್ ಇನ್ ಆತಿಜರ್. ಈರ್ನ ಐ.ಪಿ ಎಡ್ರೆಸ್ ಈ ಪುಟೊತ ಬದಲಾವಣೆ ಇತಿಹಾಸೊಡು ದಾಖಲಾಪು೦ಡು",
        "missingsummary": "'''ಗಮನಿಸಾಲೆ:''' ಈರ್ ಬದಲಾವಣೆದ ಸಾರಾ೦ಶನ್ ಕೊರ್ತಿಜರ್.\nಈರ್ ಪಿರ 'ಒರಿಪಾಲೆ' ಬಟನ್ ನ್ ಒತ್ತ್೦ಡ ಸಾರಾ೦ಶ ಇಜ್ಜ೦ದೆನೇ ಈರ್ನ ಬದಲಾವಣೆ ದಾಖಲಾಪು೦ಡು.",
-       "missingcommenttext": "ದಯ à²®à²²à³\8dತà³\8d à²¦ à²\88ರà³\8dನ à²\85ಭಿಪà³\8dರಾಯನà³\8d à²¤à²¿à²°à³\8dತà³\8d à²\95à³\8aರà³\8dಲà³\86",
+       "missingcommenttext": "ದಯ ಮಲ್ತ್ ದ ಈರ್ನ ಅಭಿಪ್ರಾಯನ್ ಕೊರ್ಲೆ",
        "missingcommentheader": "'''ಗಮನಿಸಾಲೆ:''' ಈರ್ ಈ ಅಭಿಪ್ರಾಯಗ್ \"ವಿಷಯ/ಮುಖ್ಯಾ೦ಶ\" ದಾಲ ಕೊರ್ತಿಜರ್. ಈರ್ ಪಿರ ’ಒರಿಪಾಲೆ’ ಬಟನ್ ನ್ ಒತ್ತ್೦ಡ ಈರ್ನ ಬದಲಾವಣೆ ವಿಷಯ/ಮುಖ್ಯಾ೦ಶ ಇಜ್ಜ೦ದನೇ ಒರಿಪ್ಪಾವು೦ಡು.",
        "summary-preview": "ಸಾರಾ೦ಶ ಮುನ್ನೋಟ:",
        "subject-preview": "ವಿಷಯ/ಮುಖ್ಯಾ೦ಶದ ಮುನ್ನೋಟ:",
        "userpage-userdoesnotexist": "ಬಳಕೆದಾರ ಖಾತೆ \"<nowiki>$1</nowiki>\" ದಾಖಲಾತ್‘ಜ್ಜಿ. ಈರ್ ಉಂದುವೇ ಪುಟನ್ ಸಂಪಾದನೆ ಮಲ್ಪರ ಉಂಡಾಂದ್ ಖಾತ್ರಿ ಮಲ್ತೊನಿ.",
        "userpage-userdoesnotexist-view": "ಸದಸ್ಯೆರೆ ಖಾತೆ \"$1\" ನೋಂದಣಿ ಆಯಿಜಿ.",
        "clearyourcache": "<strong>ಸೂಚನೆ:</strong> ಒರಿಪಾಯಿನ ಬೊಕ್ಕ, ಬದಲಾವಣೆಲೆನ್ ತೂಯೆರೆ ಈರ್ ಇರೆನ ಬ್ರೌಸರ್‌ದ ಕ್ಯಾಶ್ ಖಾಲಿ ಮಲ್ಪೊಡಾವು.\n*<strong>Firefox / Safari:</strong> <em>Shift</em> ಕೀನ್ ಒತ್ತುದು ಪತ್ತ್‌ದ್ <em>Reload</em>ನ್ ಒತ್ತುಲೆ ಇಜ್ಜಿಂಡ <em>Ctrl-F5</em> ಅತ್ತ್‌ಡ <em>Ctrl-R</em>ನ್ (ಮ್ಯಾಕ್‌ಡ್ <em>⌘-Shift-R</em>ನ್) ಒತ್ತುಲೆ\n* <strong>Google Chrome:</strong> <em>Ctrl-Shift-R</em>ನ್ (ಮ್ಯಾಕ್‌ಡ್ <em>⌘-Shift-R</em>ನ್) ಒತ್ತುಲೆ\n*<strong>Internet Explorer:</strong> <em>Ctrl</em> ಕೀನ್ ಒತ್ತುದು ಪತ್ತ್‌ದ್ <em>Refresh</em> ಒತ್ತುಲೆ ಇಜ್ಜಿಂಡ <em>Ctrl-F5</em>ನ್ ಒತ್ತುಲೆ.\n* <strong>Opera:</strong> <em>Menu → Settings</em>ಗ್ ಪೋಲೆ (ಮ್ಯಾಕ್‌ಡ್ <em>Opera → Preferences</em>) ಬೊಕ್ಕ <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
+       "updated": "ಪರಿಷ್ಕರಣೆ ಆಯಿನಾ",
        "previewnote": "'''ಉಂದು ಕೇವಲ ಮುನ್ನೋಟ; ಪುಟೊನು ನನಲ ಒರಿಪಾದಿಜಿ ಪನ್ಪುನೇನ್ ಮರಪಡೆ!'''",
        "continue-editing": "ಸಂಪೊಲಿಪುನ ಜಾಗೊಗು ಪೋಲೆ",
        "editing": "$1 ಲೇಕನೊನು ಈರ್ ಸಂಪಾದನೆ ಮಲ್ತೊಂದುಲ್ಲರ್",
index 0824294..6548aaa 100644 (file)
        "proxyblockreason": "మీ ఐపీ అడ్రసు ఒక ఓపెన్ ప్రాక్సీ కాబట్టి దాన్ని నిరోధించాం. మీ ఇంటర్నెట్ సేవాదారుని గానీ, సాంకేతిక సహాయకుని గానీ సంప్రదించి తీవ్రమైన ఈ భద్రతా వైఫల్యాన్ని గురించి తెలపండి.",
        "sorbsreason": "{{SITENAME}} వాడే DNSBLలో మీ ఐపీ అడ్రసు ఒక ఓపెన్ ప్రాక్సీగా నమోదై ఉంది.",
        "sorbs_create_account_reason": "మీ ఐపీ అడ్రసు DNSBL లో ఓపెను ప్రాక్సీగా నమోదయి ఉంది. మీరు ఎకౌంటును సృష్టించజాలరు.",
+       "softblockrangesreason": "మీ ఐపీ అడ్రసు ($1) నుండి అజ్ఞాతంగా చేసే మార్పులకు అనుమతి లేదు. దయచేసి లాగినవండి.",
        "cant-see-hidden-user": "మీరు నిరోధించదలచిన వాడుకరి ఇప్పటికే నిరోధించబడి, దాచబడి ఉన్నారు. మీకు హక్కు లేదు కాబట్టి, ఆ వాడుకరి నిరోధాన్ని చూడటంగానీ, దాన్ని మార్చడంగానీ చెయ్యలేరు.",
        "ipbblocked": "మీరు ఇతర వాడుకరులని నిరోధించలేరు లేదా అనిరోధించలేరు, ఎందుకంటే మిమ్మల్ని మీరే నిరోధించుకున్నారు",
        "ipbnounblockself": "మిమ్మల్ని మీరే అనిరోధించుకునే అనుమతి మీకు లేదు",
        "imported-log-entries": "$1 {{PLURAL:$1|చిట్టా పద్దు దిగుమతయ్యింది|చిట్టా పద్దులు దిగుమతయ్యాయి}}.",
        "importfailed": "దిగుమతి కాలేదు: $1",
        "importunknownsource": "దిగుమతి చేసుకుంటున్న దాని మాతృక రకం తెలియదు",
-       "importcantopen": "దిగుమతి చేయబోతున్న ఫైలును తెరవలేకపోతున్నాను",
+       "importnoprefix": "అంతర్వికీ ఆదిపదం (ప్రిఫిక్స్) ఇవ్వలేదు",
+       "importcantopen": "దిగుమతి చేయదలచిన ఫైలును తెరవలేకపోయాం",
        "importbadinterwiki": "చెడు అంతర్వికీ లింకు",
        "importsuccess": "దిగుమతి పూర్తయ్యింది!",
        "importnosources": "ఏ వికీనుండి దిగుమతి చేసుకోవాలో సూచించలేదు. సూటి చరిత్ర ఎక్కింపులను అచేతనం చేసాం.",
        "import-nonewrevisions": "కూర్పులేవీ దిగుమతి కాలేదు (అవన్నీ ఈసరికే ఉండి ఉండాలి, లేదా లోపాల కారణంగా వదిలెయ్యబడ్డాయి).",
        "xml-error-string": "$1 $2వ లైనులో, వరుస $3 ($4వ బైటు): $5",
        "import-upload": "XML డేటాను అప్‌లోడు చెయ్యి",
-       "import-token-mismatch": "సెషను డేటా పోయింది.\n\nమీరు లాగౌటై పోయి ఉండవచ్చు. <strong>లాగినై ఉన్నారో లేదో చూసుకుని, మళ్ళీ ప్రయత్నించండి</strong>.\nఅది కూడా పనిచెయ్యకపోతే, ఓసారి [[Special:UserLogout|లాగౌటై]] మళ్ళీ లాగినవండి. మీ బ్రౌజరు ఈ సైటు యొక్క కూకీలను అనుమతిస్తుందని నిర్ధారించుకోండి.",
+       "import-token-mismatch": "సెషను డేటా పోయింది.\n\nమీరు లాగౌటై పోయి ఉండవచ్చు. '''లాగినై ఉన్నారో లేదో చూసుకుని, మళ్ళీ ప్రయత్నించండి'''.\nఅయినా పనిచెయ్యకపోతే, ఓసారి [[Special:UserLogout|లాగౌటై]] మళ్ళీ లాగినవండి. మీ బ్రౌజరు ఈ సైటునుండి కూకీలను అనుమతిస్తోందో లేదో చూసుకోండి.",
        "import-invalid-interwiki": "మీరు చెప్పిన వికీనుండి దిగుమతి చేయలేము.",
        "import-error-edit": "\"$1\" పేజీలో మార్పుచేర్పులు చేసే అనుమతి మీకు లేదు కాబట్టి, దాన్ని దిగుమతి చెయ్యలేదు.",
        "import-error-create": "\"$1\" పేజీని సృష్టించే అనుమతి మీకు లేదు కాబట్టి దాన్ని దిగుమతి చెయ్యలేదు.",
        "pageinfo-file-hash": "హ్యాష్ వ్యాల్యూ",
        "markaspatrolleddiff": "పరీక్షించినట్లుగా గుర్తు పెట్టు",
        "markaspatrolledtext": "ఈ వ్యాసాన్ని పరీక్షించినట్లుగా గుర్తు పెట్టు",
+       "markaspatrolledtext-file": "దస్త్రపు ఈ కూర్పు నిఘాలో ఉందని గుర్తు పెట్టు",
        "markedaspatrolled": "పరీక్షింపబడినట్లు గుర్తింపబడింది",
        "markedaspatrolledtext": "[[:$1]] యొక్క ఎంచుకున్న కూర్పుని పరీక్షించినట్లుగా గుర్తించాం.",
        "rcpatroldisabled": "ఇటీవలి మార్పుల నిఘాను అశక్తం చేసాం",
        "markedaspatrollederrortext": "నిఘాలో ఉన్నట్లు గుర్తించేందుకుగాను, కూర్పును చూపించాలి.",
        "markedaspatrollederror-noautopatrol": "మీరు చేసిన మార్పులను మీరే నిఘాలో పెట్టలేరు.",
        "markedaspatrollednotify": "$1 లో చేసిన ఈ మార్పు పర్యవేక్షణలో ఉన్నట్టుగా గుర్తించబడింది.",
+       "markedaspatrollederrornotify": "నిఘాలో ఉన్నట్టుగా గుర్తించడం విఫలమైంది.",
        "patrol-log-page": "నిఘా చిట్టా",
        "patrol-log-header": "ఇది పర్యవేక్షించిన కూర్పుల చిట్టా.",
        "confirm-markpatrolled-button": "సరే",
+       "confirm-markpatrolled-top": "$2 యొక్క కూర్పు $3 నిఘాలో ఉన్నట్టుగా గుర్తు పెట్టాలా?",
        "deletedrevision": "పాత సంచిక $1 తొలగించబడినది.",
        "filedeleteerror-short": "ఫైలు తొలగించడంలో పొరపాటు: $1",
        "filedeleteerror-long": "ఫైలుని తొలగించడంలో పొరపాట్లు జరిగాయి:\n\n$1",
        "newimages-user": "ఐపీ చిరునామా లేదా వాడుకరి పేరు",
        "newimages-newbies": "కొత్త ఖాతాల రచనలని మాత్రమే చూపించు",
        "newimages-showbots": "బాట్లు చేసిన అప్లోడ్లు చూపించు",
+       "newimages-hidepatrolled": "నిఘాలో ఉన్న ఎక్కింపులను దాచు",
        "newimages-mediatype": "మాధ్యమ రకం:",
        "noimages": "చూసేందుకు ఏమీ లేదు.",
        "ilsubmit": "వెతుకు",
        "limitreport-expensivefunctioncount": "ఖరీదైన పార్సర్ ఫంక్షన్ల సంఖ్య",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|బైటు|బైట్లు}}",
        "expandtemplates": "మూసలను విస్తరించు",
-       "expand_templates_intro": "à°\88 à°ªà±\8dà°°à°¤à±\8dà°¯à±\87à°\95 à°ªà±\87à°\9cà±\80 à°®à±\80à°°à°¿à°\9aà±\8dà°\9aà°¿à°¨ à°®à±\82సలనà±\81 à°ªà±\82à°°à±\8dతిà°\97à°¾ à°µà°¿à°¸à±\8dతరిà°\82à°\9aà°¿, చూపిస్తుంది. ఇది <code><nowiki>{{</nowiki>#language:...}}</code> వంటి పార్సరు ఫంక్షన్లను, <code><nowiki>{{</nowiki>CURRENTDAY}}</code> వంటి చరరాశులను (వేరియబుల్) కూడా విస్తరిస్తుంది. \nనిజానికి ఇది మీసాల బ్రాకెట్లలో ఉన్న ప్రతీదాన్నీ విస్తరిస్తుంది.",
+       "expand_templates_intro": "à°\88 à°ªà±\8dà°°à°¤à±\8dà°¯à±\87à°\95 à°ªà±\87à°\9cà±\80 à°µà°¿à°\95à±\80à°\9fà±\86à°\95à±\8dà°¸à±\8dà°\9fà±\81à°¨à±\81 à°¤à±\80à°¸à±\81à°\95à±\81ని à°\85à°\82à°¦à±\81à°²à±\8b à°\89à°¨à±\8dà°¨ à°®à±\82సలనà±\8dనిà°\9fà°¿à°¨à±\80 à°µà°¿à°¸à±\8dతరిà°\82à°\9aà°¿ చూపిస్తుంది. ఇది <code><nowiki>{{</nowiki>#language:...}}</code> వంటి పార్సరు ఫంక్షన్లను, <code><nowiki>{{</nowiki>CURRENTDAY}}</code> వంటి చరరాశులను (వేరియబుల్) కూడా విస్తరిస్తుంది. \nనిజానికి ఇది మీసాల బ్రాకెట్లలో ఉన్న ప్రతీదాన్నీ విస్తరిస్తుంది.",
        "expand_templates_title": "{{FULLPAGENAME}} మొదలగు వాటి కొరకు సందర్భ శీర్షిక:",
-       "expand_templates_input": "విసà±\8dతరిà°\82à°\9aవలసిన à°ªà°¾à° à±\8dà°¯à°\82:",
+       "expand_templates_input": "à°\87à°¨à±\8dâ\80\8cà°ªà±\81à°\9fà±\8d à°µà°¿à°\95à±\80à°\9fà±\86à°\95à±\8dà°¸à±\8dà°\9fà±\8d:",
        "expand_templates_output": "ఫలితం",
        "expand_templates_xml_output": "XML ఔట్&zwnj;పుట్",
        "expand_templates_html_output": "ముడి HTML ఔట్‍పుట్",
        "log-action-filter-managetags-deactivate": "ట్యాగు అచేతనం",
        "log-action-filter-protect-protect": "సంరక్షణ",
        "log-action-filter-upload-upload": "కొత్త ఎక్కింపు",
+       "authmanager-create-disabled": "ఖాతా సృష్టించడాన్ని అశక్తం చేసాం.",
+       "authmanager-create-from-login": "ఖాతా సృష్టించడానికి, ఫీల్డులను నింపండి.",
+       "authmanager-create-not-in-progress": "ఖాతా సృష్టించే పని జరగడం లేదు. లేదా సెషను డేటా పోయింది. మళ్ళీ మొదటినుండి మొదలుపెట్టండి.",
+       "authmanager-create-no-primary": "మీరిచ్చిన విశేషాలతో ఖాతాను సృష్టించలేకపోయాం.",
+       "authmanager-link-no-primary": "మీరిచ్చిన విశేషాలతో ఖాతాలను లింకు చెయ్యలేకపోయాం.",
+       "authmanager-link-not-in-progress": "ఖాతాలను లింకు చేసే పని జరగడం లేదు. లేదా సెషను డేటా పోయింది. మళ్ళీ మొదటినుండి మొదలుపెట్టండి.",
+       "authmanager-authplugin-setpass-failed-title": "సంకేతపదం మార్పు విఫలమైంది.",
+       "authmanager-authplugin-setpass-failed-message": "సంకేతపదం మార్పును ఆథెంటికేషన్ ప్లగిన్ తిరస్కరించింది.",
+       "authmanager-authplugin-create-fail": "ఖాతా సృష్టిని ఆథెంటికేషన్ ప్లగిన్ తిరస్కరించింది.",
+       "authmanager-authplugin-setpass-denied": "ఆథెంటికేషన్ ప్లగిన్ సంకేతపదం మార్పులను అనుమతించదు.",
+       "authmanager-authplugin-setpass-bad-domain": "తప్పు డొమెయిన్",
+       "authmanager-autocreate-noperm": "ఆటోమాటిక్ ఖాతా సృష్టికి అనుమతి లేదు.",
        "authmanager-userdoesnotexist": "వాడుకరి ఖాతా \"$1\" నమోదయి లేదు.",
        "authmanager-userlogin-remembermypassword-help": "సెషను ముగిసిన తరువాత కూడా సంకేతపదాన్ని గుర్తుంచుకోమంటారా",
        "authmanager-username-help": "ధ్రువీకరణ కోసం వాడుకరిపేరు.",
index ab4cbfc..f9280a3 100644 (file)
                        "Catrope",
                        "Hedda",
                        "Fitoschido",
-                       "TmY e12"
+                       "TmY e12",
+                       "Dual"
                ]
        },
        "tog-underline": "Bağlantıların altını çizme:",
        "customcssprotected": "Bu sayfayı değiştirmeye yetkiniz bulunmamaktadır, çünkü bu sayfa başka bir kullanıcının kişisel ayarlarını içermektedir.",
        "customjsonprotected": "Başka bir kullanıcının kişisel ayarlarını içerdiği için bu JSON sayfasını düzenleme izniniz yok.",
        "customjsprotected": "Bu Java Script sayfasını değiştirmeye yetkiniz bulunmamaktadır, çünkü bu sayfa başka bir kullanıcının kişisel ayarlarını içermektedir.",
+       "sitecssprotected": "Bu CSS sayfasını düzenleyemezsiniz, çünkü bu tüm ziyaretçileri etkileyebilir.",
+       "sitejsonprotected": "Bu JSON sayfasını düzenleyemezsiniz, çünkü bu tüm ziyaretçileri etkileyebilir.",
+       "sitejsprotected": "Bu JavaScript sayfasını düzenleyemezsiniz, çünkü bu tüm ziyaretçileri etkileyebilir.",
        "mycustomcssprotected": "Bu CSS sayfasını değiştirmeye yetkiniz yok.",
        "mycustomjsonprotected": "Bu JSON sayfasını düzenleme izniniz yok.",
        "mycustomjsprotected": "Bu JavaScript sayfasını değiştirmeye yetkiniz yok.",
        "group-autoconfirmed": "Otomatik onaylanmış kullanıcılar",
        "group-bot": "Botlar",
        "group-sysop": "Hizmetliler",
-       "group-interface-admin": "Arayüz yöneticisi",
+       "group-interface-admin": "Arayüz yöneticileri",
        "group-bureaucrat": "Bürokratlar",
        "group-suppress": "Gözetmenler",
        "group-all": "(hepsi)",
        "right-reupload-shared": "Paylaşılan ortam deposundaki dosyaları yerel olarak geçersiz kıl",
        "right-upload_by_url": "Bir URL adresinden dosya yükle",
        "right-purge": "Doğrulama yapmadan bir sayfa için site belleğini temizle",
-       "right-autoconfirmed": "IP-tabanlı hız limitleri etkilenmeyecektir",
+       "right-autoconfirmed": "IP-tabanlı hız limitleri etkilenme",
        "right-bot": "Otomatik bir işlem gibi muamele gör",
        "right-nominornewtalk": "Kullanıcı tartışma sayfalarında yaptığı küçük değişiklikler kullanıcıya yeni mesaj bildirimiyle bildirilmez",
        "right-apihighlimits": "API sorgularında yüksek sınır kullan",
        "right-deletedtext": "Silinmiş metni ve silinmiş revizyonlar arasındaki değişiklikleri gör",
        "right-browsearchive": "Silinen sayfaları ara",
        "right-undelete": "Bir sayfanın silinmesini geri al",
-       "right-suppressrevision": "Sysoplardan gizlenmiş revizyonlarını gizle ve göster",
+       "right-suppressrevision": "Hizmetlilerden revizyon gizle ve geri getir",
        "right-viewsuppressed": "Herhangi bir kullanıcıdan saklanan sürümleri göster",
        "right-suppressionlog": "Özel günlükleri gör",
        "right-block": "Diğer kullanıcıların değişiklik yapmalarını engelle",
        "right-blockemail": "Bir kullanıcının e-posta göndermesini engelle",
-       "right-hideuser": "Bir kullanıcı adını engelle, genelden gizleyerek",
+       "right-hideuser": "Herkesden gizleyerek bir kullanıcı adını engelle",
        "right-ipblock-exempt": "IP engellemelerini atla, otomatik engelle ve aralık engellemeleri",
        "right-unblockself": "Kendi engellemesini kaldır",
        "right-protect": "Koruma düzeylerini değiştir ve kademeli korumalı sayfaları düzenle",
        "right-editprotected": "\"{{int:protect-level-sysop}}\" olarak korunan sayfalarda değişiklik yap",
        "right-editsemiprotected": "\"{{int:protect-level-autoconfirmed}}\" olarak korunan sayfalarda değişiklik yap",
        "right-editcontentmodel": "Sayfanın içerik modelini düzenle",
-       "right-editinterface": "Kullanıcı arayüzünü değiştirmek",
-       "right-editusercss": "Diğer kullanıcıların CSS dosyalarında değişiklik yap",
-       "right-edituserjson": "Diğer kullanıcıların JSON dosyalarını düzenle",
-       "right-edituserjs": "Diğer kullanıcıların JS dosyalarında değişiklik yap",
+       "right-editinterface": "Kullanıcı arayüzünü değiştir",
+       "right-editusercss": "Diğer kullanıcıların CSS sayfalarında değişiklik yap",
+       "right-edituserjson": "Diğer kullanıcıların JSON sayfalarında değişiklik yap",
+       "right-edituserjs": "Diğer kullanıcıların JS sayfalarında değişiklik yap",
        "right-editsitecss": "Sitewide CSS düzenle",
        "right-editsitejson": "Sitewide JSON'u düzenle",
        "right-editsitejs": "Sitewide JavaScript'i düzenle",
        "right-editmywatchlist": "Kendi izleme listeni düzenle. Not, bazı eylemler bu yetki olmadan da sayfa ekleyebilir.",
        "right-viewmyprivateinfo": "Kendi özel bilgilerini görüntüle (e-posta adresi, gerçek isim vb.)",
        "right-editmyprivateinfo": "Kendi özel bilgilerini değiştir (e-posta adresi, gerçek isim vb.)",
-       "right-editmyoptions": "tercihlerini düzenle",
+       "right-editmyoptions": "Tercihlerini düzenle",
        "right-rollback": "Belirli bir sayfayı değiştiren son kullanıcının değişikliklerini hızlıca geri döndür",
        "right-markbotedits": "Geri döndürülen değişiklikleri, bot değişiklikleri olarak işaretle",
        "right-noratelimit": "Derecelendirme sınırlamalarından etkilenme",
        "mimesearch": "MIME araması",
        "mimesearch-summary": "Bu sayfa, dosyaların MIME türlerine göre filtrelenmesini sağlar. Girdi: içerik_türü/alt_tür veya içerik_türü/*, örn. <code>image/jpeg</code>.",
        "mimetype": "MIME türü:",
-       "download": "yükle",
+       "download": "indir",
        "unwatchedpages": "İzlenmeyen sayfalar",
        "listredirects": "Yönlendirmeleri listele",
        "listduplicatedfiles": "Kopyası bulunan dosyalar listesi",
        "log": "Günlükler",
        "logeventslist-submit": "Göster",
        "logeventslist-more-filters": "Daha fazla süzgeç:",
+       "logeventslist-patrol-log": "Devriye günlüğü",
+       "logeventslist-tag-log": "Etiket günlüğü",
        "all-logs-page": "Tüm genel günlükler",
        "alllogstext": "{{SITENAME}} için mevcut tüm günlüklerin birleşik gösterimi.\nGünlük tipini, kullanıcı adını (büyük-küçük harf duyarlı), ya da etkilenen sayfayı (yine büyük-küçük harf duyarlı) seçerek görünümü daraltabilirsiniz.",
        "logempty": "Kayıtlarda eşleşen bilgi yok.",
        "dellogpage": "Silme günlüğü",
        "dellogpagetext": "Aşağıda en son silme işlemlerinin bir listesi bulunmaktadır.",
        "deletionlog": "silme günlüğü",
+       "logentry-create-create": "$1, $3 adlı sayfayı {{GENDER:$2|oluşturdu}}",
        "reverted": "Önceki sürüm geri getirildi",
        "deletecomment": "Neden:",
        "deleteotherreason": "Diğer/ilave neden:",
        "unblocked-id": "$1 engeli çıkarıldı",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] adlı kullanıcının engeli kaldırıldı.",
        "blocklist": "Engellenmiş kullanıcılar",
+       "autoblocklist-submit": "Ara",
+       "autoblocklist-legend": "Otomatik engellenenleri listele",
+       "autoblocklist-total-autoblocks": "Toplam otomatik engellenen kişi sayısı: $1",
+       "autoblocklist-empty": "Otomatik engellenenler listesi boş.",
        "ipblocklist": "Engellenmiş kullanıcılar",
        "ipblocklist-legend": "Engellenen kullanıcı ara",
        "blocklist-userblocks": "Hesap engellemelerini gizle",
index f873f83..789dc16 100644 (file)
        "rcfilters-invalid-filter": "Яраксыз фильтр",
        "rcfilters-filterlist-title": "Фильтрлар",
        "rcfilters-filterlist-feedbacklink": "Әлеге фильтрлау кораллары турында турында фикер калдырыгыз",
+       "rcfilters-highlightmenu-title": "Төсен сайлагыз",
+       "rcfilters-highlightmenu-help": "Үзлекләрен аеру өчен аның төсен сайлагыз",
        "rcfilters-filtergroup-authorship": "Үзгәртүләрнең авторлыгы",
        "rcfilters-filter-editsbyself-label": "Сезнең үзгәртүләр",
        "rcfilters-filter-editsbyself-description": "Сезнең кертемегез.",
        "rcfilters-liveupdates-button": "Автоматик яңарту",
        "rcfilters-watchlist-markseen-button": "Бар үзгәртүләрне каралган дип билгеләргә",
        "rcfilters-watchlist-edit-watchlist-button": "Күзәтү исемлегегезне үзгәртү",
+       "rcfilters-watchlist-showupdated": "Сезнең соңгы төзәтмәләрдән соң үзгәргән битләр <strong>калын</strong> һәм тулы маркер белән күрсәтелгән",
        "rcfilters-preference-label": "«Соңгы үзгәртүләр» битенең яңа юрамасын яшерү",
        "rcnotefrom": "Астарак <strong>$3, $4</strong> өчен {{PLURAL:$5|үзгәртүләр күрсәтелгән}} (<strong>$1</strong> артык түгел).",
        "rclistfrom": "$3 $2 башлап яңа үзгәртүләрне күрсәт",
        "compare-rev1": "Беренче юрама",
        "compare-rev2": "Икенче юрама",
        "compare-submit": "Чагыштыр",
+       "permanentlink": "Даими сылтама",
        "dberr-problems": "Гафу итегез! Сайтта техник кыенлыклар чыкты.",
        "dberr-again": "Сәхифәне берничә минуттан соң яңартып карагыз.",
        "dberr-info": "(Мәгълүматлар базасы серверы белән тоташырга мөмкин түгел: $1)",
index b5d8c64..ba894af 100644 (file)
        "right-suppressrevision": "перегляд, приховування та відновлення конкретних змін сторінок від будь-якого користувача",
        "right-viewsuppressed": "перегляд змін, прихованих від усіх користувачів",
        "right-suppressionlog": "перегляд приватних журналів",
-       "right-block": "забоÑ\80она Ñ\80едагÑ\83ванÑ\8c Ð´Ð»Ñ\8f Ñ\96нÑ\88иÑ\85 Ð´Ð¾Ð¿Ð¸Ñ\81увачів",
+       "right-block": "вÑ\81Ñ\82ановленнÑ\8f Ð·Ð°Ð±Ð¾Ñ\80они Ñ\80едагÑ\83ванÑ\8c Ð´Ð»Ñ\8f Ñ\96нÑ\88иÑ\85 ÐºÐ¾Ñ\80иÑ\81Ñ\82увачів",
        "right-blockemail": "блокування користувача від надсилання електронної пошти",
        "right-hideuser": "блокування імені користувача і приховування його",
        "right-ipblock-exempt": "уникнення блокування за IP-адресою, автоблокування і блокування діапазонів",
        "right-override-export-depth": "експорт сторінок, включаючи пов'язані сторінки з глибиною до 5",
        "right-sendemail": "надсилання електронної пошти іншим користувачам",
        "right-managechangetags": "створення та (де)активування [[Special:Tags|міток]]",
-       "right-applychangetags": "додаваннÑ\8f [[Special:Tags|мÑ\96Ñ\82ок]] Ñ\80азом Ð·Ñ\96 змінами",
+       "right-applychangetags": "викоÑ\80иÑ\81Ñ\82аннÑ\8f [[Special:Tags|мÑ\96Ñ\82ок]] Ñ\80азом Ð·Ñ\96 Ñ\81воÑ\97ми змінами",
        "right-changetags": "додавання або вилучення будь-яких [[Special:Tags|міток]] для певних версій сторінок або записів журналів",
        "right-deletechangetags": "вилучення [[Special:Tags|міток]] з бази даних",
        "grant-generic": "Набір прав «$1»",
        "action-undelete": "відновлення сторінок",
        "action-suppressrevision": "перегляд і відновлення прихованих версій",
        "action-suppressionlog": "перегляд цього приватного журналу",
-       "action-block": "блокÑ\83ваннÑ\8f Ñ\86Ñ\8cого Ð´Ð¾Ð¿Ð¸Ñ\81увача",
+       "action-block": "блокÑ\83ваннÑ\8f Ñ\86Ñ\8cого ÐºÐ¾Ñ\80иÑ\81Ñ\82увача",
        "action-protect": "зміну рівня захисту цієї сторінки",
        "action-rollback": "швидко відкотити редагування останнього користувача, що змінював певну сторінку",
        "action-import": "імпорт сторінок з іншої вікі",
        "edit-error-long": "Помилки:\n\n$1",
        "revid": "версія $1",
        "pageid": "ID сторінки $1",
+       "interfaceadmin-info": "$1\n\nПрава на редагування загальних CSS/JS/JSON-файлів були недавно винесені з права <code>editinterface.</code> Якщо ви не розумієте, чому ви наткнулись на цю помилку, див. [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "Теги &lt;html&gt; не можна використовувати за межами звичайних сторінок.",
        "gotointerwiki": "Ви покидаєте сайт {{SITENAME}}",
        "gotointerwiki-invalid": "Вказана назва неприпустима.",
index ca421c9..8ed22c4 100644 (file)
        "move-page-legend": "منتقلئ صفحہ",
        "movepagetext": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
        "movepagetext-noredirectfixer": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
-       "movepagetalktext": "اگر آپ اس خانے کو نشان زد کریں تو ملحقہ تبادلہ خیال صفحہ بھی نئے عنوان کی جانب خودکار طور پر منتقل ہو جائے گا اگر اس عنوان کے تحت پہلے سے کوئی تبادلۂ خیال صفحہ موجود نہ ہو۔\n\nاس صورت میں آپ کو دستی طور پر اس صفحہ کو منتقل ضم کرنا ہوگا۔",
+       "movepagetalktext": "اگر آپ اس خانے کو نشان زد کریں تو ملحقہ تبادلہ خیال صفحہ بھی (بشرطیکہ موجود ہو) نئے عنوان کی جانب خودکار طور پر منتقل ہو جائے گا۔\n\nاگر آپ نے اس خانہ کو نشان زد نہیں کیا تو ملحقہ تبادلہ خیال صفحہ کو دستی طور پر منتقل کرکے ضم کرنا ہوگا۔",
        "moveuserpage-warning": "<strong>انتباہ:</strong> آپ صارف صفحہ کو منتقل کر رہے ہیں۔ واضح رہے کہ اس منتقلی کے بعد صارف کا محض صفحہ منتقل ہوگا، اس کا صارف نام تبدیل <em>نہیں</em> ہوگا۔",
        "movecategorypage-warning": "<strong>انتباہ:</strong> آپ زمرہ منتقل کر رہے ہیں۔ واضح رہے کہ منتقلی کے بعد اس زمرے میں موجود صفحات نئے زمرے میں منتقل <em>نہیں</em> ہونگے۔",
        "movenologintext": "صفحہ کو منتقل کرنے کے لیے آپ کو اپنے کھاتے میں [[Special:UserLogin|داخل ہونا]] ضروری ہے۔",
index 8a52c64..830734a 100644 (file)
        "userrights-nodatabase": "El database $1 no l'esiste mìa o no l'è un database local.",
        "userrights-changeable-col": "Grupi che te pol canbiar",
        "userrights-unchangeable-col": "Grupi che no te pol canbiar",
+       "userrights-expiry-none": "No scade mai",
        "userrights-conflict": "Conflito de diriti utente! Aplica de novo le to modifiche.",
        "group": "Grupo:",
        "group-user": "Utenti",
        "group-autoconfirmed": "Utenti autoconvalidà",
        "group-bot": "Bot",
-       "group-sysop": "Aministradori",
+       "group-sysop": "'Ministradori",
+       "group-interface-admin": "'Ministradori de l'interfasa",
        "group-bureaucrat": "Burocrati",
        "group-suppress": "Supervisioni",
        "group-all": "(utenti)",
        "group-autoconfirmed-member": "utente autoconvalidà",
        "group-bot-member": "bot",
        "group-sysop-member": "aministrador",
+       "group-interface-admin-member": "{{GENDER:$1|'ministrador|'ministradora}} de l'interfasa",
        "group-bureaucrat-member": "burocrate",
-       "group-suppress-member": "supervision",
+       "group-suppress-member": "{{GENDER:$1|sopresor|sopresora}}",
        "grouppage-user": "{{ns:project}}:Utenti",
        "grouppage-autoconfirmed": "{{ns:project}}:Utenti autoconvalidà",
        "grouppage-bot": "{{ns:project}}:Bot",
-       "grouppage-sysop": "{{ns:project}}:Aministradori",
+       "grouppage-sysop": "{{ns:project}}:'Ministradori",
+       "grouppage-interface-admin": "{{ns:project}}:'Ministradori de l'interfasa",
        "grouppage-bureaucrat": "{{ns:project}}:Burocrati",
        "grouppage-suppress": "{{ns:project}}:Supervision",
        "right-read": "Lèzi pagine",
index 0473e43..46a76e6 100644 (file)
@@ -42,7 +42,8 @@
                        "Phjtieudoc",
                        "Harriettruong3",
                        "Fitoschido",
-                       "Leducthn"
+                       "Leducthn",
+                       "Nhatminh01"
                ]
        },
        "tog-underline": "Gạch chân liên kết:",
        "toc": "Mục lục",
        "showtoc": "hiện",
        "hidetoc": "ẩn",
-       "collapsible-collapse": "Thu gọn",
-       "collapsible-expand": "Mở rộng",
+       "collapsible-collapse": "n",
+       "collapsible-expand": "Hiện",
        "confirmable-confirm": "{{GENDER:$1}}Bạn chắc chứ?",
        "confirmable-yes": "Có",
        "confirmable-no": "Không",
        "customcssprotected": "Bạn không có quyền sửa đổi trang CSS này vì nó chứa các tùy chọn cá nhân của một thành viên khác.",
        "customjsonprotected": "Bạn không có quyền sửa đổi trang JSON này vì nó chứa các tùy chọn cá nhân của một thành viên khác.",
        "customjsprotected": "Bạn không có quyền sửa đổi trang JavaScript này vì nó chứa các tùy chọn cá nhân của một thành viên khác.",
-       "sitecssprotected": "Bạn không có quyền sửa đổi trang CSS này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang",
-       "sitejsonprotected": "Bạn không có quyền sửa đổi trang JSON này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang",
-       "sitejsprotected": "Bạn không có quyền sửa đổi trang JavaScript này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang",
+       "sitecssprotected": "Bạn không có quyền sửa đổi trang CSS này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang.",
+       "sitejsonprotected": "Bạn không có quyền sửa đổi trang JSON này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang.",
+       "sitejsprotected": "Bạn không có quyền sửa đổi trang JavaScript này vì nó có thể ảnh hưởng đến tất cả mọi người đến trang.",
        "mycustomcssprotected": "Bạn không có quyền sửa đổi trang CSS này.",
        "mycustomjsonprotected": "Bạn không có quyền sửa đổi trang JSON này.",
        "mycustomjsprotected": "Bạn không có quyền sửa đổi trang JavaScript này.",
        "ns-specialprotected": "Không thể sửa chữa các trang trong không gian tên {{ns:special}}.",
        "titleprotected": "Tựa đề này đã bị [[User:$1|$1]] khóa không cho tạo ra.\nLý do được cung cấp là <em>$2</em>.",
        "filereadonlyerror": "Không thể sửa đổi tập tin “$1” vì kho tập tin “$2” đang ở chế độ chỉ-đọc.\n\nQuản trị viên hệ thống khi khóa nó đưa lý do là: “$3”.",
+       "invalidtitle": "Tựa sai",
        "invalidtitle-knownnamespace": "Tựa trang không hợp lệ có không gian tên “$2” và văn bản “$3”",
        "invalidtitle-unknownnamespace": "Tựa trang không hợp lệ có không gian tên số $1 không rõ và văn bản “$2”",
        "exception-nologin": "Chưa đăng nhập",
        "filehist-filesize": "Kích thước tập tin",
        "filehist-comment": "Miêu tả",
        "imagelinks": "Các trang sử dụng tập tin",
-       "linkstoimage": "{{PLURAL:$1|Trang|$1 trang}} sau có liên kết đến tập tin này:",
-       "linkstoimage-more": "Có hơn $1 trang liên kết đến tập tin này.\nDanh sách dưới đây chỉ hiển thị {{PLURAL:$1|liên kết|$1 liên kết}} đầu tiên đến tập tin này.\nCó [[Special:WhatLinksHere/$2|danh sách đầy đủ ở đây]].",
-       "nolinkstoimage": "Không có trang nào chứa liên kết đến hình.",
+       "linkstoimage": "{{PLURAL:$1|Trang|$1 trang}} sau sử dụng tập tin này:",
+       "linkstoimage-more": "Có hơn $1 trang liên kết đến tập tin này.\nDanh sách dưới đây chỉ hiển thị {{PLURAL:$1|liên kết|$1 liên kết}} đầu tiên đến tập tin này.\nMột danh sách đầy đủ có sẵn [[Special:WhatLinksHere/$2|tại đây]].",
+       "nolinkstoimage": "Không có trang nào sử dụng tập tin này.",
        "morelinkstoimage": "Xem [[Special:WhatLinksHere/$1|thêm liên kết]] đến tập tin này.",
        "linkstoimage-redirect": "$1 (tập tin đổi hướng) $2",
        "duplicatesoffile": "{{PLURAL:$1|Tập tin sau|$1 tập tin sau}} là bản sao của tập tin này ([[Special:FileDuplicateSearch/$2|chi tiết]]):",
        "confirm-unwatch-top": "Bạn có muốn gỡ trang này khỏi danh sách theo dõi của bạn?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Có muốn lùi lại các sửa đổi trong trang này?",
+       "confirm-mcrundo-title": "Lùi thay đổi",
+       "mcrundofailed": "Lùi sửa bị thất bại",
+       "mcrundo-missingparam": "Yêu cầu thiếu những tham số bắt buộc.",
+       "mcrundo-changed": "Trang này đã thay đổi sau khi bạn truy cập bản khác biệt. Xin hãy xem lại thay đổi mới.",
        "ellipsis": "…",
        "quotation-marks": "“$1”",
        "imgmultipageprev": "← trang trước",
        "edit-error-long": "Lỗi:\n\n$1",
        "revid": "phiên bản $1",
        "pageid": "số trang $1",
-       "interfaceadmin-info": "$1\n\nMới đây phần mềm bắt đầu phân biệt quyền sửa đổi các tập tin CSS/JS/JSON toàn trang và quyền <code>editinterface</code>. Nếu bạn không hiểu lỗi này xuất hiện tại sao, hãy xem [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nMới đây phần mềm bắt đầu phân biệt quyền sửa đổi các tập tin CSS/JS/JSON toàn trang và quyền <code>editinterface</code>. Nếu bạn không hiểu tại sao bạn bị lỗi trên, hãy xem [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "Không thể sử dụng thẻ &lt;html&gt; bên ngoài trang bình thường.",
        "gotointerwiki": "Rời khỏi {{SITENAME}}",
        "gotointerwiki-invalid": "Tên trang chỉ định không hợp lệ.",
index 4d3ec30..5227669 100644 (file)
        "ns-specialprotected": "מען קען נישט רעדאגירן ספעציעלע בלעטער.",
        "titleprotected": "דער טיטל איז געשיצט פון ווערן געשאפֿן דורך  [[User:$1|$1]].\nדי אורזאך איז <em>$2</em>.",
        "filereadonlyerror": "נישט מעגלעך צו ענדערן די טעקע \"$1\" ווייל די טעקע רעפאזיטאריום  \"$2\" איז אין נאר־ליינען מצב.\n\nדער סיסאפ וואס האט זי פארשפארט האט געגעבן דעם הסבר:  \"$3\"",
+       "invalidtitle": "אומגילטיקער טיטל",
        "invalidtitle-knownnamespace": "אומגילטירער טיטל מיט נאמענטייל \"$2\" און טעקסט \"$3\"",
        "invalidtitle-unknownnamespace": "אומגילטיקער טיטל מיט אומבאוואוסטן נאמענטייל נומער $1 און טעקסט \"$2\"",
        "exception-nologin": "נישט אַרײַנלאגירט",
        "diff-multi-manyusers": "({{PLURAL:$1|איין מיטלסטע ווערסיע |$1 מיטלסטע ווערסיעס}} פֿון מער ווי {{PLURAL:$2|איין באַניצער|$2 באַניצער}} נישט געוויזן.)",
        "difference-missing-revision": "{{PLURAL:$2|איין ווערסיע|$2 ווערסיעס}} פון דעם דיפערענץ ($1) {{PLURAL:$2|האט}} מען נישט געטראפן.\n\nדאס געשעט געוויינלעך פון פאלגן א פארעלטערטן היסטאריע לינק צו א בלאט וואס איז געווארן אויסגעמעקט.\nפרטים קען מען געפינען אינעם [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} אויסמעקונג לאגבוך].",
        "searchresults": "זוכן רעזולטאטן",
+       "search-filter-title-prefix-reset": "זוכן אלע בלעטער",
        "searchresults-title": "זוכן רעזולטאַטן פֿאַר \"$1\"",
        "titlematches": "בלאט קעפל שטימט",
        "textmatches": "בלעטער מיט פאַסנדיקן אינהאַלט",
        "grant-createaccount": "שאַפֿן קאנטעס",
        "grant-createeditmovepage": "שאפֿן, רעדאקטירן און באוועגן בלעטער",
        "grant-delete": "אויסמעקן בלעטער, ווערסיעס און לאגבוך פרטים",
-       "grant-editinterface": "רע×\93×\90ק×\98×\99ר×\9f ×\93×¢×\9d ×\9e×¢×\93×\99×¢×\95×\95×\99ק×\99 × ×\90×\9e×¢× ×\98×\99×\99×\9c ×\90×\95×\9f ×\91×\90× ×\99צער CSS/JSON/JavaScript",
+       "grant-editinterface": "רע×\93×\90ק×\98×\99ר×\9f ×\93×¢×\9d ×\9e×¢×\93×\99×¢×\95×\95×\99ק×\99 × ×\90×\9e×¢× ×\98×\99×\99×\9c ×\90×\95×\9f ×\95×\95×\99ק×\99×\95×\95×\99×\99×\98\91×\90× ×\99צער JSON",
        "grant-editmycssjs": "רעדאקטירן אייער באניצער CSS/JSON/JavaScript",
        "grant-editmyoptions": "רעדאקטירן אײַערע באניצער פרעפֿערענצן",
        "grant-editmywatchlist": "רעדאקטירן אײַער אויפֿפאסונג ליסטע",
        "rcfilters-other-review-tools": "אנדערע רעצענזיע ווערקצייג",
        "rcfilters-group-results-by-page": "גרופירן רעזולטאטן לויט בלאט",
        "rcfilters-activefilters": "אַקטיווע פילטערס",
+       "rcfilters-activefilters-hide": "באַהאַלטן",
+       "rcfilters-activefilters-show": "ווייזן",
        "rcfilters-advancedfilters": "פֿארגעשריטענע פֿילטערס",
        "rcfilters-limit-title": "רעזולטאטן צו ווייזן",
        "rcfilters-days-title": "לעצטיקע טעג",
        "filehist-comment": "באמערקונג",
        "imagelinks": "טעקע באַניץ",
        "linkstoimage": "{{PLURAL:$1|דער פאלגנדער בלאט ניצט|די פאלגנדע בלעטער ניצן}} דאס דאזיגע בילד:",
-       "linkstoimage-more": "×\9eער ×\95×\95×\99 $1 {{PLURAL:$1|×\91×\9c×\90Ö·×\98 ×¤Ö¿×\90ַר×\91×\99× ×\93×\98\91×\9c×¢×\98ער ×¤Ö¿×\90ַר×\91×\99× ×\93×\9f}} ×¦×\95 ×\93ער ×\93×\90×\96×\99×\92ער ×\98עקע.\n×\93×\99 ×¤Ö¿×\90×\9c×\92× ×\93×¢ ×\9c×\99ס×\98×¢ ×\95×\95ײַ×\96×\98  {{PLURAL:$1|×\93×¢×\9d ×¢×¨×©×\98×\9f ×\91×\9c×\90Ö·×\98 ×\9c×\99נק|×\93×\99 ×¢×¨×©×\98×¢ $1 ×\91×\9c×\90Ö·×\98 ×\9c×\99נקע×\9f}} ×¦×\95 ×\93ער ×\98עקע.\nס'×\90×\99×\96 ×¤Ö¿×\90ַר×\90Ö·×\9f[[Special:WhatLinksHere/$2|פֿולע רשימה]].",
+       "linkstoimage-more": "×\9eער ×\95×\95×\99 $1 {{PLURAL:$1|×\91×\9c×\90Ö·×\98 × ×\99צ×\98\91×\9c×¢×\98ער × ×\99צ×\9f}} ×\93×\99 ×\93×\90×\96×\99×\92×¢ ×\98עקע.\n×\93×\99 ×¤Ö¿×\90×\9c×\92× ×\93×¢ ×\9c×\99ס×\98×¢ ×\95×\95ײַ×\96×\98 × ×\90ר {{PLURAL:$1|×\93×¢×\9d ×¢×¨×©×\98×\9f ×\91×\9c×\90Ö·×\98 ×\95×\95×\90ס × ×\99צ×\98\93×\99 ×¢×¨×©×\98×¢ $1 ×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f}} ×\93×\99 ×\98עקע.\nס'×\90×\99×\96 ×¤Ö¿×\90ַר×\90Ö·×\9f ×\90 [[Special:WhatLinksHere/$2|פֿולע רשימה]].",
        "nolinkstoimage": "נישטא קיין בלעטער וואס פארבינדן צו די טעקע.",
        "morelinkstoimage": "באַקוקן  [[Special:WhatLinksHere/$1|מער לינקען]] צו דער טעקע.",
        "linkstoimage-redirect": "$1 (טעקע ווײַטערפֿירונג) $2",
index 8e7d4db..1702852 100644 (file)
        "group-autoconfirmed": "自動確認用戶",
        "group-bot": "機械人",
        "group-sysop": "操作員",
+       "group-interface-admin": "介面管理員",
        "group-bureaucrat": "事務員",
        "group-suppress": "監督",
        "group-all": "(全部)",
        "group-autoconfirmed-member": "{{GENDER:$1|自動確認用戶}}",
        "group-bot-member": "{{GENDER:$1|機械人}}",
        "group-sysop-member": "{{GENDER:$1|管理員}}",
+       "group-interface-admin-member": "{{GENDER:$1|介面管理員}}",
        "group-bureaucrat-member": "{{GENDER:$1|事務員}}",
        "group-suppress-member": "{{GENDER:$1|監督}}",
        "grouppage-user": "{{ns:project}}:用戶",
        "grouppage-autoconfirmed": "{{ns:project}}:自動確認用戶",
        "grouppage-bot": "{{ns:project}}:機械人",
        "grouppage-sysop": "{{ns:project}}:管理員",
+       "grouppage-interface-admin": "{{ns:project}}:介面管理員",
        "grouppage-bureaucrat": "{{ns:project}}:事務員",
        "grouppage-suppress": "{{ns:project}}:監督",
        "right-read": "讀版",
        "authmanager-realname-label": "真名",
        "authmanager-realname-help": "用戶嘅真名",
        "authprovider-resetpass-skip-label": "跳過",
+       "interfaceadmin-info": "$1\n\n改全站通用 CSS/JS/JSON 檔嘅權限由 <code>editinterface</code> 權限拆咗出嚟。如果你唔明點解會出呢個錯誤訊息,請睇[[mw:MediaWiki_1.32/interface-admin]]。",
        "passwordpolicies": "密碼政策",
        "passwordpolicies-summary": "爾度係對爾個wiki定義咗嘅用戶組來講有效嘅密碼政策一覽。",
        "passwordpolicies-group": "組",
index ac26098..b09e609 100644 (file)
        "confirm-unwatch-top": "从监视列表中删除此页吗?",
        "confirm-rollback-button": "确定",
        "confirm-rollback-top": "回退此页面的编辑么?",
+       "confirm-mcrundo-title": "撤销一次更改",
+       "mcrundofailed": "撤销失败",
+       "mcrundo-missingparam": "请求中缺少必需参数。",
+       "mcrundo-changed": "在您访问的差异以来,此页面已更新。请复核新的更改。",
        "semicolon-separator": ";",
        "comma-separator": "、",
        "colon-separator": ":",
index b1109ca..ff830f9 100644 (file)
        "broken-file-category": "檔案連結損壞的頁面",
        "about": "關於",
        "article": "內容頁面",
-       "newwindow": "(以新視窗開啟)",
+       "newwindow": "(以新視窗開啟)",
        "cancel": "取消",
        "moredotdotdot": "更多...",
        "morenotlisted": "這可能只是部份清單。",
        "view": "檢視",
        "view-foreign": "在 $1 檢視",
        "edit": "編輯",
-       "edit-local": "編輯本地說明",
+       "edit-local": "編輯本地描述",
        "create": "建立",
-       "create-local": "新增本地說明",
+       "create-local": "新增本地描述",
        "delete": "刪除",
        "undelete_short": "取消刪除 $1 項修訂",
        "viewdeleted_short": "檢視 {{PLURAL:$1|1 項已刪除的修訂|$1 項已刪除的修訂}}",
        "specialpage": "特殊頁面",
        "personaltools": "個人工具",
        "talk": "討論",
-       "views": "檢è¦\96",
+       "views": "è¦\96å\9c\96",
        "toolbox": "工具",
        "tool-link-userrights": "變更{{GENDER:$1|使用者}}群組",
        "tool-link-userrights-readonly": "檢視{{GENDER:$1|使用者}}群組",
        "versionrequiredtext": "需使用 $1 版本的 MediaWiki 才能使用此頁面。\n請參考 [[Special:Version|版本]]。",
        "ok": "確定",
        "retrievedfrom": "取自 \"$1\"",
-       "youhavenewmessages": "您有 $1 ($2)。",
+       "youhavenewmessages": "{{PLURAL:$3|您有}}$1($2)。",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|您}}有來自{{PLURAL:$3|另一位使用者|$3 位使用者}}的 $1 ($2)。",
        "youhavenewmessagesmanyusers": "你有來自多位使用者的 $1 ($2)。",
        "newmessageslinkplural": "{{PLURAL:$1|一則新訊息|999=新訊息}}",
        "loginsuccesstitle": "已登入",
        "loginsuccess": "<strong>{{GENDER:|您|妳|你}}現在已經以 \"$1\" 的身分登入了 {{SITENAME}}。</strong>",
        "nosuchuser": "查無名稱為 \"$1\" 的使用者。\n使用者名稱有大小寫區分,\n請檢查您拼寫是否正確,或者 [[Special:CreateAccount|建立新帳號]]。",
-       "nosuchusershort": "查無使用者 \"$1\",\n請檢查您拼寫是否正確。",
+       "nosuchusershort": "查無使用者「$1」,請檢查您拼寫是否正確。",
        "nouserspecified": "您必須指定一個使用者名稱。",
        "login-userblocked": "這位使用者已被封鎖,不允許登入。",
        "wrongpassword": "您輸入的使用者名稱或密碼錯誤,請再試一次。",
        "link_sample": "連結標題",
        "link_tip": "內部連結",
        "extlink_sample": "http://www.example.com 連結標題",
-       "extlink_tip": "外部連結 (記得以 http:// 開頭)",
-       "headline_sample": "第 1 層標題文字",
-       "headline_tip": "第 2 層標題文字",
+       "extlink_tip": "外部連結(記得以 http:// 開頭)",
+       "headline_sample": "標題文字",
+       "headline_tip": "2級標題",
        "nowiki_sample": "插入非格式化文字",
        "nowiki_tip": "忽略 Wiki 格式化語法",
        "image_sample": "範例.jpg",
        "media_sample": "範例.ogg",
        "media_tip": "檔案連結",
        "sig_tip": "您的簽名與日期時間",
-       "hr_tip": "水平線 (少用)",
+       "hr_tip": "水平線(謹慎使用)",
        "summary": "摘要:",
        "subject": "主旨:",
        "minoredit": "這是一個次要修訂",
        "unicode-support-fail": "看起來您的瀏覽器不支援Unicode。需要Unicode才能編輯頁面,所以您的編輯無法儲存。",
        "yourdiff": "差異",
        "copyrightwarning": "請注意,所有於 {{SITENAME}} 所做的貢獻會依據 $2 授權條款發佈 (詳情請見 $1)。\n若您不希望您的著作被任意修改與散佈,請勿在此發表文章。<br />\n您同時向我們保証在此的著作內容是您自行撰寫,或是取自不受版權保護的公開領域或自由資源。\n<strong>請勿在未經授權的情況下發表文章!</strong>",
-       "copyrightwarning2": "請注意,所有於 {{SITENAME}} 所做的貢獻可能會被其他貢獻者編輯,修改或刪除。\n若您不希望您的著作被任意修改與散佈,請勿在此發表文章。<br />\n您同時向我們保証在此的著作內容是您自行撰寫,或是取自不受版權保護的公開領域或自由資源 (詳情請見 $1)。\n<strong>請勿在未經授權的情況下發表文章!</strong>",
+       "copyrightwarning2": "請注意,所有於{{SITENAME}}所做的貢獻可能會被其他貢獻者編輯,修改或刪除。\n若您不希望您的著作被任意修改與散佈,請勿在此發表文章。<br />\n您同時向我們保証在此的著作內容是您自行撰寫,或是取自不受版權保護的公開領域或自由資源(詳情請見 $1)。\n<strong>請勿在未經授權的情況下發表文章!</strong>",
        "editpage-cannot-use-custom-model": "此頁面的內容模型不能被修改。",
        "longpageerror": "<strong>錯誤:您所送出的文字內容共有 {{PLURAL:$1|1 KB|$1 KB}},已超出系統上限 {{PLURAL:$2|1 KB|$2 KB}}。</strong>\n\n無法儲存。",
        "readonlywarning": "<strong>警告:資料庫已被鎖定以進行維護,因此無法儲存您目前所做的編輯動作。</strong>\n您可先複製您的文字並貼上到文字檔案中儲存,稍後再儲存您編輯。\n\n鎖定資料庫的系統管理員有以下說明:$1",
        "history-feed-item-nocomment": "$1 於 $2",
        "history-feed-empty": "請求的頁面不存在,\n可能已被刪除或重新命名。\n請嘗試 [[Special:Search|搜尋本站]] 取得其他相關的新頁面。",
        "history-edit-tags": "編輯已選擇修訂的標籤",
-       "rev-deleted-comment": "(已移除編輯摘要)",
+       "rev-deleted-comment": "(已移除編輯摘要)",
        "rev-deleted-user": " (已移除使用者名稱)",
        "rev-deleted-event": "(已移除日誌明細)",
        "rev-deleted-user-contribs": "[使用者名稱或 IP 位址已移除 - 已隱藏貢獻清單中的編輯]",
        "youremail": "Email:",
        "username": "{{GENDER:$1|使用者名稱}}:",
        "prefs-memberingroups": "{{GENDER:$2|所屬}}{{PLURAL:$1|群組}}:",
-       "group-membership-link-with-expiry": "$1 (直到 $2)",
+       "group-membership-link-with-expiry": "$1(直到 $2)",
        "prefs-registration": "註冊時間:",
        "yourrealname": "真實姓名:",
        "yourlanguage": "語言:",
        "right-editmyuserjs": "編輯自己的使用者 JavaScript 檔",
        "right-viewmywatchlist": "檢視自己的監視清單",
        "right-editmywatchlist": "編輯自己的監視清單。注意,即使無此權限,某些操作仍會新增頁面至監視清單。",
-       "right-viewmyprivateinfo": "檢視自己的私隱資料 (如:電子郵件地址及真實姓名)",
+       "right-viewmyprivateinfo": "檢視自己的私隱資料(如:電子郵件地址及真實姓名)",
        "right-editmyprivateinfo": "編輯自己的隱私資料 (如:電子郵件地址及真實姓名)",
        "right-editmyoptions": "編輯自己的偏好設定",
        "right-rollback": "快速還原最後一位使用者對某一頁面的編輯",
        "licenses-edit": "編輯授權條款選項",
        "license-nopreview": "(不可預覽)",
        "upload_source_url": "(您選擇的檔案來自有效、可公開存取的 URL)",
-       "upload_source_file": "(您在您的電腦上選擇的檔案)",
+       "upload_source_file": "(您在您的電腦上選擇的檔案)",
        "listfiles-delete": "刪除",
        "listfiles-summary": "此特殊頁面顯示所有已上傳的檔案。",
        "listfiles_search_for": "搜尋媒體名稱:",
        "listusersfrom": "顯示使用者開始自:",
        "listusers-submit": "顯示",
        "listusers-noresult": "查無使用者。",
-       "listusers-blocked": "(已封鎖)",
+       "listusers-blocked": "(已封鎖)",
        "activeusers": "活動的使用者清單",
        "activeusers-intro": "此清單為最近 $1 天有活動的使用者。",
        "activeusers-count": "最近 $3 天內有 $1 次動作",
        "changed": "變更",
        "deletepage": "刪除頁面",
        "confirm": "確認",
-       "excontent": "內容為:\"$1\"",
+       "excontent": "內容為:「$1」",
        "excontentauthor": "內容為:\"$1\",且僅有一位貢獻者 \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|對話]])",
        "exbeforeblank": "被清空前的內容為:\"$1\"",
        "delete-confirm": "刪除 \"$1\"",
        "protectlogtext": "以下為變更頁面保護的清單。\n請參考 [[Special:ProtectedPages|受保護頁面清單]] 檢視目前受保護頁面。",
        "protectedarticle": "已保護 \"[[$1]]\"",
        "modifiedarticleprotection": "已變更 \"[[$1]]\" 的保護層級",
-       "unprotectedarticle": "已解除 \"[[$1]]\" 的保護",
+       "unprotectedarticle": "已解除「[[$1]]」的保護",
        "movedarticleprotection": "已移動 \"[[$2]]\" 的保護設定至 \"[[$1]]\"",
        "protectedarticle-comment": "{{GENDER:$2|受保護}} \"[[$1]]\"",
        "modifiedarticleprotection-comment": "{{GENDER:$2|已變更}} \"[[$1]]\" 的保護層級",
        "protect-expiring-local": "期限至 $1",
        "protect-expiry-indefinite": "無限期",
        "protect-cascade": "保護本頁中包含的頁面 (連鎖保護)",
-       "protect-cantedit": "您沒有編輯權限,無法更改此頁面的保護層級。",
+       "protect-cantedit": "您沒有編輯該頁面的權限,因此無法更改頁面的保護層級。",
        "protect-othertime": "其它時間:",
        "protect-othertime-op": "其它時間",
        "protect-existing-expiry": "已設定期限:$2 $3",
        "movesubpagetext": "此頁面有 $1 個子頁面如下所示。",
        "movesubpagetalktext": "對應的對話頁有以下 $1 頁{{PLURAL:$1|子頁面|子頁面}}。",
        "movenosubpage": "此頁面沒有任何子頁面。",
-       "movereason": "原因",
+       "movereason": "原因",
        "revertmove": "還原",
        "delete_and_move_text": "目標頁面 \"[[:$1]]\" 已存在。\n您是否要刪除該頁面以完成移動?",
        "delete_and_move_confirm": "是的,刪除該頁面",
        "previousdiff": "← 較舊編輯",
        "nextdiff": "較新編輯 →",
        "mediawarning": "<strong>警告</strong>:此檔案類型可能包含惡意代碼。\n若執行可能對您的系統造成損害。",
-       "imagemaxsize": "圖片大小限制:<br /><em>(用於檔案描述頁面)</em>",
+       "imagemaxsize": "圖片大小限制:<br /><em>(用於檔案描述頁面)</em>",
        "thumbsize": "縮圖大小:",
        "widthheightpage": "$1 × $2,$3 頁",
        "file-info": "檔案大小:$1,MIME 類型:$2",
        "exif-exposureprogram-2": "標準模式",
        "exif-exposureprogram-3": "光圈優先",
        "exif-exposureprogram-4": "快門優先",
-       "exif-exposureprogram-5": "藝術程式 (景深優先)",
-       "exif-exposureprogram-6": "運動模式 (快速快門優先)",
-       "exif-exposureprogram-7": "人像模式 (用於近距離照片,對焦不在背景)",
-       "exif-exposureprogram-8": "風景模式 (用於風景照片,對焦在背景)",
+       "exif-exposureprogram-5": "藝術程式(景深優先)",
+       "exif-exposureprogram-6": "運動模式(快速快門優先)",
+       "exif-exposureprogram-7": "人像模式(用於近距離照片,對焦不在背景)",
+       "exif-exposureprogram-8": "風景模式(用於風景照片,對焦在背景)",
        "exif-subjectdistance-value": "$1 尺",
        "exif-meteringmode-0": "不明",
        "exif-meteringmode-1": "平均",
        "confirm-unwatch-top": "從您的監視清單中移除此頁面?",
        "confirm-rollback-button": "確定",
        "confirm-rollback-top": "還原編輯到此頁面?",
+       "confirm-mcrundo-title": "還原變更",
+       "mcrundofailed": "還原失敗",
+       "mcrundo-missingparam": "請求缺少必要參數。",
+       "mcrundo-changed": "自您檢視差異之後,頁面有被變更過。請檢閱新的變更。",
        "semicolon-separator": ";",
        "comma-separator": "、",
        "colon-separator": ":",
        "tags-edit-chosen-placeholder": "選擇一些標籤",
        "tags-edit-chosen-no-results": "沒有符合條件的標籤",
        "tags-edit-reason": "原因:",
-       "tags-edit-revision-submit": "套用變更至{{PLURAL:$1|此修訂|$1 筆修訂}}",
+       "tags-edit-revision-submit": "套用變更至{{PLURAL:$1|此修訂|$1筆修訂}}",
        "tags-edit-logentry-submit": "套用變更至{{PLURAL:$1|此日誌項目|$1 筆日誌項目}}",
        "tags-edit-success": "已套用變更。",
        "tags-edit-failure": "變更被無法套用:\n$1",
        "authmanager-create-disabled": "已關閉帳號自動建立。",
        "authmanager-create-from-login": "要建立您的帳號,請先填寫此欄位。",
        "authmanager-create-not-in-progress": "帳號建立尚未進行或連線階段資料已遺失,請重頭再開始。",
-       "authmanager-create-no-primary": "提供的憑證無使用在帳號建立。",
+       "authmanager-create-no-primary": "提供的憑證不能用於帳號建立。",
        "authmanager-link-no-primary": "提供的憑證無使用在帳號連結。",
        "authmanager-link-not-in-progress": "帳號連結尚未進行或連線階段資料已遺失,請重頭再開始。",
        "authmanager-authplugin-setpass-failed-title": "密碼變更失敗",
        "edit-error-long": "錯誤:\n\n$1",
        "revid": "修訂 $1",
        "pageid": "頁面 ID $1",
-       "interfaceadmin-info": "$1\n\n編輯全站 CSS/JS/JSON 檔案的權限,剛剛已從 <code>editinterface</code> 權限裡拆分。若您不清楚為何會收到此錯誤,請查看 [[mw:MediaWiki_1.32/interface-admin]]。",
+       "interfaceadmin-info": "$1\n\n編輯全站 CSS/JS/JSON 檔案的權限,近期已從 <code>editinterface</code> 權限裡拆分。若您不清楚為何會收到此錯誤,請查看 [[mw:MediaWiki_1.32/interface-admin]]。",
        "rawhtml-notallowed": "&lt;html&gt; 標籤無法在一般頁面之外使用。",
        "gotointerwiki": "離開 {{SITENAME}}",
        "gotointerwiki-invalid": "指定的標題無效。",
index 0331aef..0ee1293 100644 (file)
@@ -63,7 +63,7 @@
        "specialpage": "特殊頁面",
        "personaltools": "個人工具",
        "talk": "討論",
-       "views": "檢è¦\96",
+       "views": "è¦\96å\9c\96",
        "toolbox": "工具",
        "jumpto": "跳到:",
        "jumptonavigation": "導覽",
index 8a69163..ef9c37b 100644 (file)
@@ -1,11 +1,12 @@
 <?php
-/** Sakha (саха тыла)
+/** Sakha (Yakut, саха)
  *
  * To improve a translation please visit https://translatewiki.net
  *
  * @ingroup Language
  * @file
  *
+ * @author Amire80
  * @author Andrijko Z.
  * @author Bert Jickty
  * @author Gartem
@@ -19,6 +20,7 @@
 $fallback = 'ru';
 
 $namespaceNames = [
+       NS_MEDIA            => 'Миэдьийэ',
        NS_SPECIAL          => 'Аналлаах',
        NS_TALK             => 'Ырытыы',
        NS_USER             => 'Кыттааччы',
@@ -26,18 +28,316 @@ $namespaceNames = [
        NS_PROJECT_TALK     => '$1_ырытыыта',
        NS_FILE             => 'Билэ',
        NS_FILE_TALK        => 'Билэ_ырытыыта',
+       NS_MEDIAWIKI        => 'MediaWiki',
+       NS_MEDIAWIKI_TALK   => 'MediaWiki-ни_ырытыы',
        NS_TEMPLATE         => 'Халыып',
-       NS_TEMPLATE_TALK    => 'ХалÑ\8bÑ\8bп_Ñ\8bÑ\80Ñ\8bÑ\82Ñ\8bÑ\8bÑ\82а',
+       NS_TEMPLATE_TALK    => 'ХалÑ\8bÑ\8bбÑ\8b\8bÑ\80Ñ\8bÑ\82Ñ\8bÑ\8b',
        NS_HELP             => 'Көмө',
-       NS_HELP_TALK        => 'Көмө_ырытыыта',
+       NS_HELP_TALK        => 'Көмөнү_ырытыы',
        NS_CATEGORY         => 'Категория',
-       NS_CATEGORY_TALK    => 'Категория_ырытыыта',
+       NS_CATEGORY_TALK    => 'Категорияны_ырытыы',
 ];
 
 $namespaceAliases = [
        'Ойуу' => NS_FILE,
        'Ойуу_ырытыыта' => NS_FILE_TALK,
+       'Ойууну_ырытыы' => NS_FILE_TALK,
+       'Халыып_ырытыыта' => NS_TEMPLATE_TALK,
+       'Көмө_ырытыыта' => NS_HELP_TALK,
+       'Категория_ырытыыта' => NS_CATEGORY_TALK,
 ];
 
 // Remove Russian aliases
 $namespaceGenderAliases = [];
+
+$specialPageAliases = [
+       'Activeusers'               => [ 'Көхтөөх_кыттааччылар' ],
+       'Allmessages'               => [ 'Тиһик_биллэриилэрэ' ],
+       'AllMyUploads'              => [ 'Билэлэрим_барыта' ],
+       'Allpages'                  => [ 'Сирэй_барыта' ],
+       'Badtitle'                  => [ 'Сатаммат_аат' ],
+       'Blankpage'                 => [ 'Кураанах_сирэй' ],
+       'Block'                     => [ 'Хааччахтаа' ],
+       'Booksources'               => [ 'Төрүт_кинигэлэр' ],
+       'BrokenRedirects'           => [ 'Быстыбыт_утаарыылар' ],
+       'Categories'                => [ 'Категориялар' ],
+       'ChangeEmail'               => [ 'E-mail-ы_уларыт' ],
+       'ChangePassword'            => [ 'Аһарыгы_уларыт' ],
+       'ComparePages'              => [ 'Сирэйдэри_тэҥнээһин' ],
+       'Confirmemail'              => [ 'E-mail-ы_бигэргэт' ],
+       'Contributions'             => [ 'Суруйуу' ],
+       'CreateAccount'             => [ 'Бэлиэ-ааты_оҥор' ],
+       'Deadendpages'              => [ 'Бүтэй_сирэйдэр' ],
+       'DeletedContributions'      => [ 'Сотуллубут_суруйуу' ],
+       'Diff'                      => [ 'Уларытыылар' ],
+       'DoubleRedirects'           => [ 'Хос_утаарыылар' ],
+       'EditWatchlist'             => [ 'Кэтиир_испииһэги_уларытыы' ],
+       'Emailuser'                 => [ 'Кыттааччыга_сурук' ],
+       'ExpandTemplates'           => [ 'Халыып_тэнийиитэ' ],
+       'Export'                    => [ 'Хачайдаан_таһаарыы' ],
+       'Fewestrevisions'           => [ 'Сэдэхтик_уларытыллыбыт' ],
+       'FileDuplicateSearch'       => [ 'Хос_билэни_көрдөөһүн' ],
+       'Filepath'                  => [ 'Билэ_суола' ],
+       'Import'                    => [ 'Импорт' ],
+       'Invalidateemail'           => [ 'Аадырыһы_бигэргэтиини_суох_гын' ],
+       'JavaScriptTest'            => [ 'JavaScript_тургутуу' ],
+       'BlockList'                 => [ 'Хааччах_испииһэгэ' ],
+       'LinkSearch'                => [ 'Сигэни_көрдөөһүн' ],
+       'Listadmins'                => [ 'Дьаһабыллар_испииһэктэрэ' ],
+       'Listbots'                  => [ 'Буоттар_испииһиэктэрэ' ],
+       'Listfiles'                 => [ 'Билэ_испииһэгэ' ],
+       'Listgrouprights'           => [ 'Кыттааччылар_бөлөхтөрүн_бырааба' ],
+       'Listredirects'             => [ 'Утаарыы_испииһэгэ' ],
+       'ListDuplicatedFiles'       => [ 'Хос_билэ_испииһэгэ' ],
+       'Listusers'                 => [ 'Кыттааччы_испииһэгэ' ],
+       'Lockdb'                    => [ 'БО_хааччахтааһын' ],
+       'Log'                       => [ 'Сурунааллар' ],
+       'Lonelypages'               => [ 'Тулаайах_сирэйдэр' ],
+       'Longpages'                 => [ 'Уһун_сирэйдэр' ],
+       'MergeHistory'              => [ 'Устуоруйаларын_холбооһун' ],
+       'MIMEsearch'                => [ 'MIME_туһанан көрдөөһүн' ],
+       'Mostcategories'            => [ 'Ордук_элбэх_категориялаахтар' ],
+       'Mostimages'                => [ 'Ордук_элбэхтик_туттуллар_билэлэр' ],
+       'Mostinterwikis'            => [ 'Элбэх_интэрбиики_сигэлээхтэр' ],
+       'Mostlinked'                => [ 'Ордук_элбэхтик_туттуллар_сирэйдэр' ],
+       'Mostlinkedcategories'      => [ 'Ордук_элбэхтик_туттуллар_категориялар' ],
+       'Mostlinkedtemplates'       => [ 'Ордук_элбэхтик_туттуллар_халыыптар' ],
+       'Mostrevisions'             => [ 'Ордук_элбэх_барыллаах' ],
+       'Movepage'                  => [ 'Сирэй_аатын_уларыт' ],
+       'Mycontributions'           => [ 'Суруйуум' ],
+       'MyLanguage'                => [ 'Тылым' ],
+       'Mypage'                    => [ 'Тус_сирэйим' ],
+       'Mytalk'                    => [ 'Тус_ырытар_сирим' ],
+       'Myuploads'                 => [ 'Хачайдааһыннарым' ],
+       'Newimages'                 => [ 'Саҥа_билэлэр' ],
+       'Newpages'                  => [ 'Саҥа_сирэйдэр' ],
+       'PasswordReset'             => [ 'Аһарыгы_уларытыы' ],
+       'PermanentLink'             => [ 'Куруук_баар_сигэ' ],
+       'Preferences'               => [ 'Туруоруулар' ],
+       'Prefixindex'               => [ 'Аатын_саҕаланыытынан_ыйынньык' ],
+       'Protectedpages'            => [ 'Көмүскэммит_сирэйдэр' ],
+       'Protectedtitles'           => [ 'Көмүскэммит_ааттар' ],
+       'Randompage'                => [ 'Түбэспиччэ_сирэй' ],
+       'Randomredirect'            => [ 'Түбэспиччэ_утаарыы' ],
+       'Recentchanges'             => [ 'Саҥа_уларытыы' ],
+       'Recentchangeslinked'       => [ 'Ситимнээх_уларытыылар' ],
+       'Revisiondelete'            => [ 'Улартыыны_суох_гыныы' ],
+       'Search'                    => [ 'Көрдөөһүн' ],
+       'Shortpages'                => [ 'Кылгас_сирэйдэр' ],
+       'Specialpages'              => [ 'Анал_сирэйдэр' ],
+       'Statistics'                => [ 'Ыстатыыстыка' ],
+       'Tags'                      => [ 'Тиэктэр' ],
+       'Unblock'                   => [ 'Хааччаҕы_устуу' ],
+       'Uncategorizedcategories'   => [ 'Категорията_суох_категориялар' ],
+       'Uncategorizedimages'       => [ 'Категорията_суох_билэлэр' ],
+       'Uncategorizedpages'        => [ 'Категорията_суох_сирэйдэр' ],
+       'Uncategorizedtemplates'    => [ 'Категорията_суох_халыыптар' ],
+       'Undelete'                  => [ 'Сөргүт' ],
+       'Unlockdb'                  => [ 'БО_хааччаҕын_устуу' ],
+       'Unusedcategories'          => [ 'Туттуллубат_категориялар' ],
+       'Unusedimages'              => [ 'Туттуллубат_билэлэр' ],
+       'Unusedtemplates'           => [ 'Туттуллубат_халыыптар' ],
+       'Upload'                    => [ 'Хачайдааһын' ],
+       'UploadStash'               => [ 'Кистэммит_хачайдааһын' ],
+       'Userlogin'                 => [ 'Киирии' ],
+       'Userlogout'                => [ 'Түмүктээһин' ],
+       'Userrights'                => [ 'Быраабы_салайыы' ],
+       'Version'                   => [ 'Торум' ],
+       'Wantedcategories'          => [ 'Көрдөнөр_категориялар' ],
+       'Wantedfiles'               => [ 'Көрдөнөр_билэлэр' ],
+       'Wantedpages'               => [ 'Көрдөнөр_сирэйдэр' ],
+       'Wantedtemplates'           => [ 'Көрдөнөр_халыыптар' ],
+       'Watchlist'                 => [ 'Кэтиир_испииһэк' ],
+       'Whatlinkshere'             => [ 'Манна_сигэниилэр' ],
+       'Withoutinterwiki'          => [ 'Интэрбиикитэ_суох' ],
+];
+
+$magicWords = [
+       'redirect'                  => [ '0', '#утаарыы', '#утр', '#REDIRECT' ],
+       'notoc'                     => [ '0', '__ИҺИНЭЭҔИТЭ_СУОХ__', '__ИҺН_СУОХ__', '__NOTOC__' ],
+       'nogallery'                 => [ '0', '__ГАЛЕРЕЯТА_СУОХ__', '__NOGALLERY__' ],
+       'forcetoc'                  => [ '0', '__БУЛГУЧЧУ_ИҺИНЭЭҔИЛЭЭХ__', '__БЛГ_ИҺН__', '__FORCETOC__' ],
+       'toc'                       => [ '0', '__ИҺИНЭЭҔИТЭ__', '__ИҺН__', '__TOC__' ],
+       'noeditsection'             => [ '0', '__САЛААНЫ_УЛАРЫППАККА__', '__NOEDITSECTION__' ],
+       'currentmonth'              => [ '1', 'БУ_ЫЙ', 'БУ_ЫЙ_2', 'CURRENTMONTH', 'CURRENTMONTH2' ],
+       'currentmonth1'             => [ '1', 'БУ_ЫЙ_1', 'CURRENTMONTH1' ],
+       'currentmonthname'          => [ '1', 'БУ_ЫЙ_ААТА', 'CURRENTMONTHNAME' ],
+       'currentmonthnamegen'       => [ '1', 'БУ_ЫЙ_ААТА_АРТҺК', 'CURRENTMONTHNAMEGEN' ],
+       'currentmonthabbrev'        => [ '1', 'БУ_ЫЙ_ААТА_АББР', 'CURRENTMONTHABBREV' ],
+       'currentday'                => [ '1', 'БУ_КҮН', 'CURRENTDAY' ],
+       'currentday2'               => [ '1', 'БУ_КҮН_2', 'CURRENTDAY2' ],
+       'currentdayname'            => [ '1', 'БУ_КҮН_ААТА', 'CURRENTDAYNAME' ],
+       'currentyear'               => [ '1', 'БУ_СЫЛ', 'CURRENTYEAR' ],
+       'currenttime'               => [ '1', 'БУ_КЭМ', 'CURRENTTIME' ],
+       'currenthour'               => [ '1', 'БУ_ЧААС', 'CURRENTHOUR' ],
+       'localmonth'                => [ '1', 'ОЛОХТООХ_ЫЙ', 'ОЛОХТООХ_ЫЙ_2', 'LOCALMONTH', 'LOCALMONTH2' ],
+       'localmonth1'               => [ '1', 'ОЛОХТООХ_ЫЙ_1', 'LOCALMONTH1' ],
+       'localmonthname'            => [ '1', 'ОЛОХТООХ_ЫЙ_ААТА', 'LOCALMONTHNAME' ],
+       'localmonthnamegen'         => [ '1', 'ОЛОХТООХ_ЫЙ_ААТА_АРТҺК', 'LOCALMONTHNAMEGEN' ],
+       'localmonthabbrev'          => [ '1', 'ОЛОХТООХ_ЫЙ_ААТА_АББР', 'LOCALMONTHABBREV' ],
+       'localday'                  => [ '1', 'ОЛОХТООХ_КҮН', 'LOCALDAY' ],
+       'localday2'                 => [ '1', 'ОЛОХТООХ_КҮН_2', 'LOCALDAY2' ],
+       'localdayname'              => [ '1', 'ОЛОХТООХ_КҮН_ААТА', 'LOCALDAYNAME' ],
+       'localyear'                 => [ '1', 'ОЛОХТООХ_СЫЛ', 'LOCALYEAR' ],
+       'localtime'                 => [ '1', 'ОЛОХТООХ_КЭМ', 'LOCALTIME' ],
+       'localhour'                 => [ '1', 'ОЛОХТООХ_ЧААС', 'LOCALHOUR' ],
+       'numberofpages'             => [ '1', 'СИРЭЙ_АХСААНА', 'NUMBEROFPAGES' ],
+       'numberofarticles'          => [ '1', 'ЫСТАТЫЙА_АХСААНА', 'NUMBEROFARTICLES' ],
+       'numberoffiles'             => [ '1', 'БИЛЭ_АХСААНА', 'NUMBEROFFILES' ],
+       'numberofusers'             => [ '1', 'КЫТТААЧЧЫ_АХСААНА', 'NUMBEROFUSERS' ],
+       'numberofactiveusers'       => [ '1', 'КӨХТӨӨХ_КЫТТААЧЧЫ_АХСААНА', 'NUMBEROFACTIVEUSERS' ],
+       'numberofedits'             => [ '1', 'УЛАРЫТЫЫ_АХСААНА', 'NUMBEROFEDITS' ],
+       'pagename'                  => [ '1', 'СИРЭЙ_ААТА', 'PAGENAME' ],
+       'pagenamee'                 => [ '1', 'СИРЭЙ_ААТА_2', 'PAGENAMEE' ],
+       'namespace'                 => [ '1', 'ААТ_ДАЛА', 'NAMESPACE' ],
+       'namespacee'                => [ '1', 'ААТ_ДАЛА_2', 'NAMESPACEE' ],
+       'namespacenumber'           => [ '1', 'ААТ_ДАЛЫН_НҮӨМЭРЭ', 'NAMESPACENUMBER' ],
+       'talkspace'                 => [ '1', 'ЫРЫТЫЫ_ДАЛА', 'TALKSPACE' ],
+       'talkspacee'                => [ '1', 'ЫРЫТЫЫ_ДАЛА_2', 'TALKSPACEE' ],
+       'subjectspace'              => [ '1', 'ЫСТАТЫЙА_ДАЛА', 'SUBJECTSPACE', 'ARTICLESPACE' ],
+       'subjectspacee'             => [ '1', 'ЫСТАТЫЙА_ДАЛА_2', 'SUBJECTSPACEE', 'ARTICLESPACEE' ],
+       'fullpagename'              => [ '1', 'СИРЭЙ_ТОЛОРУ_ААТА', 'FULLPAGENAME' ],
+       'fullpagenamee'             => [ '1', 'СИРЭЙ_ТОЛОРУ_ААТА_2', 'FULLPAGENAMEE' ],
+       'subpagename'               => [ '1', 'ИҺИНЭЭҔИ_СИРЭЙ_ААТА', 'SUBPAGENAME' ],
+       'subpagenamee'              => [ '1', 'ИҺИНЭЭҔИ_СИРЭЙ_ААТА_2', 'SUBPAGENAMEE' ],
+       'basepagename'              => [ '1', 'СИРЭЙ_ААТЫН_ТӨРДӨ', 'BASEPAGENAME' ],
+       'basepagenamee'             => [ '1', 'СИРЭЙ_ААТЫН_ТӨРДӨ_2', 'BASEPAGENAMEE' ],
+       'talkpagename'              => [ '1', 'ЫРЫТАР_СИРЭЙ_ААТА', 'TALKPAGENAME' ],
+       'talkpagenamee'             => [ '1', 'ЫРЫТАР_СИРЭЙ_ААТА_2', 'TALKPAGENAMEE' ],
+       'subjectpagename'           => [ '1', 'ЫСТАТЫЙА_СИРЭЙИН_ААТА', 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ],
+       'subjectpagenamee'          => [ '1', 'ЫСТАТЫЙА_СИРЭЙИН_ААТА_2', 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ],
+       'msg'                       => [ '0', 'СУРУК:', 'СРК:', 'MSG:' ],
+       'subst'                     => [ '0', 'УГАН_БИЭРИИ:', 'УГУУ:', 'SUBST:' ],
+       'safesubst'                 => [ '0', 'УГУУКМСКЛ:', 'SAFESUBST:' ],
+       'msgnw'                     => [ '0', 'БИИКИТЭ_СУОХ_СУРУК:', 'MSGNW:' ],
+       'img_thumbnail'             => [ '1', 'мини', 'ойуучаан', 'thumb', 'thumbnail' ],
+       'img_manualthumb'           => [ '1', 'мини=$1', 'ойуучаан=$1', 'thumbnail=$1', 'thumb=$1' ],
+       'img_right'                 => [ '1', 'уҥа', 'right' ],
+       'img_left'                  => [ '1', 'хаҥас', 'left' ],
+       'img_none'                  => [ '1', 'суох', 'none' ],
+       'img_width'                 => [ '1', '$1пкс', '$1px' ],
+       'img_center'                => [ '1', 'орто', 'center', 'centre' ],
+       'img_framed'                => [ '1', 'раамка', 'frame', 'framed', 'enframed' ],
+       'img_frameless'             => [ '1', 'раамката_суох', 'frameless' ],
+       'img_page'                  => [ '1', 'сирэй=$1', 'сирэй $1', 'page=$1', 'page $1' ],
+       'img_upright'               => [ '1', 'үөһээуҥа', 'үөһээуҥа=$1', 'үөһээуҥа $1', 'upright', 'upright=$1', 'upright $1' ],
+       'img_border'                => [ '1', 'кирбии', 'border' ],
+       'img_baseline'              => [ '1', 'олох-дьураа', 'baseline' ],
+       'img_sub'                   => [ '1', 'алын', 'sub' ],
+       'img_super'                 => [ '1', 'үрүт', 'super', 'sup' ],
+       'img_top'                   => [ '1', 'үрдүнэн', 'top' ],
+       'img_text_top'              => [ '1', 'тиэкис-үрдүгэр', 'text-top' ],
+       'img_middle'                => [ '1', 'ортотунан', 'middle' ],
+       'img_bottom'                => [ '1', 'аллараа', 'bottom' ],
+       'img_text_bottom'           => [ '1', 'тиэкис-аллара', 'text-bottom' ],
+       'img_link'                  => [ '1', 'сигэ=$1', 'link=$1' ],
+       'img_alt'                   => [ '1', 'альт=$1', 'alt=$1' ],
+       'int'                       => [ '0', 'ИС:', 'INT:' ],
+       'sitename'                  => [ '1', 'СИТИМ-СИР_ААТА', 'SITENAME' ],
+       'ns'                        => [ '0', 'АД:', 'NS:' ],
+       'nse'                       => [ '0', 'АДК:', 'NSE:' ],
+       'localurl'                  => [ '0', 'ОЛОХТООХ_ААДЫРЫС:', 'LOCALURL:' ],
+       'localurle'                 => [ '0', 'ОЛОХТООХ_ААДЫРЫС_2:', 'LOCALURLE:' ],
+       'articlepath'               => [ '0', 'ЫСТАТЫЙА_СУОЛА', 'ARTICLEPATH' ],
+       'pageid'                    => [ '0', 'СИРЭЙ_НҮӨМЭРЭ', 'PAGEID' ],
+       'server'                    => [ '0', 'СИЭРБЭР', 'SERVER' ],
+       'servername'                => [ '0', 'СИЭРБЭР_ААТА', 'SERVERNAME' ],
+       'scriptpath'                => [ '0', 'СКРИП_СУОЛА', 'SCRIPTPATH' ],
+       'stylepath'                 => [ '0', 'ИСТИИЛ_СУОЛА', 'STYLEPATH' ],
+       'grammar'                   => [ '0', 'ТҮҺҮК:', 'GRAMMAR:' ],
+       'gender'                    => [ '0', 'АҤАРДАМ:', 'GENDER:' ],
+       'notitleconvert'            => [ '0', '__ААТЫН_УЛАРЫППАККА__', '__NOTITLECONVERT__', '__NOTC__' ],
+       'nocontentconvert'          => [ '0', '__ТИЭКИҺИН_УЛАРЫППАККА__', '__NOCONTENTCONVERT__', '__NOCC__' ],
+       'currentweek'               => [ '1', 'БУ_НЭДИЭЛЭ', 'CURRENTWEEK' ],
+       'currentdow'                => [ '1', 'НЭДИЭЛЭ_БУ_КҮНЭ', 'CURRENTDOW' ],
+       'localweek'                 => [ '1', 'ОЛОХТООХ_НЭДИЭЛЭ', 'LOCALWEEK' ],
+       'localdow'                  => [ '1', 'ОЛОХТООХ_НЭДИЭЛЭ_КҮНЭ', 'LOCALDOW' ],
+       'revisionid'                => [ '1', 'ТОРУМ_НҮӨМЭРЭ', 'REVISIONID' ],
+       'revisionday'               => [ '1', 'ТОРУМ_НҮӨМЭРЭ', 'REVISIONDAY' ],
+       'revisionday2'              => [ '1', 'ТОРУМ_НҮӨМЭРЭ_2', 'REVISIONDAY2' ],
+       'revisionmonth'             => [ '1', 'ТОРУМ_ЫЙА', 'REVISIONMONTH' ],
+       'revisionmonth1'            => [ '1', 'ТОРУМ_ЫЙА_1', 'REVISIONMONTH1' ],
+       'revisionyear'              => [ '1', 'ТОРУМ_СЫЛА', 'REVISIONYEAR' ],
+       'revisiontimestamp'         => [ '1', 'ТОРУМ_КЭМИН_БЭЛИЭТЭ', 'REVISIONTIMESTAMP' ],
+       'revisionuser'              => [ '1', 'КЫТТААЧЧЫ_ТОРУМА', 'REVISIONUSER' ],
+       'plural'                    => [ '0', 'ЭЛБЭХ_АХСААН:', 'PLURAL:' ],
+       'fullurl'                   => [ '0', 'ТОЛОРУ_ААДЫРЫС:', 'FULLURL:' ],
+       'fullurle'                  => [ '0', 'ТОЛОРУ_ААДЫРЫС_2:', 'FULLURLE:' ],
+       'lcfirst'                   => [ '0', 'БАСТАКЫ_БУУКУБА_КЫРА:', 'LCFIRST:' ],
+       'ucfirst'                   => [ '0', 'БАСТАКЫ_БУУКУБА_УЛАХАН:', 'UCFIRST:' ],
+       'lc'                        => [ '0', 'КЫРА_БУУКУБАННАН:', 'LC:' ],
+       'uc'                        => [ '0', 'УЛАХАН_БУУКУБАННАН:', 'UC:' ],
+       'raw'                       => [ '0', 'ТАҤАСТАММАТАХ:', 'RAW:' ],
+       'displaytitle'              => [ '1', 'ААТЫН_КӨРДӨР', 'DISPLAYTITLE' ],
+       'rawsuffix'                 => [ '1', 'Н', 'R' ],
+       'newsectionlink'            => [ '1', '__САҤА_САЛААҔА_СИГЭ__', '__NEWSECTIONLINK__' ],
+       'nonewsectionlink'          => [ '1', '__САҤА_САЛААҔА_СИГЭТЭ_СУОХ__', '__NONEWSECTIONLINK__' ],
+       'currentversion'            => [ '1', 'БИЛИҤҤИ_ТОРУМ', 'CURRENTVERSION' ],
+       'urlencode'                 => [ '0', 'КУОДТАММЫТ_ААДЫРЫС:', 'URLENCODE:' ],
+       'anchorencode'              => [ '0', 'ТИЭГИ_КУОДТАА', 'ANCHORENCODE' ],
+       'currenttimestamp'          => [ '1', 'БИЛИҤҤИ_КЭМ_БЭЛИЭТЭ', 'CURRENTTIMESTAMP' ],
+       'localtimestamp'            => [ '1', 'ОЛОХТООХ_КЭМ_БЭЛИЭТЭ', 'LOCALTIMESTAMP' ],
+       'directionmark'             => [ '1', 'СУРУК-БИЧИК_ХАЙЫСХАТА', 'DIRECTIONMARK', 'DIRMARK' ],
+       'language'                  => [ '0', '#ТЫЛ:', '#LANGUAGE:' ],
+       'contentlanguage'           => [ '1', 'ИҺИНЭЭҔИТИН_ТЫЛА', 'CONTENTLANGUAGE', 'CONTENTLANG' ],
+       'pagesinnamespace'          => [ '1', 'ААТ_ДАЛЫГАР_СИРЭЙ_АХСААНА:', 'PAGESINNAMESPACE:', 'PAGESINNS:' ],
+       'numberofadmins'            => [ '1', 'ДЬАҺАБЫЛ_АХСААНА', 'NUMBEROFADMINS' ],
+       'formatnum'                 => [ '0', 'ЧЫЫҺЫЛАНЫ_ФОРМААТТАА', 'FORMATNUM' ],
+       'padleft'                   => [ '0', 'ХАҤАСТАН_ТОЛОР', 'PADLEFT' ],
+       'padright'                  => [ '0', 'УҤАТТАН_ТОЛОР', 'PADRIGHT' ],
+       'special'                   => [ '0', 'аналлаах', 'special' ],
+       'defaultsort'               => [ '1', 'АНААН_ЭТИЛЛИБЭТЭҔИНЭ_НАРДААҺЫН', 'НААРДААҺЫН_КҮЛҮҮҺЭ', 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ],
+       'filepath'                  => [ '0', 'БИЛЭ_СУОЛА:', 'FILEPATH:' ],
+       'tag'                       => [ '0', 'тиэк', 'тег', 'тэг', 'tag' ],
+       'hiddencat'                 => [ '1', '__КИСТЭММИТ_КАТЕГОРИЯ__', '__HIDDENCAT__' ],
+       'pagesincategory'           => [ '1', 'КАТЕГОРИЯ_СИРЭЙИН_АХСААНА', 'PAGESINCATEGORY', 'PAGESINCAT' ],
+       'pagesize'                  => [ '1', 'СИРЭЙ_КЭЭМЭЙЭ', 'PAGESIZE' ],
+       'index'                     => [ '1', '__ИНДЕКС__', '__INDEX__' ],
+       'noindex'                   => [ '1', '__ИНДЕКСТЭЭМЭ__', '__NOINDEX__' ],
+       'numberingroup'             => [ '1', 'БӨЛӨХХӨ_АХСААНА', 'NUMBERINGROUP', 'NUMINGROUP' ],
+       'staticredirect'            => [ '1', '__ХАЛБАҤНААБАТ_УТААРЫЫ__', '__STATICREDIRECT__' ],
+       'protectionlevel'           => [ '1', 'КӨМҮСКЭЛ_ТАҺЫМА', 'PROTECTIONLEVEL' ],
+       'formatdate'                => [ '0', 'күн-дьыл_формаата', 'formatdate', 'dateformat' ],
+       'url_path'                  => [ '0', 'СУОЛ', 'PATH' ],
+       'url_wiki'                  => [ '0', 'БИИКИ', 'WIKI' ],
+       'url_query'                 => [ '0', 'КӨРДӨБҮЛ', 'QUERY' ],
+       'pagesincategory_all'       => [ '0', 'барыта', 'all' ],
+       'pagesincategory_pages'     => [ '0', 'сирэйдэр', 'pages' ],
+       'pagesincategory_subcats'   => [ '0', 'иһинээҕи_категория', 'subcats' ],
+       'pagesincategory_files'     => [ '0', 'билэ', 'билэлэр', 'files' ],
+];
+
+$dateFormats = [
+       'mdy time' => 'H:i',
+       'mdy date' => 'xg j, Y',
+       'mdy both' => 'H:i, xg j, Y',
+
+       'dmy time' => 'H:i',
+       'dmy date' => 'j xg Y',
+       'dmy both' => 'H:i, j xg Y',
+
+       'ymd time' => 'H:i',
+       'ymd date' => 'Y xg j',
+       'ymd both' => 'H:i, Y xg j',
+
+       'ISO 8601 time' => 'xnH:xni:xns',
+       'ISO 8601 date' => 'xnY-xnm-xnd',
+       'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
+];
+
+$bookstoreList = [
+       'Поиск по библиотекам «Сигла»' => 'http://www.sigla.ru/results.jsp?f=7&t=3&v0=$1',
+       'Findbook.ru' => 'http://findbook.ru/search/d0?ptype=4&pvalue=$1',
+       'Яндекс.Маркет' => 'http://market.yandex.ru/search.xml?text=$1',
+       'ОЗОН' => 'http://www.ozon.ru/?context=advsearch_book&isbn=$1',
+       'Books.Ru' => 'http://www.books.ru/shop/search?query=$1',
+       'Amazon.com' => 'https://www.amazon.com/exec/obidos/ISBN=$1'
+];
+
+$separatorTransformTable = [
+       ',' => "\u{00A0}", # nbsp
+       '.' => ','
+];
+$minimumGroupingDigits = 2;
+
+$linkTrail = '/^([a-zабвгҕдеёжзийклмнҥоөпрсһтуүфхцчшщъыьэюя]+)(.*)$/sDu';
index 9a6c51f..5b32f91 100644 (file)
@@ -95,29 +95,50 @@ $datePreferenceMigrationMap = [
 $specialPageAliases = [
        'Activeusers'               => [ 'АктивниКорисници', 'Активни_корисници' ],
        'Allmessages'               => [ 'СвеПоруке', 'Све_поруке' ],
+       'AllMyUploads'              => [ 'СваМојаОтпремања', 'СвеМојеДатотеке' ],
        'Allpages'                  => [ 'Све_странице' ],
+       'ApiSandbox'                => [ 'API_песак', 'АПИ_песак' ],
        'Ancientpages'              => [ 'НајстаријеСтранице', 'НајстаријиЧланци' ],
+       'AutoblockList'             => [ 'СписакАутоблокова', 'Аутоблокови' ],
        'Badtitle'                  => [ 'Лош_наслов' ],
        'Blankpage'                 => [ 'ПразнаСтраница' ],
        'Block'                     => [ 'Блокирај', 'БлокирајИП', 'БлокирајКорисника' ],
+       'Booksources'               => [ 'КњижевниИзвори', 'ШтампаниИзвори' ],
+       'BotPasswords'              => [ 'ЛозинкеБотова' ],
        'BrokenRedirects'           => [ 'Покварена_преусмерења', 'Неисправна_преусмерења' ],
        'Categories'                => [ 'Категорије' ],
+       'ChangeContentModel'        => [ 'ПромениМоделСадржаја', 'ИзмениМоделСадржаја' ],
+       'ChangeCredentials'         => [ 'ПромениАкредитиве' ],
+       'ChangeEmail'               => [ 'ПромениИмејлАдресу' ],
        'ChangePassword'            => [ 'ПромениЛозинку' ],
        'ComparePages'              => [ 'Упореди_странице' ],
        'Confirmemail'              => [ 'ПотврдиЕ-пошту', 'Потврда_е-поште' ],
        'Contributions'             => [ 'Доприноси', 'Прилози' ],
        'CreateAccount'             => [ 'ОтвориНалог', 'Отвори_налог' ],
+       'Deadendpages'              => [ 'Ћорсокаци', 'СтраницеКојеНеВодеНикуда', 'СлепеСтранице' ],
        'DeletedContributions'      => [ 'ОбрисаниДоприноси' ],
+       'Diff'                      => [ 'Разлике' ],
        'DoubleRedirects'           => [ 'Двострука_преусмерења' ],
+       'EditTags'                  => [ 'УредиОзнаке' ],
+       'EditWatchlist'             => [ 'УредиСписакНадгледања' ],
+       'Emailuser'                 => [ 'ПошаљиИмејлКориснику' ],
+       'ExpandTemplates'           => [ 'ПрошириШаблоне' ],
        'Export'                    => [ 'Извези' ],
        'Fewestrevisions'           => [ 'НајмањеИзмена', 'ЧланциСаНајмањеРевизија' ],
+       'FileDuplicateSearch'       => [ 'ПретрагаДупликатаДатотека' ],
        'Filepath'                  => [ 'Путања_датотеке' ],
+       'GoToInterwiki'             => [ 'ПосетиМеђувики' ],
        'Import'                    => [ 'Увези' ],
+       'Invalidateemail'           => [ 'ПоништиИмејл' ],
+       'JavaScriptTest'            => [ 'ТестирањеЈаваскрипта' ],
        'BlockList'                 => [ 'СписакБлокираних', 'ПописБлокираних' ],
+       'LinkSearch'                => [ 'ПретрагаВеза' ],
+       'LinkAccounts'              => [ 'ПовежиНалоге' ],
        'Listadmins'                => [ 'СписакАдминистратора', 'ПописАдминистратора', 'Списак_администратора' ],
        'Listbots'                  => [ 'СписакБотова', 'ПописБотова', 'Списак_ботова' ],
        'Listfiles'                 => [ 'СписакДатотека', 'СписакСлика', 'Списак_датотека' ],
        'Listgrouprights'           => [ 'СписакКорисничкихПрава', 'Списак_корисничких_права' ],
+       'Listgrants'                => [ 'СписакДозвола' ],
        'Listredirects'             => [ 'СписакПреусмерења', 'Списак_преусмерења' ],
        'ListDuplicatedFiles'       => [ 'СписакДупликата' ],
        'Listusers'                 => [ 'СписакКорисника', 'КорисничкиСписак', 'Списак_корисника', 'Кориснички_списак' ],
@@ -125,6 +146,7 @@ $specialPageAliases = [
        'Log'                       => [ 'Извештај', 'Извештаји' ],
        'Lonelypages'               => [ 'Сирочићи' ],
        'Longpages'                 => [ 'ДугачкеСтране' ],
+       'MediaStatistics'           => [ 'СтатистикеМедија' ],
        'MergeHistory'              => [ 'СпојиИсторију', 'Споји_историју' ],
        'MIMEsearch'                => [ 'MIME_претрага' ],
        'Mostcategories'            => [ 'НајвишеКатегорија', 'ЧланциСаНајвишеКатегорија' ],
@@ -142,24 +164,40 @@ $specialPageAliases = [
        'Myuploads'                 => [ 'Моја_слања' ],
        'Newimages'                 => [ 'НовеДатотеке', 'НовиФајлови', 'НовеСлике' ],
        'Newpages'                  => [ 'НовеСтране' ],
-       'PermanentLink'             => [ 'Привремена_веза' ],
+       'PagesWithProp'             => [ 'СтраницеСаСвојством' ],
+       'PageData'                  => [ 'ПодациСтранице' ],
+       'PageLanguage'              => [ 'ЈезикСтранице' ],
+       'PasswordPolicies'          => [ 'ПравилаЗаЛозинке' ],
+       'PasswordReset'             => [ 'РесетовањеЛозинке' ],
+       'PermanentLink'             => [ 'ТрајнаВеза', 'Привремена_веза' ],
        'Preferences'               => [ 'Подешавања', 'Поставке' ],
+       'Prefixindex'               => [ 'СтраницеСаПрефиксом' ],
        'Protectedpages'            => [ 'ЗаштићенеСтранице', 'Заштићене_странице' ],
        'Protectedtitles'           => [ 'ЗаштићениНаслови', 'Заштићени_наслови' ],
        'Randompage'                => [ 'СлучајнаСтрана', 'Насумична_страница' ],
+       'RandomInCategory'          => [ 'Случајна_страна_у_категорији' ],
        'Randomredirect'            => [ 'СлучајноПреусмерење' ],
+       'Randomrootpage'            => [ 'СлучајнаОсновнаСтрана' ],
        'Recentchanges'             => [ 'СкорашњеИзмене', 'Скорашње_измене' ],
+       'Recentchangeslinked'       => [ 'СроднеИзмене' ],
+       'Redirect'                  => [ 'Преусмерење' ],
+       'RemoveCredentials'         => [ 'УклониАкредитиве' ],
+       'ResetTokens'               => [ 'РесетујЖетоне' ],
+       'Revisiondelete'            => [ 'УклањањеИзмене' ],
+       'RunJobs'                   => [ 'ИзвршиПослове' ],
        'Search'                    => [ 'Претражи' ],
        'Shortpages'                => [ 'КраткеСтранице', 'КраткиЧланци' ],
-       'Specialpages'              => [ 'СпеÑ\86иÑ\98алнеСÑ\82Ñ\80ане', 'Ð\9fоÑ\81ебне_странице' ],
+       'Specialpages'              => [ 'Ð\9fоÑ\81ебнеСÑ\82Ñ\80ане', 'СпеÑ\86иÑ\98алнеСÑ\82Ñ\80ане', 'Ð\9fоÑ\81ебне_Ñ\81Ñ\82Ñ\80аниÑ\86е', 'СпеÑ\86иÑ\98алне_странице' ],
        'Statistics'                => [ 'Статистике' ],
        'Tags'                      => [ 'Ознаке' ],
+       'TrackingCategories'        => [ 'КатегоријеЗаПраћење' ],
        'Unblock'                   => [ 'Деблокирај' ],
        'Uncategorizedcategories'   => [ 'НекатегорисанеКатегорије', 'КатегоријеБезКатегорија' ],
        'Uncategorizedimages'       => [ 'НекатегорисанеДатотеке', 'СликеБезКатегорија' ],
        'Uncategorizedpages'        => [ 'НекатегорисанеСтранице', 'ЧланциБезКатегорија', 'Чланци_без_категорија' ],
        'Uncategorizedtemplates'    => [ 'НекатегорисаниШаблони', 'ШаблониБезКатегорија' ],
        'Undelete'                  => [ 'Врати' ],
+       'UnlinkAccounts'            => [ 'УклониПовезивањеНалога' ],
        'Unlockdb'                  => [ 'ОткључајБазу', 'Откључај_базу' ],
        'Unusedcategories'          => [ 'НеискоришћенеКатегорије' ],
        'Unusedimages'              => [ 'НеискоришћенеДатотеке', 'НеискоришћенеСлике' ],
index 7e9220c..2a05046 100644 (file)
@@ -165,26 +165,11 @@ FILE_PATTERNS          = *.c \
                          *.odl \
                          *.cs \
                          *.php \
-                         *.php5 \
                          *.inc \
                          *.m \
                          *.mm \
                          *.dox \
                          *.py \
-                         *.C \
-                         *.CC \
-                         *.C++ \
-                         *.II \
-                         *.I++ \
-                         *.H \
-                         *.HH \
-                         *.H++ \
-                         *.CS \
-                         *.PHP \
-                         *.PHP5 \
-                         *.M \
-                         *.MM \
-                         *.PY \
                          *.txt \
                          README
 RECURSIVE              = YES
@@ -192,7 +177,6 @@ EXCLUDE                = {{EXCLUDE}}
 EXCLUDE_SYMLINKS       = YES
 EXCLUDE_PATTERNS       = LocalSettings.php \
                          AdminSettings.php \
-                         StartProfiler.php \
                          .svn \
                          */.git/* \
                          {{EXCLUDE_PATTERNS}}
diff --git a/maintenance/archives/patch-tc-timestamp.sql b/maintenance/archives/patch-tc-timestamp.sql
deleted file mode 100644 (file)
index 3f7dde4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE /*_*/transcache MODIFY tc_time binary(14);
-UPDATE /*_*/transcache SET tc_time = DATE_FORMAT(FROM_UNIXTIME(tc_time), "%Y%c%d%H%i%s");
-
-INSERT INTO /*_*/updatelog(ul_key) VALUES ('convert transcache field');
diff --git a/maintenance/archives/patch-transcache-fix-pk.sql b/maintenance/archives/patch-transcache-fix-pk.sql
deleted file mode 100644 (file)
index 2e8fea1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE /*_*/transcache DROP KEY /*i*/tc_url_idx, ADD PRIMARY KEY (tc_url);
diff --git a/maintenance/archives/patch-transcache.sql b/maintenance/archives/patch-transcache.sql
deleted file mode 100644 (file)
index 70870ef..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE TABLE /*$wgDBprefix*/transcache (
-       tc_url          varbinary(255) NOT NULL,
-       tc_contents     TEXT,
-       tc_time         binary(14) NOT NULL,
-       UNIQUE INDEX tc_url_idx(tc_url)
-) /*$wgDBTableOptions*/;
-
index dad79b0..2442caa 100644 (file)
@@ -35,6 +35,7 @@ class DeduplicateArchiveRevId extends LoggedUpdateMaintenance {
                $this->output( "Deduplicating ar_rev_id...\n" );
 
                $dbw = $this->getDB( DB_MASTER );
+               PopulateArchiveRevId::checkMysqlAutoIncrementBug( $dbw );
 
                $minId = $dbw->selectField( 'archive', 'MIN(ar_rev_id)', [], __METHOD__ );
                $maxId = $dbw->selectField( 'archive', 'MAX(ar_rev_id)', [], __METHOD__ );
index 70fdebf..dc1de4f 100644 (file)
@@ -485,7 +485,9 @@ class GenerateSitemap extends Maintenance {
         */
        function indexEntry( $filename ) {
                return "\t<sitemap>\n" .
-                       "\t\t<loc>{$this->urlpath}$filename</loc>\n" .
+                       "\t\t<loc>" . wfGetServerUrl( PROTO_CANONICAL ) .
+                               ( substr( $this->urlpath, 0, 1 ) === "/" ? "" : "/" ) .
+                               "{$this->urlpath}$filename</loc>\n" .
                        "\t\t<lastmod>{$this->timestamp}</lastmod>\n" .
                        "\t</sitemap>\n";
        }
index bebee85..7ff972e 100644 (file)
@@ -8,7 +8,6 @@
                                        "mw",
                                        "mw.Message",
                                        "mw.loader",
-                                       "mw.loader.store",
                                        "mw.html",
                                        "mw.html.Cdata",
                                        "mw.html.Raw",
@@ -83,7 +82,6 @@
                                "classes": [
                                        "mw.log",
                                        "mw.inspect",
-                                       "mw.inspect.reports",
                                        "mw.Debug"
                                ]
                        }
index ebbd6e3..c9a1d12 100644 (file)
@@ -1149,18 +1149,6 @@ CREATE TABLE /*_*/objectcache (
 CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime);
 
 
---
--- Cache of interwiki transclusion
---
-CREATE TABLE /*_*/transcache (
-  tc_url nvarchar(255) NOT NULL,
-  tc_contents nvarchar(max),
-  tc_time varchar(14) NOT NULL
-);
-
-CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url);
-
-
 CREATE TABLE /*_*/logging (
   -- Log ID, for referring to this specific log entry, probably for deletion and such.
   log_id int NOT NULL PRIMARY KEY IDENTITY(0,1),
index 7497c20..3763d19 100644 (file)
@@ -775,13 +775,6 @@ CREATE TABLE &mw_prefix.objectcache (
 );
 CREATE INDEX &mw_prefix.objectcache_i01 ON &mw_prefix.objectcache (exptime);
 
-CREATE TABLE &mw_prefix.transcache (
-  tc_url       VARCHAR2(255)         NOT NULL,
-  tc_contents  CLOB         NOT NULL,
-  tc_time      TIMESTAMP(6) WITH TIME ZONE  NOT NULL
-);
-CREATE UNIQUE INDEX &mw_prefix.transcache_u01 ON &mw_prefix.transcache (tc_url);
-
 
 CREATE SEQUENCE logging_log_id_seq;
 CREATE TABLE &mw_prefix.logging (
index e493506..60f5e8a 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Maintenance
  */
 
+use Wikimedia\Rdbms\DBQueryError;
 use Wikimedia\Rdbms\IDatabase;
 
 require_once __DIR__ . '/Maintenance.php';
@@ -49,6 +50,7 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance {
        protected function doDBUpdates() {
                $this->output( "Populating ar_rev_id...\n" );
                $dbw = $this->getDB( DB_MASTER );
+               self::checkMysqlAutoIncrementBug( $dbw );
 
                // Quick exit if there are no rows needing updates.
                $any = $dbw->selectField(
@@ -86,6 +88,53 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance {
                }
        }
 
+       /**
+        * Check for (and work around) a MySQL auto-increment bug
+        *
+        * (T202032) MySQL until 8.0 and MariaDB until some version after 10.1.34
+        * don't save the auto-increment value to disk, so on server restart it
+        * might reuse IDs from deleted revisions. We can fix that with an insert
+        * with an explicit rev_id value, if necessary.
+        *
+        * @param IDatabase $dbw
+        */
+       public static function checkMysqlAutoIncrementBug( IDatabase $dbw ) {
+               if ( $dbw->getType() !== 'mysql' ) {
+                       return;
+               }
+
+               if ( !self::$dummyRev ) {
+                       self::$dummyRev = self::makeDummyRevisionRow( $dbw );
+               }
+
+               $ok = false;
+               while ( !$ok ) {
+                       try {
+                               $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) {
+                                       $dbw->insert( 'revision', self::$dummyRev, $fname );
+                                       $id = $dbw->insertId();
+                                       $toDelete[] = $id;
+
+                                       $maxId = max(
+                                               (int)$dbw->selectField( 'archive', 'MAX(ar_rev_id)', [], __METHOD__ ),
+                                               (int)$dbw->selectField( 'slots', 'MAX(slot_revision_id)', [], __METHOD__ )
+                                       );
+                                       if ( $id <= $maxId ) {
+                                               $dbw->insert( 'revision', [ 'rev_id' => $maxId + 1 ] + self::$dummyRev, $fname );
+                                               $toDelete[] = $maxId + 1;
+                                       }
+
+                                       $dbw->delete( 'revision', [ 'rev_id' => $toDelete ], $fname );
+                               } );
+                               $ok = true;
+                       } catch ( DBQueryError $e ) {
+                               if ( $e->errno != 1062 ) { // 1062 is "duplicate entry", ignore it and retry
+                                       throw $e;
+                               }
+                       }
+               }
+       }
+
        /**
         * Assign new ar_rev_ids to a set of ar_ids.
         * @param IDatabase $dbw
index db68248..1a594f0 100644 (file)
@@ -647,12 +647,6 @@ CREATE TABLE objectcache (
 );
 CREATE INDEX objectcacache_exptime ON objectcache (exptime);
 
-CREATE TABLE transcache (
-  tc_url       TEXT         NOT NULL  UNIQUE,
-  tc_contents  TEXT         NOT NULL,
-  tc_time      TIMESTAMPTZ  NOT NULL
-);
-
 
 CREATE SEQUENCE logging_log_id_seq;
 CREATE TABLE logging (
index b8d9848..6bb130d 100644 (file)
@@ -1,17 +1,39 @@
 ### Format of this file
 #
 # The top-level keys are module names (as registered in Resources.php).
-# The values of these keys are resource descriptors.
+# Each top-level key holds a resource descriptor that must have one of
+# the following `type` values:
 #
-# In each resource descriptor object, the `src` and `integrity` keys are required.
+# - `tar`: For tarball archive (may be gzip-compressed).
+# - `file: For a plain file.
+# - `multi-file`: For multiple plain files.
 #
-# * `src`: Full URL to a remote resource.
-# * `integrity`: Cryptographic hash used to verify the remote content.
-#    Uses the "integrity metadata" format defined at <https://www.w3.org/TR/SRI/>.
-# * `dest`: An object mapping paths from the remote resource to a destination in
-#    `/resources/lib/$module/`. The value may be omitted to indicate that
-#    paths should be extracted to the destination directory itself.
+### Type tar
+#
+# The `src` and `integrity` keys are quired.
+#
+# * `src`: Full URL to thes remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: An object mapping paths to files or directory from the remote resource to a destination
+#    in the module directory. The value of key in dest may be omitted, which will extract the key
+#    directly to the module directory.
+#
+### Type file
+#
+# The `src` and `integrity` keys are quired.
+#
+# * `src`: Full URL to thes remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: The name of the file in the module directory. Default: Basename of URL.
+#
+### Type mult-file
+#
+# The `files` key is required.
+#
+# * `files`: An object mapping destination paths to an object containing `src` and `integrity`
+#    keys.
 oojs:
+  type: tar
   src: https://registry.npmjs.org/oojs/-/oojs-2.2.2.tgz
   integrity: sha256-ebgQW2EGrSkBCnDJBGqDpsBDjA3PMN/M8U5DyLHt9mw=
   dest:
@@ -20,6 +42,7 @@ oojs:
     package/LICENSE-MIT:
     package/README.md:
 oojs-ui:
+  type: tar
   src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.28.0.tgz
   integrity: sha384-j8bzlCPrfS4sca+U9JO9tdcewDlLlDlOVOsLn+Vqlcg5GU59vLSd7TVm4FiuTowy
   dest:
@@ -48,3 +71,19 @@ oojs-ui:
     package/dist/History.md:
     package/dist/LICENSE-MIT:
     package/dist/README.md:
+jquery:
+  type: file
+  src: https://code.jquery.com/jquery-3.2.1.js
+  # Integrity from link modals https://code.jquery.com/jquery/
+  integrity: sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=
+  dest: jquery.js
+qunitjs:
+  type: multi-file
+  # Integrity from link modals at https://code.jquery.com/qunit/
+  files:
+    qunit.js:
+      src: https://code.jquery.com/qunit/qunit-2.6.0.js
+      integrity: sha256-QdI40P4EEDzPRIS0mktlE0sSyoXCnOs8fB4OSmy+VxI=
+    qunit.css:
+      src: https://code.jquery.com/qunit/qunit-2.6.0.css
+      integrity: sha256-F4O5nugrHEEjfO0tfu/LKnSRFKctZ9Rdmi1oj22UD1s=
index 528d6e7..41e579b 100644 (file)
@@ -30,6 +30,8 @@ require_once __DIR__ . '/../Maintenance.php';
 class ManageForeignResources extends Maintenance {
        private $defaultAlgo = 'sha384';
        private $tmpParentDir;
+       private $action;
+       private $failAfterOutput = false;
 
        public function __construct() {
                global $IP;
@@ -40,17 +42,16 @@ Manage foreign resources registered with ResourceLoader.
 This helps developers to download, verify and update local copies of upstream
 libraries registered as ResourceLoader modules. See also foreign-resources.yaml.
 
-For sources that don't publish an integrity hash, leave the value empty at
-first, and run this script with --make-sri to compute the hashes.
+For sources that don't publish an integrity hash, omit "integrity" (or leave empty)
+and run the "make-sri" action to compute the missing hashes.
 
 This script runs in dry mode by default. Use --update to actually change, remove,
 or add files to /resources/lib/.
 TEXT
                );
+               $this->addArg( 'action', 'One of "update", "verify" or "make-sri"', true );
                $this->addArg( 'module', 'Name of a single module (Default: all)', false );
-               $this->addOption( 'update', ' resources/lib/ missing integrity metadata' );
-               $this->addOption( 'make-sri', 'Compute missing integrity metadata' );
-               $this->addOption( 'verbose', 'Be verbose' );
+               $this->addOption( 'verbose', 'Be verbose', false, false, 'v' );
 
                // Use a directory in $IP instead of wfTempDir() because
                // PHP's rename() does not work across file systems.
@@ -59,67 +60,127 @@ TEXT
 
        public function execute() {
                global $IP;
-               $module = $this->getArg();
-               $makeSRI = $this->hasOption( 'make-sri' );
+               $this->action = $this->getArg( 0 );
+               if ( !in_array( $this->action, [ 'update', 'verify', 'make-sri' ] ) ) {
+                       $this->fatalError( "Invalid action argument." );
+               }
 
                $registry = $this->parseBasicYaml(
                        file_get_contents( __DIR__ . '/foreign-resources.yaml' )
                );
+               $module = $this->getArg( 1, 'all' );
                foreach ( $registry as $moduleName => $info ) {
-                       if ( $module !== null && $moduleName !== $module ) {
+                       if ( $module !== 'all' && $moduleName !== $module ) {
                                continue;
                        }
                        $this->verbose( "\n### {$moduleName}\n\n" );
+                       $destDir = "{$IP}/resources/lib/$moduleName";
 
-                       // Validate required keys
-                       $info += [ 'src' => null, 'integrity' => null, 'dest' => null ];
-                       if ( $info['src'] === null ) {
-                               $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+                       if ( $this->action === 'update' ) {
+                               $this->output( "... updating '{$moduleName}'\n" );
+                               $this->verbose( "... emptying /resources/lib/$moduleName\n" );
+                               wfRecursiveRemoveDir( $destDir );
+                       } elseif ( $this->action === 'verify' ) {
+                               $this->output( "... verifying '{$moduleName}'\n" );
+                       } else {
+                               $this->output( "... checking '{$moduleName}'\n" );
                        }
-                       $integrity = is_string( $info['integrity'] ) ? $info['integrity'] : $makeSRI;
-                       if ( $integrity === false ) {
-                               $this->fatalError( "Module '$moduleName' must have an 'integrity' key." );
+
+                       $this->verbose( "... preparing {$this->tmpParentDir}\n" );
+                       wfRecursiveRemoveDir( $this->tmpParentDir );
+                       if ( !wfMkdirParents( $this->tmpParentDir ) ) {
+                               $this->fatalError( "Unable to create {$this->tmpParentDir}" );
                        }
 
-                       // Download the resource
-                       $data = Http::get( $info['src'], [ 'followRedirects' => false ] );
-                       if ( $data === false ) {
-                               $this->fatalError( "Failed to download resource for '$moduleName'." );
+                       if ( !isset( $info['type'] ) ) {
+                               $this->fatalError( "Module '$moduleName' must have a 'type' key." );
+                       }
+                       switch ( $info['type'] ) {
+                               case 'tar':
+                                       $this->handleTypeTar( $moduleName, $destDir, $info );
+                                       break;
+                               case 'file':
+                                       $this->handleTypeFile( $moduleName, $destDir, $info );
+                                       break;
+                               case 'multi-file':
+                                       $this->handleTypeMultiFile( $moduleName, $destDir, $info );
+                                       break;
+                               default:
+                                       $this->fatalError( "Unknown type '{$info['type']}' for '$moduleName'" );
                        }
+               }
 
-                       // Validate integrity metadata
-                       $this->output( "... checking integrity of '{$moduleName}'\n" );
-                       $algo = $integrity === true ? $this->defaultAlgo : explode( '-', $integrity )[0];
-                       $actualIntegrity = $algo . '-' . base64_encode( hash( $algo, $data, true ) );
-                       if ( $integrity === true ) {
-                               $this->output( "Integrity for '{$moduleName}':\n\t${actualIntegrity}\n" );
-                               continue;
-                       } elseif ( $integrity !== $actualIntegrity ) {
-                               $this->fatalError( "Integrity check failed for '{$moduleName}:\n" .
-                                       "Expected: {$integrity}\n" .
-                                       "Actual: {$actualIntegrity}"
+               $this->cleanUp();
+               $this->output( "\nDone!\n" );
+               if ( $this->failAfterOutput ) {
+                       // The verify mode should check all modules/files and fail after, not during.
+                       return false;
+               }
+       }
+
+       private function fetch( $src, $integrity ) {
+               $data = Http::get( $src, [ 'followRedirects' => false ] );
+               if ( $data === false ) {
+                       $this->fatalError( "Failed to download resource at {$src}" );
+               }
+               $algo = $integrity === null ? $this->defaultAlgo : explode( '-', $integrity )[0];
+               $actualIntegrity = $algo . '-' . base64_encode( hash( $algo, $data, true ) );
+               if ( $integrity === $actualIntegrity ) {
+                       $this->verbose( "... passed integrity check for {$src}\n" );
+               } else {
+                       if ( $this->action === 'make-sri' ) {
+                               $this->output( "Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
+                       } else {
+                               $this->fatalError( "Integrity check failed for {$src}\n" .
+                                       "\tExpected: {$integrity}\n" .
+                                       "\tActual: {$actualIntegrity}"
                                );
                        }
-
-                       // Determine destination
-                       $destDir = "{$IP}/resources/lib/$moduleName";
-                       $this->output( "... extracting files for '{$moduleName}'\n" );
-                       $this->handleTypeTar( $moduleName, $data, $destDir, $info );
                }
+               return $data;
+       }
 
-               // Clean up
-               wfRecursiveRemoveDir( $this->tmpParentDir );
-               $this->output( "\nDone!\n" );
+       private function handleTypeFile( $moduleName, $destDir, array $info ) {
+               if ( !isset( $info['src'] ) ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+               }
+               $data = $this->fetch( $info['src'], $info['integrity'] ?? null );
+               $dest = $info['dest'] ?? basename( $info['src'] );
+               $path = "$destDir/$dest";
+               if ( $this->action === 'verify' && sha1_file( $path ) !== sha1( $data ) ) {
+                       $this->fatalError( "File for '$moduleName' is different." );
+               } elseif ( $this->action === 'update' ) {
+                       wfMkdirParents( $destDir );
+                       file_put_contents( "$destDir/$dest", $data );
+               }
        }
 
-       private function handleTypeTar( $moduleName, $data, $destDir, array $info ) {
-               global $IP;
-               wfRecursiveRemoveDir( $this->tmpParentDir );
-               if ( !wfMkdirParents( $this->tmpParentDir ) ) {
-                       $this->fatalError( "Unable to create {$this->tmpParentDir}" );
+       private function handleTypeMultiFile( $moduleName, $destDir, array $info ) {
+               if ( !isset( $info['files'] ) ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'files' key." );
                }
+               foreach ( $info['files'] as $dest => $file ) {
+                       if ( !isset( $file['src'] ) ) {
+                               $this->fatalError( "Module '$moduleName' file '$dest' must have a 'src' key." );
+                       }
+                       $data = $this->fetch( $file['src'], $file['integrity'] ?? null );
+                       $path = "$destDir/$dest";
+                       if ( $this->action === 'verify' && sha1_file( $path ) !== sha1( $data ) ) {
+                               $this->fatalError( "File '$dest' for '$moduleName' is different." );
+                       } elseif ( $this->action === 'update' ) {
+                               wfMkdirParents( $destDir );
+                               file_put_contents( "$destDir/$dest", $data );
+                       }
+               }
+       }
 
-               // Write resource to temporary file and open it
+       private function handleTypeTar( $moduleName, $destDir, array $info ) {
+               $info += [ 'src' => null, 'integrity' => null, 'dest' => null ];
+               if ( $info['src'] === null ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+               }
+               // Download the resource to a temporary file and open it
+               $data = $this->fetch( $info['src'], $info['integrity' ] );
                $tmpFile = "{$this->tmpParentDir}/$moduleName.tar";
                $this->verbose( "... writing '$moduleName' src to $tmpFile\n" );
                file_put_contents( $tmpFile, $data );
@@ -129,46 +190,45 @@ TEXT
                unset( $data, $p );
 
                if ( $info['dest'] === null ) {
-                       // Replace the entire directory as-is
-                       if ( !$this->hasOption( 'update' ) ) {
-                               $this->output( "[dry run] Would replace /resources/lib/$moduleName\n" );
-                       } else {
-                               wfRecursiveRemoveDir( $destDir );
-                               if ( !rename( $tmpDir, $destDir ) ) {
-                                       $this->fatalError( "Could not move $destDir to $tmpDir." );
-                               }
-                       }
-                       return;
-               }
-
-               // Create and/or empty the destination
-               if ( !$this->hasOption( 'update' ) ) {
-                       $this->output( "... [dry run] would empty /resources/lib/$moduleName\n" );
+                       // Default: Replace the entire directory
+                       $toCopy = [ $tmpDir => $destDir ];
                } else {
-                       wfRecursiveRemoveDir( $destDir );
-                       wfMkdirParents( $destDir );
-               }
-
-               // Expand and normalise the 'dest' entries
-               $toCopy = [];
-               foreach ( $info['dest'] as $fromSubPath => $toSubPath ) {
-                       // Use glob() to expand wildcards and check existence
-                       $fromPaths = glob( "{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
-                       if ( !$fromPaths ) {
-                               $this->fatalError( "Path '$fromSubPath' of '$moduleName' not found." );
-                       }
-                       foreach ( $fromPaths as $fromPath ) {
-                               $toCopy[$fromPath] = $toSubPath === null
-                                       ? "$destDir/" . basename( $fromPath )
-                                       : "$destDir/$toSubPath/" . basename( $fromPath );
+                       // Expand and normalise the 'dest' entries
+                       $toCopy = [];
+                       foreach ( $info['dest'] as $fromSubPath => $toSubPath ) {
+                               // Use glob() to expand wildcards and check existence
+                               $fromPaths = glob( "{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
+                               if ( !$fromPaths ) {
+                                       $this->fatalError( "Path '$fromSubPath' of '$moduleName' not found." );
+                               }
+                               foreach ( $fromPaths as $fromPath ) {
+                                       $toCopy[$fromPath] = $toSubPath === null
+                                               ? "$destDir/" . basename( $fromPath )
+                                               : "$destDir/$toSubPath/" . basename( $fromPath );
+                               }
                        }
                }
                foreach ( $toCopy as $from => $to ) {
-                       if ( !$this->hasOption( 'update' ) ) {
-                               $shortFrom = strtr( $from, [ "$tmpDir/" => '' ] );
-                               $shortTo = strtr( $to, [ "$IP/" => '' ] );
-                               $this->output( "... [dry run] would move $shortFrom to $shortTo\n" );
-                       } else {
+                       if ( $this->action === 'verify' ) {
+                               $this->verbose( "... verifying $to\n" );
+                               if ( is_dir( $from ) ) {
+                                       $rii = new RecursiveIteratorIterator( new RecursiveDirectoryIterator(
+                                               $from,
+                                               RecursiveDirectoryIterator::SKIP_DOTS
+                                       ) );
+                                       foreach ( $rii as $file ) {
+                                               $remote = $file->getPathname();
+                                               $local = strtr( $remote, [ $from => $to ] );
+                                               if ( sha1_file( $remote ) !== sha1_file( $local ) ) {
+                                                       $this->error( "File '$local' is different." );
+                                                       $this->failAfterOutput = true;
+                                               }
+                                       }
+                               } elseif ( sha1_file( $from ) !== sha1_file( $to ) ) {
+                                       $this->error( "File '$to' is different." );
+                                       $this->failAfterOutput = true;
+                               }
+                       } elseif ( $this->action === 'update' ) {
                                $this->verbose( "... moving $from to $to\n" );
                                wfMkdirParents( dirname( $to ) );
                                if ( !rename( $from, $to ) ) {
@@ -184,6 +244,15 @@ TEXT
                }
        }
 
+       private function cleanUp() {
+               wfRecursiveRemoveDir( $this->tmpParentDir );
+       }
+
+       protected function fatalError( $msg, $exitCode = 1 ) {
+               $this->cleanUp();
+               parent::fatalError( $msg, $exitCode );
+       }
+
        /**
         * Basic YAML parser.
         *
index f6c55fc..ab273a5 100644 (file)
@@ -394,14 +394,6 @@ CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page);
 CREATE INDEX /*i*/si_title ON /*_*/searchindex (si_title);
 CREATE INDEX /*i*/si_text ON /*_*/searchindex (si_text);
 
-DROP TABLE IF EXISTS /*_*/transcache;
-CREATE TABLE /*_*/transcache (
-  tc_url varbinary(255) NOT NULL,
-  tc_contents text,
-  tc_time int NOT NULL
-) /*$wgDBTableOptions*/;
-CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url);
-
 DROP TABLE IF EXISTS /*_*/querycache_info;
 CREATE TABLE /*_*/querycache_info (
   qci_type varbinary(32) NOT NULL default '',
diff --git a/maintenance/sqlite/archives/patch-tc-timestamp.sql b/maintenance/sqlite/archives/patch-tc-timestamp.sql
deleted file mode 100644 (file)
index 5c09bf3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-UPDATE /*_*/transcache SET tc_time = strftime('%Y%m%d%H%M%S', datetime(tc_time, 'unixepoch'));
-
-INSERT INTO /*_*/updatelog (ul_key) VALUES ('convert transcache field');
diff --git a/maintenance/sqlite/archives/patch-transcache-fix-pk.sql b/maintenance/sqlite/archives/patch-transcache-fix-pk.sql
deleted file mode 100644 (file)
index 53f83e1..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE /*_*/transcache_tmp (
-  tc_url varbinary(255) NOT NULL PRIMARY KEY,
-  tc_contents text,
-  tc_time binary(14) NOT NULL
-) /*$wgDBTableOptions*/;
-
-INSERT INTO /*_*/transcache_tmp
-       SELECT * FROM /*_*/transcache;
-
-DROP TABLE /*_*/transcache;
-
-ALTER TABLE /*_*/transcache_tmp RENAME TO /*_*/transcache;
\ No newline at end of file
index 8cda4f9..245f35c 100644 (file)
@@ -687,6 +687,8 @@ CREATE TABLE /*_*/slots (
 
   -- The revision ID of the revision that originated the slot's content.
   -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+  -- TODO: Is that actually true? Rollback seems to violate it by setting
+  --  slot_origin to an older rev_id. Undeletions could result in the same situation.
   slot_origin bigint unsigned NOT NULL,
 
   PRIMARY KEY ( slot_revision_id, slot_role_id )
@@ -1582,16 +1584,6 @@ CREATE TABLE /*_*/objectcache (
 CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime);
 
 
---
--- Cache of interwiki transclusion
---
-CREATE TABLE /*_*/transcache (
-  tc_url varbinary(255) NOT NULL PRIMARY KEY,
-  tc_contents text,
-  tc_time binary(14) NOT NULL
-) /*$wgDBTableOptions*/;
-
-
 CREATE TABLE /*_*/logging (
   -- Log ID, for referring to this specific log entry, probably for deletion and such.
   log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
diff --git a/maintenance/tidyUpBug37714.php b/maintenance/tidyUpBug37714.php
deleted file mode 100644 (file)
index 0dd0341..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-require_once __DIR__ . '/Maintenance.php';
-
-/**
- * Fixes all rows affected by https://bugzilla.wikimedia.org/show_bug.cgi?id=37714
- */
-class TidyUpBug37714 extends Maintenance {
-       public function execute() {
-               // Search for all log entries which are about changing the visability of other log entries.
-               $result = $this->getDB( DB_REPLICA )->select(
-                       'logging',
-                       [ 'log_id', 'log_params' ],
-                       [
-                               'log_type' => [ 'suppress', 'delete' ],
-                               'log_action' => 'event',
-                               'log_namespace' => NS_SPECIAL,
-                               'log_title' => SpecialPage::getTitleFor( 'Log' )->getText()
-                       ],
-                       __METHOD__
-               );
-
-               foreach ( $result as $row ) {
-                       $ids = explode( ',', explode( "\n", $row->log_params )[0] );
-                       $result = $this->getDB( DB_REPLICA )->select( // Work out what log entries were changed here.
-                               'logging',
-                               'log_type',
-                               [ 'log_id' => $ids ],
-                               __METHOD__,
-                               'DISTINCT'
-                       );
-                       if ( $result->numRows() === 1 ) {
-                               // If there's only one type, the target title can be set to include it.
-                               $logTitle = SpecialPage::getTitleFor( 'Log', $result->current()->log_type )->getText();
-                               $this->output( 'Set log_title to "' . $logTitle . '" for log entry ' . $row->log_id . ".\n" );
-                               $this->getDB( DB_MASTER )->update(
-                                       'logging',
-                                       [ 'log_title' => $logTitle ],
-                                       [ 'log_id' => $row->log_id ],
-                                       __METHOD__
-                               );
-                               wfWaitForSlaves();
-                       }
-               }
-       }
-}
-
-$maintClass = TidyUpBug37714::class;
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/tidyUpT39714.php b/maintenance/tidyUpT39714.php
new file mode 100644 (file)
index 0000000..9dacdaa
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Fixes all rows affected by T39714
+ */
+class TidyUpT39714 extends Maintenance {
+       public function execute() {
+               // Search for all log entries which are about changing the visability of other log entries.
+               $result = $this->getDB( DB_REPLICA )->select(
+                       'logging',
+                       [ 'log_id', 'log_params' ],
+                       [
+                               'log_type' => [ 'suppress', 'delete' ],
+                               'log_action' => 'event',
+                               'log_namespace' => NS_SPECIAL,
+                               'log_title' => SpecialPage::getTitleFor( 'Log' )->getText()
+                       ],
+                       __METHOD__
+               );
+
+               foreach ( $result as $row ) {
+                       $ids = explode( ',', explode( "\n", $row->log_params )[0] );
+                       $result = $this->getDB( DB_REPLICA )->select( // Work out what log entries were changed here.
+                               'logging',
+                               'log_type',
+                               [ 'log_id' => $ids ],
+                               __METHOD__,
+                               'DISTINCT'
+                       );
+                       if ( $result->numRows() === 1 ) {
+                               // If there's only one type, the target title can be set to include it.
+                               $logTitle = SpecialPage::getTitleFor( 'Log', $result->current()->log_type )->getText();
+                               $this->output( 'Set log_title to "' . $logTitle . '" for log entry ' . $row->log_id . ".\n" );
+                               $this->getDB( DB_MASTER )->update(
+                                       'logging',
+                                       [ 'log_title' => $logTitle ],
+                                       [ 'log_id' => $row->log_id ],
+                                       __METHOD__
+                               );
+                               wfWaitForSlaves();
+                       }
+               }
+       }
+}
+
+$maintClass = TidyUpT39714::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
index adfc2f8..d75c151 100644 (file)
@@ -6,6 +6,7 @@
     "doc": "jsduck",
     "postdoc": "grunt copy:jsduck",
     "selenium": "bash ./tests/selenium/selenium.sh",
+    "selenium-daily": "npm run selenium-test",
     "selenium-test": "wdio ./tests/selenium/wdio.conf.js"
   },
   "devDependencies": {
index 264b5eb..0a60b08 100644 (file)
@@ -294,7 +294,7 @@ class profile_point {
        public function fmttime() {
                return sprintf( '%5.02f', $this->time );
        }
-};
+}
 
 function compare_point( profile_point $a, profile_point $b ) {
        // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
index c40ef93..14dab33 100644 (file)
@@ -286,6 +286,7 @@ return [
        ],
        'jquery.localize' => [
                'scripts' => 'resources/src/jquery/jquery.localize.js',
+               'deprecated' => 'Please use "jquery.i18n" instead.',
        ],
        'jquery.makeCollapsible' => [
                'dependencies' => [ 'jquery.makeCollapsible.styles' ],
index 1d0aa67..4491634 100644 (file)
                 */
                getName: function () {
                        if (
-                               $.inArray( this.namespace, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ||
+                               mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( this.namespace ) !== -1 ||
                                !this.title.length
                        ) {
                                return this.title;
index 9536b67..284b21a 100644 (file)
@@ -22,7 +22,6 @@
                mwLoaderTrack = mw.track,
                trackCallbacks = $.Callbacks( 'memory' ),
                trackHandlers = [],
-               hasOwn = Object.prototype.hasOwnProperty,
                queue;
 
        /**
         * @class mw.hook
         */
        mw.hook = ( function () {
-               var lists = {};
+               var lists = Object.create( null );
 
                /**
                 * Create an instance of mw.hook.
                 * @return {mw.hook}
                 */
                return function ( name ) {
-                       var list = hasOwn.call( lists, name ) ?
-                               lists[ name ] :
-                               lists[ name ] = $.Callbacks( 'memory' );
+                       var list = lists[ name ] || ( lists[ name ] = $.Callbacks( 'memory' ) );
 
                        return {
                                /**
index 6c4b80d..f4545de 100644 (file)
        function sortByProperty( array, prop, descending ) {
                var order = descending ? -1 : 1;
                return array.sort( function ( a, b ) {
+                       if ( a[ prop ] === undefined || b[ prop ] === undefined ) {
+                               // Sort undefined to the end, regardless of direction
+                               return a[ prop ] !== undefined ? -1 : b[ prop ] !== undefined ? 1 : 0;
+                       }
                        return a[ prop ] > b[ prop ] ? order : a[ prop ] < b[ prop ] ? -order : 0;
                } );
        }
         *
         * When invoked without arguments, prints all available reports.
         *
-        * @param {...string} [reports] One or more of "size", "css", or "store".
+        * @param {...string} [reports] One or more of "size", "css", "store", or "time".
         */
        inspect.runReports = function () {
                var reports = arguments.length > 0 ?
        };
 
        /**
+        * @private
         * @class mw.inspect.reports
         * @singleton
         */
                                } catch ( e ) {}
                        }
                        return [ stats ];
+               },
+
+               /**
+                * Generate a breakdown of all loaded modules and their time
+                * spent during initialisation (measured in milliseconds).
+                *
+                * This timing data is collected by mw.loader.profiler.
+                *
+                * @return {Object[]} Table rows
+                */
+               time: function () {
+                       var modules;
+
+                       if ( !mw.loader.profiler ) {
+                               mw.log.warn( 'mw.inspect: The time report requires $wgResourceLoaderEnableJSProfiler.' );
+                               return [];
+                       }
+
+                       modules = inspect.getLoadedModules()
+                               .map( function ( moduleName ) {
+                                       return mw.loader.profiler.getProfile( moduleName );
+                               } )
+                               .filter( function ( perf ) {
+                                       // Exclude modules that reached "ready" state without involvement from mw.loader.
+                                       // This is primarily styles-only as loaded via <link rel="stylesheet">.
+                                       return perf !== null;
+                               } );
+
+                       // Sort by total time spent, highest first.
+                       sortByProperty( modules, 'total', true );
+
+                       // Add human-readable strings
+                       modules.forEach( function ( module ) {
+                               module.totalInMs = module.total;
+                               module.total = module.totalInMs.toLocaleString() + ' ms';
+                       } );
+
+                       return modules;
                }
        };
 
index cb4edc1..676ddb0 100644 (file)
                 * @return {boolean}
                 */
                isCascadeableLevel: function ( level ) {
-                       return $.inArray( level, mw.config.get( 'wgCascadeableLevels' ) ) !== -1;
+                       var cascadeableLevels = mw.config.get( 'wgCascadeableLevels' );
+
+                       if ( !Array.isArray( cascadeableLevels ) ) {
+                               return false;
+                       }
+
+                       return cascadeableLevels.indexOf( level ) !== -1;
                },
 
                /**
index aa86a4b..a163a3d 100644 (file)
@@ -2,7 +2,7 @@
        'use strict';
 
        var notification,
-               // The #mw-notification-area div that all notifications are contained inside.
+               // The .mw-notification-area div that all notifications are contained inside.
                $area,
                // Number of open notification boxes at any time
                openNotificationCount = 0,
 
                // Write to the DOM:
                // Prepend the notification area to the content area and save its object.
+               // The ID attribute here is deprecated.
                $area = $( '<div id="mw-notification-area" class="mw-notification-area mw-notification-area-layout"></div>' )
                        // Pause auto-hide timers when the mouse is in the notification area.
                        .on( {
index 52abb30..beac624 100644 (file)
                                return widget.apiCheckValid();
                        } );
                        $.when.apply( $, promises ).then( function () {
-                               that.apiIsValid = $.inArray( false, arguments ) === -1;
+                               that.apiIsValid = Array.prototype.indexOf.call( arguments, false ) === -1;
                                if ( that.getOutlineItem() ) {
                                        that.getOutlineItem().setIcon( that.apiIsValid || suppressErrors ? null : 'alert' );
                                        that.getOutlineItem().setIconTitle(
index b2985d1..5e96485 100644 (file)
@@ -2,7 +2,7 @@
  * @class mw.user
  * @singleton
  */
-/* global Uint32Array */
+/* global Uint16Array */
 ( function ( mw, $ ) {
        var userInfoPromise, pageviewRandomId;
 
                 * mobile usages of this code is probably higher.
                 *
                 * Rationale:
-                * We need about 64 bits to make sure that probability of collision
-                * on 500 million (5*10^8) is <= 1%
-                * See https://en.wikipedia.org/wiki/Birthday_problem#Probability_table
+                * We need about 80 bits to make sure that probability of collision
+                * on 155 billion  is <= 1%
                 *
-                * @return {string} 64 bit integer in hex format, padded
+                * See https://en.wikipedia.org/wiki/Birthday_attack#Mathematics
+                * n(p;H) = n(0.01,2^80)= sqrt (2 * 2^80 * ln(1/(1-0.01)))
+
+                * @return {string} 80 bit integer in hex format, padded
                 */
                generateRandomSessionId: function () {
                        var rnds, i,
-                               hexRnds = new Array( 2 ),
                                // Support: IE 11
                                crypto = window.crypto || window.msCrypto;
 
-                       if ( crypto && crypto.getRandomValues && typeof Uint32Array === 'function' ) {
-                               // Fill an array with 2 random values, each of which is 32 bits.
-                               // Note that Uint32Array is array-like but does not implement Array.
-                               rnds = new Uint32Array( 2 );
+                       if ( crypto && crypto.getRandomValues && typeof Uint16Array === 'function' ) {
+                               // Fill an array with 5 random values, each of which is 16 bits.
+                               // Note that Uint16Array is array-like but does not implement Array.
+                               rnds = new Uint16Array( 5 );
                                crypto.getRandomValues( rnds );
                        } else {
-                               rnds = [
-                                       Math.floor( Math.random() * 0x100000000 ),
-                                       Math.floor( Math.random() * 0x100000000 )
-                               ];
-                       }
-                       // Convert number to a string with 16 hex characters
-                       for ( i = 0; i < 2; i++ ) {
-                               // Add 0x100000000 before converting to hex and strip the extra character
-                               // after converting to keep the leading zeros.
-                               hexRnds[ i ] = ( rnds[ i ] + 0x100000000 ).toString( 16 ).slice( 1 );
+                               rnds = new Array( 5 );
+                               // 0x10000 is 2^16 so the operation below will return a number
+                               // between 2^16 and zero
+                               for ( i = 0; i < 5; i++ ) {
+                                       rnds[ i ] = Math.floor( Math.random() * 0x10000 );
+                               }
                        }
 
+                       // Convert the 5 16bit-numbers into 20 characters (4 hex per 16 bits).
                        // Concatenation of two random integers with entropy n and m
-                       // returns a string with entropy n+m if those strings are independent
-                       return hexRnds.join( '' );
+                       // returns a string with entropy n+m if those strings are independent.
+                       // Tested that below code is faster than array + loop + join.
+                       return ( rnds[ 0 ] + 0x10000 ).toString( 16 ).slice( 1 ) +
+                               ( rnds[ 1 ] + 0x10000 ).toString( 16 ).slice( 1 ) +
+                               ( rnds[ 2 ] + 0x10000 ).toString( 16 ).slice( 1 ) +
+                               ( rnds[ 3 ] + 0x10000 ).toString( 16 ).slice( 1 ) +
+                               ( rnds[ 4 ] + 0x10000 ).toString( 16 ).slice( 1 );
                },
 
                /**
@@ -76,7 +79,7 @@
                 * cached within this class (also known as a page view token).
                 *
                 * @since 1.32
-                * @return {string} 64 bit integer in hex format, padded
+                * @return {string} 80 bit integer in hex format, padded
                 */
                getPageviewToken: function () {
                        if ( !pageviewRandomId ) {
index f9a69b8..f927aad 100644 (file)
@@ -7,7 +7,7 @@
  * @alternateClassName mediaWiki
  * @singleton
  */
-/* global $VARS */
+/* global $VARS, $CODE */
 
 ( function () {
        'use strict';
                         * @class
                         */
                        function StringSet() {
-                               this.set = {};
+                               this.set = Object.create( null );
                        }
                        StringSet.prototype.add = function ( value ) {
                                this.set[ value ] = true;
                        };
                        StringSet.prototype.has = function ( value ) {
-                               return hasOwn.call( this.set, value );
+                               return value in this.set;
                        };
                        return StringSet;
                }() );
         *  copied in one direction only. Changes to globals do not reflect in the map.
         */
        function Map( global ) {
-               this.values = {};
+               this.values = Object.create( null );
                if ( global === true ) {
                        // Override #set to also set the global variable
                        this.set = function ( selection, value ) {
                                results = {};
                                for ( i = 0; i < selection.length; i++ ) {
                                        if ( typeof selection[ i ] === 'string' ) {
-                                               results[ selection[ i ] ] = hasOwn.call( this.values, selection[ i ] ) ?
+                                               results[ selection[ i ] ] = selection[ i ] in this.values ?
                                                        this.values[ selection[ i ] ] :
                                                        fallback;
                                        }
                        }
 
                        if ( typeof selection === 'string' ) {
-                               return hasOwn.call( this.values, selection ) ?
+                               return selection in this.values ?
                                        this.values[ selection ] :
                                        fallback;
                        }
                        var i;
                        if ( Array.isArray( selection ) ) {
                                for ( i = 0; i < selection.length; i++ ) {
-                                       if ( typeof selection[ i ] !== 'string' || !hasOwn.call( this.values, selection[ i ] ) ) {
+                                       if ( typeof selection[ i ] !== 'string' || !( selection[ i ] in this.values ) ) {
                                                return false;
                                        }
                                }
                                return true;
                        }
-                       return typeof selection === 'string' && hasOwn.call( this.values, selection );
+                       return typeof selection === 'string' && selection in this.values;
                }
        };
 
                                 */
                                marker = document.querySelector( 'meta[name="ResourceLoaderDynamicStyles"]' ),
 
-                               // For addEmbeddedCSS()
-                               cssBuffer = '',
-                               cssBufferTimer = null,
-                               cssCallbacks = [],
+                               // For #addEmbeddedCSS()
+                               nextCssBuffer,
                                rAF = window.requestAnimationFrame || setTimeout;
 
                        /**
                                return el;
                        }
 
+                       /**
+                        * @private
+                        * @param {Object} cssBuffer
+                        */
+                       function flushCssBuffer( cssBuffer ) {
+                               var i;
+                               // Mark this object as inactive now so that further calls to addEmbeddedCSS() from
+                               // the callbacks go to a new buffer instead of this one (T105973)
+                               cssBuffer.active = false;
+                               newStyleTag( cssBuffer.cssText, marker );
+                               for ( i = 0; i < cssBuffer.callbacks.length; i++ ) {
+                                       cssBuffer.callbacks[ i ]();
+                               }
+                       }
+
                        /**
                         * Add a bit of CSS text to the current browser page.
                         *
-                        * The CSS will be appended to an existing ResourceLoader-created `<style>` tag
-                        * or create a new one based on whether the given `cssText` is safe for extension.
+                        * The creation and insertion of the `<style>` element is debounced for two reasons:
+                        *
+                        * - Performing the insertion before the next paint round via requestAnimationFrame
+                        *   avoids forced or wasted style recomputations, which are expensive in browsers.
+                        * - Reduce how often new stylesheets are inserted by letting additional calls to this
+                        *   function accumulate into a buffer for at least one JavaScript tick. Modules are
+                        *   received from the server in batches, which means there is likely going to be many
+                        *   calls to this function in a row within the same tick / the same call stack.
+                        *   See also T47810.
                         *
                         * @private
-                        * @param {string} [cssText=cssBuffer] If called without cssText,
-                        *  the internal buffer will be inserted instead.
-                        * @param {Function} [callback]
+                        * @param {string} cssText CSS text to be added in a `<style>` tag.
+                        * @param {Function} callback Called after the insertion has occurred
                         */
                        function addEmbeddedCSS( cssText, callback ) {
-                               function fireCallbacks() {
-                                       var i,
-                                               oldCallbacks = cssCallbacks;
-                                       // Reset cssCallbacks variable so it's not polluted by any calls to
-                                       // addEmbeddedCSS() from one of the callbacks (T105973)
-                                       cssCallbacks = [];
-                                       for ( i = 0; i < oldCallbacks.length; i++ ) {
-                                               oldCallbacks[ i ]();
-                                       }
-                               }
-
-                               if ( callback ) {
-                                       cssCallbacks.push( callback );
+                               // Create a buffer if:
+                               // - We don't have one yet.
+                               // - The previous one is closed.
+                               // - The next CSS chunk syntactically needs to be at the start of a stylesheet (T37562).
+                               if ( !nextCssBuffer || nextCssBuffer.active === false || cssText.slice( 0, '@import'.length ) === '@import' ) {
+                                       nextCssBuffer = {
+                                               cssText: '',
+                                               callbacks: [],
+                                               active: null
+                                       };
                                }
 
-                               // Yield once before creating the <style> tag. This lets multiple stylesheets
-                               // accumulate into one buffer, allowing us to reduce how often new stylesheets
-                               // are inserted in the browser. Appending a stylesheet and waiting for the
-                               // browser to repaint is fairly expensive. (T47810)
-                               if ( cssText ) {
-                                       // Don't extend the buffer if the item needs its own stylesheet.
-                                       // Keywords like `@import` are only valid at the start of a stylesheet (T37562).
-                                       if ( !cssBuffer || cssText.slice( 0, '@import'.length ) !== '@import' ) {
-                                               // Linebreak for somewhat distinguishable sections
-                                               cssBuffer += '\n' + cssText;
-                                               if ( !cssBufferTimer ) {
-                                                       cssBufferTimer = rAF( function () {
-                                                               // Wrap in anonymous function that takes no arguments
-                                                               // Support: Firefox < 13
-                                                               // Firefox 12 has non-standard behaviour of passing a number
-                                                               // as first argument to a setTimeout callback.
-                                                               // http://benalman.com/news/2009/07/the-mysterious-firefox-settime/
-                                                               addEmbeddedCSS();
-                                                       } );
-                                               }
-                                               return;
-                                       }
+                               // Linebreak for somewhat distinguishable sections
+                               nextCssBuffer.cssText += '\n' + cssText;
+                               nextCssBuffer.callbacks.push( callback );
 
-                               // This is a scheduled flush for the buffer
-                               } else {
-                                       cssBufferTimer = null;
-                                       cssText = cssBuffer;
-                                       cssBuffer = '';
+                               if ( nextCssBuffer.active === null ) {
+                                       nextCssBuffer.active = true;
+                                       // The flushCssBuffer callback has its parameter bound by reference, which means
+                                       // 1) We can still extend the buffer from our object reference after this point.
+                                       // 2) We can safely re-assign the variable (not the object) to start a new buffer.
+                                       rAF( flushCssBuffer.bind( null, nextCssBuffer ) );
                                }
-
-                               newStyleTag( cssText, marker );
-
-                               fireCallbacks();
                        }
 
                        /**
                         * See also #work().
                         *
                         * @private
-                        * @param {string|string[]} dependencies Module name or array of string module names
+                        * @param {string[]} dependencies Array of module names in the registry
                         * @param {Function} [ready] Callback to execute when all dependencies are ready
                         * @param {Function} [error] Callback to execute when any dependency fails
                         */
                        function enqueue( dependencies, ready, error ) {
-                               // Allow calling by single module name
-                               if ( typeof dependencies === 'string' ) {
-                                       dependencies = [ dependencies ];
-                               }
-
                                if ( allReady( dependencies ) ) {
                                        // Run ready immediately
                                        if ( ready !== undefined ) {
                                                ready();
                                        }
-
                                        return;
                                }
 
                                                        dependencies
                                                );
                                        }
-
                                        return;
                                }
 
                                        jobs.push( {
                                                // Narrow down the list to modules that are worth waiting for
                                                dependencies: dependencies.filter( function ( module ) {
-                                                       var state = mw.loader.getState( module );
+                                                       var state = registry[ module ].state;
                                                        return state === 'registered' || state === 'loaded' || state === 'loading' || state === 'executing';
                                                } ),
                                                ready: ready,
                                }
 
                                dependencies.forEach( function ( module ) {
-                                       var state = mw.loader.getState( module );
                                        // Only queue modules that are still in the initial 'registered' state
                                        // (not ones already loading, ready or error).
-                                       if ( state === 'registered' && queue.indexOf( module ) === -1 ) {
+                                       if ( registry[ module ].state === 'registered' && queue.indexOf( module ) === -1 ) {
                                                // Private modules must be embedded in the page. Don't bother queuing
                                                // these as the server will deny them anyway (T101806).
                                                if ( registry[ module ].group === 'private' ) {
                         * @param {string} module Module name to execute
                         */
                        function execute( module ) {
-                               var key, value, media, i, urls, cssHandle, checkCssHandles, runScript,
-                                       cssHandlesRegistered = false;
+                               var key, value, media, i, urls, cssHandle, siteDeps, siteDepErr, runScript,
+                                       cssPending = 0;
 
                                if ( !hasOwn.call( registry, module ) ) {
                                        throw new Error( 'Module has not been registered yet: ' + module );
                                }
 
                                registry[ module ].state = 'executing';
+                               $CODE.profileExecuteStart();
 
                                runScript = function () {
                                        var script, markModuleReady, nestedAddScript;
 
+                                       $CODE.profileScriptStart();
                                        script = registry[ module ].script;
                                        markModuleReady = function () {
+                                               $CODE.profileScriptEnd();
                                                registry[ module ].state = 'ready';
                                                handlePending( module );
                                        };
                                                // Use mw.track instead of mw.log because these errors are common in production mode
                                                // (e.g. undefined variable), and mw.log is only enabled in debug mode.
                                                registry[ module ].state = 'error';
+                                               $CODE.profileScriptEnd();
                                                mw.trackError( 'resourceloader.exception', {
                                                        exception: e, module:
                                                        module, source: 'module-execute'
                                        mw.templates.set( module, registry[ module ].templates );
                                }
 
-                               // Make sure we don't run the scripts until all stylesheet insertions have completed.
-                               ( function () {
-                                       var pending = 0;
-                                       checkCssHandles = function () {
-                                               var ex, dependencies;
-                                               // cssHandlesRegistered ensures we don't take off too soon, e.g. when
-                                               // one of the cssHandles is fired while we're still creating more handles.
-                                               if ( cssHandlesRegistered && pending === 0 && runScript ) {
-                                                       if ( module === 'user' ) {
-                                                               // Implicit dependency on the site module. Not real dependency because
-                                                               // it should run after 'site' regardless of whether it succeeds or fails.
-                                                               // Note: This is a simplified version of mw.loader.using(), inlined here
-                                                               // as using() depends on jQuery (T192623).
-                                                               try {
-                                                                       dependencies = resolve( [ 'site' ] );
-                                                               } catch ( e ) {
-                                                                       ex = e;
-                                                                       runScript();
-                                                               }
-                                                               if ( ex === undefined ) {
-                                                                       enqueue( dependencies, runScript, runScript );
-                                                               }
-                                                       } else {
-                                                               runScript();
-                                                       }
-                                                       runScript = undefined; // Revoke
+                               // Adding of stylesheets is asynchronous via addEmbeddedCSS().
+                               // The below function uses a counting semaphore to make sure we don't call
+                               // runScript() until after this module's stylesheets have been inserted
+                               // into the DOM.
+                               cssHandle = function () {
+                                       // Increase semaphore, when creating a callback for addEmbeddedCSS.
+                                       cssPending++;
+                                       return function () {
+                                               var runScriptCopy;
+                                               // Decrease semaphore, when said callback is invoked.
+                                               cssPending--;
+                                               if ( cssPending === 0 ) {
+                                                       // Paranoia:
+                                                       // This callback is exposed to addEmbeddedCSS, which is outside the execute()
+                                                       // function and is not concerned with state-machine integrity. In turn,
+                                                       // addEmbeddedCSS() actually exposes stuff further into the browser (rAF).
+                                                       // If increment and decrement callbacks happen in the wrong order, or start
+                                                       // again afterwards, then this branch could be reached multiple times.
+                                                       // To protect the integrity of the state-machine, prevent that from happening
+                                                       // by making runScript() cannot be called more than once.  We store a private
+                                                       // reference when we first reach this branch, then deference the original, and
+                                                       // call our reference to it.
+                                                       runScriptCopy = runScript;
+                                                       runScript = undefined;
+                                                       runScriptCopy();
                                                }
                                        };
-                                       cssHandle = function () {
-                                               var check = checkCssHandles;
-                                               pending++;
-                                               return function () {
-                                                       if ( check ) {
-                                                               pending--;
-                                                               check();
-                                                               check = undefined; // Revoke
-                                                       }
-                                               };
-                                       };
-                               }() );
+                               };
 
                                // Process styles (see also mw.loader.implement)
                                // * back-compat: { <media>: css }
                                        }
                                }
 
-                               // Kick off.
-                               cssHandlesRegistered = true;
-                               checkCssHandles();
+                               // End profiling of execute()-self before we call runScript(),
+                               // which we want to measure separately without overlap.
+                               $CODE.profileExecuteEnd();
+
+                               if ( module === 'user' ) {
+                                       // Implicit dependency on the site module. Not a real dependency because it should
+                                       // run after 'site' regardless of whether it succeeds or fails.
+                                       // Note: This is a simplified version of mw.loader.using(), inlined here because
+                                       // mw.loader.using() is part of mediawiki.base (depends on jQuery; T192623).
+                                       try {
+                                               siteDeps = resolve( [ 'site' ] );
+                                       } catch ( e ) {
+                                               siteDepErr = e;
+                                               runScript();
+                                       }
+                                       if ( siteDepErr === undefined ) {
+                                               enqueue( siteDeps, runScript, runScript );
+                                       }
+                               } else if ( cssPending === 0 ) {
+                                       // Regular module without styles
+                                       runScript();
+                               }
+                               // else: runScript will get called via cssHandle()
                        }
 
                        function sortQuery( o ) {
                         * @param {string[]} batch
                         */
                        function batchRequest( batch ) {
-                               var reqBase, splits, maxQueryLength, b, bSource, bGroup, bSourceGroup,
+                               var reqBase, splits, maxQueryLength, b, bSource, bGroup,
                                        source, group, i, modules, sourceLoadScript,
                                        currReqBase, currReqBaseLength, moduleMap, currReqModules, l,
                                        lastDotIndex, prefix, suffix, bytesAdded;
                                maxQueryLength = mw.config.get( 'wgResourceLoaderMaxQueryLength', 2000 );
 
                                // Split module list by source and by group.
-                               splits = {};
+                               splits = Object.create( null );
                                for ( b = 0; b < batch.length; b++ ) {
                                        bSource = registry[ batch[ b ] ].source;
                                        bGroup = registry[ batch[ b ] ].group;
-                                       if ( !hasOwn.call( splits, bSource ) ) {
-                                               splits[ bSource ] = {};
+                                       if ( !splits[ bSource ] ) {
+                                               splits[ bSource ] = Object.create( null );
                                        }
-                                       if ( !hasOwn.call( splits[ bSource ], bGroup ) ) {
+                                       if ( !splits[ bSource ][ bGroup ] ) {
                                                splits[ bSource ][ bGroup ] = [];
                                        }
-                                       bSourceGroup = splits[ bSource ][ bGroup ];
-                                       bSourceGroup.push( batch[ b ] );
+                                       splits[ bSource ][ bGroup ].push( batch[ b ] );
                                }
 
                                for ( source in splits ) {
-
                                        sourceLoadScript = sources[ source ];
 
                                        for ( group in splits[ source ] ) {
                                                // We may need to split up the request to honor the query string length limit,
                                                // so build it piece by piece.
                                                l = currReqBaseLength;
-                                               moduleMap = {}; // { prefix: [ suffixes ] }
+                                               moduleMap = Object.create( null ); // { prefix: [ suffixes ] }
                                                currReqModules = [];
 
                                                for ( i = 0; i < modules.length; i++ ) {
                                                        // If lastDotIndex is -1, substr() returns an empty string
                                                        prefix = modules[ i ].substr( 0, lastDotIndex );
                                                        suffix = modules[ i ].slice( lastDotIndex + 1 );
-                                                       bytesAdded = hasOwn.call( moduleMap, prefix ) ?
+                                                       bytesAdded = moduleMap[ prefix ] ?
                                                                suffix.length + 3 : // '%2C'.length == 3
                                                                modules[ i ].length + 3; // '%7C'.length == 3
 
                                                                doRequest();
                                                                // .. and start again.
                                                                l = currReqBaseLength;
-                                                               moduleMap = {};
+                                                               moduleMap = Object.create( null );
                                                                currReqModules = [];
 
                                                                mw.track( 'resourceloader.splitRequest', { maxQueryLength: maxQueryLength } );
                                                        }
-                                                       if ( !hasOwn.call( moduleMap, prefix ) ) {
+                                                       if ( !moduleMap[ prefix ] ) {
                                                                moduleMap[ prefix ] = [];
                                                        }
                                                        l += bytesAdded;
                                 *  a list of arguments compatible with this method
                                 * @param {string|number} version Module version hash (falls backs to empty string)
                                 *  Can also be a number (timestamp) for compatibility with MediaWiki 1.25 and earlier.
-                                * @param {string|Array} dependencies One string or array of strings of module
-                                *  names on which this module depends.
+                                * @param {string[]} [dependencies] Array of module names on which this module depends.
                                 * @param {string} [group=null] Group which the module is in
                                 * @param {string} [source='local'] Name of the source
                                 * @param {string} [skip=null] Script body of the skip function
                                 */
                                register: function ( module, version, dependencies, group, source, skip ) {
-                                       var i, deps;
+                                       var i;
                                        // Allow multiple registration
                                        if ( typeof module === 'object' ) {
                                                resolveIndexedDependencies( module );
                                        if ( hasOwn.call( registry, module ) ) {
                                                throw new Error( 'module already registered: ' + module );
                                        }
-                                       if ( typeof dependencies === 'string' ) {
-                                               // A single module name
-                                               deps = [ dependencies ];
-                                       } else if ( typeof dependencies === 'object' ) {
-                                               // Array of module names
-                                               deps = dependencies;
-                                       }
                                        // List the module as registered
                                        registry[ module ] = {
                                                // Exposed to execute() for mw.loader.implement() closures.
                                                module: {
                                                        exports: {}
                                                },
-                                               version: version !== undefined ? String( version ) : '',
-                                               dependencies: deps || [],
+                                               version: String( version || '' ),
+                                               dependencies: dependencies || [],
                                                group: typeof group === 'string' ? group : null,
                                                source: typeof source === 'string' ? source : 'local',
                                                state: 'registered',
                                /**
                                 * Change the state of one or more modules.
                                 *
-                                * @param {Object|string} modules Object of module name/state pairs
+                                * @param {Object} modules Object of module name/state pairs
                                 */
                                state: function ( modules ) {
                                        var module, state;
                                 * modules and cache each of them separately, using each module's versioning scheme
                                 * to determine when the cache should be invalidated.
                                 *
+                                * @private
                                 * @singleton
                                 * @class mw.loader.store
                                 */
                                         * @return {string} String of concatenated vary conditions.
                                         */
                                        getVary: function () {
-                                               return [
-                                                       mw.config.get( 'skin' ),
-                                                       mw.config.get( 'wgResourceLoaderStorageVersion' ),
-                                                       mw.config.get( 'wgUserLanguage' )
-                                               ].join( ':' );
+                                               return mw.config.get( 'skin' ) + ':' +
+                                                       mw.config.get( 'wgResourceLoaderStorageVersion' ) + ':' +
+                                                       mw.config.get( 'wgUserLanguage' );
                                        },
 
                                        /**
                                        init: function () {
                                                var raw, data;
 
-                                               if ( mw.loader.store.enabled !== null ) {
+                                               if ( this.enabled !== null ) {
                                                        // Init already ran
                                                        return;
                                                }
                                                        !mw.config.get( 'wgResourceLoaderStorageEnabled' )
                                                ) {
                                                        // Clear any previous store to free up space. (T66721)
-                                                       mw.loader.store.clear();
-                                                       mw.loader.store.enabled = false;
+                                                       this.clear();
+                                                       this.enabled = false;
                                                        return;
                                                }
                                                if ( mw.config.get( 'debug' ) ) {
                                                        // Disable module store in debug mode
-                                                       mw.loader.store.enabled = false;
+                                                       this.enabled = false;
                                                        return;
                                                }
 
                                                try {
-                                                       raw = localStorage.getItem( mw.loader.store.getStoreKey() );
+                                                       // This a string we stored, or `null` if the key does not (yet) exist.
+                                                       raw = localStorage.getItem( this.getStoreKey() );
                                                        // If we get here, localStorage is available; mark enabled
-                                                       mw.loader.store.enabled = true;
+                                                       this.enabled = true;
+                                                       // If null, JSON.parse() will cast to string and re-parse, still null.
                                                        data = JSON.parse( raw );
-                                                       if ( data && typeof data.items === 'object' && data.vary === mw.loader.store.getVary() ) {
-                                                               mw.loader.store.items = data.items;
+                                                       if ( data && typeof data.items === 'object' && data.vary === this.getVary() ) {
+                                                               this.items = data.items;
                                                                return;
                                                        }
                                                } catch ( e ) {
                                                        } );
                                                }
 
+                                               // If we get here, one of four things happened:
+                                               //
+                                               // 1. localStorage did not contain our store key.
+                                               //    This means `raw` is `null`, and we're on a fresh page view (cold cache).
+                                               //    The store was enabled, and `items` starts fresh.
+                                               //
+                                               // 2. localStorage contained parseable data under our store key,
+                                               //    but it's not applicable to our current context (see getVary).
+                                               //    The store was enabled, and `items` starts fresh.
+                                               //
+                                               // 3. JSON.parse threw (localStorage contained corrupt data).
+                                               //    This means `raw` contains a string.
+                                               //    The store was enabled, and `items` starts fresh.
+                                               //
+                                               // 4. localStorage threw (disabled or otherwise unavailable).
+                                               //    This means `raw` was never assigned.
+                                               //    We will disable the store below.
                                                if ( raw === undefined ) {
                                                        // localStorage failed; disable store
-                                                       mw.loader.store.enabled = false;
-                                               } else {
-                                                       mw.loader.store.update();
+                                                       this.enabled = false;
                                                }
                                        },
 
                                        get: function ( module ) {
                                                var key;
 
-                                               if ( !mw.loader.store.enabled ) {
+                                               if ( !this.enabled ) {
                                                        return false;
                                                }
 
                                                key = getModuleKey( module );
-                                               if ( key in mw.loader.store.items ) {
-                                                       mw.loader.store.stats.hits++;
-                                                       return mw.loader.store.items[ key ];
+                                               if ( key in this.items ) {
+                                                       this.stats.hits++;
+                                                       return this.items[ key ];
                                                }
-                                               mw.loader.store.stats.misses++;
+                                               this.stats.misses++;
                                                return false;
                                        },
 
                                         *
                                         * @param {string} module Module name
                                         * @param {Object} descriptor The module's descriptor as set in the registry
-                                        * @return {boolean} Module was set
                                         */
                                        set: function ( module, descriptor ) {
                                                var args, key, src;
 
-                                               if ( !mw.loader.store.enabled ) {
-                                                       return false;
+                                               if ( !this.enabled ) {
+                                                       return;
                                                }
 
                                                key = getModuleKey( module );
 
                                                if (
                                                        // Already stored a copy of this exact version
-                                                       key in mw.loader.store.items ||
+                                                       key in this.items ||
                                                        // Module failed to load
                                                        descriptor.state !== 'ready' ||
                                                        // Unversioned, private, or site-/user-specific
                                                                descriptor.templates ].indexOf( undefined ) !== -1
                                                ) {
                                                        // Decline to store
-                                                       return false;
+                                                       return;
                                                }
 
                                                try {
                                                                JSON.stringify( descriptor.messages ),
                                                                JSON.stringify( descriptor.templates )
                                                        ];
-                                                       // Attempted workaround for a possible Opera bug (bug T59567).
-                                                       // This regex should never match under sane conditions.
-                                                       if ( /^\s*\(/.test( args[ 1 ] ) ) {
-                                                               args[ 1 ] = 'function' + args[ 1 ];
-                                                               mw.trackError( 'resourceloader.assert', { source: 'bug-T59567' } );
-                                                       }
                                                } catch ( e ) {
                                                        mw.trackError( 'resourceloader.exception', {
                                                                exception: e,
                                                                source: 'store-localstorage-json'
                                                        } );
-                                                       return false;
+                                                       return;
                                                }
 
                                                src = 'mw.loader.implement(' + args.join( ',' ) + ');';
-                                               if ( src.length > mw.loader.store.MODULE_SIZE_MAX ) {
-                                                       return false;
+                                               if ( src.length > this.MODULE_SIZE_MAX ) {
+                                                       return;
                                                }
-                                               mw.loader.store.items[ key ] = src;
-                                               mw.loader.store.update();
-                                               return true;
+                                               this.items[ key ] = src;
+                                               this.update();
                                        },
 
                                        /**
                                         * Iterate through the module store, removing any item that does not correspond
                                         * (in name and version) to an item in the module registry.
-                                        *
-                                        * @return {boolean} Store was pruned
                                         */
                                        prune: function () {
                                                var key, module;
 
-                                               if ( !mw.loader.store.enabled ) {
-                                                       return false;
-                                               }
-
-                                               for ( key in mw.loader.store.items ) {
+                                               for ( key in this.items ) {
                                                        module = key.slice( 0, key.indexOf( '@' ) );
                                                        if ( getModuleKey( module ) !== key ) {
-                                                               mw.loader.store.stats.expired++;
-                                                               delete mw.loader.store.items[ key ];
-                                                       } else if ( mw.loader.store.items[ key ].length > mw.loader.store.MODULE_SIZE_MAX ) {
+                                                               this.stats.expired++;
+                                                               delete this.items[ key ];
+                                                       } else if ( this.items[ key ].length > this.MODULE_SIZE_MAX ) {
                                                                // This value predates the enforcement of a size limit on cached modules.
-                                                               delete mw.loader.store.items[ key ];
+                                                               delete this.items[ key ];
                                                        }
                                                }
-                                               return true;
                                        },
 
                                        /**
                                         * Clear the entire module store right now.
                                         */
                                        clear: function () {
-                                               mw.loader.store.items = {};
+                                               this.items = {};
                                                try {
-                                                       localStorage.removeItem( mw.loader.store.getStoreKey() );
-                                               } catch ( ignored ) {}
+                                                       localStorage.removeItem( this.getStoreKey() );
+                                               } catch ( e ) {}
                                        },
 
                                        /**
                                         * Sync in-memory store back to localStorage.
                                         *
-                                        * This function debounces updates. When called with a flush already pending,
-                                        * the call is coalesced into the pending update. The call to
-                                        * localStorage.setItem will be naturally deferred until the page is quiescent.
+                                        * This function debounces updates. When called with a flush already pending, the
+                                        * scheduled flush is postponed. The call to localStorage.setItem will be keep
+                                        * being deferred until the page is quiescent for 2 seconds.
                                         *
                                         * Because localStorage is shared by all pages from the same origin, if multiple
                                         * pages are loaded with different module sets, the possibility exists that
-                                        * modules saved by one page will be clobbered by another. But the impact would
-                                        * be minor and the problem would be corrected by subsequent page views.
+                                        * modules saved by one page will be clobbered by another. The only impact of this
+                                        * is minor (merely a less efficient cache use) and the problem would be corrected
+                                        * by subsequent page views.
                                         *
                                         * @method
                                         */
                                        update: ( function () {
-                                               var hasPendingWrite = false;
+                                               var timer, hasPendingWrites = false;
 
                                                function flushWrites() {
                                                        var data, key;
-                                                       if ( !hasPendingWrite || !mw.loader.store.enabled ) {
+                                                       if ( !mw.loader.store.enabled ) {
                                                                return;
                                                        }
 
                                                                } );
                                                        }
 
-                                                       hasPendingWrite = false;
+                                                       hasPendingWrites = false;
                                                }
 
-                                               return function () {
-                                                       if ( !hasPendingWrite ) {
-                                                               hasPendingWrite = true;
+                                               function request() {
+                                                       // If another mw.loader.store.set()/update() call happens in the narrow
+                                                       // time window between requestIdleCallback() and flushWrites firing, ignore it.
+                                                       // It'll be saved by the already-scheduled flush.
+                                                       if ( !hasPendingWrites ) {
+                                                               hasPendingWrites = true;
                                                                mw.requestIdleCallback( flushWrites );
                                                        }
+                                               }
+
+                                               return function () {
+                                                       // Cancel the previous timer (if it hasn't fired yet)
+                                                       clearTimeout( timer );
+                                                       timer = setTimeout( request, 2000 );
                                                };
                                        }() )
                                }
diff --git a/resources/src/startup/profiler.js b/resources/src/startup/profiler.js
new file mode 100644 (file)
index 0000000..5e9b6ab
--- /dev/null
@@ -0,0 +1,81 @@
+/*!
+ * Augment mw.loader to facilitate module-level profiling.
+ *
+ * @author Timo Tijhof
+ * @since 1.32
+ */
+/* global mw */
+( function () {
+       'use strict';
+
+       var moduleTimes = Object.create( null );
+
+       /**
+        * Private hooks inserted into mw.loader code if MediaWiki configuration
+        * `$wgResourceLoaderEnableJSProfiler` is `true`.
+        *
+        * To use this data, run `mw.inspect( 'time' )` from the browser console.
+        * See mw#inspect().
+        *
+        * @private
+        * @class
+        * @singleton
+        */
+       mw.loader.profiler = {
+               onExecuteStart: function ( moduleName ) {
+                       var time = performance.now();
+                       if ( moduleTimes[ moduleName ] ) {
+                               throw new Error( 'Unexpected perf record for "' + moduleName + '".' );
+                       }
+                       moduleTimes[ moduleName ] = {
+                               executeStart: time,
+                               executeEnd: null,
+                               scriptStart: null,
+                               scriptEnd: null
+                       };
+               },
+               onExecuteEnd: function ( moduleName ) {
+                       var time = performance.now();
+                       moduleTimes[ moduleName ].executeEnd = time;
+               },
+               onScriptStart: function ( moduleName ) {
+                       var time = performance.now();
+                       moduleTimes[ moduleName ].scriptStart = time;
+               },
+               onScriptEnd: function ( moduleName ) {
+                       var time = performance.now();
+                       moduleTimes[ moduleName ].scriptEnd = time;
+               },
+
+               /**
+                * For internal use by inspect.reports#time.
+                *
+                * @private
+                * @param {string} moduleName
+                * @return {Object|null}
+                * @throws {Error} If the perf record is incomplete.
+                */
+               getProfile: function ( moduleName ) {
+                       var times, key, execute, script, total;
+                       times = moduleTimes[ moduleName ];
+                       if ( !times ) {
+                               return null;
+                       }
+                       for ( key in times ) {
+                               if ( times[ key ] === null ) {
+                                       throw new Error( 'Incomplete perf record for "' + moduleName + '".', times );
+                               }
+                       }
+                       execute = times.executeEnd - times.executeStart;
+                       script = times.scriptEnd - times.scriptStart;
+                       total = execute + script;
+                       return {
+                               name: moduleName,
+                               execute: execute,
+                               script: script,
+                               total: total
+                       };
+               }
+       };
+
+}() );
index 7e7fd6a..03141b9 100644 (file)
@@ -55,7 +55,7 @@ window.isCompatible = function ( str ) {
                // https://caniuse.com/#feat=json / https://phabricator.wikimedia.org/T141344#2784065
                ( function () {
                        'use strict';
-                       return !this && !!Function.prototype.bind && !!window.JSON;
+                       return !this && Function.prototype.bind && window.JSON;
                }() ) &&
 
                // https://caniuse.com/#feat=queryselector
@@ -145,5 +145,5 @@ window.isCompatible = function ( str ) {
        // This embeds mediawiki.js, which defines 'mw' and 'mw.loader'.
        $CODE.defineLoader();
 
-       mw.requestIdleCallback( startUp );
+       startUp();
 }() );
index f76b1e3..585ebb9 100644 (file)
@@ -346,8 +346,6 @@ return [
                "PhanUndeclaredMethod",
                // approximate error count: 1224
                "PhanUndeclaredProperty",
-               // approximate error count: 3
-               "PhanUndeclaredStaticMethod",
                // approximate error count: 58
                "PhanUndeclaredVariableDim",
        ],
index 6972165..5cc45f5 100644 (file)
@@ -8,6 +8,7 @@ use Psr\Log\LoggerInterface;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\IMaintainableDatabase;
 use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\LBFactory;
 use Wikimedia\TestingAccessWrapper;
 
@@ -109,6 +110,11 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         */
        private $loggers = [];
 
+       /**
+        * @var LoggerInterface
+        */
+       private $testLogger;
+
        /**
         * Table name prefixes. Oracle likes it shorter.
         */
@@ -131,6 +137,11 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                $this->backupGlobals = false;
                $this->backupStaticAttributes = false;
+               $this->testLogger = self::getTestLogger();
+       }
+
+       private static function getTestLogger() {
+               return LoggerFactory::getInstance( 'tests-phpunit' );
        }
 
        public function __destruct() {
@@ -446,6 +457,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( !self::$dbSetup || $this->needsDB() ) {
                        // set up a DB connection for this test to use
+                       $this->testLogger->info( "Setting up DB for " . $this->toString() );
 
                        self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
                        self::$reuseDB = $this->getCliArg( 'reuse-db' );
@@ -472,9 +484,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        $needsResetDB = true;
                }
 
+               $this->testLogger->info( "Starting test " . $this->toString() );
                parent::run( $result );
+               $this->testLogger->info( "Finished test " . $this->toString() );
 
                if ( $needsResetDB ) {
+                       $this->testLogger->info( "Resetting DB" );
                        $this->resetDB( $this->db, $this->tablesUsed );
                }
        }
@@ -565,7 +580,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        }
                        // Check for unsafe queries
                        if ( $this->db->getType() === 'mysql' ) {
-                               $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'" );
+                               $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'", __METHOD__ );
                        }
                }
 
@@ -617,7 +632,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                                $this->db->rollback( __METHOD__, 'flush' );
                        }
                        if ( $this->db->getType() === 'mysql' ) {
-                               $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ) );
+                               $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ),
+                                       __METHOD__ );
                        }
                }
 
@@ -1204,6 +1220,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @since 1.32
         */
        protected function addCoreDBData() {
+               $this->testLogger->info( __METHOD__ );
                if ( $this->db->getType() == 'oracle' ) {
                        # Insert 0 user to prevent FK violations
                        # Anonymous user
@@ -1448,7 +1465,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                // Assuming this isn't needed for External Store database, and not sure if the procedure
                // would be available there.
                if ( $db->getType() == 'oracle' ) {
-                       $db->query( 'BEGIN FILL_WIKI_INFO; END;' );
+                       $db->query( 'BEGIN FILL_WIKI_INFO; END;', __METHOD__ );
                }
 
                Hooks::run( 'UnitTestsAfterDatabaseSetup', [ $db, $prefix ] );
@@ -1732,10 +1749,14 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         */
        private function resetDB( $db, $tablesUsed ) {
                if ( $db ) {
+                       // NOTE: Do not reset the slot_roles and content_models tables, but let them
+                       // leak across tests. Resetting them would require to reset all NamedTableStore
+                       // instances for these tables, of which there may be several beyond the ones
+                       // known to MediaWikiServices. See T202641.
                        $userTables = [ 'user', 'user_groups', 'user_properties', 'actor' ];
                        $pageTables = [
                                'page', 'revision', 'ip_changes', 'revision_comment_temp', 'comment', 'archive',
-                               'revision_actor_temp', 'slots', 'content', 'content_models', 'slot_roles',
+                               'revision_actor_temp', 'slots', 'content',
                        ];
                        $coreDBDataTables = array_merge( $userTables, $pageTables );
 
@@ -1761,41 +1782,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                                }
                        }
 
-                       $truncate = in_array( $db->getType(), [ 'oracle', 'mysql' ] );
                        foreach ( $tablesUsed as $tbl ) {
-                               if ( !$db->tableExists( $tbl ) ) {
-                                       continue;
-                               }
-
-                               if ( $truncate ) {
-                                       $db->query( 'TRUNCATE TABLE ' . $db->tableName( $tbl ), __METHOD__ );
-                               } else {
-                                       $db->delete( $tbl, '*', __METHOD__ );
-                               }
-
-                               if ( in_array( $db->getType(), [ 'postgres', 'sqlite' ], true ) ) {
-                                       // Reset the table's sequence too.
-                                       $db->resetSequenceForTable( $tbl, __METHOD__ );
-                               }
-
-                               if ( $tbl === 'interwiki' ) {
-                                       if ( !$this->interwikiTable ) {
-                                               // @todo We should probably throw here, but this causes test failures that I
-                                               // can't figure out, so for now we silently continue.
-                                               continue;
-                                       }
-                                       $db->insert(
-                                               'interwiki',
-                                               array_values( array_map( 'get_object_vars', iterator_to_array( $this->interwikiTable ) ) ),
-                                               __METHOD__
-                                       );
-                               }
-
-                               if ( $tbl === 'page' ) {
-                                       // Forget about the pages since they don't
-                                       // exist in the DB.
-                                       MediaWikiServices::getInstance()->getLinkCache()->clear();
-                               }
+                               $this->truncateTable( $tbl, $db );
                        }
 
                        if ( array_intersect( $tablesUsed, $coreDBDataTables ) ) {
@@ -1805,6 +1793,56 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                }
        }
 
+       /**
+        * Empties the given table and resets any auto-increment counters.
+        * Will also purge caches associated with some well known tables.
+        * If the table is not know, this method just returns.
+        *
+        * @param string $tableName
+        * @param IDatabase|null $db
+        */
+       protected function truncateTable( $tableName, IDatabase $db = null ) {
+               if ( !$db ) {
+                       $db = $this->db;
+               }
+
+               if ( !$db->tableExists( $tableName ) ) {
+                       return;
+               }
+
+               $truncate = in_array( $db->getType(), [ 'oracle', 'mysql' ] );
+
+               if ( $truncate ) {
+                       $db->query( 'TRUNCATE TABLE ' . $db->tableName( $tableName ), __METHOD__ );
+               } else {
+                       $db->delete( $tableName, '*', __METHOD__ );
+               }
+
+               if ( in_array( $db->getType(), [ 'postgres', 'sqlite' ], true ) ) {
+                       // Reset the table's sequence too.
+                       $db->resetSequenceForTable( $tableName, __METHOD__ );
+               }
+
+               if ( $tableName === 'interwiki' ) {
+                       if ( !$this->interwikiTable ) {
+                               // @todo We should probably throw here, but this causes test failures that I
+                               // can't figure out, so for now we silently continue.
+                               return;
+                       }
+                       $db->insert(
+                               'interwiki',
+                               array_values( array_map( 'get_object_vars', iterator_to_array( $this->interwikiTable ) ) ),
+                               __METHOD__
+                       );
+               }
+
+               if ( $tableName === 'page' ) {
+                       // Forget about the pages since they don't
+                       // exist in the DB.
+                       MediaWikiServices::getInstance()->getLinkCache()->clear();
+               }
+       }
+
        private static function unprefixTable( &$tableName, $ind, $prefix ) {
                $tableName = substr( $tableName, strlen( $prefix ) );
        }
index 4de071d..ac100af 100644 (file)
@@ -45,7 +45,7 @@ class ReleaseNotesTest extends MediaWikiTestCase {
                                $this->assertLessThanOrEqual(
                                        // FILE_IGNORE_NEW_LINES drops the \n at the EOL, so max length is 80 not 81.
                                        80,
-                                       strlen( $line ),
+                                       mb_strlen( $line ),
                                        "Release notes file '$fileName' line $i is longer than 80 chars:\n\t'$line'"
                                );
                        }
index 1037b37..0f241cd 100644 (file)
@@ -4,28 +4,37 @@
  */
 class GitInfoTest extends MediaWikiTestCase {
 
+       private static $tempDir;
+
        public static function setUpBeforeClass() {
-               mkdir( __DIR__ . '/../data/gitrepo' );
-               mkdir( __DIR__ . '/../data/gitrepo/1' );
-               mkdir( __DIR__ . '/../data/gitrepo/2' );
-               mkdir( __DIR__ . '/../data/gitrepo/3' );
-               mkdir( __DIR__ . '/../data/gitrepo/1/.git' );
-               mkdir( __DIR__ . '/../data/gitrepo/1/.git/refs' );
-               mkdir( __DIR__ . '/../data/gitrepo/1/.git/refs/heads' );
-               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/HEAD',
+               self::$tempDir = wfTempDir() . '/mw-phpunit-' . wfRandomString( 8 );
+               if ( !mkdir( self::$tempDir ) ) {
+                       self::$tempDir = null;
+                       throw new Exception( 'Unable to create temporary directory' );
+               }
+               mkdir( self::$tempDir . '/gitrepo' );
+               mkdir( self::$tempDir . '/gitrepo/1' );
+               mkdir( self::$tempDir . '/gitrepo/2' );
+               mkdir( self::$tempDir . '/gitrepo/3' );
+               mkdir( self::$tempDir . '/gitrepo/1/.git' );
+               mkdir( self::$tempDir . '/gitrepo/1/.git/refs' );
+               mkdir( self::$tempDir . '/gitrepo/1/.git/refs/heads' );
+               file_put_contents( self::$tempDir . '/gitrepo/1/.git/HEAD',
                        "ref: refs/heads/master\n" );
-               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/refs/heads/master',
+               file_put_contents( self::$tempDir . '/gitrepo/1/.git/refs/heads/master',
                        "0123456789012345678901234567890123abcdef\n" );
-               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/packed-refs',
+               file_put_contents( self::$tempDir . '/gitrepo/1/.git/packed-refs',
                        "abcdef6789012345678901234567890123456789 refs/heads/master\n" );
-               file_put_contents( __DIR__ . '/../data/gitrepo/2/.git',
+               file_put_contents( self::$tempDir . '/gitrepo/2/.git',
                        "gitdir: ../1/.git\n" );
-               file_put_contents( __DIR__ . '/../data/gitrepo/3/.git',
-                       'gitdir: ' . __DIR__ . "/../data/gitrepo/1/.git\n" );
+               file_put_contents( self::$tempDir . '/gitrepo/3/.git',
+                       'gitdir: ' . self::$tempDir . "/gitrepo/1/.git\n" );
        }
 
        public static function tearDownAfterClass() {
-               wfRecursiveRemoveDir( __DIR__ . '/../data/gitrepo' );
+               if ( self::$tempDir ) {
+                       wfRecursiveRemoveDir( self::$tempDir );
+               }
        }
 
        protected function setUp() {
@@ -68,7 +77,7 @@ class GitInfoTest extends MediaWikiTestCase {
        }
 
        public function testReadingHead() {
-               $dir = __DIR__ . '/../data/gitrepo/1';
+               $dir = self::$tempDir . '/gitrepo/1';
                $fixture = new GitInfo( $dir );
 
                $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
@@ -76,7 +85,7 @@ class GitInfoTest extends MediaWikiTestCase {
        }
 
        public function testIndirection() {
-               $dir = __DIR__ . '/../data/gitrepo/2';
+               $dir = self::$tempDir . '/gitrepo/2';
                $fixture = new GitInfo( $dir );
 
                $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
@@ -84,7 +93,7 @@ class GitInfoTest extends MediaWikiTestCase {
        }
 
        public function testIndirection2() {
-               $dir = __DIR__ . '/../data/gitrepo/3';
+               $dir = self::$tempDir . '/gitrepo/3';
                $fixture = new GitInfo( $dir );
 
                $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
@@ -92,8 +101,8 @@ class GitInfoTest extends MediaWikiTestCase {
        }
 
        public function testReadingPackedRefs() {
-               $dir = __DIR__ . '/../data/gitrepo/1';
-               unlink( __DIR__ . '/../data/gitrepo/1/.git/refs/heads/master' );
+               $dir = self::$tempDir . '/gitrepo/1';
+               unlink( self::$tempDir . '/gitrepo/1/.git/refs/heads/master' );
                $fixture = new GitInfo( $dir );
 
                $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
index ee4819f..32c190e 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\Logger\LegacyLogger;
+
 /**
  * @group Database
  * @group GlobalFunctions
@@ -325,8 +327,9 @@ class GlobalTest extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgDebugLogFile' => $debugLogFile,
                        #  @todo FIXME: $wgDebugTimestamps should be tested
-                       'wgDebugTimestamps' => false
+                       'wgDebugTimestamps' => false,
                ] );
+               $this->setLogger( 'wfDebug', new LegacyLogger( 'wfDebug' ) );
 
                wfDebug( "This is a normal string" );
                $this->assertEquals( "This is a normal string\n", file_get_contents( $debugLogFile ) );
index 070a029..62094b6 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 class HtmlTest extends MediaWikiTestCase {
+       private $restoreWarnings;
 
        protected function setUp() {
                parent::setUp();
@@ -36,6 +37,15 @@ class HtmlTest extends MediaWikiTestCase {
                ] );
                $this->setUserLang( $langObj );
                $this->setContentLang( $langObj );
+               $this->restoreWarnings = false;
+       }
+
+       protected function tearDown() {
+               if ( $this->restoreWarnings ) {
+                       $this->restoreWarnings = false;
+                       Wikimedia\restoreWarnings();
+               }
+               parent::tearDown();
        }
 
        /**
@@ -802,21 +812,30 @@ class HtmlTest extends MediaWikiTestCase {
                        ],
                        'Ampersand' => [
                                'EXAMPLE.is(a && b);',
-                               '<script>/*<![CDATA[*/EXAMPLE.is(a && b);/*]]>*/</script>'
+                               '<script>EXAMPLE.is(a && b);</script>'
                        ],
                        'HTML' => [
                                'EXAMPLE.label("<a>");',
-                               '<script>/*<![CDATA[*/EXAMPLE.label("<a>");/*]]>*/</script>'
+                               '<script>EXAMPLE.label("<a>");</script>'
                        ],
-                       'Script closing string' => [
+                       'Script closing string (lower)' => [
                                'EXAMPLE.label("</script>");',
-                               // Broken: First </script> ends the script in HTML
-                               '<script>/*<![CDATA[*/EXAMPLE.label("</script>");/*]]>*/</script>'
+                               '<script>/* ERROR: Invalid script */</script>',
+                               true,
                        ],
-                       'CDATA string' => [
-                               'EXAMPLE.label("&> CDATA ]]>");',
-                               // Broken: Works in HTML, but is invalid XML.
-                               '<script>/*<![CDATA[*/EXAMPLE.label("&> CDATA ]]>");/*]]>*/</script>'
+                       'Script closing with non-standard attributes (mixed)' => [
+                               'EXAMPLE.label("</SCriPT and STyLE>");',
+                               '<script>/* ERROR: Invalid script */</script>',
+                               true,
+                       ],
+                       'HTML-comment-open and script-open' => [
+                               // In HTML, <script> contents aren't just plain CDATA until </script>,
+                               // there are levels of escaping modes, and the below sequence puts an
+                               // HTML parser in a state where </script> would *not* close the script.
+                               // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escape-end-state
+                               'var a = "<!--<script>";',
+                               '<script>/* ERROR: Invalid script */</script>',
+                               true,
                        ],
                ];
        }
@@ -825,7 +844,11 @@ class HtmlTest extends MediaWikiTestCase {
         * @dataProvider provideInlineScript
         * @covers Html::inlineScript
         */
-       public function testInlineScript( $code, $expected ) {
+       public function testInlineScript( $code, $expected, $error = false ) {
+               if ( $error ) {
+                       Wikimedia\suppressWarnings();
+                       $this->restoreWarnings = true;
+               }
                $this->assertSame( Html::inlineScript( $code ), $expected );
        }
 }
index b0cefc7..42ea9ed 100644 (file)
@@ -2037,82 +2037,6 @@ class OutputPageTest extends MediaWikiTestCase {
                ] );
        }
 
-       /**
-        * @dataProvider providePreloadLinkHeaders
-        * @covers OutputPage::addLogoPreloadLinkHeaders
-        * @covers ResourceLoaderSkinModule::getLogo
-        */
-       public function testPreloadLinkHeaders( $config, $result, $baseDir = null ) {
-               if ( $baseDir ) {
-                       $this->setMwGlobals( 'IP', $baseDir );
-               }
-               $out = TestingAccessWrapper::newFromObject( $this->newInstance( $config ) );
-               $out->addLogoPreloadLinkHeaders();
-
-               $this->assertEquals( $result, $out->getLinkHeader() );
-       }
-
-       public function providePreloadLinkHeaders() {
-               return [
-                       [
-                               [
-                                       'ResourceBasePath' => '/w',
-                                       'Logo' => '/img/default.png',
-                                       'LogoHD' => [
-                                               '1.5x' => '/img/one-point-five.png',
-                                               '2x' => '/img/two-x.png',
-                                       ],
-                               ],
-                               'Link: </img/default.png>;rel=preload;as=image;media=' .
-                               'not all and (min-resolution: 1.5dppx),' .
-                               '</img/one-point-five.png>;rel=preload;as=image;media=' .
-                               '(min-resolution: 1.5dppx) and (max-resolution: 1.999999dppx),' .
-                               '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
-                       ],
-                       [
-                               [
-                                       'ResourceBasePath' => '/w',
-                                       'Logo' => '/img/default.png',
-                                       'LogoHD' => false,
-                               ],
-                               'Link: </img/default.png>;rel=preload;as=image'
-                       ],
-                       [
-                               [
-                                       'ResourceBasePath' => '/w',
-                                       'Logo' => '/img/default.png',
-                                       'LogoHD' => [
-                                               '2x' => '/img/two-x.png',
-                                       ],
-                               ],
-                               'Link: </img/default.png>;rel=preload;as=image;media=' .
-                               'not all and (min-resolution: 2dppx),' .
-                               '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
-                       ],
-                       [
-                               [
-                                       'ResourceBasePath' => '/w',
-                                       'Logo' => '/img/default.png',
-                                       'LogoHD' => [
-                                               'svg' => '/img/vector.svg',
-                                       ],
-                               ],
-                               'Link: </img/vector.svg>;rel=preload;as=image'
-
-                       ],
-                       [
-                               [
-                                       'ResourceBasePath' => '/w',
-                                       'Logo' => '/w/test.jpg',
-                                       'LogoHD' => false,
-                                       'UploadPath' => '/w/images',
-                               ],
-                               'Link: </w/test.jpg?edcf2>;rel=preload;as=image',
-                               'baseDir' => dirname( __DIR__ ) . '/data/media',
-                       ],
-               ];
-       }
-
        /**
         * @return OutputPage
         */
diff --git a/tests/phpunit/includes/Revision/RenderedRevisionTest.php b/tests/phpunit/includes/Revision/RenderedRevisionTest.php
new file mode 100644 (file)
index 0000000..a2a9d09
--- /dev/null
@@ -0,0 +1,454 @@
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use Content;
+use Language;
+use MediaWiki\Revision\RenderedRevision;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\SuppressedDataException;
+use MediaWiki\User\UserIdentityValue;
+use MediaWikiTestCase;
+use ParserOptions;
+use ParserOutput;
+use PHPUnit\Framework\MockObject\MockObject;
+use Title;
+use User;
+use WikitextContent;
+
+/**
+ * @covers \MediaWiki\Revision\RenderedRevision
+ */
+class RenderedRevisionTest extends MediaWikiTestCase {
+
+       /** @var callable */
+       private $combinerCallback;
+
+       public function setUp() {
+               parent::setUp();
+
+               $this->combinerCallback = function ( RenderedRevision $rr, array $hints = [] ) {
+                       return $this->combineOutput( $rr, $hints );
+               };
+       }
+
+       private function combineOutput( RenderedRevision $rrev, array $hints = [] ) {
+               // NOTE: the is a slightly simplified version of RevisionRenderer::combineSlotOutput
+
+               $withHtml = $hints['generate-html'] ?? true;
+
+               $revision = $rrev->getRevision();
+               $slots = $revision->getSlots()->getSlots();
+
+               $combinedOutput = new ParserOutput( null );
+               $slotOutput = [];
+               foreach ( $slots as $role => $slot ) {
+                       $out = $rrev->getSlotParserOutput( $role, $hints );
+                       $slotOutput[$role] = $out;
+
+                       $combinedOutput->mergeInternalMetaDataFrom( $out );
+                       $combinedOutput->mergeTrackingMetaDataFrom( $out );
+               }
+
+               if ( $withHtml ) {
+                       $html = '';
+                       /** @var ParserOutput $out */
+                       foreach ( $slotOutput as $role => $out ) {
+
+                               if ( $html !== '' ) {
+                                       // skip header for the first slot
+                                       $html .= "(($role))";
+                               }
+
+                               $html .= $out->getRawText();
+                               $combinedOutput->mergeHtmlMetaDataFrom( $out );
+                       }
+
+                       $combinedOutput->setText( $html );
+               }
+
+               return $combinedOutput;
+       }
+
+       /**
+        * @param $articleId
+        * @param $revisionId
+        * @return Title
+        */
+       private function getMockTitle( $articleId, $revisionId ) {
+               /** @var Title|MockObject $mock */
+               $mock = $this->getMockBuilder( Title::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mock->expects( $this->any() )
+                       ->method( 'getNamespace' )
+                       ->will( $this->returnValue( NS_MAIN ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getText' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getPrefixedText' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getDBkey' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getArticleID' )
+                       ->will( $this->returnValue( $articleId ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getLatestRevId' )
+                       ->will( $this->returnValue( $revisionId ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getContentModel' )
+                       ->will( $this->returnValue( CONTENT_MODEL_WIKITEXT ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getPageLanguage' )
+                       ->will( $this->returnValue( Language::factory( 'en' ) ) );
+               $mock->expects( $this->any() )
+                       ->method( 'isContentPage' )
+                       ->will( $this->returnValue( true ) );
+               $mock->expects( $this->any() )
+                       ->method( 'equals' )
+                       ->willReturnCallback( function ( Title $other ) use ( $mock ) {
+                               return $mock->getArticleID() === $other->getArticleID();
+                       } );
+               $mock->expects( $this->any() )
+                       ->method( 'userCan' )
+                       ->willReturnCallback( function ( $perm, User $user ) use ( $mock ) {
+                               return $user->isAllowed( $perm );
+                       } );
+
+               return $mock;
+       }
+
+       public function testGetRevisionParserOutput_new() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+               $text .= "* [[Link It]]\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+       }
+
+       public function testGetRevisionParserOutput_current() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 21 ); // current!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:21', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRevisionParserOutput_old() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRevisionParserOutput_suppressed() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $this->setExpectedException( SuppressedDataException::class );
+               $rr->getRevisionParserOutput();
+       }
+
+       public function testGetRevisionParserOutput_privileged() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $sysop = $this->getTestUser( [ 'sysop' ] )->getUser(); // privileged!
+               $rr = new RenderedRevision(
+                       $title,
+                       $rev,
+                       $options,
+                       $this->combinerCallback,
+                       RevisionRecord::FOR_THIS_USER,
+                       $sysop
+               );
+
+               $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               // Suppressed content should be visible for sysops
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRevisionParserOutput_raw() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision(
+                       $title,
+                       $rev,
+                       $options,
+                       $this->combinerCallback,
+                       RevisionRecord::RAW
+               );
+
+               $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               // Suppressed content should be visible for sysops
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRevisionParserOutput_multi() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $rev->setContent( 'main', new WikitextContent( '[[Kittens]]' ) );
+               $rev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $combinedOutput = $rr->getRevisionParserOutput();
+               $mainOutput = $rr->getSlotParserOutput( 'main' );
+               $auxOutput = $rr->getSlotParserOutput( 'aux' );
+
+               $combinedHtml = $combinedOutput->getText();
+               $mainHtml = $mainOutput->getText();
+               $auxHtml = $auxOutput->getText();
+
+               $this->assertContains( 'Kittens', $mainHtml );
+               $this->assertContains( 'Goats', $auxHtml );
+               $this->assertNotContains( 'Goats', $mainHtml );
+               $this->assertNotContains( 'Kittens', $auxHtml );
+               $this->assertContains( 'Kittens', $combinedHtml );
+               $this->assertContains( 'Goats', $combinedHtml );
+               $this->assertContains( 'aux', $combinedHtml, 'slot section header' );
+
+               $combinedLinks = $combinedOutput->getLinks();
+               $mainLinks = $mainOutput->getLinks();
+               $auxLinks = $auxOutput->getLinks();
+               $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Kittens'] ), 'links from main slot' );
+               $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Goats'] ), 'links from aux slot' );
+               $this->assertFalse( isset( $mainLinks[NS_MAIN]['Goats'] ), 'no aux links in main' );
+               $this->assertFalse( isset( $auxLinks[NS_MAIN]['Kittens'] ), 'no main links in aux' );
+       }
+
+       public function testNoHtml() {
+               /** @var MockObject|Content $mockContent */
+               $mockContent = $this->getMockBuilder( WikitextContent::class )
+                       ->setMethods( [ 'getParserOutput' ] )
+                       ->setConstructorArgs( [ 'Whatever' ] )
+                       ->getMock();
+               $mockContent->method( 'getParserOutput' )
+                       ->willReturnCallback( function ( Title $title, $revId = null,
+                               ParserOptions $options = null, $generateHtml = true
+                       ) {
+                               if ( !$generateHtml ) {
+                                       return new ParserOutput( null );
+                               } else {
+                                       $this->fail( 'Should not be called with $generateHtml == true' );
+                                       return null; // never happens, make analyzer happy
+                               }
+                       } );
+
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setContent( 'main', $mockContent );
+               $rev->setContent( 'aux', $mockContent );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $output = $rr->getSlotParserOutput( 'main', [ 'generate-html' => false ] );
+               $this->assertFalse( $output->hasText(), 'hasText' );
+
+               $output = $rr->getRevisionParserOutput( [ 'generate-html' => false ] );
+               $this->assertFalse( $output->hasText(), 'hasText' );
+       }
+
+       public function testUpdateRevision() {
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+               $rev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
+
+               $firstOutput = $rr->getRevisionParserOutput();
+               $mainOutput = $rr->getSlotParserOutput( 'main' );
+               $auxOutput = $rr->getSlotParserOutput( 'aux' );
+
+               // emulate a saved revision
+               $savedRev = new MutableRevisionRecord( $title );
+               $savedRev->setContent( 'main', new WikitextContent( $text ) );
+               $savedRev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
+               $savedRev->setId( 23 ); // saved, new
+               $savedRev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $savedRev->setTimestamp( '20180101000003' );
+
+               $rr->updateRevision( $savedRev );
+
+               $this->assertNotSame( $mainOutput, $rr->getSlotParserOutput( 'main' ), 'Reset main' );
+               $this->assertSame( $auxOutput, $rr->getSlotParserOutput( 'aux' ), 'Keep aux' );
+
+               $updatedOutput = $rr->getRevisionParserOutput();
+               $html = $updatedOutput->getText();
+
+               $this->assertNotSame( $firstOutput, $updatedOutput, 'Reset merged' );
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:23', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+               $this->assertContains( 'Goats', $html );
+
+               $rr->updateRevision( $savedRev ); // should do nothing
+               $this->assertSame( $updatedOutput, $rr->getRevisionParserOutput(), 'no more reset needed' );
+       }
+
+}
diff --git a/tests/phpunit/includes/Revision/RevisionRendererTest.php b/tests/phpunit/includes/Revision/RevisionRendererTest.php
new file mode 100644 (file)
index 0000000..ea195f1
--- /dev/null
@@ -0,0 +1,460 @@
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use Content;
+use Language;
+use LogicException;
+use MediaWiki\Revision\RevisionRenderer;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\User\UserIdentityValue;
+use MediaWikiTestCase;
+use ParserOptions;
+use ParserOutput;
+use PHPUnit\Framework\MockObject\MockObject;
+use Title;
+use User;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILoadBalancer;
+use WikitextContent;
+
+/**
+ * @covers \MediaWiki\Revision\RevisionRenderer
+ */
+class RevisionRendererTest extends MediaWikiTestCase {
+
+       /**
+        * @param $articleId
+        * @param $revisionId
+        * @return Title
+        */
+       private function getMockTitle( $articleId, $revisionId ) {
+               /** @var Title|MockObject $mock */
+               $mock = $this->getMockBuilder( Title::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mock->expects( $this->any() )
+                       ->method( 'getNamespace' )
+                       ->will( $this->returnValue( NS_MAIN ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getText' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getPrefixedText' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getDBkey' )
+                       ->will( $this->returnValue( __CLASS__ ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getArticleID' )
+                       ->will( $this->returnValue( $articleId ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getLatestRevId' )
+                       ->will( $this->returnValue( $revisionId ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getContentModel' )
+                       ->will( $this->returnValue( CONTENT_MODEL_WIKITEXT ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getPageLanguage' )
+                       ->will( $this->returnValue( Language::factory( 'en' ) ) );
+               $mock->expects( $this->any() )
+                       ->method( 'isContentPage' )
+                       ->will( $this->returnValue( true ) );
+               $mock->expects( $this->any() )
+                       ->method( 'equals' )
+                       ->willReturnCallback(
+                               function ( Title $other ) use ( $mock ) {
+                                       return $mock->getArticleID() === $other->getArticleID();
+                               }
+                       );
+               $mock->expects( $this->any() )
+                       ->method( 'userCan' )
+                       ->willReturnCallback(
+                               function ( $perm, User $user ) use ( $mock ) {
+                                       return $user->isAllowed( $perm );
+                               }
+                       );
+
+               return $mock;
+       }
+
+       /**
+        * @param int $maxRev
+        * @param int $linkCount
+        *
+        * @return IDatabase
+        */
+       private function getMockDatabaseConnection( $maxRev = 100, $linkCount = 0 ) {
+               /** @var IDatabase|MockObject $db */
+               $db = $this->getMock( IDatabase::class );
+               $db->method( 'selectField' )
+                       ->willReturnCallback(
+                               function ( $table, $fields, $cond ) use ( $maxRev, $linkCount ) {
+                                       return $this->selectFieldCallback(
+                                               $table,
+                                               $fields,
+                                               $cond,
+                                               $maxRev,
+                                               $linkCount
+                                       );
+                               }
+                       );
+
+               return $db;
+       }
+
+       /**
+        * @return RevisionRenderer
+        */
+       private function newRevisionRenderer( $maxRev = 100, $useMaster = false ) {
+               $dbIndex = $useMaster ? DB_MASTER : DB_REPLICA;
+
+               $db = $this->getMockDatabaseConnection( $maxRev );
+
+               /** @var ILoadBalancer|MockObject $lb */
+               $lb = $this->getMock( ILoadBalancer::class );
+               $lb->method( 'getConnection' )
+                       ->with( $dbIndex )
+                       ->willReturn( $db );
+               $lb->method( 'getConnectionRef' )
+                       ->with( $dbIndex )
+                       ->willReturn( $db );
+               $lb->method( 'getLazyConnectionRef' )
+                       ->with( $dbIndex )
+                       ->willReturn( $db );
+
+               return new RevisionRenderer( $lb );
+       }
+
+       private function selectFieldCallback( $table, $fields, $cond, $maxRev ) {
+               if ( [ $table, $fields, $cond ] === [ 'revision', 'MAX(rev_id)', [] ] ) {
+                       return $maxRev;
+               }
+
+               $this->fail( 'Unexpected call to selectField' );
+               throw new LogicException( 'Ooops' ); // Can't happen, make analyzer happy
+       }
+
+       public function testGetRenderedRevision_new() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+               $text .= "* [[Link It]]\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision( $rev, $options );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:101', $html ); // from speculativeRevIdCallback
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_current() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 21 ); // current!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision( $rev, $options );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:21', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_master() {
+               $renderer = $this->newRevisionRenderer( 100, true ); // use master
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 21 ); // current!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision( $rev, $options, null, [ 'use-master' => true ] );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'rev:21', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_old() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision( $rev, $options );
+
+               $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_suppressed() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision( $rev, $options );
+
+               $this->assertNull( $rr, 'getRenderedRevision' );
+       }
+
+       public function testGetRenderedRevision_privileged() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $sysop = $this->getTestUser( [ 'sysop' ] )->getUser(); // privileged!
+               $rr = $renderer->getRenderedRevision( $rev, $options, $sysop );
+
+               $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               // Suppressed content should be visible for sysops
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_raw() {
+               $renderer = $this->newRevisionRenderer( 100 );
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( 11 ); // old!
+               $rev->setVisibility( RevisionRecord::DELETED_TEXT ); // suppressed!
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $text = "";
+               $text .= "* page:{{PAGENAME}}\n";
+               $text .= "* rev:{{REVISIONID}}\n";
+               $text .= "* user:{{REVISIONUSER}}\n";
+               $text .= "* time:{{REVISIONTIMESTAMP}}\n";
+
+               $rev->setContent( 'main', new WikitextContent( $text ) );
+
+               $options = ParserOptions::newCanonical( 'canonical' );
+               $rr = $renderer->getRenderedRevision(
+                       $rev,
+                       $options,
+                       null,
+                       [ 'audience' => RevisionRecord::RAW ]
+               );
+
+               $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
+
+               $this->assertSame( $rev, $rr->getRevision() );
+               $this->assertSame( $options, $rr->getOptions() );
+
+               $html = $rr->getRevisionParserOutput()->getText();
+
+               // Suppressed content should be visible in raw mode
+               $this->assertContains( 'page:' . __CLASS__, $html );
+               $this->assertContains( 'rev:11', $html );
+               $this->assertContains( 'user:Frank', $html );
+               $this->assertContains( 'time:20180101000003', $html );
+
+               $this->assertSame( $html, $rr->getSlotParserOutput( 'main' )->getText() );
+       }
+
+       public function testGetRenderedRevision_multi() {
+               $renderer = $this->newRevisionRenderer();
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
+               $rev->setTimestamp( '20180101000003' );
+
+               $rev->setContent( 'main', new WikitextContent( '[[Kittens]]' ) );
+               $rev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
+
+               $rr = $renderer->getRenderedRevision( $rev );
+
+               $combinedOutput = $rr->getRevisionParserOutput();
+               $mainOutput = $rr->getSlotParserOutput( 'main' );
+               $auxOutput = $rr->getSlotParserOutput( 'aux' );
+
+               $combinedHtml = $combinedOutput->getText();
+               $mainHtml = $mainOutput->getText();
+               $auxHtml = $auxOutput->getText();
+
+               $this->assertContains( 'Kittens', $mainHtml );
+               $this->assertContains( 'Goats', $auxHtml );
+               $this->assertNotContains( 'Goats', $mainHtml );
+               $this->assertNotContains( 'Kittens', $auxHtml );
+               $this->assertContains( 'Kittens', $combinedHtml );
+               $this->assertContains( 'Goats', $combinedHtml );
+               $this->assertContains( '>aux<', $combinedHtml, 'slot header' );
+               $this->assertNotContains( '<mw:slotheader', $combinedHtml, 'slot header placeholder' );
+
+               // make sure output wrapping works right
+               $this->assertContains( 'class="mw-parser-output"', $mainHtml );
+               $this->assertContains( 'class="mw-parser-output"', $auxHtml );
+               $this->assertContains( 'class="mw-parser-output"', $combinedHtml );
+
+               // there should be only one wrapper div
+               $this->assertSame( 1, preg_match_all( '#class="mw-parser-output"#', $combinedHtml ) );
+               $this->assertNotContains( 'class="mw-parser-output"', $combinedOutput->getRawText() );
+
+               $combinedLinks = $combinedOutput->getLinks();
+               $mainLinks = $mainOutput->getLinks();
+               $auxLinks = $auxOutput->getLinks();
+               $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Kittens'] ), 'links from main slot' );
+               $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Goats'] ), 'links from aux slot' );
+               $this->assertFalse( isset( $mainLinks[NS_MAIN]['Goats'] ), 'no aux links in main' );
+               $this->assertFalse( isset( $auxLinks[NS_MAIN]['Kittens'] ), 'no main links in aux' );
+       }
+
+       public function testGetRenderedRevision_noHtml() {
+               /** @var MockObject|Content $mockContent */
+               $mockContent = $this->getMockBuilder( WikitextContent::class )
+                       ->setMethods( [ 'getParserOutput' ] )
+                       ->setConstructorArgs( [ 'Whatever' ] )
+                       ->getMock();
+               $mockContent->method( 'getParserOutput' )
+                       ->willReturnCallback( function ( Title $title, $revId = null,
+                               ParserOptions $options = null, $generateHtml = true
+                       ) {
+                               if ( !$generateHtml ) {
+                                       return new ParserOutput( null );
+                               } else {
+                                       $this->fail( 'Should not be called with $generateHtml == true' );
+                                       return null; // never happens, make analyzer happy
+                               }
+                       } );
+
+               $renderer = $this->newRevisionRenderer();
+               $title = $this->getMockTitle( 7, 21 );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setContent( 'main', $mockContent );
+               $rev->setContent( 'aux', $mockContent );
+
+               // NOTE: we are testing the private combineSlotOutput() callback here.
+               $rr = $renderer->getRenderedRevision( $rev );
+
+               $output = $rr->getSlotParserOutput( 'main', [ 'generate-html' => false ] );
+               $this->assertFalse( $output->hasText(), 'hasText' );
+
+               $output = $rr->getRevisionParserOutput( [ 'generate-html' => false ] );
+               $this->assertFalse( $output->hasText(), 'hasText' );
+       }
+
+}
index c7f83de..0e0d609 100644 (file)
@@ -73,14 +73,22 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $user = $this->getTestUser()->getUser();
                $comment = CommentStoreComment::newUnsavedComment( $summary );
 
-               if ( !$content instanceof Content ) {
+               if ( $content === null || is_string( $content ) ) {
                        $content = new WikitextContent( $content ?? $summary );
                }
 
+               if ( !is_array( $content ) ) {
+                       $content = [ 'main' => $content ];
+               }
+
                $this->getDerivedPageDataUpdater( $page ); // flush cached instance before.
 
                $updater = $page->newPageUpdater( $user );
-               $updater->setContent( 'main', $content );
+
+               foreach ( $content as $role => $c ) {
+                       $updater->setContent( $role, $c );
+               }
+
                $rev = $updater->saveRevision( $comment );
 
                $this->getDerivedPageDataUpdater( $page ); // flush cached instance after.
@@ -110,7 +118,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $this->assertSame( MediaWikiServices::getInstance()->getContentLanguage(),
                        $options1->getUserLangObj() );
 
-               $speculativeId = call_user_func( $options1->getSpeculativeRevIdCallback(), $page->getTitle() );
+               $speculativeId = $options1->getSpeculativeRevId();
                $this->assertSame( $parentRev->getId() + 1, $speculativeId );
 
                $rev = $this->makeRevision(
@@ -123,7 +131,6 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $updater->prepareUpdate( $rev );
 
                $options2 = $updater->getCanonicalParserOptions();
-               $this->assertNotSame( $options1, $options2 );
 
                $currentRev = call_user_func( $options2->getCurrentRevisionCallback(), $page->getTitle() );
                $this->assertSame( $rev->getId(), $currentRev->getId() );
@@ -167,7 +174,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
         * @covers \MediaWiki\Storage\DerivedPageDataUpdater::getCanonicalParserOutput()
         */
        public function testPrepareContent() {
-               $user = $this->getTestUser()->getUser();
+               $sysop = $this->getTestUser( [ 'sysop' ] )->getUser();
                $updater = $this->getDerivedPageDataUpdater( __METHOD__ );
 
                $this->assertFalse( $updater->isContentPrepared() );
@@ -186,10 +193,10 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $update->modifySlot( SlotRecord::newInherited( $auxSlot ) );
                // TODO: MCR: test removing slots!
 
-               $updater->prepareContent( $user, $update, false );
+               $updater->prepareContent( $sysop, $update, false );
 
                // second be ok to call again with the same params
-               $updater->prepareContent( $user, $update, false );
+               $updater->prepareContent( $sysop, $update, false );
 
                $this->assertNull( $updater->grabCurrentRevision() );
                $this->assertTrue( $updater->isContentPrepared() );
@@ -197,7 +204,10 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $this->assertFalse( $updater->pageExisted() );
                $this->assertTrue( $updater->isCreation() );
                $this->assertTrue( $updater->isChange() );
-               $this->assertTrue( $updater->isContentPublic() );
+               $this->assertFalse( $updater->isContentDeleted() );
+
+               $this->assertNotNull( $updater->getRevision() );
+               $this->assertNotNull( $updater->getRenderedRevision() );
 
                $this->assertEquals( [ 'main', 'aux' ], $updater->getSlots()->getSlotRoles() );
                $this->assertEquals( [ 'main' ], array_keys( $updater->getSlots()->getOriginalSlots() ) );
@@ -208,7 +218,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $mainSlot = $updater->getRawSlot( 'main' );
                $this->assertInstanceOf( SlotRecord::class, $mainSlot );
                $this->assertNotContains( '~~~', $mainSlot->getContent()->serialize(), 'PST should apply.' );
-               $this->assertContains( $user->getName(), $mainSlot->getContent()->serialize() );
+               $this->assertContains( $sysop->getName(), $mainSlot->getContent()->serialize() );
 
                $auxSlot = $updater->getRawSlot( 'aux' );
                $this->assertInstanceOf( SlotRecord::class, $auxSlot );
@@ -222,6 +232,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $canonicalOutput = $updater->getCanonicalParserOutput();
                $this->assertContains( 'first', $canonicalOutput->getText() );
                $this->assertContains( '<a ', $canonicalOutput->getText() );
+               $this->assertContains( 'inherited ', $canonicalOutput->getText() );
                $this->assertNotEmpty( $canonicalOutput->getLinks() );
        }
 
@@ -232,18 +243,19 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
         * @covers \MediaWiki\Storage\DerivedPageDataUpdater::isChange()
         */
        public function testPrepareContentInherit() {
-               $user = $this->getTestUser()->getUser();
+               $sysop = $this->getTestUser( [ 'sysop' ] )->getUser();
                $page = $this->getPage( __METHOD__ );
 
-               $mainContent1 = new WikitextContent( 'first [[main]] ~~~' );
+               $mainContent1 = new WikitextContent( 'first [[main]] ({{REVISIONUSER}}) ~~~' );
                $mainContent2 = new WikitextContent( 'second' );
 
-               $this->createRevision( $page, 'first', $mainContent1 );
+               $rev = $this->createRevision( $page, 'first', $mainContent1 );
+               $mainContent1 = $rev->getContent( 'main' ); // get post-pst content
 
                $update = new RevisionSlotsUpdate();
                $update->modifyContent( 'main', $mainContent1 );
                $updater1 = $this->getDerivedPageDataUpdater( $page );
-               $updater1->prepareContent( $user, $update, false );
+               $updater1->prepareContent( $sysop, $update, false );
 
                $this->assertNotNull( $updater1->grabCurrentRevision() );
                $this->assertTrue( $updater1->isContentPrepared() );
@@ -251,11 +263,20 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $this->assertFalse( $updater1->isCreation() );
                $this->assertFalse( $updater1->isChange() );
 
+               $this->assertNotNull( $updater1->getRevision() );
+               $this->assertNotNull( $updater1->getRenderedRevision() );
+
+               // parser-output for null-edit uses the original author's name
+               $html = $updater1->getRenderedRevision()->getRevisionParserOutput()->getText();
+               $this->assertNotContains( $sysop->getName(), $html, '{{REVISIONUSER}}' );
+               $this->assertNotContains( '{{REVISIONUSER}}', $html, '{{REVISIONUSER}}' );
+               $this->assertContains( '(' . $rev->getUser()->getName() . ')', $html, '{{REVISIONUSER}}' );
+
                // TODO: MCR: test inheritance from parent
                $update = new RevisionSlotsUpdate();
                $update->modifyContent( 'main', $mainContent2 );
                $updater2 = $this->getDerivedPageDataUpdater( $page );
-               $updater2->prepareContent( $user, $update, false );
+               $updater2->prepareContent( $sysop, $update, false );
 
                $this->assertFalse( $updater2->isCreation() );
                $this->assertTrue( $updater2->isChange() );
@@ -292,7 +313,10 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $this->assertTrue( $updater1->isContentPrepared() );
                $this->assertTrue( $updater1->isCreation() );
                $this->assertTrue( $updater1->isChange() );
-               $this->assertTrue( $updater1->isContentPublic() );
+               $this->assertFalse( $updater1->isContentDeleted() );
+
+               $this->assertNotNull( $updater1->getRevision() );
+               $this->assertNotNull( $updater1->getRenderedRevision() );
 
                $this->assertEquals( [ 'main' ], $updater1->getSlots()->getSlotRoles() );
                $this->assertEquals( [ 'main' ], array_keys( $updater1->getSlots()->getOriginalSlots() ) );
@@ -698,10 +722,20 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
        public function testDoUpdates() {
                $page = $this->getPage( __METHOD__ );
 
-               $mainContent1 = new WikitextContent( 'first [[main]]' );
-               $rev = $this->createRevision( $page, 'first', $mainContent1 );
+               $content = [ 'main' => new WikitextContent( 'first [[main]]' ) ];
+
+               if ( $this->hasMultiSlotSupport() ) {
+                       $content['aux'] = new WikitextContent( 'Aux [[Nix]]' );
+               }
+
+               $rev = $this->createRevision( $page, 'first', $content );
                $pageId = $page->getId();
+
                $oldStats = $this->db->selectRow( 'site_stats', '*', '1=1' );
+               $this->db->delete( 'pagelinks', '*' );
+
+               $pcache = MediaWikiServices::getInstance()->getParserCache();
+               $pcache->deleteOptionsKey( $page );
 
                $updater = $this->getDerivedPageDataUpdater( $page, $rev );
                $updater->setArticleCountMethod( 'link' );
@@ -712,15 +746,25 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                $updater->doUpdates();
 
                // links table update
-               $linkCount = $this->db->selectRowCount( 'pagelinks', '*', [ 'pl_from' => $pageId ] );
-               $this->assertSame( 1, $linkCount );
+               $pageLinks = $this->db->select(
+                       'pagelinks',
+                       '*',
+                       [ 'pl_from' => $pageId ],
+                       __METHOD__,
+                       [ 'ORDER BY' => 'pl_namespace, pl_title' ]
+               );
 
-               $pageLinksRow = $this->db->selectRow( 'pagelinks', '*', [ 'pl_from' => $pageId ] );
+               $pageLinksRow = $pageLinks->fetchObject();
                $this->assertInternalType( 'object', $pageLinksRow );
                $this->assertSame( 'Main', $pageLinksRow->pl_title );
 
+               if ( $this->hasMultiSlotSupport() ) {
+                       $pageLinksRow = $pageLinks->fetchObject();
+                       $this->assertInternalType( 'object', $pageLinksRow );
+                       $this->assertSame( 'Nix', $pageLinksRow->pl_title );
+               }
+
                // parser cache update
-               $pcache = MediaWikiServices::getInstance()->getParserCache();
                $cached = $pcache->get( $page, $updater->getCanonicalParserOptions() );
                $this->assertInternalType( 'object', $cached );
                $this->assertSame( $updater->getCanonicalParserOutput(), $cached );
@@ -742,4 +786,11 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                // TODO: test category membership update (with setRcWatchCategoryMembership())
        }
 
+       private function hasMultiSlotSupport() {
+               global $wgMultiContentRevisionSchemaMigrationStage;
+
+               return ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW )
+                       && ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW );
+       }
+
 }
index cbae4c7..492d00c 100644 (file)
@@ -173,51 +173,84 @@ class McrReadNewRevisionStoreDbTest extends RevisionStoreDbTestBase {
        }
 
        public function provideGetSlotsQueryInfo() {
-               yield [
+               yield 'no options' => [
                        [],
+                       [
+                               'tables' => [
+                                       'slots'
+                               ],
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                               ],
+                               'joins' => [],
+                       ]
+               ];
+               yield 'role option' => [
+                       [ 'role' ],
                        [
                                'tables' => [
                                        'slots',
                                        'slot_roles',
                                ],
-                               'fields' => array_merge(
-                                       [
-                                               'slot_revision_id',
-                                               'slot_content_id',
-                                               'slot_origin',
-                                               'role_name',
-                                       ]
-                               ),
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'role_name',
+                               ],
                                'joins' => [
-                                       'slot_roles' => [ 'INNER JOIN', [ 'slot_role_id = role_id' ] ],
+                                       'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ],
                                ],
                        ]
                ];
-               yield [
+               yield 'content option' => [
                        [ 'content' ],
                        [
                                'tables' => [
                                        'slots',
-                                       'slot_roles',
+                                       'content',
+                               ],
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'content_size',
+                                       'content_sha1',
+                                       'content_address',
+                                       'content_model',
+                               ],
+                               'joins' => [
+                                       'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
+                               ],
+                       ]
+               ];
+               yield 'content and model options' => [
+                       [ 'content', 'model' ],
+                       [
+                               'tables' => [
+                                       'slots',
                                        'content',
                                        'content_models',
                                ],
-                               'fields' => array_merge(
-                                       [
-                                               'slot_revision_id',
-                                               'slot_content_id',
-                                               'slot_origin',
-                                               'role_name',
-                                               'content_size',
-                                               'content_sha1',
-                                               'content_address',
-                                               'model_name',
-                                       ]
-                               ),
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'content_size',
+                                       'content_sha1',
+                                       'content_address',
+                                       'content_model',
+                                       'model_name',
+                               ],
                                'joins' => [
-                                       'slot_roles' => [ 'INNER JOIN', [ 'slot_role_id = role_id' ] ],
                                        'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
-                                       'content_models' => [ 'INNER JOIN', [ 'content_model = model_id' ] ],
+                                       'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ],
                                ],
                        ]
                ];
index 9a118d7..af19f72 100644 (file)
@@ -3,6 +3,7 @@ namespace MediaWiki\Tests\Storage;
 
 use CommentStoreComment;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\MutableRevisionRecord;
 use MediaWiki\Storage\RevisionRecord;
 use MediaWiki\Storage\SlotRecord;
 use TextContent;
@@ -189,54 +190,139 @@ class McrRevisionStoreDbTest extends RevisionStoreDbTestBase {
        }
 
        public function provideGetSlotsQueryInfo() {
-               yield [
+               yield 'no options' => [
                        [],
+                       [
+                               'tables' => [
+                                       'slots'
+                               ],
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                               ],
+                               'joins' => [],
+                       ]
+               ];
+               yield 'role option' => [
+                       [ 'role' ],
                        [
                                'tables' => [
                                        'slots',
                                        'slot_roles',
                                ],
-                               'fields' => array_merge(
-                                       [
-                                               'slot_revision_id',
-                                               'slot_content_id',
-                                               'slot_origin',
-                                               'role_name',
-                                       ]
-                               ),
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'role_name',
+                               ],
                                'joins' => [
-                                       'slot_roles' => [ 'INNER JOIN', [ 'slot_role_id = role_id' ] ],
+                                       'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ],
                                ],
                        ]
                ];
-               yield [
+               yield 'content option' => [
                        [ 'content' ],
                        [
                                'tables' => [
                                        'slots',
-                                       'slot_roles',
+                                       'content',
+                               ],
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'content_size',
+                                       'content_sha1',
+                                       'content_address',
+                                       'content_model',
+                               ],
+                               'joins' => [
+                                       'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
+                               ],
+                       ]
+               ];
+               yield 'content and model options' => [
+                       [ 'content', 'model' ],
+                       [
+                               'tables' => [
+                                       'slots',
                                        'content',
                                        'content_models',
                                ],
-                               'fields' => array_merge(
-                                       [
-                                               'slot_revision_id',
-                                               'slot_content_id',
-                                               'slot_origin',
-                                               'role_name',
-                                               'content_size',
-                                               'content_sha1',
-                                               'content_address',
-                                               'model_name',
-                                       ]
-                               ),
+                               'fields' => [
+                                       'slot_revision_id',
+                                       'slot_content_id',
+                                       'slot_origin',
+                                       'slot_role_id',
+                                       'content_size',
+                                       'content_sha1',
+                                       'content_address',
+                                       'content_model',
+                                       'model_name',
+                               ],
                                'joins' => [
-                                       'slot_roles' => [ 'INNER JOIN', [ 'slot_role_id = role_id' ] ],
                                        'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
-                                       'content_models' => [ 'INNER JOIN', [ 'content_model = model_id' ] ],
+                                       'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ],
                                ],
                        ]
                ];
        }
 
+       /**
+        * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn
+        * @covers \MediaWiki\Storage\RevisionStore::insertSlotRowOn
+        * @covers \MediaWiki\Storage\RevisionStore::insertContentRowOn
+        */
+       public function testInsertRevisionOn_T202032() {
+               // This test only makes sense for MySQL
+               if ( $this->db->getType() !== 'mysql' ) {
+                       $this->assertTrue( true );
+                       return;
+               }
+
+               // NOTE: must be done before checking MAX(rev_id)
+               $page = $this->getTestPage();
+
+               $maxRevId = $this->db->selectField( 'revision', 'MAX(rev_id)' );
+
+               // Construct a slot row that will conflict with the insertion of the next revision ID,
+               // to emulate the failure mode described in T202032. Nothing will ever read this row,
+               // we just need it to trigger a primary key conflict.
+               $this->db->insert( 'slots', [
+                       'slot_revision_id' => $maxRevId + 1,
+                       'slot_role_id' => 1,
+                       'slot_content_id' => 0,
+                       'slot_origin' => 0
+               ], __METHOD__ );
+
+               $rev = new MutableRevisionRecord( $page->getTitle() );
+               $rev->setTimestamp( '20180101000000' );
+               $rev->setComment( CommentStoreComment::newUnsavedComment( 'test' ) );
+               $rev->setUser( $this->getTestUser()->getUser() );
+               $rev->setContent( 'main', new WikitextContent( 'Text' ) );
+               $rev->setPageId( $page->getId() );
+
+               $store = MediaWikiServices::getInstance()->getRevisionStore();
+               $return = $store->insertRevisionOn( $rev, $this->db );
+
+               $this->assertSame( $maxRevId + 2, $return->getId() );
+
+               // is the new revision correct?
+               $this->assertRevisionCompleteness( $return );
+               $this->assertRevisionRecordsEqual( $rev, $return );
+
+               // can we find it directly in the database?
+               $this->assertRevisionExistsInDatabase( $return );
+
+               // can we load it from the store?
+               $loaded = $store->getRevisionById( $return->getId() );
+               $this->assertRevisionCompleteness( $loaded );
+               $this->assertRevisionRecordsEqual( $return, $loaded );
+       }
+
 }
index 62093f0..43678f9 100644 (file)
@@ -5,6 +5,7 @@ namespace MediaWiki\Tests\Storage;
 use CommentStoreComment;
 use InvalidArgumentException;
 use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\MutableRevisionSlots;
 use MediaWiki\Storage\RevisionAccessException;
 use MediaWiki\Storage\RevisionRecord;
 use MediaWiki\Storage\RevisionSlotsUpdate;
@@ -195,6 +196,11 @@ class MutableRevisionRecordTest extends MediaWikiTestCase {
                $this->assertSame( 'someHash', $record->getSha1() );
        }
 
+       public function testGetSlots() {
+               $record = new MutableRevisionRecord( Title::newFromText( 'Foo' ) );
+               $this->assertInstanceOf( MutableRevisionSlots::class, $record->getSlots() );
+       }
+
        public function testSetGetSize() {
                $record = new MutableRevisionRecord( Title::newFromText( 'Foo' ) );
                $this->assertSame( 0, $record->getSize() );
index b5b2e0d..1517964 100644 (file)
@@ -26,6 +26,10 @@ class NameTableStoreTest extends MediaWikiTestCase {
                parent::setUp();
        }
 
+       protected function addCoreDBData() {
+               // The default implementation causes the slot_roles to already have content. Skip that.
+       }
+
        private function populateTable( $values ) {
                $insertValues = [];
                foreach ( $values as $name ) {
@@ -139,6 +143,9 @@ class NameTableStoreTest extends MediaWikiTestCase {
                $name,
                $expectedId
        ) {
+               // Make sure the table is empty!
+               $this->truncateTable( 'slot_roles' );
+
                $this->populateTable( $existingValues );
                $store = $this->getNameTableSqlStore( $cacheBag, (int)$needsInsert, $selectCalls );
 
@@ -266,6 +273,21 @@ class NameTableStoreTest extends MediaWikiTestCase {
                $this->assertSame( $expected, TestingAccessWrapper::newFromObject( $store )->tableCache );
        }
 
+       public function testReloadMap() {
+               $this->populateTable( [ 'foo' ] );
+               $store = $this->getNameTableSqlStore( new HashBagOStuff(), 0, 2 );
+
+               // force load
+               $this->assertCount( 1, $store->getMap() );
+
+               // add more stuff to the table, so the cache gets out of sync
+               $this->populateTable( [ 'bar' ] );
+
+               $expected = [ 1 => 'foo', 2 => 'bar' ];
+               $this->assertSame( $expected, $store->reloadMap() );
+               $this->assertSame( $expected, $store->getMap() );
+       }
+
        public function testCacheRaceCondition() {
                $wanHashBag = new HashBagOStuff();
                $store1 = $this->getNameTableSqlStore( $wanHashBag, 1, 1 );
index f01c6ba..2805ea8 100644 (file)
@@ -7,6 +7,7 @@ use Content;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Storage\RevisionRecord;
 use MediaWikiTestCase;
+use ParserOptions;
 use RecentChange;
 use Revision;
 use TextContent;
@@ -19,6 +20,13 @@ use WikiPage;
  */
 class PageUpdaterTest extends MediaWikiTestCase {
 
+       public static function setUpBeforeClass() {
+               parent::setUpBeforeClass();
+
+               // force service reset!
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'RevisionStore' );
+       }
+
        private function getDummyTitle( $method ) {
                return Title::newFromText( $method, $this->getDefaultWikitextNS() );
        }
@@ -217,6 +225,7 @@ class PageUpdaterTest extends MediaWikiTestCase {
 
                // check site stats - this asserts that derived data updates where run.
                $stats = $this->db->selectRow( 'site_stats', '*', '1=1' );
+               $this->assertNotNull( $stats, 'site_stats' );
                $this->assertSame( $oldStats->ss_total_pages + 0, (int)$stats->ss_total_pages );
                $this->assertSame( $oldStats->ss_total_edits + 2, (int)$stats->ss_total_edits );
        }
@@ -486,4 +495,89 @@ class PageUpdaterTest extends MediaWikiTestCase {
                );
        }
 
+       public function provideMagicWords() {
+               yield 'PAGEID' => [
+                       'Test {{PAGEID}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return $rev->getPageId();
+                       }
+               ];
+
+               yield 'REVISIONID' => [
+                       'Test {{REVISIONID}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return $rev->getId();
+                       }
+               ];
+
+               yield 'REVISIONUSER' => [
+                       'Test {{REVISIONUSER}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return $rev->getUser()->getName();
+                       }
+               ];
+
+               yield 'REVISIONTIMESTAMP' => [
+                       'Test {{REVISIONTIMESTAMP}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return $rev->getTimestamp();
+                       }
+               ];
+
+               yield 'subst:REVISIONUSER' => [
+                       'Test {{subst:REVISIONUSER}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return $rev->getUser()->getName();
+                       }
+               ];
+
+               yield 'subst:PAGENAME' => [
+                       'Test {{subst:PAGENAME}} Test',
+                       function ( RevisionRecord $rev ) {
+                               return 'PageUpdaterTest::testMagicWords';
+                       }
+               ];
+       }
+
+       /**
+        * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
+        *
+        * Integration test for PageUpdater, DerivedPageDataUpdater, RevisionRenderer
+        * and RenderedRevision, that ensures that magic words depending on revision meta-data
+        * are handled correctly. Note that each magic word needs to be tested separately,
+        * to assert correct behavior for each "vary" flag in the ParserOutput.
+        *
+        * @dataProvider provideMagicWords
+        */
+       public function testMagicWords( $wikitext, $callback ) {
+               $user = $this->getTestUser()->getUser();
+
+               $title = $this->getDummyTitle( __METHOD__ . '-' . $this->getName() );
+               $page = WikiPage::factory( $title );
+               $updater = $page->newPageUpdater( $user );
+
+               $updater->setContent( 'main', new \WikitextContent( $wikitext ) );
+
+               $summary = CommentStoreComment::newUnsavedComment( 'Just a test' );
+               $rev = $updater->saveRevision( $summary, EDIT_NEW );
+
+               if ( !$rev ) {
+                       $this->fail( $updater->getStatus()->getWikiText() );
+               }
+
+               $expected = strval( $callback( $rev ) );
+
+               $cache = MediaWikiServices::getInstance()->getParserCache();
+               $output = $cache->get(
+                       $page,
+                       ParserOptions::newCanonical(
+                               'canonical'
+                       )
+               );
+
+               $this->assertNotNull( $output, 'ParserCache::get' );
+
+               $this->assertContains( $expected, $output->getText() );
+       }
+
 }
index ad1e013..6679754 100644 (file)
@@ -77,15 +77,12 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
 
                $this->tablesUsed += $this->getMcrTablesToReset();
 
-               $this->setMwGlobals(
-                       'wgMultiContentRevisionSchemaMigrationStage',
-                       $this->getMcrMigrationStage()
-               );
-
-               $this->setMwGlobals(
-                       'wgContentHandlerUseDB',
-                       $this->getContentHandlerUseDB()
-               );
+               $this->setMwGlobals( [
+                       'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
+                       'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
+                       'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
+                       'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
+               ] );
 
                $this->overrideMwServices();
        }
@@ -244,14 +241,14 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $this->assertSame( 0, $count );
        }
 
-       private function assertLinkTargetsEqual( LinkTarget $l1, LinkTarget $l2 ) {
+       protected function assertLinkTargetsEqual( LinkTarget $l1, LinkTarget $l2 ) {
                $this->assertEquals( $l1->getDBkey(), $l2->getDBkey() );
                $this->assertEquals( $l1->getNamespace(), $l2->getNamespace() );
                $this->assertEquals( $l1->getFragment(), $l2->getFragment() );
                $this->assertEquals( $l1->getInterwiki(), $l2->getInterwiki() );
        }
 
-       private function assertRevisionRecordsEqual( RevisionRecord $r1, RevisionRecord $r2 ) {
+       protected function assertRevisionRecordsEqual( RevisionRecord $r1, RevisionRecord $r2 ) {
                $this->assertEquals(
                        $r1->getPageAsLinkTarget()->getNamespace(),
                        $r2->getPageAsLinkTarget()->getNamespace()
@@ -291,7 +288,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                }
        }
 
-       private function assertSlotRecordsEqual( SlotRecord $s1, SlotRecord $s2 ) {
+       protected function assertSlotRecordsEqual( SlotRecord $s1, SlotRecord $s2 ) {
                $this->assertSame( $s1->getRole(), $s2->getRole() );
                $this->assertSame( $s1->getModel(), $s2->getModel() );
                $this->assertSame( $s1->getFormat(), $s2->getFormat() );
@@ -303,7 +300,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $s1->hasAddress() ? $this->assertSame( $s1->hasAddress(), $s2->hasAddress() ) : null;
        }
 
-       private function assertRevisionCompleteness( RevisionRecord $r ) {
+       protected function assertRevisionCompleteness( RevisionRecord $r ) {
                $this->assertTrue( $r->hasSlot( 'main' ) );
                $this->assertInstanceOf( SlotRecord::class, $r->getSlot( 'main' ) );
                $this->assertInstanceOf( Content::class, $r->getContent( 'main' ) );
@@ -313,7 +310,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                }
        }
 
-       private function assertSlotCompleteness( RevisionRecord $r, SlotRecord $slot ) {
+       protected function assertSlotCompleteness( RevisionRecord $r, SlotRecord $slot ) {
                $this->assertTrue( $slot->hasAddress() );
                $this->assertSame( $r->getId(), $slot->getRevision() );
 
index d585240..f36fbfd 100644 (file)
@@ -967,4 +967,32 @@ class TitleTest extends MediaWikiTestCase {
                        [ 'zz:Foo#тест', '#.D1.82.D0.B5.D1.81.D1.82' ],
                ];
        }
+
+       /**
+        * @covers Title::isRawHtmlMessage
+        * @dataProvider provideIsRawHtmlMessage
+        */
+       public function testIsRawHtmlMessage( $textForm, $expected ) {
+               $this->setMwGlobals( 'wgRawHtmlMessages', [
+                       'foobar',
+                       'foo_bar',
+                       'foo-bar',
+               ] );
+
+               $title = Title::newFromText( $textForm );
+               $this->assertSame( $expected, $title->isRawHtmlMessage() );
+       }
+
+       public function provideIsRawHtmlMessage() {
+               return [
+                       [ 'MediaWiki:Foobar', true ],
+                       [ 'MediaWiki:Foo bar', true ],
+                       [ 'MediaWiki:Foo-bar', true ],
+                       [ 'MediaWiki:foo bar', true ],
+                       [ 'MediaWiki:foo-bar', true ],
+                       [ 'MediaWiki:foobar', true ],
+                       [ 'MediaWiki:some-other-message', false ],
+                       [ 'Main Page', false ],
+               ];
+       }
 }
index 374ea3c..65adedc 100644 (file)
@@ -125,10 +125,10 @@ class ApiBlockTest extends ApiTestCase {
                $this->doBlock( [ 'tags' => 'custom tag' ] );
 
                $dbw = wfGetDB( DB_MASTER );
-               $this->assertSame( 'custom tag', $dbw->selectField(
+               $this->assertSame( 1, (int)$dbw->selectField(
                        [ 'change_tag', 'logging' ],
-                       'ct_tag',
-                       [ 'log_type' => 'block' ],
+                       'COUNT(*)',
+                       [ 'log_type' => 'block', 'ct_tag' => 'custom tag' ],
                        __METHOD__,
                        [],
                        [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id = log_id' ] ]
index 0428335..30e1d0c 100644 (file)
@@ -73,6 +73,9 @@ class ApiComparePagesTest extends ApiTestCase {
                self::$repl['revF1'] = $this->addPage( 'F', "== Section 1 ==\nF 1.1\n\n== Section 2 ==\nF 1.2" );
                self::$repl['pageF'] = Title::newFromText( 'ApiComparePagesTest F' )->getArticleId();
 
+               self::$repl['revG1'] = $this->addPage( 'G', "== Section 1 ==\nG 1.1", CONTENT_MODEL_TEXT );
+               self::$repl['pageG'] = Title::newFromText( 'ApiComparePagesTest G' )->getArticleId();
+
                WikiPage::factory( Title::newFromText( 'ApiComparePagesTest C' ) )
                        ->doDeleteArticleReal( 'Test for ApiComparePagesTest' );
 
@@ -132,6 +135,7 @@ class ApiComparePagesTest extends ApiTestCase {
 
                $params += [
                        'action' => 'compare',
+                       'errorformat' => 'none',
                ];
 
                $user = $sysop
@@ -153,6 +157,25 @@ class ApiComparePagesTest extends ApiTestCase {
                }
        }
 
+       private static function makeDeprecationWarnings( ...$params ) {
+               $warn = [];
+               foreach ( $params as $p ) {
+                       $warn[] = [
+                               'code' => 'deprecation',
+                               'data' => [ 'feature' => "action=compare&{$p}" ],
+                               'module' => 'compare',
+                       ];
+                       if ( count( $warn ) === 1 ) {
+                               $warn[] = [
+                                       'code' => 'deprecation-help',
+                                       'module' => 'main',
+                               ];
+                       }
+               }
+
+               return $warn;
+       }
+
        public static function provideDiff() {
                // phpcs:disable Generic.Files.LineLength.TooLong
                return [
@@ -269,10 +292,12 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text' => [
                                [
-                                       'fromtext' => 'From text',
-                                       'fromcontentmodel' => 'wikitext',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
-                                       'tocontentmodel' => 'wikitext',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
+                                       'fromcontentmodel-main' => 'wikitext',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
+                                       'tocontentmodel-main' => 'wikitext',
                                ],
                                [
                                        'compare' => [
@@ -284,9 +309,11 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text 2' => [
                                [
-                                       'fromtext' => 'From text',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
-                                       'tocontentmodel' => 'wikitext',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
+                                       'tocontentmodel-main' => 'wikitext',
                                ],
                                [
                                        'compare' => [
@@ -298,15 +325,13 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, guessed model' => [
                                [
-                                       'fromtext' => 'From text',
-                                       'totext' => 'To text',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text',
                                ],
                                [
-                                       'warnings' => [
-                                               'compare' => [
-                                                       'warnings' => 'No content model could be determined, assuming wikitext.',
-                                               ],
-                                       ],
+                                       'warnings' => [ [ 'code' => 'compare-nocontentmodel', 'module' => 'compare' ] ],
                                        'compare' => [
                                                'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
                                                        . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
@@ -316,9 +341,11 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text with title and PST' => [
                                [
-                                       'fromtext' => 'From text',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
                                        'totitle' => 'Test',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
                                        'topst' => true,
                                ],
                                [
@@ -331,9 +358,11 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text with page ID and PST' => [
                                [
-                                       'fromtext' => 'From text',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
                                        'toid' => '{{REPL:pageB}}',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
                                        'topst' => true,
                                ],
                                [
@@ -346,9 +375,11 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text with revision and PST' => [
                                [
-                                       'fromtext' => 'From text',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
                                        'torev' => '{{REPL:revB2}}',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
                                        'topst' => true,
                                ],
                                [
@@ -361,9 +392,11 @@ class ApiComparePagesTest extends ApiTestCase {
                        ],
                        'Basic diff, text with deleted revision and PST' => [
                                [
-                                       'fromtext' => 'From text',
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => 'From text',
                                        'torev' => '{{REPL:revC2}}',
-                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => 'To text {{subst:PAGENAME}}',
                                        'topst' => true,
                                ],
                                [
@@ -378,20 +411,23 @@ class ApiComparePagesTest extends ApiTestCase {
                        'Basic diff, test with sections' => [
                                [
                                        'fromtitle' => 'ApiComparePagesTest F',
-                                       'fromsection' => 1,
-                                       'totext' => "== Section 1 ==\nTo text\n\n== Section 2 ==\nTo text?",
-                                       'tosection' => 2,
+                                       'fromslots' => 'main',
+                                       'fromtext-main' => "== Section 2 ==\nFrom text?",
+                                       'fromsection-main' => 2,
+                                       'totitle' => 'ApiComparePagesTest F',
+                                       'toslots' => 'main',
+                                       'totext-main' => "== Section 1 ==\nTo text?",
+                                       'tosection-main' => 1,
                                ],
                                [
                                        'compare' => [
                                                'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
                                                        . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
-                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>== Section <del class="diffchange diffchange-inline">1 </del>==</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>== Section <ins class="diffchange diffchange-inline">2 </ins>==</div></td></tr>' . "\n"
-                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">F 1.1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To text?</ins></div></td></tr>' . "\n",
-                                               'fromid' => '{{REPL:pageF}}',
-                                               'fromrevid' => '{{REPL:revF1}}',
-                                               'fromns' => '0',
-                                               'fromtitle' => 'ApiComparePagesTest F',
+                                                       . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 1 ==</div></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 1 ==</div></td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">F 1.1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To text?</ins></div></td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'></td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 2 ==</div></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 2 ==</div></td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From text?</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">F 1.2</ins></div></td></tr>' . "\n",
                                        ]
                                ],
                        ],
@@ -517,6 +553,197 @@ class ApiComparePagesTest extends ApiTestCase {
                                        ]
                                ],
                        ],
+                       'Diff for specific slots' => [
+                               // @todo Use a page with multiple slots here
+                               [
+                                       'fromrev' => '{{REPL:revA1}}',
+                                       'torev' => '{{REPL:revA3}}',
+                                       'prop' => 'diff',
+                                       'slots' => 'main',
+                               ],
+                               [
+                                       'compare' => [
+                                               'bodies' => [
+                                                       'main' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                               . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                               . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>A <del class="diffchange diffchange-inline">1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>A <ins class="diffchange diffchange-inline">3</ins></div></td></tr>' . "\n",
+                                               ],
+                                       ],
+                               ],
+                       ],
+                       // @todo Add a test for diffing with a deleted slot. Deleting 'main' doesn't work.
+
+                       'Basic diff, deprecated text' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'fromcontentmodel' => 'wikitext',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'tocontentmodel' => 'wikitext',
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'fromcontentmodel', 'totext', 'tocontentmodel' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text 2' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'tocontentmodel' => 'wikitext',
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext', 'tocontentmodel' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text, guessed model' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'totext' => 'To text',
+                               ],
+                               [
+                                       'warnings' => array_merge( self::makeDeprecationWarnings( 'fromtext', 'totext' ), [
+                                               [ 'code' => 'compare-nocontentmodel', 'module' => 'compare' ],
+                                       ] ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text</div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text with title and PST' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'totitle' => 'Test',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'topst' => true,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">Test</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text with page ID and PST' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'toid' => '{{REPL:pageB}}',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'topst' => true,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text with revision and PST' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'torev' => '{{REPL:revB2}}',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'topst' => true,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, deprecated text with deleted revision and PST' => [
+                               [
+                                       'fromtext' => 'From text',
+                                       'torev' => '{{REPL:revC2}}',
+                                       'totext' => 'To text {{subst:PAGENAME}}',
+                                       'topst' => true,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest C</ins></div></td></tr>' . "\n",
+                                       ]
+                               ],
+                               false, true
+                       ],
+                       'Basic diff, test with deprecated sections' => [
+                               [
+                                       'fromtitle' => 'ApiComparePagesTest F',
+                                       'fromsection' => 1,
+                                       'totext' => "== Section 1 ==\nTo text\n\n== Section 2 ==\nTo text?",
+                                       'tosection' => 2,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromsection', 'totext', 'tosection' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>== Section <del class="diffchange diffchange-inline">1 </del>==</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>== Section <ins class="diffchange diffchange-inline">2 </ins>==</div></td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">F 1.1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To text?</ins></div></td></tr>' . "\n",
+                                               'fromid' => '{{REPL:pageF}}',
+                                               'fromrevid' => '{{REPL:revF1}}',
+                                               'fromns' => '0',
+                                               'fromtitle' => 'ApiComparePagesTest F',
+                                       ]
+                               ],
+                       ],
+                       'Basic diff, test with deprecated sections and revdel, non-sysop' => [
+                               [
+                                       'fromrev' => '{{REPL:revB2}}',
+                                       'fromsection' => 0,
+                                       'torev' => '{{REPL:revB4}}',
+                                       'tosection' => 0,
+                               ],
+                               [],
+                               'missingcontent'
+                       ],
+                       'Basic diff, test with deprecated sections and revdel, sysop' => [
+                               [
+                                       'fromrev' => '{{REPL:revB2}}',
+                                       'fromsection' => 0,
+                                       'torev' => '{{REPL:revB4}}',
+                                       'tosection' => 0,
+                               ],
+                               [
+                                       'warnings' => self::makeDeprecationWarnings( 'fromsection', 'tosection' ),
+                                       'compare' => [
+                                               'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
+                                                       . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
+                                                       . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>B <del class="diffchange diffchange-inline">2</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>B <ins class="diffchange diffchange-inline">4</ins></div></td></tr>' . "\n",
+                                               'fromid' => '{{REPL:pageB}}',
+                                               'fromrevid' => '{{REPL:revB2}}',
+                                               'fromns' => 0,
+                                               'fromtitle' => 'ApiComparePagesTest B',
+                                               'fromtexthidden' => true,
+                                               'fromuserhidden' => true,
+                                               'fromcommenthidden' => true,
+                                               'toid' => '{{REPL:pageB}}',
+                                               'torevid' => '{{REPL:revB4}}',
+                                               'tons' => 0,
+                                               'totitle' => 'ApiComparePagesTest B',
+                                       ]
+                               ],
+                               false, true,
+                       ],
 
                        'Error, missing title' => [
                                [
@@ -647,6 +874,68 @@ class ApiComparePagesTest extends ApiTestCase {
                                [],
                                'missingcontent'
                        ],
+                       'Error, Relative diff, no prev' => [
+                               [
+                                       'fromrev' => '{{REPL:revA1}}',
+                                       'torelative' => 'prev',
+                                       'prop' => 'ids',
+                               ],
+                               [],
+                               'baddiff'
+                       ],
+                       'Error, Relative diff, no next' => [
+                               [
+                                       'fromrev' => '{{REPL:revA4}}',
+                                       'torelative' => 'next',
+                                       'prop' => 'ids',
+                               ],
+                               [],
+                               'baddiff'
+                       ],
+                       'Error, section diff with no revision' => [
+                               [
+                                       'fromtitle' => 'ApiComparePagesTest F',
+                                       'toslots' => 'main',
+                                       'totext-main' => "== Section 1 ==\nTo text?",
+                                       'tosection-main' => 1,
+                               ],
+                               [],
+                               'compare-notorevision',
+                       ],
+                       'Error, section diff with revdeleted revision' => [
+                               [
+                                       'fromtitle' => 'ApiComparePagesTest F',
+                                       'torev' => '{{REPL:revB2}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => "== Section 1 ==\nTo text?",
+                                       'tosection-main' => 1,
+                               ],
+                               [],
+                               'missingcontent',
+                       ],
+                       'Error, section diff with a content model not supporting sections' => [
+                               [
+                                       'fromtitle' => 'ApiComparePagesTest G',
+                                       'torev' => '{{REPL:revG1}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => "== Section 1 ==\nTo text?",
+                                       'tosection-main' => 1,
+                               ],
+                               [],
+                               'sectionsnotsupported',
+                       ],
+                       'Error, section diff with bad content model' => [
+                               [
+                                       'fromtitle' => 'ApiComparePagesTest F',
+                                       'torev' => '{{REPL:revF1}}',
+                                       'toslots' => 'main',
+                                       'totext-main' => "== Section 1 ==\nTo text?",
+                                       'tosection-main' => 1,
+                                       'tocontentmodel-main' => CONTENT_MODEL_TEXT,
+                               ],
+                               [],
+                               'sectionreplacefailed',
+                       ],
                ];
                // phpcs:enable
        }
index 8a40266..7f2c1a6 100644 (file)
@@ -77,11 +77,15 @@ class ApiParseTest extends ApiTestCase {
                        $expectedEnd = "</div>";
                        $this->assertSame( $expectedEnd, substr( $html, -strlen( $expectedEnd ) ) );
 
+                       $unexpectedEnd = '#<!-- \nNewPP limit report|' .
+                               '<!--\nTransclusion expansion time report#s';
+                       $this->assertNotRegExp( $unexpectedEnd, $html );
+
                        $html = substr( $html, 0, strlen( $html ) - strlen( $expectedEnd ) );
                } else {
                        $expectedEnd = '#\n<!-- \nNewPP limit report\n(?>.+?\n-->)\n' .
                                '<!--\nTransclusion expansion time report \(%,ms,calls,template\)\n(?>.*?\n-->)\n' .
-                               '</div>(\n<!-- Saved in parser cache (?>.*?\n -->)\n)?$#s';
+                               '(\n<!-- Saved in parser cache (?>.*?\n -->)\n)?</div>$#s';
                        $this->assertRegExp( $expectedEnd, $html );
 
                        $html = preg_replace( $expectedEnd, '', $html );
index 40f6807..3336235 100644 (file)
@@ -86,14 +86,17 @@ class DifferenceEngineTest extends MediaWikiTestCase {
        public function testLoadRevisionData() {
                $cases = $this->getLoadRevisionDataCases();
 
-               foreach ( $cases as $case ) {
-                       list( $expectedOld, $expectedNew, $old, $new, $message ) = $case;
+               foreach ( $cases as $testName => $case ) {
+                       list( $expectedOld, $expectedNew, $expectedRet, $old, $new ) = $case;
 
                        $diffEngine = new DifferenceEngine( $this->context, $old, $new, 2, true, false );
-                       $diffEngine->loadRevisionData();
+                       $ret = $diffEngine->loadRevisionData();
+                       $ret2 = $diffEngine->loadRevisionData();
 
-                       $this->assertEquals( $diffEngine->getOldid(), $expectedOld, $message );
-                       $this->assertEquals( $diffEngine->getNewid(), $expectedNew, $message );
+                       $this->assertEquals( $expectedOld, $diffEngine->getOldid(), $testName );
+                       $this->assertEquals( $expectedNew, $diffEngine->getNewid(), $testName );
+                       $this->assertEquals( $expectedRet, $ret, $testName );
+                       $this->assertEquals( $expectedRet, $ret2, $testName );
                }
        }
 
@@ -101,10 +104,12 @@ class DifferenceEngineTest extends MediaWikiTestCase {
                $revs = self::$revisions;
 
                return [
-                       [ $revs[2], $revs[3], $revs[3], 'prev', 'diff=prev' ],
-                       [ $revs[2], $revs[3], $revs[2], 'next', 'diff=next' ],
-                       [ $revs[1], $revs[3], $revs[1], $revs[3], 'diff=' . $revs[3] ],
-                       [ $revs[1], $revs[3], $revs[1], 0, 'diff=0' ]
+                       'diff=prev' => [ $revs[2], $revs[3], true, $revs[3], 'prev' ],
+                       'diff=next' => [ $revs[2], $revs[3], true, $revs[2], 'next' ],
+                       'diff=' . $revs[3] => [ $revs[1], $revs[3], true, $revs[1], $revs[3] ],
+                       'diff=0' => [ $revs[1], $revs[3], true, $revs[1], 0 ],
+                       'diff=prev&oldid=<first>' => [ false, $revs[0], true, $revs[0], 'prev' ],
+                       'invalid' => [ 123456789, $revs[1], false, 123456789, $revs[1] ],
                ];
        }
 
index 276fee3..4bd845d 100644 (file)
@@ -29,6 +29,8 @@ class StaticArrayWriterTest extends PHPUnit\Framework\TestCase {
                        'foo' => 'bar',
                        'baz' => 'rawr',
                        "they're" => '"quoted properly"',
+                       'nested' => [ 'elements', 'work' ],
+                       'and' => [ 'these' => 'do too' ],
                ];
                $writer = new StaticArrayWriter();
                $actual = $writer->create( $data, "Header\nWith\nNewlines" );
@@ -41,6 +43,13 @@ return [
        'foo' => 'bar',
        'baz' => 'rawr',
        'they\'re' => '"quoted properly"',
+       'nested' => [
+               0 => 'elements',
+               1 => 'work',
+       ],
+       'and' => [
+               'these' => 'do too',
+       ],
 ];
 
 PHP;
diff --git a/tests/phpunit/includes/page/ArticleViewTest.php b/tests/phpunit/includes/page/ArticleViewTest.php
new file mode 100644 (file)
index 0000000..d721274
--- /dev/null
@@ -0,0 +1,488 @@
+<?php
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionRecord;
+use PHPUnit\Framework\MockObject\MockObject;
+
+/**
+ * @covers \Article::view()
+ */
+class ArticleViewTest extends MediaWikiTestCase {
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setUserLang( 'qqx' );
+       }
+
+       private function getHtml( OutputPage $output ) {
+               return preg_replace( '/<!--.*?-->/s', '', $output->getHTML() );
+       }
+
+       /**
+        * @param string|Title $title
+        * @param Content[]|string[] $revisionContents Content of the revisions to create
+        *        (as Content or string).
+        * @param RevisionRecord[] &$revisions will be filled with the RevisionRecord for $content.
+        *
+        * @return WikiPage
+        * @throws MWException
+        */
+       private function getPage( $title, array $revisionContents = [], array &$revisions = [] ) {
+               if ( is_string( $title ) ) {
+                       $title = Title::makeTitle( $this->getDefaultWikitextNS(), $title );
+               }
+
+               $page = WikiPage::factory( $title );
+
+               $user = $this->getTestUser()->getUser();
+
+               foreach ( $revisionContents as $key => $cont ) {
+                       if ( is_string( $cont ) ) {
+                               $cont = new WikitextContent( $cont );
+                       }
+
+                       $u = $page->newPageUpdater( $user );
+                       $u->setContent( 'main', $cont );
+                       $rev = $u->saveRevision( CommentStoreComment::newUnsavedComment( 'Rev ' . $key ) );
+
+                       $revisions[ $key ] = $rev;
+               }
+
+               return $page;
+       }
+
+       /**
+        * @covers Article::getOldId()
+        * @covers Article::getRevIdFetched()
+        */
+       public function testGetOldId() {
+               $revisions = [];
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
+
+               $idA = $revisions[1]->getId();
+               $idB = $revisions[2]->getId();
+
+               // oldid in constructor
+               $article = new Article( $page->getTitle(), $idA );
+               $this->assertSame( $idA, $article->getOldID() );
+               $article->getRevisionFetched();
+               $this->assertSame( $idA, $article->getRevIdFetched() );
+
+               // oldid 0 in constructor
+               $article = new Article( $page->getTitle(), 0 );
+               $this->assertSame( 0, $article->getOldID() );
+               $article->getRevisionFetched();
+               $this->assertSame( $idB, $article->getRevIdFetched() );
+
+               // oldid in request
+               $article = new Article( $page->getTitle() );
+               $context = new RequestContext();
+               $context->setRequest( new FauxRequest( [ 'oldid' => $idA ] ) );
+               $article->setContext( $context );
+               $this->assertSame( $idA, $article->getOldID() );
+               $article->getRevisionFetched();
+               $this->assertSame( $idA, $article->getRevIdFetched() );
+
+               // no oldid
+               $article = new Article( $page->getTitle() );
+               $context = new RequestContext();
+               $context->setRequest( new FauxRequest( [] ) );
+               $article->setContext( $context );
+               $this->assertSame( 0, $article->getOldID() );
+               $article->getRevisionFetched();
+               $this->assertSame( $idB, $article->getRevIdFetched() );
+       }
+
+       public function testView() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'Test B', $this->getHtml( $output ) );
+               $this->assertNotContains( 'id="mw-revision-info"', $this->getHtml( $output ) );
+               $this->assertNotContains( 'id="mw-revision-nav"', $this->getHtml( $output ) );
+       }
+
+       public function testViewCached() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
+
+               $po = new ParserOutput( 'Cached Text' );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+
+               $cache = MediaWikiServices::getInstance()->getParserCache();
+               $cache->save( $po, $page, $article->getParserOptions() );
+
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'Cached Text', $this->getHtml( $output ) );
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
+       }
+
+       /**
+        * @covers Article::getRedirectTarget()
+        */
+       public function testViewRedirect() {
+               $target = Title::makeTitle( $this->getDefaultWikitextNS(), 'Test_Target' );
+               $redirectText = '#REDIRECT [[' . $target->getPrefixedText() . ']]';
+
+               $page = $this->getPage( __METHOD__, [ $redirectText ] );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $this->assertNotNull(
+                       $article->getRedirectTarget()->getPrefixedDBkey()
+               );
+               $this->assertSame(
+                       $target->getPrefixedDBkey(),
+                       $article->getRedirectTarget()->getPrefixedDBkey()
+               );
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'class="redirectText"', $this->getHtml( $output ) );
+               $this->assertContains(
+                       '>' . htmlspecialchars( $target->getPrefixedText() ) . '<',
+                       $this->getHtml( $output )
+               );
+       }
+
+       public function testViewNonText() {
+               $dummy = $this->getPage( __METHOD__, [ 'Dummy' ] );
+               $dummyRev = $dummy->getRevision()->getRevisionRecord();
+               $title = $dummy->getTitle();
+
+               /** @var MockObject|ContentHandler $mockHandler */
+               $mockHandler = $this->getMockBuilder( ContentHandler::class )
+                       ->setMethods(
+                               [
+                                       'isParserCacheSupported',
+                                       'serializeContent',
+                                       'unserializeContent',
+                                       'makeEmptyContent',
+                               ]
+                       )
+                       ->setConstructorArgs( [ 'NotText', [ 'application/frobnitz' ] ] )
+                       ->getMock();
+
+               $mockHandler->method( 'isParserCacheSupported' )
+                       ->willReturn( false );
+
+               $this->setTemporaryHook(
+                       'ContentHandlerForModelID',
+                       function ( $id, &$handler ) use ( $mockHandler ) {
+                               $handler = $mockHandler;
+                       }
+               );
+
+               /** @var MockObject|Content $content */
+               $content = $this->getMock( Content::class );
+               $content->method( 'getParserOutput' )
+                       ->willReturn( new ParserOutput( 'Structured Output' ) );
+               $content->method( 'getModel' )
+                       ->willReturn( 'NotText' );
+               $content->method( 'getNativeData' )
+                       ->willReturn( [ (object)[ 'x' => 'stuff' ] ] );
+               $content->method( 'copy' )
+                       ->willReturn( $content );
+
+               $rev = new MutableRevisionRecord( $title );
+               $rev->setId( $dummyRev->getId() );
+               $rev->setPageId( $title->getArticleID() );
+               $rev->setUser( $dummyRev->getUser() );
+               $rev->setComment( $dummyRev->getComment() );
+               $rev->setTimestamp( $dummyRev->getTimestamp() );
+
+               $rev->setContent( 'main', $content );
+
+               $rev = new Revision( $rev );
+
+               /** @var MockObject|WikiPage $page */
+               $page = $this->getMockBuilder( WikiPage::class )
+                       ->setMethods( [ 'getRevision', 'getLatest' ] )
+                       ->setConstructorArgs( [ $title ] )
+                       ->getMock();
+
+               $page->method( 'getRevision' )
+                       ->willReturn( $rev );
+               $page->method( 'getLatest' )
+                       ->willReturn( $rev->getId() );
+
+               $article = Article::newFromWikiPage( $page, RequestContext::getMain() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'Structured Output', $this->getHtml( $output ) );
+               $this->assertNotContains( 'Dummy', $this->getHtml( $output ) );
+       }
+
+       public function testViewOfOldRevision() {
+               $revisions = [];
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
+               $idA = $revisions[1]->getId();
+
+               $article = new Article( $page->getTitle(), $idA );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertContains( 'id="mw-revision-info"', $output->getSubtitle() );
+               $this->assertContains( 'id="mw-revision-nav"', $output->getSubtitle() );
+
+               $this->assertNotContains( 'id="revision-info-current"', $output->getSubtitle() );
+               $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
+       }
+
+       public function testViewOfCurrentRevision() {
+               $revisions = [];
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
+               $idB = $revisions[2]->getId();
+
+               $article = new Article( $page->getTitle(), $idB );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'Test B', $this->getHtml( $output ) );
+               $this->assertContains( 'id="mw-revision-info-current"', $output->getSubtitle() );
+               $this->assertContains( 'id="mw-revision-nav"', $output->getSubtitle() );
+       }
+
+       public function testViewOfMissingRevision() {
+               $revisions = [];
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A' ], $revisions );
+               $badId = $revisions[1]->getId() + 100;
+
+               $article = new Article( $page->getTitle(), $badId );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'missing-revision: ' . $badId, $this->getHtml( $output ) );
+
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+       }
+
+       public function testViewOfDeletedRevision() {
+               $revisions = [];
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
+               $idA = $revisions[1]->getId();
+
+               $revDelList = new RevDelRevisionList(
+                       RequestContext::getMain(), $page->getTitle(), [ $idA ]
+               );
+               $revDelList->setVisibility( [
+                       'value' => [ RevisionRecord::DELETED_TEXT => 1 ],
+                       'comment' => "Testing",
+               ] );
+
+               $article = new Article( $page->getTitle(), $idA );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( '(rev-deleted-text-permission)', $this->getHtml( $output ) );
+
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
+       }
+
+       public function testViewMissingPage() {
+               $page = $this->getPage( __METHOD__ );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
+       }
+
+       public function testViewDeletedPage() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
+               $page->doDeleteArticle( 'Test' );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( 'moveddeleted', $this->getHtml( $output ) );
+               $this->assertContains( 'logentry-delete-delete', $this->getHtml( $output ) );
+               $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
+
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
+       }
+
+       public function testViewMessagePage() {
+               $title = Title::makeTitle( NS_MEDIAWIKI, 'Mainpage' );
+               $page = $this->getPage( $title );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains(
+                       wfMessage( 'mainpage' )->inContentLanguage()->parse(),
+                       $this->getHtml( $output )
+               );
+               $this->assertNotContains( '(noarticletextanon)', $this->getHtml( $output ) );
+       }
+
+       public function testViewMissingUserPage() {
+               $user = $this->getTestUser()->getUser();
+               $user->addToDatabase();
+
+               $title = Title::makeTitle( NS_USER, $user->getName() );
+
+               $page = $this->getPage( $title );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
+               $this->assertNotContains( '(userpage-userdoesnotexist-view)', $this->getHtml( $output ) );
+       }
+
+       public function testViewUserPageOfNonexistingUser() {
+               $user = User::newFromName( 'Testing ' . __METHOD__ );
+
+               $title = Title::makeTitle( NS_USER, $user->getName() );
+
+               $page = $this->getPage( $title );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
+               $this->assertContains( '(userpage-userdoesnotexist-view:', $this->getHtml( $output ) );
+       }
+
+       public function testArticleViewHeaderHook() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+
+               $this->setTemporaryHook(
+                       'ArticleViewHeader',
+                       function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
+                               $this->assertSame( $article, $articlePage, '$articlePage' );
+
+                               $outputDone = new ParserOutput( 'Hook Text' );
+                               $outputDone->setTitleText( 'Hook Title' );
+
+                               $articlePage->getContext()->getOutput()->addParserOutput( $outputDone );
+                       }
+               );
+
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
+               $this->assertSame( 'Hook Title', $output->getPageTitle() );
+       }
+
+       public function testArticleContentViewCustomHook() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+
+               // use ArticleViewHeader hook to bypass the parser cache
+               $this->setTemporaryHook(
+                       'ArticleViewHeader',
+                       function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
+                               $useParserCache = false;
+                       }
+               );
+
+               $this->setTemporaryHook(
+                       'ArticleContentViewCustom',
+                       function ( Content $content, Title $title, OutputPage $output ) use ( $page ) {
+                               $this->assertSame( $page->getTitle(), $title, '$title' );
+                               $this->assertSame( 'Test A', $content->getNativeData(), '$content' );
+
+                               $output->addHTML( 'Hook Text' );
+                               return false;
+                       }
+               );
+
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
+       }
+
+       public function testArticleAfterFetchContentObjectHook() {
+               $page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
+
+               $article = new Article( $page->getTitle(), 0 );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+
+               // use ArticleViewHeader hook to bypass the parser cache
+               $this->setTemporaryHook(
+                       'ArticleViewHeader',
+                       function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
+                               $useParserCache = false;
+                       }
+               );
+
+               $this->setTemporaryHook(
+                       'ArticleAfterFetchContentObject',
+                       function ( Article &$articlePage, Content &$content ) use ( $page, $article ) {
+                               $this->assertSame( $article, $articlePage, '$articlePage' );
+                               $this->assertSame( 'Test A', $content->getNativeData(), '$content' );
+
+                               $content = new WikitextContent( 'Hook Text' );
+                       }
+               );
+
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
+               $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
+       }
+
+       public function testShowMissingArticleHook() {
+               $page = $this->getPage( __METHOD__ );
+
+               $article = new Article( $page->getTitle() );
+               $article->getContext()->getOutput()->setTitle( $page->getTitle() );
+
+               $this->setTemporaryHook(
+                       'ShowMissingArticle',
+                       function ( Article $articlePage ) use ( $article ) {
+                               $this->assertSame( $article, $articlePage, '$articlePage' );
+
+                               $articlePage->getContext()->getOutput()->addHTML( 'Hook Text' );
+                       }
+               );
+
+               $article->view();
+
+               $output = $article->getContext()->getOutput();
+               $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
+               $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
+       }
+
+}
index d2ed441..497c6b5 100644 (file)
@@ -180,6 +180,18 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
                ];
        }
 
+       public function testWrapOutput() {
+               global $wgParser;
+               $title = Title::newFromText( 'foo' );
+               $po = new ParserOptions();
+               $wgParser->parse( 'Hello World', $title, $po );
+               $text = $wgParser->getOutput()->getText();
+
+               $this->assertContains( 'Hello World', $text );
+               $this->assertContains( '<div', $text );
+               $this->assertContains( 'class="mw-parser-output"', $text );
+       }
+
        // @todo Add tests for cleanSig() / cleanSigInSig(), getSection(),
        // replaceSection(), getPreloadText()
 }
index 8c17780..6413ddd 100644 (file)
@@ -13,6 +13,7 @@ class ParserOptionsTest extends MediaWikiTestCase {
                $wrap->defaults = null;
                $wrap->lazyOptions = [
                        'dateformat' => [ ParserOptions::class, 'initDateFormat' ],
+                       'speculativeRevId' => [ ParserOptions::class, 'initSpeculativeRevId' ],
                ];
                $wrap->inCacheKey = [
                        'dateformat' => true,
@@ -309,4 +310,19 @@ class ParserOptionsTest extends MediaWikiTestCase {
                ], ParserOptions::allCacheVaryingOptions() );
        }
 
+       public function testGetSpeculativeRevid() {
+               $options = new ParserOptions();
+
+               $this->assertFalse( $options->getSpeculativeRevId() );
+
+               $counter = 0;
+               $options->setSpeculativeRevIdCallback( function () use( &$counter ) {
+                       return ++$counter;
+               } );
+
+               // make sure the same value is re-used once it is determined
+               $this->assertSame( 1, $options->getSpeculativeRevId() );
+               $this->assertSame( 1, $options->getSpeculativeRevId() );
+       }
+
 }
index b08ba6c..3c73430 100644 (file)
@@ -1,10 +1,11 @@
 <?php
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group Database
  *        ^--- trigger DB shadowing because we are using Title magic
  */
-class ParserOutputTest extends MediaWikiTestCase {
+class ParserOutputTest extends MediaWikiLangTestCase {
 
        public static function provideIsLinkInternal() {
                return [
@@ -89,6 +90,59 @@ class ParserOutputTest extends MediaWikiTestCase {
                $this->assertArrayNotHasKey( 'foo', $properties );
        }
 
+       /**
+        * @covers ParserOutput::getWrapperDivClass
+        * @covers ParserOutput::addWrapperDivClass
+        * @covers ParserOutput::clearWrapperDivClass
+        * @covers ParserOutput::getText
+        */
+       public function testWrapperDivClass() {
+               $po = new ParserOutput();
+
+               $po->setText( 'Kittens' );
+               $this->assertContains( 'Kittens', $po->getText() );
+               $this->assertNotContains( '<div', $po->getText() );
+               $this->assertSame( 'Kittens', $po->getRawText() );
+
+               $po->addWrapperDivClass( 'foo' );
+               $text = $po->getText();
+               $this->assertContains( 'Kittens', $text );
+               $this->assertContains( '<div', $text );
+               $this->assertContains( 'class="foo"', $text );
+
+               $po->addWrapperDivClass( 'bar' );
+               $text = $po->getText();
+               $this->assertContains( 'Kittens', $text );
+               $this->assertContains( '<div', $text );
+               $this->assertContains( 'class="foo bar"', $text );
+
+               $po->addWrapperDivClass( 'bar' ); // second time does nothing, no "foo bar bar".
+               $text = $po->getText( [ 'unwrap' => true ] );
+               $this->assertContains( 'Kittens', $text );
+               $this->assertNotContains( '<div', $text );
+               $this->assertNotContains( 'class="foo bar"', $text );
+
+               $text = $po->getText( [ 'wrapperDivClass' => '' ] );
+               $this->assertContains( 'Kittens', $text );
+               $this->assertNotContains( '<div', $text );
+               $this->assertNotContains( 'class="foo bar"', $text );
+
+               $text = $po->getText( [ 'wrapperDivClass' => 'xyzzy' ] );
+               $this->assertContains( 'Kittens', $text );
+               $this->assertContains( '<div', $text );
+               $this->assertContains( 'class="xyzzy"', $text );
+               $this->assertNotContains( 'class="foo bar"', $text );
+
+               $text = $po->getRawText();
+               $this->assertSame( 'Kittens', $text );
+
+               $po->clearWrapperDivClass();
+               $text = $po->getText();
+               $this->assertContains( 'Kittens', $text );
+               $this->assertNotContains( '<div', $text );
+               $this->assertNotContains( 'class="foo bar"', $text );
+       }
+
        /**
         * @covers ParserOutput::getText
         * @dataProvider provideGetText
@@ -111,7 +165,7 @@ class ParserOutputTest extends MediaWikiTestCase {
        public static function provideGetText() {
                // phpcs:disable Generic.Files.LineLength
                $text = <<<EOF
-<div class="mw-parser-output"><p>Test document.
+<p>Test document.
 </p>
 <mw:toc><div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
 <ul>
@@ -136,7 +190,7 @@ class ParserOutputTest extends MediaWikiTestCase {
 </p>
 <h2><span class="mw-headline" id="Section_3">Section 3</span><mw:editsection page="Test Page" section="4">Section 3</mw:editsection></h2>
 <p>Three
-</p></div>
+</p>
 EOF;
 
                $dedupText = <<<EOF
@@ -155,7 +209,7 @@ EOF;
                return [
                        'No options' => [
                                [], $text, <<<EOF
-<div class="mw-parser-output"><p>Test document.
+<p>Test document.
 </p>
 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
 <ul>
@@ -180,12 +234,12 @@ EOF;
 </p>
 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p>Three
-</p></div>
+</p>
 EOF
                        ],
                        'Disable section edit links' => [
                                [ 'enableSectionEditLinks' => false ], $text, <<<EOF
-<div class="mw-parser-output"><p>Test document.
+<p>Test document.
 </p>
 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
 <ul>
@@ -210,11 +264,11 @@ EOF
 </p>
 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
 <p>Three
-</p></div>
+</p>
 EOF
                        ],
-                       'Disable TOC' => [
-                               [ 'allowTOC' => false ], $text, <<<EOF
+                       'Disable TOC, but wrap' => [
+                               [ 'allowTOC' => false, 'wrapperDivClass' => 'mw-parser-output' ], $text, <<<EOF
 <div class="mw-parser-output"><p>Test document.
 </p>
 
@@ -231,44 +285,6 @@ EOF
 <p>Three
 </p></div>
 EOF
-                       ],
-                       'Unwrap text' => [
-                               [ 'unwrap' => true ], $text, <<<EOF
-<p>Test document.
-</p>
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
-<ul>
-<li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
-<li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
-<ul>
-<li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
-</ul>
-</li>
-<li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
-</ul>
-</div>
-
-<h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<p>One
-</p>
-<h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<p>Two
-</p>
-<h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
-<p>Two point one
-</p>
-<h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<p>Three
-</p>
-EOF
-                       ],
-                       'Unwrap without a mw-parser-output wrapper' => [
-                               [ 'unwrap' => true ], '<div class="foobar">Content</div>', '<div class="foobar">Content</div>'
-                       ],
-                       'Unwrap with extra comment at end' => [
-                               [ 'unwrap' => true ], '<div class="mw-parser-output"><p>Test document.</p></div>
-<!-- Saved in parser cache... -->', '<p>Test document.</p>
-<!-- Saved in parser cache... -->'
                        ],
                        'Style deduplication' => [
                                [], $dedupText, <<<EOF
@@ -291,4 +307,601 @@ EOF
                // phpcs:enable
        }
 
+       /**
+        * @covers ParserOutput::hasText
+        */
+       public function testHasText() {
+               $po = new ParserOutput();
+               $this->assertTrue( $po->hasText() );
+
+               $po = new ParserOutput( null );
+               $this->assertFalse( $po->hasText() );
+
+               $po = new ParserOutput( '' );
+               $this->assertTrue( $po->hasText() );
+
+               $po = new ParserOutput( null );
+               $po->setText( '' );
+               $this->assertTrue( $po->hasText() );
+       }
+
+       /**
+        * @covers ParserOutput::getText
+        */
+       public function testGetText_failsIfNoText() {
+               $po = new ParserOutput( null );
+
+               $this->setExpectedException( LogicException::class );
+               $po->getText();
+       }
+
+       /**
+        * @covers ParserOutput::getRawText
+        */
+       public function testGetRawText_failsIfNoText() {
+               $po = new ParserOutput( null );
+
+               $this->setExpectedException( LogicException::class );
+               $po->getRawText();
+       }
+
+       public function provideMergeHtmlMetaDataFrom() {
+               // title text ------------
+               $a = new ParserOutput();
+               $a->setTitleText( 'X' );
+               $b = new ParserOutput();
+               yield 'only left title text' => [ $a, $b, [ 'getTitleText' => 'X' ] ];
+
+               $a = new ParserOutput();
+               $b = new ParserOutput();
+               $b->setTitleText( 'Y' );
+               yield 'only right title text' => [ $a, $b, [ 'getTitleText' => 'Y' ] ];
+
+               $a = new ParserOutput();
+               $a->setTitleText( 'X' );
+               $b = new ParserOutput();
+               $b->setTitleText( 'Y' );
+               yield 'left title text wins' => [ $a, $b, [ 'getTitleText' => 'X' ] ];
+
+               // index policy ------------
+               $a = new ParserOutput();
+               $a->setIndexPolicy( 'index' );
+               $b = new ParserOutput();
+               yield 'only left index policy' => [ $a, $b, [ 'getIndexPolicy' => 'index' ] ];
+
+               $a = new ParserOutput();
+               $b = new ParserOutput();
+               $b->setIndexPolicy( 'index' );
+               yield 'only right index policy' => [ $a, $b, [ 'getIndexPolicy' => 'index' ] ];
+
+               $a = new ParserOutput();
+               $a->setIndexPolicy( 'noindex' );
+               $b = new ParserOutput();
+               $b->setIndexPolicy( 'index' );
+               yield 'left noindex wins' => [ $a, $b, [ 'getIndexPolicy' => 'noindex' ] ];
+
+               $a = new ParserOutput();
+               $a->setIndexPolicy( 'index' );
+               $b = new ParserOutput();
+               $b->setIndexPolicy( 'noindex' );
+               yield 'right noindex wins' => [ $a, $b, [ 'getIndexPolicy' => 'noindex' ] ];
+
+               // head items and friends ------------
+               $a = new ParserOutput();
+               $a->addHeadItem( '<foo1>' );
+               $a->addHeadItem( '<bar1>', 'bar' );
+               $a->addModules( 'test-module-a' );
+               $a->addModuleScripts( 'test-module-script-a' );
+               $a->addModuleStyles( 'test-module-styles-a' );
+               $b->addJsConfigVars( 'test-config-var-a', 'a' );
+
+               $b = new ParserOutput();
+               $b->setIndexPolicy( 'noindex' );
+               $b->addHeadItem( '<foo2>' );
+               $b->addHeadItem( '<bar2>', 'bar' );
+               $b->addModules( 'test-module-b' );
+               $b->addModuleScripts( 'test-module-script-b' );
+               $b->addModuleStyles( 'test-module-styles-b' );
+               $b->addJsConfigVars( 'test-config-var-b', 'b' );
+               $b->addJsConfigVars( 'test-config-var-a', 'X' );
+
+               yield 'head items and friends' => [ $a, $b, [
+                       'getHeadItems' => [
+                               '<foo1>',
+                               '<foo2>',
+                               'bar' => '<bar2>', // overwritten
+                       ],
+                       'getModules' => [
+                               'test-module-a',
+                               'test-module-b',
+                       ],
+                       'getModuleScripts' => [
+                               'test-module-script-a',
+                               'test-module-script-b',
+                       ],
+                       'getModuleStyles' => [
+                               'test-module-styles-a',
+                               'test-module-styles-b',
+                       ],
+                       'getJsConfigVars' => [
+                               'test-config-var-a' => 'X', // overwritten
+                               'test-config-var-b' => 'b',
+                       ],
+               ] ];
+
+               // TOC ------------
+               $a = new ParserOutput();
+               $a->setTOCHTML( '<p>TOC A</p>' );
+               $a->setSections( [ [ 'fromtitle' => 'A1' ], [ 'fromtitle' => 'A2' ] ] );
+
+               $b = new ParserOutput();
+               $b->setTOCHTML( '<p>TOC B</p>' );
+               $b->setSections( [ [ 'fromtitle' => 'B1' ], [ 'fromtitle' => 'B2' ] ] );
+
+               yield 'concat TOC' => [ $a, $b, [
+                       'getTOCHTML' => '<p>TOC A</p><p>TOC B</p>',
+                       'getSections' => [
+                               [ 'fromtitle' => 'A1' ],
+                               [ 'fromtitle' => 'A2' ],
+                               [ 'fromtitle' => 'B1' ],
+                               [ 'fromtitle' => 'B2' ]
+                       ],
+               ] ];
+
+               // Skin Control  ------------
+               $a = new ParserOutput();
+               $a->setNewSection( true );
+               $a->hideNewSection( true );
+               $a->setNoGallery( true );
+               $a->addWrapperDivClass( 'foo' );
+
+               $a->setIndicator( 'foo', 'Foo!' );
+               $a->setIndicator( 'bar', 'Bar!' );
+
+               $a->setExtensionData( 'foo', 'Foo!' );
+               $a->setExtensionData( 'bar', 'Bar!' );
+
+               $b = new ParserOutput();
+               $b->setNoGallery( true );
+               $b->setEnableOOUI( true );
+               $b->preventClickjacking( true );
+               $a->addWrapperDivClass( 'bar' );
+
+               $b->setIndicator( 'zoo', 'Zoo!' );
+               $b->setIndicator( 'bar', 'Barrr!' );
+
+               $b->setExtensionData( 'zoo', 'Zoo!' );
+               $b->setExtensionData( 'bar', 'Barrr!' );
+
+               yield 'skin control flags' => [ $a, $b, [
+                       'getNewSection' => true,
+                       'getHideNewSection' => true,
+                       'getNoGallery' => true,
+                       'getEnableOOUI' => true,
+                       'preventClickjacking' => true,
+                       'getIndicators' => [
+                               'foo' => 'Foo!',
+                               'bar' => 'Barrr!',
+                               'zoo' => 'Zoo!',
+                       ],
+                       'getWrapperDivClass' => 'foo bar',
+                       '$mExtensionData' => [
+                               'foo' => 'Foo!',
+                               'bar' => 'Barrr!',
+                               'zoo' => 'Zoo!',
+                       ],
+               ] ];
+       }
+
+       /**
+        * @dataProvider provideMergeHtmlMetaDataFrom
+        * @covers ParserOutput::mergeHtmlMetaDataFrom
+        *
+        * @param ParserOutput $a
+        * @param ParserOutput $b
+        * @param array $expected
+        */
+       public function testMergeHtmlMetaDataFrom( ParserOutput $a, ParserOutput $b, $expected ) {
+               $a->mergeHtmlMetaDataFrom( $b );
+
+               $this->assertFieldValues( $a, $expected );
+
+               // test twice, to make sure the operation is idempotent (except for the TOC, see below)
+               $a->mergeHtmlMetaDataFrom( $b );
+
+               // XXX: TOC joining should get smarter. Can we make it idempotent as well?
+               unset( $expected['getTOCHTML'] );
+               unset( $expected['getSections'] );
+
+               $this->assertFieldValues( $a, $expected );
+       }
+
+       private function assertFieldValues( ParserOutput $po, $expected ) {
+               $po = TestingAccessWrapper::newFromObject( $po );
+
+               foreach ( $expected as $method => $value ) {
+                       if ( $method[0] === '$' ) {
+                               $field = substr( $method, 1 );
+                               $actual = $po->__get( $field );
+                       } else {
+                               $actual = $po->__call( $method, [] );
+                       }
+
+                       $this->assertEquals( $value, $actual, $method );
+               }
+       }
+
+       public function provideMergeTrackingMetaDataFrom() {
+               // links ------------
+               $a = new ParserOutput();
+               $a->addLink( Title::makeTitle( NS_MAIN, 'Kittens' ), 6 );
+               $a->addLink( Title::makeTitle( NS_TALK, 'Kittens' ), 16 );
+               $a->addLink( Title::makeTitle( NS_MAIN, 'Goats' ), 7 );
+
+               $a->addTemplate( Title::makeTitle( NS_TEMPLATE, 'Goats' ), 107, 1107 );
+
+               $a->addLanguageLink( 'de' );
+               $a->addLanguageLink( 'ru' );
+               $a->addInterwikiLink( Title::makeTitle( NS_MAIN, 'Kittens DE', '', 'de' ) );
+               $a->addInterwikiLink( Title::makeTitle( NS_MAIN, 'Kittens RU', '', 'ru' ) );
+               $a->addExternalLink( 'https://kittens.wikimedia.test' );
+               $a->addExternalLink( 'https://goats.wikimedia.test' );
+
+               $a->addCategory( 'Foo', 'X' );
+               $a->addImage( 'Billy.jpg', '20180101000013', 'DEAD' );
+
+               $b = new ParserOutput();
+               $b->addLink( Title::makeTitle( NS_MAIN, 'Goats' ), 7 );
+               $b->addLink( Title::makeTitle( NS_TALK, 'Goats' ), 17 );
+               $b->addLink( Title::makeTitle( NS_MAIN, 'Dragons' ), 8 );
+               $b->addLink( Title::makeTitle( NS_FILE, 'Dragons.jpg' ), 28 );
+
+               $b->addTemplate( Title::makeTitle( NS_TEMPLATE, 'Dragons' ), 108, 1108 );
+               $a->addTemplate( Title::makeTitle( NS_MAIN, 'Dragons' ), 118, 1118 );
+
+               $b->addLanguageLink( 'fr' );
+               $b->addLanguageLink( 'ru' );
+               $b->addInterwikiLink( Title::makeTitle( NS_MAIN, 'Kittens FR', '', 'fr' ) );
+               $b->addInterwikiLink( Title::makeTitle( NS_MAIN, 'Dragons RU', '', 'ru' ) );
+               $b->addExternalLink( 'https://dragons.wikimedia.test' );
+               $b->addExternalLink( 'https://goats.wikimedia.test' );
+
+               $b->addCategory( 'Bar', 'Y' );
+               $b->addImage( 'Puff.jpg', '20180101000017', 'BEEF' );
+
+               yield 'all kinds of links' => [ $a, $b, [
+                       'getLinks' => [
+                               NS_MAIN => [
+                                       'Kittens' => 6,
+                                       'Goats' => 7,
+                                       'Dragons' => 8,
+                               ],
+                               NS_TALK => [
+                                       'Kittens' => 16,
+                                       'Goats' => 17,
+                               ],
+                               NS_FILE => [
+                                       'Dragons.jpg' => 28,
+                               ],
+                       ],
+                       'getTemplates' => [
+                               NS_MAIN => [
+                                       'Dragons' => 118,
+                               ],
+                               NS_TEMPLATE => [
+                                       'Dragons' => 108,
+                                       'Goats' => 107,
+                               ],
+                       ],
+                       'getTemplateIds' => [
+                               NS_MAIN => [
+                                       'Dragons' => 1118,
+                               ],
+                               NS_TEMPLATE => [
+                                       'Dragons' => 1108,
+                                       'Goats' => 1107,
+                               ],
+                       ],
+                       'getLanguageLinks' => [ 'de', 'ru', 'fr' ],
+                       'getInterwikiLinks' => [
+                               'de' => [ 'Kittens_DE' => 1 ],
+                               'ru' => [ 'Kittens_RU' => 1, 'Dragons_RU' => 1, ],
+                               'fr' => [ 'Kittens_FR' => 1 ],
+                       ],
+                       'getCategories' => [ 'Foo' => 'X', 'Bar' => 'Y' ],
+                       'getImages' => [ 'Billy.jpg' => 1, 'Puff.jpg' => 1 ],
+                       'getFileSearchOptions' => [
+                               'Billy.jpg' => [ 'time' => '20180101000013', 'sha1' => 'DEAD' ],
+                               'Puff.jpg' => [ 'time' => '20180101000017', 'sha1' => 'BEEF' ],
+                       ],
+                       'getExternalLinks' => [
+                               'https://dragons.wikimedia.test' => 1,
+                               'https://kittens.wikimedia.test' => 1,
+                               'https://goats.wikimedia.test' => 1,
+                       ]
+               ] ];
+
+               // properties ------------
+               $a = new ParserOutput();
+
+               $a->setProperty( 'foo', 'Foo!' );
+               $a->setProperty( 'bar', 'Bar!' );
+
+               $a->setExtensionData( 'foo', 'Foo!' );
+               $a->setExtensionData( 'bar', 'Bar!' );
+
+               $b = new ParserOutput();
+
+               $b->setProperty( 'zoo', 'Zoo!' );
+               $b->setProperty( 'bar', 'Barrr!' );
+
+               $b->setExtensionData( 'zoo', 'Zoo!' );
+               $b->setExtensionData( 'bar', 'Barrr!' );
+
+               yield 'properties' => [ $a, $b, [
+                       'getProperties' => [
+                               'foo' => 'Foo!',
+                               'bar' => 'Barrr!',
+                               'zoo' => 'Zoo!',
+                       ],
+                       '$mExtensionData' => [
+                               'foo' => 'Foo!',
+                               'bar' => 'Barrr!',
+                               'zoo' => 'Zoo!',
+                       ],
+               ] ];
+       }
+
+       /**
+        * @dataProvider provideMergeTrackingMetaDataFrom
+        * @covers ParserOutput::mergeTrackingMetaDataFrom
+        *
+        * @param ParserOutput $a
+        * @param ParserOutput $b
+        * @param array $expected
+        */
+       public function testMergeTrackingMetaDataFrom( ParserOutput $a, ParserOutput $b, $expected ) {
+               $a->mergeTrackingMetaDataFrom( $b );
+
+               $this->assertFieldValues( $a, $expected );
+
+               // test twice, to make sure the operation is idempotent
+               $a->mergeTrackingMetaDataFrom( $b );
+
+               $this->assertFieldValues( $a, $expected );
+       }
+
+       public function provideMergeInternalMetaDataFrom() {
+               // hooks
+               $a = new ParserOutput();
+
+               $a->addOutputHook( 'foo', 'X' );
+               $a->addOutputHook( 'bar' );
+
+               $b = new ParserOutput();
+
+               $b->addOutputHook( 'foo', 'Y' );
+               $b->addOutputHook( 'bar' );
+               $b->addOutputHook( 'zoo' );
+
+               yield 'hooks' => [ $a, $b, [
+                       'getOutputHooks' => [
+                               [ 'foo', 'X' ],
+                               [ 'bar', false ],
+                               [ 'foo', 'Y' ],
+                               [ 'zoo', false ],
+                       ],
+               ] ];
+
+               // flags & co
+               $a = new ParserOutput();
+
+               $a->addWarning( 'Oops' );
+               $a->addWarning( 'Whoops' );
+
+               $a->setFlag( 'foo' );
+               $a->setFlag( 'bar' );
+
+               $a->recordOption( 'Foo' );
+               $a->recordOption( 'Bar' );
+
+               $b = new ParserOutput();
+
+               $b->addWarning( 'Yikes' );
+               $b->addWarning( 'Whoops' );
+
+               $b->setFlag( 'zoo' );
+               $b->setFlag( 'bar' );
+
+               $b->recordOption( 'Zoo' );
+               $b->recordOption( 'Bar' );
+
+               yield 'flags' => [ $a, $b, [
+                       'getWarnings' => [ 'Oops', 'Whoops', 'Yikes' ],
+                       '$mFlags' => [ 'foo' => true, 'bar' => true, 'zoo' => true ],
+                       'getUsedOptions' => [ 'Foo', 'Bar', 'Zoo' ],
+               ] ];
+
+               // timestamp ------------
+               $a = new ParserOutput();
+               $a->setTimestamp( '20180101000011' );
+               $b = new ParserOutput();
+               yield 'only left timestamp' => [ $a, $b, [ 'getTimestamp' => '20180101000011' ] ];
+
+               $a = new ParserOutput();
+               $b = new ParserOutput();
+               $b->setTimestamp( '20180101000011' );
+               yield 'only right timestamp' => [ $a, $b, [ 'getTimestamp' => '20180101000011' ] ];
+
+               $a = new ParserOutput();
+               $a->setTimestamp( '20180101000011' );
+               $b = new ParserOutput();
+               $b->setTimestamp( '20180101000001' );
+               yield 'left timestamp wins' => [ $a, $b, [ 'getTimestamp' => '20180101000011' ] ];
+
+               $a = new ParserOutput();
+               $a->setTimestamp( '20180101000001' );
+               $b = new ParserOutput();
+               $b->setTimestamp( '20180101000011' );
+               yield 'right timestamp wins' => [ $a, $b, [ 'getTimestamp' => '20180101000011' ] ];
+
+               // speculative rev id ------------
+               $a = new ParserOutput();
+               $a->setSpeculativeRevIdUsed( 9 );
+               $b = new ParserOutput();
+               yield 'only left speculative rev id' => [ $a, $b, [ 'getSpeculativeRevIdUsed' => 9 ] ];
+
+               $a = new ParserOutput();
+               $b = new ParserOutput();
+               $b->setSpeculativeRevIdUsed( 9 );
+               yield 'only right speculative rev id' => [ $a, $b, [ 'getSpeculativeRevIdUsed' => 9 ] ];
+
+               $a = new ParserOutput();
+               $a->setSpeculativeRevIdUsed( 9 );
+               $b = new ParserOutput();
+               $b->setSpeculativeRevIdUsed( 9 );
+               yield 'same speculative rev id' => [ $a, $b, [ 'getSpeculativeRevIdUsed' => 9 ] ];
+
+               // limit report (recursive max) ------------
+               $a = new ParserOutput();
+
+               $a->setLimitReportData( 'naive1', 7 );
+               $a->setLimitReportData( 'naive2', 27 );
+
+               $a->setLimitReportData( 'limitreport-simple1', 7 );
+               $a->setLimitReportData( 'limitreport-simple2', 27 );
+
+               $a->setLimitReportData( 'limitreport-pair1', [ 7, 9 ] );
+               $a->setLimitReportData( 'limitreport-pair2', [ 27, 29 ] );
+
+               $a->setLimitReportData( 'limitreport-more1', [ 7, 9, 1 ] );
+               $a->setLimitReportData( 'limitreport-more2', [ 27, 29, 21 ] );
+
+               $a->setLimitReportData( 'limitreport-only-a', 13 );
+
+               $b = new ParserOutput();
+
+               $b->setLimitReportData( 'naive1', 17 );
+               $b->setLimitReportData( 'naive2', 17 );
+
+               $b->setLimitReportData( 'limitreport-simple1', 17 );
+               $b->setLimitReportData( 'limitreport-simple2', 17 );
+
+               $b->setLimitReportData( 'limitreport-pair1', [ 17, 19 ] );
+               $b->setLimitReportData( 'limitreport-pair2', [ 17, 19 ] );
+
+               $b->setLimitReportData( 'limitreport-more1', [ 17, 19, 11 ] );
+               $b->setLimitReportData( 'limitreport-more2', [ 17, 19, 11 ] );
+
+               $b->setLimitReportData( 'limitreport-only-b', 23 );
+
+               // first write wins
+               yield 'limit report' => [ $a, $b, [
+                       'getLimitReportData' => [
+                               'naive1' => 7,
+                               'naive2' => 27,
+                               'limitreport-simple1' => 7,
+                               'limitreport-simple2' => 27,
+                               'limitreport-pair1' => [ 7, 9 ],
+                               'limitreport-pair2' => [ 27, 29 ],
+                               'limitreport-more1' => [ 7, 9, 1 ],
+                               'limitreport-more2' => [ 27, 29, 21 ],
+                               'limitreport-only-a' => 13,
+                       ],
+                       'getLimitReportJSData' => [
+                               'naive1' => 7,
+                               'naive2' => 27,
+                               'limitreport' => [
+                                       'simple1' => 7,
+                                       'simple2' => 27,
+                                       'pair1' => [ 'value' => 7, 'limit' => 9 ],
+                                       'pair2' => [ 'value' => 27, 'limit' => 29 ],
+                                       'more1' => [ 7, 9, 1 ],
+                                       'more2' => [ 27, 29, 21 ],
+                                       'only-a' => 13,
+                               ],
+                       ],
+               ] ];
+       }
+
+       /**
+        * @dataProvider provideMergeInternalMetaDataFrom
+        * @covers ParserOutput::mergeInternalMetaDataFrom
+        *
+        * @param ParserOutput $a
+        * @param ParserOutput $b
+        * @param array $expected
+        */
+       public function testMergeInternalMetaDataFrom( ParserOutput $a, ParserOutput $b, $expected ) {
+               $a->mergeInternalMetaDataFrom( $b );
+
+               $this->assertFieldValues( $a, $expected );
+
+               // test twice, to make sure the operation is idempotent
+               $a->mergeInternalMetaDataFrom( $b );
+
+               $this->assertFieldValues( $a, $expected );
+       }
+
+       public function testMergeInternalMetaDataFrom_parseStartTime() {
+               /** @var object $a */
+               $a = new ParserOutput();
+               $a = TestingAccessWrapper::newFromObject( $a );
+
+               $a->resetParseStartTime();
+               $aClocks = $a->mParseStartTime;
+
+               $b = new ParserOutput();
+
+               $a->mergeInternalMetaDataFrom( $b );
+               $mergedClocks = $a->mParseStartTime;
+
+               foreach ( $mergedClocks as $clock => $timestamp ) {
+                       $this->assertSame( $aClocks[$clock], $timestamp, $clock );
+               }
+
+               // try again, with times in $b also set, and later than $a's
+               usleep( 1234 );
+
+               /** @var object $b */
+               $b = new ParserOutput();
+               $b = TestingAccessWrapper::newFromObject( $b );
+
+               $b->resetParseStartTime();
+
+               $bClocks = $b->mParseStartTime;
+
+               $a->mergeInternalMetaDataFrom( $b->object, 'b' );
+               $mergedClocks = $a->mParseStartTime;
+
+               foreach ( $mergedClocks as $clock => $timestamp ) {
+                       $this->assertSame( $aClocks[$clock], $timestamp, $clock );
+                       $this->assertLessThanOrEqual( $bClocks[$clock], $timestamp, $clock );
+               }
+
+               // try again, with $a's times being later
+               usleep( 1234 );
+               $a->resetParseStartTime();
+               $aClocks = $a->mParseStartTime;
+
+               $a->mergeInternalMetaDataFrom( $b->object, 'b' );
+               $mergedClocks = $a->mParseStartTime;
+
+               foreach ( $mergedClocks as $clock => $timestamp ) {
+                       $this->assertSame( $bClocks[$clock], $timestamp, $clock );
+                       $this->assertLessThanOrEqual( $aClocks[$clock], $timestamp, $clock );
+               }
+
+               // try again, with no times in $a set
+               $a = new ParserOutput();
+               $a = TestingAccessWrapper::newFromObject( $a );
+
+               $a->mergeInternalMetaDataFrom( $b->object, 'b' );
+               $mergedClocks = $a->mParseStartTime;
+
+               foreach ( $mergedClocks as $clock => $timestamp ) {
+                       $this->assertSame( $bClocks[$clock], $timestamp, $clock );
+               }
+       }
+
 }
index c925339..0c707d5 100644 (file)
@@ -151,8 +151,8 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
                ] );
                $this->assertEquals( $raw, $module->getScript( $context ), 'Raw script' );
                $this->assertEquals(
-                       [ 'scripts' => $build ],
-                       $module->getModuleContent( $context ),
+                       $build,
+                       $module->getModuleContent( $context )[ 'scripts' ],
                        $message
                );
        }
index 61ab8a5..231979d 100644 (file)
@@ -1,9 +1,11 @@
 <?php
 
+use Wikimedia\TestingAccessWrapper;
+
 /**
  * @group ResourceLoader
  */
-class ResourceLoaderSkinModuleTest extends PHPUnit\Framework\TestCase {
+class ResourceLoaderSkinModuleTest extends MediaWikiTestCase {
 
        use MediaWikiCoversValidator;
 
@@ -107,25 +109,23 @@ CSS
        }
 
        /**
-        * @dataProvider provideGetLogo
-        * @covers ResourceLoaderSkinModule::getLogo
+        * @dataProvider provideGetLogoData
+        * @covers ResourceLoaderSkinModule::getLogoData
         */
-       public function testGetLogo( $config, $expected, $baseDir = null ) {
+       public function testGetLogoData( $config, $expected, $baseDir = null ) {
                if ( $baseDir ) {
-                       $oldIP = $GLOBALS['IP'];
-                       $GLOBALS['IP'] = $baseDir;
-                       $teardown = new Wikimedia\ScopedCallback( function () use ( $oldIP ) {
-                               $GLOBALS['IP'] = $oldIP;
-                       } );
+                       $this->setMwGlobals( 'IP', $baseDir );
                }
+               // Allow testing of protected method
+               $module = TestingAccessWrapper::newFromObject( new ResourceLoaderSkinModule() );
 
                $this->assertEquals(
                        $expected,
-                       ResourceLoaderSkinModule::getLogo( new HashConfig( $config ) )
+                       $module->getLogoData( new HashConfig( $config ) )
                );
        }
 
-       public function provideGetLogo() {
+       public function provideGetLogoData() {
                return [
                        'simple' => [
                                'config' => [
@@ -203,4 +203,80 @@ CSS
                        ],
                ];
        }
+
+       /**
+        * @dataProvider providePreloadLinks
+        * @covers ResourceLoaderSkinModule::getPreloadLinks
+        * @covers ResourceLoaderSkinModule::getLogoPreloadlinks
+        * @covers ResourceLoaderSkinModule::getLogoData
+        */
+       public function testPreloadLinkHeaders( $config, $result ) {
+               $this->setMwGlobals( $config );
+               $ctx = $this->getMockBuilder( ResourceLoaderContext::class )
+                       ->disableOriginalConstructor()->getMock();
+               $module = new ResourceLoaderSkinModule();
+
+               $this->assertEquals( [ $result ], $module->getHeaders( $ctx ) );
+       }
+
+       public function providePreloadLinks() {
+               return [
+                       [
+                               [
+                                       'wgResourceBasePath' => '/w',
+                                       'wgLogo' => '/img/default.png',
+                                       'wgLogoHD' => [
+                                               '1.5x' => '/img/one-point-five.png',
+                                               '2x' => '/img/two-x.png',
+                                       ],
+                               ],
+                               'Link: </img/default.png>;rel=preload;as=image;media=' .
+                               'not all and (min-resolution: 1.5dppx),' .
+                               '</img/one-point-five.png>;rel=preload;as=image;media=' .
+                               '(min-resolution: 1.5dppx) and (max-resolution: 1.999999dppx),' .
+                               '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
+                       ],
+                       [
+                               [
+                                       'wgResourceBasePath' => '/w',
+                                       'wgLogo' => '/img/default.png',
+                                       'wgLogoHD' => false,
+                               ],
+                               'Link: </img/default.png>;rel=preload;as=image'
+                       ],
+                       [
+                               [
+                                       'wgResourceBasePath' => '/w',
+                                       'wgLogo' => '/img/default.png',
+                                       'wgLogoHD' => [
+                                               '2x' => '/img/two-x.png',
+                                       ],
+                               ],
+                               'Link: </img/default.png>;rel=preload;as=image;media=' .
+                               'not all and (min-resolution: 2dppx),' .
+                               '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
+                       ],
+                       [
+                               [
+                                       'wgResourceBasePath' => '/w',
+                                       'wgLogo' => '/img/default.png',
+                                       'wgLogoHD' => [
+                                               'svg' => '/img/vector.svg',
+                                       ],
+                               ],
+                               'Link: </img/vector.svg>;rel=preload;as=image'
+
+                       ],
+                       [
+                               [
+                                       'wgResourceBasePath' => '/w',
+                                       'wgLogo' => '/w/test.jpg',
+                                       'wgLogoHD' => false,
+                                       'wgUploadPath' => '/w/images',
+                                       'IP' => dirname( dirname( __DIR__ ) ) . '/data/media',
+                               ],
+                               'Link: </w/test.jpg?edcf2>;rel=preload;as=image',
+                       ],
+               ];
+       }
 }
index 3b8e710..f86987a 100644 (file)
@@ -524,13 +524,13 @@ class UserTest extends MediaWikiTestCase {
 
                $touched = $user->getDBTouched();
                $this->assertTrue(
-                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded" );
+                       $user->checkAndSetTouched(), "checkAndSetTouched() succedeed" );
                $this->assertGreaterThan(
                        $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
 
                $touched = $user->getDBTouched();
                $this->assertTrue(
-                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded #2" );
+                       $user->checkAndSetTouched(), "checkAndSetTouched() succedeed #2" );
                $this->assertGreaterThan(
                        $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
        }
index 9b90bfe..4b7a7eb 100644 (file)
@@ -24,7 +24,7 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
         * exception and store it until we are in setUp and may finally rethrow
         * the exception without crashing the test suite.
         *
-        * @var Exception|null
+        * @var \Exception|null
         */
        protected $exceptionFromAddDBData = null;
 
index ad9bf3e..b8a60be 100644 (file)
@@ -2,7 +2,9 @@
 
 namespace MediaWiki\Tests\Maintenance;
 
+use Exception;
 use MediaWikiLangTestCase;
+use MWException;
 use TextContentHandler;
 use TextPassDumper;
 use Title;
index 83e695f..37b6c88 100644 (file)
                assert.strictEqual( conf.set( 'undef' ), false, 'Map.set requires explicit value (no undefined default)' );
 
                assert.strictEqual( conf.set( 'undef', undefined ), true, 'Map.set allows setting value to `undefined`' );
-               assert.strictEqual( conf.get( 'undef', 'fallback' ), undefined, 'Map.get supports retreiving value of `undefined`' );
+               assert.strictEqual( conf.get( 'undef', 'fallback' ), undefined, 'Map.get supports retrieving value of `undefined`' );
 
                assert.strictEqual( conf.set( funky, 'Funky' ), false, 'Map.set returns boolean false if key was invalid (Function)' );
                assert.strictEqual( conf.set( arry, 'Arry' ), false, 'Map.set returns boolean false if key was invalid (Array)' );
index 7044069..751155d 100644 (file)
@@ -2,15 +2,19 @@
        QUnit.module( 'mediawiki.user', QUnit.newMwEnvironment( {
                setup: function () {
                        this.server = this.sandbox.useFakeServer();
-                       this.crypto = window.crypto;
-                       this.msCrypto = window.msCrypto;
+                       // Cannot stub by simple assignment because read-only.
+                       // Instead, stub in tests by using 'delete', and re-create
+                       // in teardown using the original descriptor (including its
+                       // accessors and readonly settings etc.)
+                       this.crypto = Object.getOwnPropertyDescriptor( window, 'crypto' );
+                       this.msCrypto = Object.getOwnPropertyDescriptor( window, 'msCrypto' );
                },
                teardown: function () {
                        if ( this.crypto ) {
-                               window.crypto = this.crypto;
+                               Object.defineProperty( window, 'crypto', this.crypto );
                        }
                        if ( this.msCrypto ) {
-                               window.msCrypto = this.msCrypto;
+                               Object.defineProperty( window, 'msCrypto', this.msCrypto );
                        }
                }
        } ) );
@@ -70,7 +74,7 @@
                result = mw.user.generateRandomSessionId();
                assert.strictEqual( typeof result, 'string', 'type' );
                assert.strictEqual( result.trim(), result, 'no whitespace at beginning or end' );
-               assert.strictEqual( result.length, 16, 'size' );
+               assert.strictEqual( result.length, 20, 'size' );
 
                result2 = mw.user.generateRandomSessionId();
                assert.notEqual( result, result2, 'different when called multiple times' );
                var result, result2;
 
                // Pretend crypto API is not there to test the Math.random fallback
-               if ( window.crypto ) {
-                       window.crypto = undefined;
-               }
-               if ( window.msCrypto ) {
-                       window.msCrypto = undefined;
-               }
+               delete window.crypto;
+               delete window.msCrypto;
+               // Assert that the above actually worked. If we use the wrong method
+               // of stubbing, JavaScript silently continues and we need to know that
+               // it was the wrong method. As of writing, assigning undefined is
+               // ineffective as the window property for Crypto is read-only.
+               // However, deleting does work. (T203275)
+               assert.strictEqual( window.crypto || window.msCrypto, undefined, 'fallback is active' );
 
                result = mw.user.generateRandomSessionId();
                assert.strictEqual( typeof result, 'string', 'type' );
                assert.strictEqual( result.trim(), result, 'no whitespace at beginning or end' );
-               assert.strictEqual( result.length, 16, 'size' );
+               assert.strictEqual( result.length, 20, 'size' );
 
                result2 = mw.user.generateRandomSessionId();
                assert.notEqual( result, result2, 'different when called multiple times' );
                var result = mw.user.getPageviewToken(),
                        result2 = mw.user.getPageviewToken();
                assert.strictEqual( typeof result, 'string', 'type' );
-               assert.strictEqual( /^[a-f0-9]{16}$/.test( result ), true, '16 HEX symbols string' );
+               assert.strictEqual( /^[a-f0-9]{20}$/.test( result ), true, '20 HEX symbols string' );
                assert.strictEqual( result2, result, 'sticky' );
        } );
 
index cc74c89..7032909 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -500,7 +500,7 @@ function wfGenerateThumbnail( File $file, array $params, $thumbName, $thumbPath
        }
 
        /** @noinspection PhpUnusedLocalVariableInspection */
-       $done = true; // no PHP fatal occured
+       $done = true; // no PHP fatal occurred
 
        if ( !$thumb || $thumb->isError() ) {
                // Randomize TTL to reduce stampedes