Merge "Upgrade premature implicit transaction commits to exceptions"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 10 Aug 2016 02:57:52 +0000 (02:57 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 10 Aug 2016 02:57:52 +0000 (02:57 +0000)
416 files changed:
RELEASE-NOTES-1.28
UPGRADE
autoload.php
composer.json
docs/README
docs/extension.schema.json
docs/extension.schema.v1.json
docs/hooks.txt
extensions/README
includes/CategoryFinder.php
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/OutputPage.php
includes/Pingback.php
includes/Preferences.php
includes/ServiceWiring.php
includes/Services/ServiceContainer.php
includes/Setup.php
includes/SiteStats.php
includes/Status.php
includes/actions/UnwatchAction.php
includes/actions/WatchAction.php
includes/api/ApiAMCreateAccount.php
includes/api/ApiAuthManagerHelper.php
includes/api/ApiClientLogin.php
includes/api/ApiCreateAccount.php [deleted file]
includes/api/ApiLogin.php
includes/api/ApiPageSet.php
includes/api/ApiQueryUsers.php
includes/api/ApiResult.php
includes/api/ApiWatch.php
includes/api/i18n/ba.json
includes/api/i18n/en.json
includes/api/i18n/gl.json
includes/api/i18n/it.json
includes/api/i18n/ko.json
includes/api/i18n/pl.json
includes/api/i18n/qqq.json
includes/api/i18n/uk.json
includes/api/i18n/zh-hans.json
includes/auth/AuthManager.php
includes/auth/LocalPasswordPrimaryAuthenticationProvider.php
includes/collation/IcuCollation.php
includes/content/ContentHandler.php
includes/content/TextContentHandler.php
includes/content/WikiTextStructure.php [new file with mode: 0644]
includes/content/WikitextContentHandler.php
includes/db/DatabaseMssql.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabasePostgres.php
includes/db/IDatabase.php
includes/db/loadbalancer/LBFactoryMulti.php
includes/db/loadbalancer/LoadBalancer.php
includes/deferred/CdnCacheUpdate.php
includes/diff/DifferenceEngine.php
includes/filerepo/FileRepoStatus.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php
includes/htmlform/HTMLApiField.php [deleted file]
includes/htmlform/HTMLAutoCompleteSelectField.php [deleted file]
includes/htmlform/HTMLButtonField.php [deleted file]
includes/htmlform/HTMLCheckField.php [deleted file]
includes/htmlform/HTMLCheckMatrix.php [deleted file]
includes/htmlform/HTMLComboboxField.php [deleted file]
includes/htmlform/HTMLEditTools.php [deleted file]
includes/htmlform/HTMLFloatField.php [deleted file]
includes/htmlform/HTMLFormFieldCloner.php [deleted file]
includes/htmlform/HTMLFormFieldWithButton.php [deleted file]
includes/htmlform/HTMLHiddenField.php [deleted file]
includes/htmlform/HTMLInfoField.php [deleted file]
includes/htmlform/HTMLIntField.php [deleted file]
includes/htmlform/HTMLMultiSelectField.php [deleted file]
includes/htmlform/HTMLRadioField.php [deleted file]
includes/htmlform/HTMLSelectAndOtherField.php [deleted file]
includes/htmlform/HTMLSelectField.php [deleted file]
includes/htmlform/HTMLSelectLimitField.php [deleted file]
includes/htmlform/HTMLSelectNamespace.php [deleted file]
includes/htmlform/HTMLSelectNamespaceWithButton.php [deleted file]
includes/htmlform/HTMLSelectOrOtherField.php [deleted file]
includes/htmlform/HTMLSubmitField.php [deleted file]
includes/htmlform/HTMLTagFilter.php [deleted file]
includes/htmlform/HTMLTextAreaField.php [deleted file]
includes/htmlform/HTMLTextField.php [deleted file]
includes/htmlform/HTMLTextFieldWithButton.php [deleted file]
includes/htmlform/HTMLTitleTextField.php [deleted file]
includes/htmlform/HTMLUserTextField.php [deleted file]
includes/htmlform/fields/HTMLApiField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLAutoCompleteSelectField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLButtonField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLCheckField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLCheckMatrix.php [new file with mode: 0644]
includes/htmlform/fields/HTMLComboboxField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLEditTools.php [new file with mode: 0644]
includes/htmlform/fields/HTMLFloatField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLFormFieldCloner.php [new file with mode: 0644]
includes/htmlform/fields/HTMLFormFieldWithButton.php [new file with mode: 0644]
includes/htmlform/fields/HTMLHiddenField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLInfoField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLIntField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLMultiSelectField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLRadioField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectAndOtherField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectLimitField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectNamespace.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectNamespaceWithButton.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSelectOrOtherField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLSubmitField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLTagFilter.php [new file with mode: 0644]
includes/htmlform/fields/HTMLTextAreaField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLTextField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLTextFieldWithButton.php [new file with mode: 0644]
includes/htmlform/fields/HTMLTitleTextField.php [new file with mode: 0644]
includes/htmlform/fields/HTMLUserTextField.php [new file with mode: 0644]
includes/installer/i18n/diq.json
includes/installer/i18n/dty.json [new file with mode: 0644]
includes/installer/i18n/eu.json
includes/installer/i18n/fa.json
includes/installer/i18n/gl.json
includes/installer/i18n/he.json
includes/installer/i18n/pl.json
includes/installer/i18n/uk.json
includes/installer/i18n/zh-hant.json
includes/jobqueue/JobRunner.php
includes/libs/HtmlArmor.php
includes/libs/objectcache/BagOStuff.php
includes/libs/objectcache/CachedBagOStuff.php
includes/libs/objectcache/IExpiringStore.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/objectcache/ReplicatedBagOStuff.php
includes/libs/objectcache/WANObjectCache.php
includes/media/MediaHandler.php
includes/media/MediaHandlerFactory.php [new file with mode: 0644]
includes/objectcache/ObjectCache.php
includes/objectcache/SqlBagOStuff.php
includes/page/Article.php
includes/page/WikiPage.php
includes/profiler/ProfileSection.php
includes/profiler/ProfilerFunctions.php
includes/profiler/TransactionProfiler.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderSiteModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/resourceloader/ResourceLoaderUserModule.php
includes/resourceloader/ResourceLoaderUserStylesModule.php [new file with mode: 0644]
includes/revisiondelete/RevDelArchivedFileItem.php
includes/revisiondelete/RevDelFileItem.php
includes/search/SearchEngine.php
includes/session/SessionManager.php
includes/site/SiteSQLStore.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialChangeCredentials.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialMostlinkedcategories.php
includes/specials/SpecialNewimages.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialProtectedpages.php
includes/specials/SpecialResetTokens.php
includes/specials/SpecialShortpages.php
includes/specials/SpecialTags.php
includes/specials/SpecialUpload.php
includes/specials/SpecialUploadStash.php
includes/specials/SpecialWatchlist.php
includes/specials/pagers/ImageListPager.php
includes/specials/pagers/NewFilesPager.php
includes/specials/pre-authmanager/README [deleted file]
includes/specials/pre-authmanager/SpecialChangeEmail.php [deleted file]
includes/specials/pre-authmanager/SpecialChangePassword.php [deleted file]
includes/specials/pre-authmanager/SpecialCreateAccount.php [deleted file]
includes/specials/pre-authmanager/SpecialPasswordReset.php [deleted file]
includes/specials/pre-authmanager/SpecialUserlogin.php [deleted file]
includes/specials/pre-authmanager/SpecialUserlogout.php [deleted file]
includes/templates/Usercreate.php [deleted file]
includes/templates/Userlogin.php [deleted file]
includes/tidy/Balancer.php
includes/upload/UploadBase.php
includes/upload/UploadFromStash.php
includes/user/User.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowIterator.php
includes/utils/MWCryptRand.php
languages/i18n/ar.json
languages/i18n/arz.json
languages/i18n/ast.json
languages/i18n/az.json
languages/i18n/ba.json
languages/i18n/bar.json
languages/i18n/bcl.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/bo.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/cs.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/dsb.json
languages/i18n/dty.json
languages/i18n/en-gb.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/gl.json
languages/i18n/got.json
languages/i18n/gu.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hsb.json
languages/i18n/ht.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/ilo.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/kiu.json
languages/i18n/kn.json
languages/i18n/ko.json
languages/i18n/krl.json
languages/i18n/ksh.json
languages/i18n/la.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/lki.json
languages/i18n/lt.json
languages/i18n/lv.json
languages/i18n/mai.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/nah.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/ne.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/roa-tara.json
languages/i18n/ru.json
languages/i18n/sco.json
languages/i18n/sgs.json
languages/i18n/sh.json
languages/i18n/sl.json
languages/i18n/so.json
languages/i18n/sq.json
languages/i18n/sv.json
languages/i18n/szl.json
languages/i18n/tcy.json
languages/i18n/te.json
languages/i18n/th.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/tyv.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/vi.json
languages/i18n/yi.json
languages/i18n/yo.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesCs.php
languages/messages/MessagesGom_deva.php
languages/messages/MessagesTcy.php
maintenance/Maintenance.php
maintenance/changePassword.php
maintenance/convertExtensionToRegistration.php
maintenance/createAndPromote.php
maintenance/doMaintenance.php
maintenance/generateLocalAutoload.php
package.json
resources/Resources.php
resources/lib/oojs-ui/i18n/cy.json
resources/lib/oojs-ui/i18n/et.json
resources/lib/oojs-ui/i18n/ko.json
resources/lib/oojs-ui/i18n/sq.json
resources/lib/oojs-ui/oojs-ui-apex.js
resources/lib/oojs-ui/oojs-ui-core-apex.css
resources/lib/oojs-ui/oojs-ui-core-mediawiki.css
resources/lib/oojs-ui/oojs-ui-core.js
resources/lib/oojs-ui/oojs-ui-mediawiki.js
resources/lib/oojs-ui/oojs-ui-toolbars-apex.css
resources/lib/oojs-ui/oojs-ui-toolbars-mediawiki.css
resources/lib/oojs-ui/oojs-ui-toolbars.js
resources/lib/oojs-ui/oojs-ui-widgets-apex.css
resources/lib/oojs-ui/oojs-ui-widgets-mediawiki.css
resources/lib/oojs-ui/oojs-ui-widgets.js
resources/lib/oojs-ui/oojs-ui-windows-apex.css
resources/lib/oojs-ui/oojs-ui-windows-mediawiki.css
resources/lib/oojs-ui/oojs-ui-windows.js
resources/lib/oojs-ui/themes/apex/icons-alerts.json [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bell.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bell.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/eye.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/eye.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/tray.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/tray.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/icons-alerts.json
resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png
resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg
resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.svg [new file with mode: 0644]
resources/src/jquery/jquery.accessKeyLabel.js
resources/src/jquery/jquery.tablesorter.js
resources/src/mediawiki.action/mediawiki.action.edit.styles.css
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/oldshared.css
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.special/mediawiki.special.css
resources/src/mediawiki.special/mediawiki.special.upload.styles.css
resources/src/mediawiki/mediawiki.Title.js
resources/src/mediawiki/mediawiki.htmlform.ooui.css
resources/src/mediawiki/mediawiki.js
resources/src/mediawiki/page/mediawiki.page.patrol.css [new file with mode: 0644]
resources/src/mediawiki/page/mediawiki.page.patrol.print.css [new file with mode: 0644]
tests/TestsAutoLoader.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/data/templates/conds.mustache [deleted file]
tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/api/ApiLoginTest.php
tests/phpunit/includes/api/ApiTestCase.php
tests/phpunit/includes/auth/AbstractAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPreAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AuthenticationRequestTest.php
tests/phpunit/includes/auth/AuthenticationRequestTestCase.php
tests/phpunit/includes/auth/AuthenticationResponseTest.php
tests/phpunit/includes/auth/CheckBlocksSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ConfirmLinkSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/LegacyHookPreAuthenticationProviderTest.php
tests/phpunit/includes/auth/LocalPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ResetPasswordSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/TemporaryPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ThrottlePreAuthenticationProviderTest.php
tests/phpunit/includes/auth/ThrottlerTest.php
tests/phpunit/includes/content/ContentHandlerTest.php
tests/phpunit/includes/content/TextContentHandlerTest.php
tests/phpunit/includes/content/WikitextContentHandlerTest.php
tests/phpunit/includes/content/WikitextStructureTest.php [new file with mode: 0644]
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/upload/UploadBaseTest.php
tests/phpunit/includes/user/UserTest.php
tests/phpunit/mocks/media/MockMediaHandlerFactory.php [new file with mode: 0644]
tests/phpunit/phpunit.php
tests/phpunit/structure/AutoLoaderTest.php
tests/phpunit/suites/ExtensionsTestSuite.php
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js

index cff734b..f26f240 100644 (file)
@@ -36,6 +36,11 @@ production.
 * Added a new hook, 'UploadVerifyUpload', which can be used to reject a file
   upload. Unlike 'UploadVerifyFile' it provides information about upload comment
   and the file description page, but does not run for uploads to stash.
+* (T141604) Extensions can now provide a better error message when their
+  maintenance scripts are run without the extension being installed.
+* (T8948) Numeric sorting in categories is now supported by setting $wgCategoryCollation
+  to uca-default-u-kn or uca-<langcode>-u-kn. If migrating from another
+  collation, you will need to run the updateCollation.php maintenance script.
 
 === External library changes in 1.28 ===
 
@@ -87,9 +92,19 @@ changes to languages because of Phabricator reports.
   MediaWiki\Linker\LinkRenderer. In addition, the LinkBegin and LinkEnd hooks
   were replaced by HtmlPageLinkRendererBegin and HtmlPageLinkRendererEnd
   respectively. See docs/hooks.txt for the specific changes needed for those hooks.
+* Aliases for Linker methods, deprecated since 1.21, were removed from Skin:
+  * Skin::commentBlock() (use Linker::commentBlock() instead)
+  * Skin::generateRollback() (use Linker::generateRollback() instead)
+  * Skin::link() (use MediaWiki\Linker\LinkRenderer instead)
+  * Skin::linkKnown() (use MediaWiki\Linker\LinkRenderer instead)
+  * Skin::userLink() (use Linker::userLink() instead)
+  * Skin::userToolLinks() (use Linker::userToolLinks() instead)
 * The 'ParserLimitReportFormat' hook was removed.
 * Disabled "bug 2702" HTML tidying of parsed UI messages on wikis where Tidy is
   disabled.
+* DifferenceEngine::generateDiffBody() was removed (deprecated since 1.21).
+* UploadBase::stashFileGetKey() and UploadBase::stashSession() were deprecated.
+  Use ...->stashFile()->getFileKey() instead.
 
 == Compatibility ==
 
diff --git a/UPGRADE b/UPGRADE
index 088701a..0fff289 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,18 +1,17 @@
-
 This file provides an overview of the MediaWiki upgrade process. For help with
 specific problems, check
 
-* the documentation at https://www.mediawiki.org
+* the documentation at https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents/
 * the mediawiki-l mailing list archive at
   http://lists.wikimedia.org/pipermail/mediawiki-l/
-* the bug tracker at https://phabricator.wikimedia.org
+* the bug tracker at https://phabricator.wikimedia.org/
 
 for information and workarounds to common issues.
 
 == Overview ==
 
 Comprehensive documentation on upgrading to the latest version of the software
-is available at https://www.mediawiki.org/wiki/Manual:Upgrading.
+is available at https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Upgrading
 
 === Consult the release notes ===
 
@@ -28,7 +27,7 @@ you take a complete backup of your wiki database and files and verify it. While
 the upgrade scripts are somewhat robust, there is no guarantee that things will
 not fail, leaving the database in an inconsistent state.
 
-https://www.mediawiki.org/wiki/Manual:Backing_up_a_wiki provides an overview of
+https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Backing_up_a_wiki provides an overview of
 the backup process. You should also refer to the documentation for your
 database management system for information on backing up a database, and to
 your operating system documentation for information on making copies of files.
index 5808040..513ec96 100644 (file)
@@ -28,7 +28,6 @@ $wgAutoloadLocalClasses = [
        'ApiClientLogin' => __DIR__ . '/includes/api/ApiClientLogin.php',
        'ApiComparePages' => __DIR__ . '/includes/api/ApiComparePages.php',
        'ApiContinuationManager' => __DIR__ . '/includes/api/ApiContinuationManager.php',
-       'ApiCreateAccount' => __DIR__ . '/includes/api/ApiCreateAccount.php',
        'ApiDelete' => __DIR__ . '/includes/api/ApiDelete.php',
        'ApiDisabled' => __DIR__ . '/includes/api/ApiDisabled.php',
        'ApiEditPage' => __DIR__ . '/includes/api/ApiEditPage.php',
@@ -514,41 +513,41 @@ $wgAutoloadLocalClasses = [
        'GitInfo' => __DIR__ . '/includes/GitInfo.php',
        'GlobalDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'GlobalVarConfig' => __DIR__ . '/includes/config/GlobalVarConfig.php',
-       'HTMLApiField' => __DIR__ . '/includes/htmlform/HTMLApiField.php',
-       'HTMLAutoCompleteSelectField' => __DIR__ . '/includes/htmlform/HTMLAutoCompleteSelectField.php',
-       'HTMLButtonField' => __DIR__ . '/includes/htmlform/HTMLButtonField.php',
+       'HTMLApiField' => __DIR__ . '/includes/htmlform/fields/HTMLApiField.php',
+       'HTMLAutoCompleteSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLAutoCompleteSelectField.php',
+       'HTMLButtonField' => __DIR__ . '/includes/htmlform/fields/HTMLButtonField.php',
        'HTMLCacheUpdate' => __DIR__ . '/includes/deferred/HTMLCacheUpdate.php',
        'HTMLCacheUpdateJob' => __DIR__ . '/includes/jobqueue/jobs/HTMLCacheUpdateJob.php',
-       'HTMLCheckField' => __DIR__ . '/includes/htmlform/HTMLCheckField.php',
-       'HTMLCheckMatrix' => __DIR__ . '/includes/htmlform/HTMLCheckMatrix.php',
-       'HTMLComboboxField' => __DIR__ . '/includes/htmlform/HTMLComboboxField.php',
-       'HTMLEditTools' => __DIR__ . '/includes/htmlform/HTMLEditTools.php',
+       'HTMLCheckField' => __DIR__ . '/includes/htmlform/fields/HTMLCheckField.php',
+       'HTMLCheckMatrix' => __DIR__ . '/includes/htmlform/fields/HTMLCheckMatrix.php',
+       'HTMLComboboxField' => __DIR__ . '/includes/htmlform/fields/HTMLComboboxField.php',
+       'HTMLEditTools' => __DIR__ . '/includes/htmlform/fields/HTMLEditTools.php',
        'HTMLFileCache' => __DIR__ . '/includes/cache/HTMLFileCache.php',
-       'HTMLFloatField' => __DIR__ . '/includes/htmlform/HTMLFloatField.php',
+       'HTMLFloatField' => __DIR__ . '/includes/htmlform/fields/HTMLFloatField.php',
        'HTMLForm' => __DIR__ . '/includes/htmlform/HTMLForm.php',
        'HTMLFormField' => __DIR__ . '/includes/htmlform/HTMLFormField.php',
-       'HTMLFormFieldCloner' => __DIR__ . '/includes/htmlform/HTMLFormFieldCloner.php',
+       'HTMLFormFieldCloner' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldCloner.php',
        'HTMLFormFieldRequiredOptionsException' => __DIR__ . '/includes/htmlform/HTMLFormFieldRequiredOptionsException.php',
-       'HTMLFormFieldWithButton' => __DIR__ . '/includes/htmlform/HTMLFormFieldWithButton.php',
-       'HTMLHiddenField' => __DIR__ . '/includes/htmlform/HTMLHiddenField.php',
-       'HTMLInfoField' => __DIR__ . '/includes/htmlform/HTMLInfoField.php',
-       'HTMLIntField' => __DIR__ . '/includes/htmlform/HTMLIntField.php',
-       'HTMLMultiSelectField' => __DIR__ . '/includes/htmlform/HTMLMultiSelectField.php',
+       'HTMLFormFieldWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldWithButton.php',
+       'HTMLHiddenField' => __DIR__ . '/includes/htmlform/fields/HTMLHiddenField.php',
+       'HTMLInfoField' => __DIR__ . '/includes/htmlform/fields/HTMLInfoField.php',
+       'HTMLIntField' => __DIR__ . '/includes/htmlform/fields/HTMLIntField.php',
+       'HTMLMultiSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLMultiSelectField.php',
        'HTMLNestedFilterable' => __DIR__ . '/includes/htmlform/HTMLNestedFilterable.php',
-       'HTMLRadioField' => __DIR__ . '/includes/htmlform/HTMLRadioField.php',
-       'HTMLSelectAndOtherField' => __DIR__ . '/includes/htmlform/HTMLSelectAndOtherField.php',
-       'HTMLSelectField' => __DIR__ . '/includes/htmlform/HTMLSelectField.php',
-       'HTMLSelectLimitField' => __DIR__ . '/includes/htmlform/HTMLSelectLimitField.php',
-       'HTMLSelectNamespace' => __DIR__ . '/includes/htmlform/HTMLSelectNamespace.php',
-       'HTMLSelectNamespaceWithButton' => __DIR__ . '/includes/htmlform/HTMLSelectNamespaceWithButton.php',
-       'HTMLSelectOrOtherField' => __DIR__ . '/includes/htmlform/HTMLSelectOrOtherField.php',
-       'HTMLSubmitField' => __DIR__ . '/includes/htmlform/HTMLSubmitField.php',
-       'HTMLTagFilter' => __DIR__ . '/includes/htmlform/HTMLTagFilter.php',
-       'HTMLTextAreaField' => __DIR__ . '/includes/htmlform/HTMLTextAreaField.php',
-       'HTMLTextField' => __DIR__ . '/includes/htmlform/HTMLTextField.php',
-       'HTMLTextFieldWithButton' => __DIR__ . '/includes/htmlform/HTMLTextFieldWithButton.php',
-       'HTMLTitleTextField' => __DIR__ . '/includes/htmlform/HTMLTitleTextField.php',
-       'HTMLUserTextField' => __DIR__ . '/includes/htmlform/HTMLUserTextField.php',
+       'HTMLRadioField' => __DIR__ . '/includes/htmlform/fields/HTMLRadioField.php',
+       'HTMLSelectAndOtherField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectAndOtherField.php',
+       'HTMLSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectField.php',
+       'HTMLSelectLimitField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectLimitField.php',
+       'HTMLSelectNamespace' => __DIR__ . '/includes/htmlform/fields/HTMLSelectNamespace.php',
+       'HTMLSelectNamespaceWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLSelectNamespaceWithButton.php',
+       'HTMLSelectOrOtherField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectOrOtherField.php',
+       'HTMLSubmitField' => __DIR__ . '/includes/htmlform/fields/HTMLSubmitField.php',
+       'HTMLTagFilter' => __DIR__ . '/includes/htmlform/fields/HTMLTagFilter.php',
+       'HTMLTextAreaField' => __DIR__ . '/includes/htmlform/fields/HTMLTextAreaField.php',
+       'HTMLTextField' => __DIR__ . '/includes/htmlform/fields/HTMLTextField.php',
+       'HTMLTextFieldWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLTextFieldWithButton.php',
+       'HTMLTitleTextField' => __DIR__ . '/includes/htmlform/fields/HTMLTitleTextField.php',
+       'HTMLUserTextField' => __DIR__ . '/includes/htmlform/fields/HTMLUserTextField.php',
        'HWLDFWordAccumulator' => __DIR__ . '/includes/diff/DairikiDiff.php',
        'HashBagOStuff' => __DIR__ . '/includes/libs/objectcache/HashBagOStuff.php',
        'HashConfig' => __DIR__ . '/includes/config/HashConfig.php',
@@ -748,8 +747,6 @@ $wgAutoloadLocalClasses = [
        'LoggedOutEditToken' => __DIR__ . '/includes/user/LoggedOutEditToken.php',
        'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
        'LoginForm' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LoginFormAuthManager' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LoginFormPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogin.php',
        'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
        'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
        'LonelyPagesPage' => __DIR__ . '/includes/specials/SpecialLonelypages.php',
@@ -790,6 +787,7 @@ $wgAutoloadLocalClasses = [
        'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
        'McTest' => __DIR__ . '/maintenance/mctest.php',
        'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
+       'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
        'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
        'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
        'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
@@ -1169,6 +1167,7 @@ $wgAutoloadLocalClasses = [
        'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
        'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
        'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
+       'ResourceLoaderUserStylesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserStylesModule.php',
        'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
        'ResourceLoaderWikiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderWikiModule.php',
        'RestbaseVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/RestbaseVirtualRESTService.php',
@@ -1279,13 +1278,10 @@ $wgAutoloadLocalClasses = [
        'SpecialChangeContentModel' => __DIR__ . '/includes/specials/SpecialChangeContentModel.php',
        'SpecialChangeCredentials' => __DIR__ . '/includes/specials/SpecialChangeCredentials.php',
        'SpecialChangeEmail' => __DIR__ . '/includes/specials/SpecialChangeEmail.php',
-       'SpecialChangeEmailPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangeEmail.php',
        'SpecialChangePassword' => __DIR__ . '/includes/specials/SpecialChangePassword.php',
-       'SpecialChangePasswordPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangePassword.php',
        'SpecialComparePages' => __DIR__ . '/includes/specials/SpecialComparePages.php',
        'SpecialContributions' => __DIR__ . '/includes/specials/SpecialContributions.php',
        'SpecialCreateAccount' => __DIR__ . '/includes/specials/SpecialCreateAccount.php',
-       'SpecialCreateAccountPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialCreateAccount.php',
        'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
        'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
        'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
@@ -1318,7 +1314,6 @@ $wgAutoloadLocalClasses = [
        'SpecialPageLanguage' => __DIR__ . '/includes/specials/SpecialPageLanguage.php',
        'SpecialPagesWithProp' => __DIR__ . '/includes/specials/SpecialPagesWithProp.php',
        'SpecialPasswordReset' => __DIR__ . '/includes/specials/SpecialPasswordReset.php',
-       'SpecialPasswordResetPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialPasswordReset.php',
        'SpecialPermanentLink' => __DIR__ . '/includes/specials/SpecialPermanentLink.php',
        'SpecialPreferences' => __DIR__ . '/includes/specials/SpecialPreferences.php',
        'SpecialPrefixindex' => __DIR__ . '/includes/specials/SpecialPrefixindex.php',
@@ -1349,7 +1344,6 @@ $wgAutoloadLocalClasses = [
        'SpecialUploadStashTooLargeException' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
        'SpecialUserLogin' => __DIR__ . '/includes/specials/SpecialUserLogin.php',
        'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
-       'SpecialUserlogoutPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogout.php',
        'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
        'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
        'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatlinkshere.php',
@@ -1485,8 +1479,6 @@ $wgAutoloadLocalClasses = [
        'UserOptions' => __DIR__ . '/maintenance/userOptions.inc',
        'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php',
        'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
-       'UsercreateTemplate' => __DIR__ . '/includes/templates/Usercreate.php',
-       'UserloginTemplate' => __DIR__ . '/includes/templates/Userlogin.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
        'UsersPager' => __DIR__ . '/includes/specials/pagers/UsersPager.php',
        'UtfNormal' => __DIR__ . '/includes/compat/normal/UtfNormal.php',
@@ -1539,6 +1531,7 @@ $wgAutoloadLocalClasses = [
        'WikiReference' => __DIR__ . '/includes/WikiMap.php',
        'WikiRevision' => __DIR__ . '/includes/import/WikiRevision.php',
        'WikiStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
+       'WikiTextStructure' => __DIR__ . '/includes/content/WikiTextStructure.php',
        'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
        'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
        'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
index 1bd3d4c..9bd0fa1 100644 (file)
@@ -25,7 +25,7 @@
                "ext-xml": "*",
                "liuggio/statsd-php-client": "1.0.18",
                "mediawiki/at-ease": "1.1.0",
-               "oojs/oojs-ui": "0.17.6",
+               "oojs/oojs-ui": "0.17.7",
                "oyejorge/less.php": "1.7.0.10",
                "php": ">=5.5.9",
                "psr/log": "1.0.0",
index 5bc8bfc..6f3da97 100644 (file)
@@ -5,7 +5,7 @@ The 'docs' directory contain various text files that should help you understand
 the most important parts of the code of MediaWiki. More in-depth documentation
 can be found at:
   https://www.mediawiki.org/wiki/Manual:Code
-
+  https://www.mediawiki.org/wiki/Developer_hub
 API documentation is automatically generated and updated daily at:
   https://doc.wikimedia.org/mediawiki-core/master/php/html/
 
index 110e99d..c010014 100644 (file)
                                                                        "type": "string",
                                                                        "description": "Group with which this module should be loaded"
                                                                },
+                                                               "deprecated": {
+                                                                       "type": ["object", "boolean"],
+                                                                       "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message."
+                                                               },
                                                                "position": {
                                                                        "type": "string",
                                                                        "description": "Position on the page to load this module at",
index 37235e9..d707864 100644 (file)
                                                                        "type": "string",
                                                                        "description": "Group which this module should be loaded together with"
                                                                },
+                                                               "deprecated": {
+                                                                       "type": ["object", "boolean"],
+                                                                       "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message."
+                                                               },
                                                                "position": {
                                                                        "type": "string",
                                                                        "description": "Position on the page to load this module at",
index 57240c9..8fa3793 100644 (file)
@@ -608,6 +608,7 @@ $reason: the reason the article was deleted
 $id: id of the article that was deleted
 $content: the Content of the deleted page
 $logEntry: the ManualLogEntry used to record the deletion
+$archivedRevisionCount: the number of revisions archived during the deletion
 
 'ArticleEditUpdateNewTalk': Before updating user_newtalk when a user talk page
 was changed.
@@ -1103,6 +1104,9 @@ $row: the DB row for this line
 $id: User identifier
 $title: User page title
 &$tools: Array of tool links
+$specialPage: SpecialPage instance for context and services. Can be either
+  SpecialContributions or DeletedContributionsPage. Extensions should type
+  hint against a generic SpecialPage though.
 
 'ConvertContent': Called by AbstractContent::convert when a conversion to
 another content model is requested.
@@ -1141,6 +1145,85 @@ $page: SpecialPage object for DeletedContributions
 $row: the DB row for this line
 &$classes: the classes to add to the surrounding <li>
 
+'DifferenceEngineMarkPatrolledLink': Allows extensions to change the "mark as patrolled" link
+which is shown both on the diff header as well as on the bottom of a page, usually
+wrapped in a span element which has class="patrollink".
+$differenceEngine: DifferenceEngine object
+&$markAsPatrolledLink: The "mark as patrolled" link HTML (string)
+$rcid: Recent change ID (rc_id) for this change (int)
+$token: Patrol token; $rcid is used in generating this variable
+
+'DifferenceEngineMarkPatrolledRCID': Allows extensions to possibly change the rcid parameter.
+For example the rcid might be set to zero due to the user being the same as the
+performer of the change but an extension might still want to show it under certain
+conditions.
+&$rcid: rc_id (int) of the change or 0
+$differenceEngine: DifferenceEngine object
+$change: RecentChange object
+$user: User object representing the current user
+
+'DifferenceEngineNewHeader': Allows extensions to change the $newHeader variable, which
+contains information about the new revision, such as the revision's author, whether
+the revision was marked as a minor edit or not, etc.
+$differenceEngine: DifferenceEngine object
+&$newHeader: The string containing the various #mw-diff-otitle[1-5] divs, which
+include things like revision author info, revision comment, RevisionDelete link and more
+$formattedRevisionTools: Array containing revision tools, some of which may have
+been injected with the DiffRevisionTools hook
+$nextlink: String containing the link to the next revision (if any); also included in $newHeader
+$rollback: Rollback link (string) to roll this revision back to the previous one, if any
+$newminor: String indicating if the new revision was marked as a minor edit
+$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating
+whether we should show just the diff; passed in as a query string parameter to the
+various URLs constructed here (i.e. $nextlink)
+$rdel: RevisionDelete link for the new revision, if the current user is allowed
+to use the RevisionDelete feature
+$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions
+
+'DifferenceEngineOldHeader': Allows extensions to change the $oldHeader variable, which
+contains information about the old revision, such as the revision's author, whether
+the revision was marked as a minor edit or not, etc.
+$differenceEngine: DifferenceEngine object
+&$oldHeader: The string containing the various #mw-diff-otitle[1-5] divs, which
+include things like revision author info, revision comment, RevisionDelete link and more
+$prevlink: String containing the link to the previous revision (if any); also included in $oldHeader
+$oldminor: String indicating if the old revision was marked as a minor edit
+$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating
+whether we should show just the diff; passed in as a query string parameter to the
+various URLs constructed here (i.e. $prevlink)
+$ldel: RevisionDelete link for the old revision, if the current user is allowed
+to use the RevisionDelete feature
+$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions
+
+'DifferenceEngineOldHeaderNoOldRev': Change the $oldHeader variable in cases when
+there is no old revision
+&$oldHeader: empty string by default
+
+'DifferenceEngineRenderRevisionAddParserOutput': Allows extensions to change the parser output.
+Return false to not add parser output via OutputPage's addParserOutput method.
+$differenceEngine: DifferenceEngine object
+$out: OutputPage object
+$parserOutput: ParserOutput object
+$wikiPage: WikiPage object
+
+DifferenceEngineRenderRevisionShowFinalPatrolLink': An extension can hook into this hook
+point and return false to not show the final "mark as patrolled" link on the bottom
+of a page.
+This hook has no arguments.
+
+'DifferenceEngineShowDiff': Allows extensions to affect the diff text which
+eventually gets sent to the OutputPage object.
+$differenceEngine: DifferenceEngine object
+
+'DifferenceEngineShowEmptyOldContent': Allows extensions to change the diff table
+body (without header) in cases when there is no old revision or the old and new
+revisions are identical.
+$differenceEngine: DifferenceEngine object
+
+'DifferenceEngineShowDiffPage': Add additional output via the available OutputPage
+object into the diff view
+$out: OutputPage object
+
 'DiffRevisionTools': Override or extend the revision tools available from the
 diff view, i.e. undo, etc.
 $newRev: Revision object of the "new" revision
@@ -2620,6 +2703,18 @@ search results.
 $title: Current Title object being displayed in search results.
 &$id: Revision ID (default is false, for latest)
 
+'SearchIndexFields': Add fields to search index mapping.
+&$fields: Array of fields, all implement SearchIndexField
+$engine: SearchEngine instance for which mapping is being built.
+
+'SearchDataForIndex': Add data to search document. Allows to add any data to
+the field map used to index the document.
+&$fields: Array of name => value pairs for fields
+$handler: ContentHandler for the content being indexed
+$page: WikiPage that is being indexed
+$output: ParserOutput that is produced from the page
+$engine: SearchEngine for which the indexing is intended
+
 'SecondaryDataUpdates': Allows modification of the list of DataUpdates to
 perform when page content is modified. Currently called by
 AbstractContent::getSecondaryDataUpdates.
index 923a19b..5c9bf53 100644 (file)
@@ -1,9 +1,12 @@
+== User Information ==
+
 Extensions are distributed separately. Drop them into this directory and enable
 as per the extension's installation instructions.
 
 You can find a list of extensions and documentation at
-<https://www.mediawiki.org/wiki/Category:Extensions>.
+<https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions>.
 
+== Development Information ==
 
 If you are a developer, you might want to fetch the extension tree in another
 directory and make a symbolic link:
index 3f0528e..3d5e6c5 100644 (file)
@@ -33,8 +33,8 @@
  *
  *     $cf = new CategoryFinder;
  *     $cf->seed(
- *         array( 12345 ),
- *         array( 'Category 1', 'Category 2' ),
+ *         [ 12345 ],
+ *         [ 'Category 1', 'Category 2' ],
  *         'AND'
  *     );
  *     $a = $cf->run();
@@ -49,7 +49,7 @@ class CategoryFinder {
        /** @var array Array of DBKEY category names for categories that don't have a page */
        protected $deadend = [];
 
-       /** @var array Array of [ID => array()] */
+       /** @var array Array of [ ID => [] ] */
        protected $parents = [];
 
        /** @var array Array of article/category IDs */
index 5926328..8363b32 100644 (file)
@@ -945,22 +945,11 @@ $wgTrustedMediaFormats = [
 /**
  * Plugins for media file type handling.
  * Each entry in the array maps a MIME type to a class name
+ *
+ * Core media handlers are listed in MediaHandlerFactory,
+ * and extensions should use extension.json.
  */
-$wgMediaHandlers = [
-       'image/jpeg' => 'JpegHandler',
-       'image/png' => 'PNGHandler',
-       'image/gif' => 'GIFHandler',
-       'image/tiff' => 'TiffHandler',
-       'image/webp' => 'WebPHandler',
-       'image/x-ms-bmp' => 'BmpHandler',
-       'image/x-bmp' => 'BmpHandler',
-       'image/x-xcf' => 'XCFHandler',
-       'image/svg+xml' => 'SvgHandler', // official
-       'image/svg' => 'SvgHandler', // compat
-       'image/vnd.djvu' => 'DjVuHandler', // official
-       'image/x.djvu' => 'DjVuHandler', // compat
-       'image/x-djvu' => 'DjVuHandler', // compat
-];
+$wgMediaHandlers = [];
 
 /**
  * Plugins for page content model handling.
@@ -2524,7 +2513,7 @@ $wgFileCacheDepth = 2;
 
 /**
  * Kept for extension compatibility; see $wgParserCacheType
- * @deprecated 1.26
+ * @deprecated since 1.26
  */
 $wgEnableParserCache = true;
 
@@ -4458,13 +4447,6 @@ $wgPasswordPolicy = [
        ],
 ];
 
-/**
- * Disable AuthManager
- * @since 1.27
- * @deprecated since 1.27, for use during development only
- */
-$wgDisableAuthManager = false;
-
 /**
  * Configure AuthManager
  *
@@ -8184,13 +8166,6 @@ $wgTextModelsToParse = [
        CONTENT_MODEL_CSS, // Make categories etc work, people put them into comments.
 ];
 
-/**
- * Whether the user must enter their password to change their e-mail address
- *
- * @since 1.20
- */
-$wgRequirePasswordforEmailChange = true;
-
 /**
  * Register handlers for specific types of sites.
  *
index 674cf28..ee06993 100644 (file)
@@ -2714,8 +2714,9 @@ class EditPage {
                $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
                        Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
 
-               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
-                       self::getPreviewLimitReport( $this->mParserOutput ) ) );
+               if ( $this->mParserOutput ) {
+                       $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
+               }
 
                $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
 
@@ -3442,41 +3443,12 @@ HTML
                        return '';
                }
 
-               $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
-                       wfMessage( 'limitreport-title' )->parseAsBlock()
+               return ResourceLoader::makeInlineScript(
+                       ResourceLoader::makeConfigSetScript(
+                               [ 'wgPageParseReport' => $output->getLimitReportData() ],
+                               true
+                       )
                );
-
-               // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
-               $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
-
-               $limitReport .= Html::openElement( 'table', [
-                       'class' => 'preview-limit-report wikitable'
-               ] ) .
-                       Html::openElement( 'tbody' );
-
-               foreach ( $output->getLimitReportData() as $key => $value ) {
-                       if ( Hooks::run( 'ParserLimitReportFormat',
-                               [ $key, &$value, &$limitReport, true, true ]
-                       ) ) {
-                               $keyMsg = wfMessage( $key );
-                               $valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
-                               if ( !$valueMsg->exists() ) {
-                                       $valueMsg = new RawMessage( '$1' );
-                               }
-                               if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
-                                       $limitReport .= Html::openElement( 'tr' ) .
-                                               Html::rawElement( 'th', null, $keyMsg->parse() ) .
-                                               Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
-                                               Html::closeElement( 'tr' );
-                               }
-                       }
-               }
-
-               $limitReport .= Html::closeElement( 'tbody' ) .
-                       Html::closeElement( 'table' ) .
-                       Html::closeElement( 'div' );
-
-               return $limitReport;
        }
 
        protected function showStandardInputs( &$tabindex = 2 ) {
index e19c36c..7117f4c 100644 (file)
@@ -2950,7 +2950,7 @@ function wfRelativePath( $path, $from ) {
  * Supports base 2 through 36; digit values 10-36 are represented
  * as lowercase letters a-z. Input is case-insensitive.
  *
- * @deprecated 1.27 Use Wikimedia\base_convert() directly
+ * @deprecated since 1.27 Use Wikimedia\base_convert() directly
  *
  * @param string $input Input number
  * @param int $sourceBase Base of the input number
@@ -3525,7 +3525,7 @@ function wfGetParserCacheStorage() {
  * @param string|null $deprecatedVersion Optionally mark hook as deprecated with version number
  *
  * @return bool True if no handler aborted the hook
- * @deprecated 1.25 - use Hooks::run
+ * @deprecated since 1.25 - use Hooks::run
  */
 function wfRunHooks( $event, array $args = [], $deprecatedVersion = null ) {
        return Hooks::run( $event, $args, $deprecatedVersion );
index 21857b9..7dac0ec 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * The MediaWiki class is the helper class for the index.php entry point.
@@ -761,8 +762,9 @@ class MediaWiki {
         * @param string $mode Use 'fast' to always skip job running
         */
        public function restInPeace( $mode = 'fast' ) {
+               $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
                // Assure deferred updates are not in the main transaction
-               wfGetLBFactory()->commitMasterChanges( __METHOD__ );
+               $factory->commitMasterChanges( __METHOD__ );
 
                // Loosen DB query expectations since the HTTP client is unblocked
                $trxProfiler = Profiler::instance()->getTransactionProfiler();
@@ -788,7 +790,6 @@ class MediaWiki {
                wfLogProfilingData();
 
                // Commit and close up!
-               $factory = wfGetLBFactory();
                $factory->commitMasterChanges( __METHOD__ );
                $factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT );
 
index ff292cf..ac5fbe0 100644 (file)
@@ -11,6 +11,7 @@ use LBFactory;
 use LinkCache;
 use Liuggio\StatsdClient\Factory\StatsdDataFactory;
 use LoadBalancer;
+use MediaHandlerFactory;
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\Linker\LinkRendererFactory;
 use MediaWiki\Services\SalvageableService;
@@ -511,6 +512,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'WatchedItemQueryService' );
        }
 
+       /**
+        * @since 1.28
+        * @return MediaHandlerFactory
+        */
+       public function getMediaHandlerFactory() {
+               return $this->getService( 'MediaHandlerFactory' );
+       }
+
        /**
         * @since 1.28
         * @return GenderCache
index d34ace8..b88db92 100644 (file)
@@ -633,7 +633,7 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * Add or replace an header item to the output
+        * Add or replace a head item to the output
         *
         * Whenever possible, use more specific options like ResourceLoader modules,
         * OutputPage::addLink(), OutputPage::addMetaLink() and OutputPage::addFeedLink()
@@ -648,6 +648,16 @@ class OutputPage extends ContextSource {
                $this->mHeadItems[$name] = $value;
        }
 
+       /**
+        * Add one or more head items to the output
+        *
+        * @since 1.28
+        * @param string|string[] $value Raw HTML
+        */
+       public function addHeadItems( $values ) {
+               $this->mHeadItems = array_merge( $this->mHeadItems, (array)$values );
+       }
+
        /**
         * Check if the header item $name is already set
         *
@@ -1763,7 +1773,7 @@ class OutputPage extends ContextSource {
                }
 
                // Include profiling data
-               $this->limitReportData = $parserOutput->getLimitReportData();
+               $this->setLimitReportData( $parserOutput->getLimitReportData() );
 
                // Link flags are ignored for now, but may in the future be
                // used to mark individual language links.
@@ -3650,7 +3660,7 @@ class OutputPage extends ContextSource {
                ) {
                        // We're on a preview of a CSS subpage
                        // Exclude this page from the user module in case it's in there (bug 26283)
-                       $link = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES,
+                       $link = $this->makeResourceLoaderLink( 'user.styles', ResourceLoaderModule::TYPE_STYLES,
                                [ 'excludepage' => $this->getTitle()->getPrefixedDBkey() ]
                        );
                        $otherTags = array_merge( $otherTags, $link['html'] );
@@ -3665,7 +3675,7 @@ class OutputPage extends ContextSource {
                        $otherTags[] = Html::inlineStyle( $previewedCSS );
                } else {
                        // Load the user styles normally
-                       $moduleStyles[] = 'user';
+                       $moduleStyles[] = 'user.styles';
                }
 
                // Per-user preference styles
@@ -4041,4 +4051,12 @@ class OutputPage extends ContextSource {
                // public API or you'll be severely disappointed when T87871 is fixed and it disappears.
                $this->addMeta( 'X-OOUI-PHP', '1' );
        }
+
+       /**
+        * @param array $data Data from ParserOutput::getLimitReportData()
+        * @since 1.28
+        */
+       public function setLimitReportData( array $data ) {
+               $this->limitReportData = $data;
+       }
 }
index 10d2904..dd68102 100644 (file)
@@ -202,7 +202,7 @@ class Pingback {
         * <https://github.com/wikimedia/mediawiki-extensions-EventLogging/
         *   blob/7e5fe4f1ef/includes/EventLogging.php#L32-L74>
         *
-        * @param data Pingback data as an associative array
+        * @param array $data Pingback data as an associative array
         * @return bool true on success, false on failure
         */
        private function postPingback( array $data ) {
index 3083a8d..70addfc 100644 (file)
@@ -207,8 +207,9 @@ class Preferences {
         * @return void
         */
        static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               global $wgAuth, $wgContLang, $wgParser, $wgDisableAuthManager;
+               global $wgContLang, $wgParser;
 
+               $authManager = AuthManager::singleton();
                $config = $context->getConfig();
                // retrieving user name for GENDER and misc.
                $userName = $user->getName();
@@ -283,21 +284,19 @@ class Preferences {
                $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
 
                // Actually changeable stuff
-               $realnameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'realname' )
-                       : AuthManager::singleton()->allowsPropertyChange( 'realname' );
                $defaultPreferences['realname'] = [
                        // (not really "private", but still shouldn't be edited without permission)
-                       'type' => $canEditPrivateInfo && $realnameChangeAllowed ? 'text' : 'info',
+                       'type' => $canEditPrivateInfo && $authManager->allowsPropertyChange( 'realname' )
+                               ? 'text' : 'info',
                        'default' => $user->getRealName(),
                        'section' => 'personal/info',
                        'label-message' => 'yourrealname',
                        'help-message' => 'prefs-help-realname',
                ];
 
-               $allowPasswordChange = $wgDisableAuthManager ? $wgAuth->allowPasswordChange()
-                       : AuthManager::singleton()->allowsAuthenticationDataChange(
-                               new PasswordAuthenticationRequest(), false )->isGood();
-               if ( $canEditPrivateInfo && $allowPasswordChange ) {
+               if ( $canEditPrivateInfo && $authManager->allowsAuthenticationDataChange(
+                       new PasswordAuthenticationRequest(), false )->isGood()
+               ) {
                        $link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ),
                                $context->msg( 'prefs-resetpass' )->escaped(), [],
                                [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
@@ -418,10 +417,8 @@ class Preferences {
                        'default' => $oldsigHTML,
                        'section' => 'personal/signature',
                ];
-               $nicknameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'nickname' )
-                       : AuthManager::singleton()->allowsPropertyChange( 'nickname' );
                $defaultPreferences['nickname'] = [
-                       'type' => $nicknameChangeAllowed ? 'text' : 'info',
+                       'type' => $authManager->allowsPropertyChange( 'nickname' ) ? 'text' : 'info',
                        'maxlength' => $config->get( 'MaxSigChars' ),
                        'label-message' => 'yournick',
                        'validation-callback' => [ 'Preferences', 'validateSignature' ],
@@ -450,9 +447,7 @@ class Preferences {
                                }
 
                                $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
-                               $emailChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'emailaddress' )
-                                       : AuthManager::singleton()->allowsPropertyChange( 'emailaddress' );
-                               if ( $canEditPrivateInfo && $emailChangeAllowed ) {
+                               if ( $canEditPrivateInfo && $authManager->allowsPropertyChange( 'emailaddress' ) ) {
                                        $link = Linker::link(
                                                SpecialPage::getTitleFor( 'ChangeEmail' ),
                                                $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
index d4f16ee..21c6377 100644 (file)
@@ -158,6 +158,12 @@ return [
                return new WatchedItemQueryService( $services->getDBLoadBalancer() );
        },
 
+       'MediaHandlerFactory' => function( MediaWikiServices $services ) {
+               return new MediaHandlerFactory(
+                       $services->getMainConfig()->get( 'MediaHandlers' )
+               );
+       },
+
        'LinkCache' => function( MediaWikiServices $services ) {
                return new LinkCache(
                        $services->getTitleFormatter()
index b336795..bad0ef9 100644 (file)
@@ -367,4 +367,12 @@ class ServiceContainer implements DestructibleService {
                return $service;
        }
 
+       /**
+        * @param string $name
+        * @return bool Whether the service is disabled
+        * @since 1.28
+        */
+       public function isServiceDisabled( $name ) {
+               return isset( $this->disabled[$name] );
+       }
 }
index 6c5de90..7909889 100644 (file)
@@ -452,22 +452,6 @@ if ( $wgProfileOnly ) {
        $wgDebugLogFile = '';
 }
 
-// Disable AuthManager API modules if $wgDisableAuthManager
-if ( $wgDisableAuthManager ) {
-       $wgAPIModules += [
-               'clientlogin' => 'ApiDisabled',
-               'createaccount' => 'ApiCreateAccount', // Use the non-AuthManager version
-               'linkaccount' => 'ApiDisabled',
-               'unlinkaccount' => 'ApiDisabled',
-               'changeauthenticationdata' => 'ApiDisabled',
-               'removeauthenticationdata' => 'ApiDisabled',
-               'resetpassword' => 'ApiDisabled',
-       ];
-       $wgAPIMetaModules += [
-               'authmanagerinfo' => 'ApiQueryDisabled',
-       ];
-}
-
 // Backwards compatibility with old password limits
 if ( $wgMinimalPasswordLength !== false ) {
        $wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength;
@@ -711,12 +695,10 @@ $wgContLang->initContLang();
 $wgRequest->interpolateTitle();
 
 if ( !is_object( $wgAuth ) ) {
-       $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin;
+       $wgAuth = new MediaWiki\Auth\AuthManagerAuthPlugin;
        Hooks::run( 'AuthPluginSetup', [ &$wgAuth ] );
 }
-if ( !$wgDisableAuthManager &&
-       $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin
-) {
+if ( $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin ) {
        MediaWiki\Auth\AuthManager::singleton()->forcePrimaryAuthenticationProviders( [
                new MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider( [
                        'authoritative' => false,
@@ -852,15 +834,11 @@ if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
        $sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser();
        if ( $sessionUser->getId() === 0 && User::isValidUserName( $sessionUser->getName() ) ) {
                $ps_autocreate = Profiler::instance()->scopedProfileIn( $fname . '-autocreate' );
-               if ( $wgDisableAuthManager ) {
-                       $res = MediaWiki\Session\SessionManager::autoCreateUser( $sessionUser );
-               } else {
-                       $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
-                               $sessionUser,
-                               MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
-                               true
-                       );
-               }
+               $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+                       $sessionUser,
+                       MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+                       true
+               );
                Profiler::instance()->scopedProfileOut( $ps_autocreate );
                \MediaWiki\Logger\LoggerFactory::getInstance( 'authmanager' )->info( 'Autocreation attempt', [
                        'event' => 'autocreate',
index 6c536dd..03b4b8c 100644 (file)
@@ -24,7 +24,7 @@
  * Static accessor class for site_stats and related things
  */
 class SiteStats {
-       /** @var bool|ResultWrapper */
+       /** @var bool|stdClass */
        private static $row;
 
        /** @var bool */
@@ -62,7 +62,7 @@ class SiteStats {
        }
 
        /**
-        * @return bool|ResultWrapper
+        * @return bool|stdClass
         */
        static function loadAndLazyInit() {
                global $wgMiserMode;
@@ -96,7 +96,7 @@ class SiteStats {
 
        /**
         * @param IDatabase $db
-        * @return bool|ResultWrapper
+        * @return bool|stdClass
         */
        static function doLoad( $db ) {
                return $db->selectRow( 'site_stats', [
@@ -107,7 +107,7 @@ class SiteStats {
                                'ss_users',
                                'ss_active_users',
                                'ss_images',
-                       ], false, __METHOD__ );
+                       ], [], __METHOD__ );
        }
 
        /**
index 45d8bed..e578873 100644 (file)
@@ -385,7 +385,7 @@ class Status {
         *
         * @return array A list in which each entry is an array with a message key as its first element.
         *         The remaining array elements are the message parameters.
-        * @deprecated 1.25
+        * @deprecated since 1.25
         */
        public function getErrorsArray() {
                return $this->getStatusArray( 'error' );
@@ -396,7 +396,7 @@ class Status {
         *
         * @return array A list in which each entry is an array with a message key as its first element.
         *         The remaining array elements are the message parameters.
-        * @deprecated 1.25
+        * @deprecated since 1.25
         */
        public function getWarningsArray() {
                return $this->getStatusArray( 'warning' );
index f8f1dc1..7f043e4 100644 (file)
@@ -50,7 +50,8 @@ class UnwatchAction extends WatchAction {
        }
 
        public function onSuccess() {
-               $this->getOutput()->addWikiMsg( 'removedwatchtext', $this->getTitle()->getPrefixedText() );
+               $msgKey = $this->getTitle()->isTalkPage() ? 'removedwatchtext-talk' : 'removedwatchtext';
+               $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText() );
        }
 
        public function doesWrites() {
index 890740f..23505c0 100644 (file)
@@ -67,7 +67,8 @@ class WatchAction extends FormAction {
        }
 
        public function onSuccess() {
-               $this->getOutput()->addWikiMsg( 'addedwatchtext', $this->getTitle()->getPrefixedText() );
+               $msgKey = $this->getTitle()->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
+               $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText() );
        }
 
        /* Static utility methods */
index 52a7951..2511e3b 100644 (file)
@@ -66,13 +66,15 @@ class ApiAMCreateAccount extends ApiBase {
                $helper = new ApiAuthManagerHelper( $this );
                $manager = AuthManager::singleton();
 
-               // Make sure it's possible to log in
+               // Make sure it's possible to create accounts
                if ( !$manager->canCreateAccounts() ) {
                        $this->getResult()->addValue( null, 'createaccount', $helper->formatAuthenticationResponse(
                                AuthenticationResponse::newFail(
                                        $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_CREATE )
                                )
                        ) );
+                       $helper->logAuthenticationResult( 'accountcreation',
+                               'userlogin-cannot-' . AuthManager::ACTION_CREATE );
                        return;
                }
 
@@ -93,6 +95,7 @@ class ApiAMCreateAccount extends ApiBase {
 
                $this->getResult()->addValue( null, 'createaccount',
                        $helper->formatAuthenticationResponse( $res ) );
+               $helper->logAuthenticationResult( 'accountcreation', $res );
        }
 
        public function isReadMode() {
index e30f22b..fe5675a 100644 (file)
@@ -25,6 +25,7 @@ use MediaWiki\Auth\AuthManager;
 use MediaWiki\Auth\AuthenticationRequest;
 use MediaWiki\Auth\AuthenticationResponse;
 use MediaWiki\Auth\CreateFromLoginAuthenticationRequest;
+use MediaWiki\Logger\LoggerFactory;
 
 /**
  * Helper class for AuthManager-using API modules. Intended for use via
@@ -220,6 +221,30 @@ class ApiAuthManagerHelper {
                return $ret;
        }
 
+       /**
+        * Logs successful or failed authentication.
+        * @param string|AuthenticationResponse $result Response or error message
+        * @param string $event Event type (e.g. 'accountcreation')
+        */
+       public function logAuthenticationResult( $event, $result ) {
+               if ( is_string( $result ) ) {
+                       $status = Status::newFatal( $result );
+               } elseif ( $result->status === AuthenticationResponse::PASS ) {
+                       $status = Status::newGood();
+               } elseif ( $result->status === AuthenticationResponse::FAIL ) {
+                       $status = Status::newFatal( $result->message );
+               } else {
+                       return;
+               }
+
+               $module = $this->module->getModuleName();
+               LoggerFactory::getInstance( 'authmanager' )->info( "$module API attempt", [
+                       'event' => $event,
+                       'status' => $status,
+                       'module' => $module,
+               ] );
+       }
+
        /**
         * Fetch the preserved CreateFromLoginAuthenticationRequest, if any
         * @return CreateFromLoginAuthenticationRequest|null
index 8e5a3c7..cbb1524 100644 (file)
@@ -72,6 +72,7 @@ class ApiClientLogin extends ApiBase {
                        $this->getResult()->addValue( null, 'clientlogin', $helper->formatAuthenticationResponse(
                                AuthenticationResponse::newFail( $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_LOGIN ) )
                        ) );
+                       $helper->logAuthenticationResult( 'login', 'userlogin-cannot-' . AuthManager::ACTION_LOGIN );
                        return;
                }
 
@@ -99,6 +100,7 @@ class ApiClientLogin extends ApiBase {
 
                $this->getResult()->addValue( null, 'clientlogin',
                        $helper->formatAuthenticationResponse( $res ) );
+               $helper->logAuthenticationResult( 'login', $res );
        }
 
        public function isReadMode() {
diff --git a/includes/api/ApiCreateAccount.php b/includes/api/ApiCreateAccount.php
deleted file mode 100644 (file)
index 6a48610..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-<?php
-/**
- * Created on August 7, 2012
- *
- * Copyright © 2012 Tyler Romeo <tylerromeo@gmail.com>
- *
- * 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
- */
-use MediaWiki\Logger\LoggerFactory;
-
-/**
- * Unit to authenticate account registration attempts to the current wiki.
- *
- * @ingroup API
- * @deprecated since 1.27, only used when $wgDisableAuthManager is true
- */
-class ApiCreateAccount extends ApiBase {
-       public function execute() {
-               // If we're in a mode that breaks the same-origin policy, no tokens can
-               // be obtained
-               if ( $this->lacksSameOriginSecurity() ) {
-                       $this->dieUsage(
-                               'Cannot create account when the same-origin policy is not applied', 'aborted'
-                       );
-               }
-
-               // $loginForm->addNewaccountInternal will throw exceptions
-               // if wiki is read only (already handled by api), user is blocked or does not have rights.
-               // Use userCan in order to hit GlobalBlock checks (according to Special:userlogin)
-               $loginTitle = SpecialPage::getTitleFor( 'Userlogin' );
-               if ( !$loginTitle->userCan( 'createaccount', $this->getUser() ) ) {
-                       $this->dieUsage(
-                               'You do not have the right to create a new account',
-                               'permdenied-createaccount'
-                       );
-               }
-               if ( $this->getUser()->isBlockedFromCreateAccount() ) {
-                       $this->dieUsage(
-                               'You cannot create a new account because you are blocked',
-                               'blocked',
-                               0,
-                               [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $this->getUser()->getBlock() ) ]
-                       );
-               }
-
-               $params = $this->extractRequestParams();
-
-               // Make sure session is persisted
-               MediaWiki\Session\SessionManager::getGlobalSession()->persist();
-
-               if ( $params['mailpassword'] && !$params['email'] ) {
-                       $this->dieUsageMsg( 'noemail' );
-               }
-
-               if ( $params['language'] && !Language::isSupportedLanguage( $params['language'] ) ) {
-                       $this->dieUsage( 'Invalid language parameter', 'langinvalid' );
-               }
-
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setRequest( new DerivativeRequest(
-                       $this->getContext()->getRequest(),
-                       [
-                               'type' => 'signup',
-                               'uselang' => $params['language'],
-                               'wpName' => $params['name'],
-                               'wpPassword' => $params['password'],
-                               'wpRetype' => $params['password'],
-                               'wpDomain' => $params['domain'],
-                               'wpEmail' => $params['email'],
-                               'wpRealName' => $params['realname'],
-                               'wpCreateaccountToken' => $params['token'],
-                               'wpCreateaccount' => $params['mailpassword'] ? null : '1',
-                               'wpCreateaccountMail' => $params['mailpassword'] ? '1' : null
-                       ]
-               ) );
-
-               $loginForm = new LoginForm();
-               $loginForm->setContext( $context );
-               Hooks::run( 'AddNewAccountApiForm', [ $this, $loginForm ] );
-               $loginForm->load();
-
-               $status = $loginForm->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt via API', [
-                       'event' => 'accountcreation',
-                       'status' => $status,
-               ] );
-               $result = [];
-               if ( $status->isGood() ) {
-                       // Success!
-                       $user = $status->getValue();
-
-                       if ( $params['language'] ) {
-                               $user->setOption( 'language', $params['language'] );
-                       }
-
-                       if ( $params['mailpassword'] ) {
-                               // If mailpassword was set, disable the password and send an email.
-                               $user->setPassword( null );
-                               $status->merge( $loginForm->mailPasswordInternal(
-                                       $user,
-                                       false,
-                                       'createaccount-title',
-                                       'createaccount-text'
-                               ) );
-                       } elseif ( $this->getConfig()->get( 'EmailAuthentication' ) &&
-                               Sanitizer::validateEmail( $user->getEmail() )
-                       ) {
-                               // Send out an email authentication message if needed
-                               $status->merge( $user->sendConfirmationMail() );
-                       }
-
-                       // Save settings (including confirmation token)
-                       $user->saveSettings();
-
-                       Hooks::run( 'AddNewAccount', [ $user, $params['mailpassword'] ] );
-
-                       if ( $params['mailpassword'] ) {
-                               $logAction = 'byemail';
-                       } elseif ( $this->getUser()->isLoggedIn() ) {
-                               $logAction = 'create2';
-                       } else {
-                               $logAction = 'create';
-                       }
-                       $user->addNewUserLogEntry( $logAction, (string)$params['reason'] );
-
-                       // Add username, id, and token to result.
-                       $result['username'] = $user->getName();
-                       $result['userid'] = $user->getId();
-                       $result['token'] = $user->getToken();
-               }
-
-               $apiResult = $this->getResult();
-
-               if ( $status->hasMessage( 'sessionfailure' ) || $status->hasMessage( 'nocookiesfornew' ) ) {
-                       // Token was incorrect, so add it to result, but don't throw an exception
-                       // since not having the correct token is part of the normal
-                       // flow of events.
-                       $result['token'] = LoginForm::getCreateaccountToken()->toString();
-                       $result['result'] = 'NeedToken';
-                       $this->setWarning( 'Fetching a token via action=createaccount is deprecated. ' .
-                               'Use action=query&meta=tokens&type=createaccount instead.' );
-                       $this->logFeatureUsage( 'action=createaccount&!token' );
-               } elseif ( !$status->isOK() ) {
-                       // There was an error. Die now.
-                       $this->dieStatus( $status );
-               } elseif ( !$status->isGood() ) {
-                       // Status is not good, but OK. This means warnings.
-                       $result['result'] = 'Warning';
-
-                       // Add any warnings to the result
-                       $warnings = $status->getErrorsByType( 'warning' );
-                       if ( $warnings ) {
-                               foreach ( $warnings as &$warning ) {
-                                       ApiResult::setIndexedTagName( $warning['params'], 'param' );
-                               }
-                               ApiResult::setIndexedTagName( $warnings, 'warning' );
-                               $result['warnings'] = $warnings;
-                       }
-               } else {
-                       // Everything was fine.
-                       $result['result'] = 'Success';
-               }
-
-               // Give extensions a chance to modify the API result data
-               Hooks::run( 'AddNewAccountApiResult', [ $this, $loginForm, &$result ] );
-
-               $apiResult->addValue( null, 'createaccount', $result );
-       }
-
-       public function mustBePosted() {
-               return true;
-       }
-
-       public function isReadMode() {
-               return false;
-       }
-
-       public function isWriteMode() {
-               return true;
-       }
-
-       public function getAllowedParams() {
-               return [
-                       'name' => [
-                               ApiBase::PARAM_TYPE => 'user',
-                               ApiBase::PARAM_REQUIRED => true
-                       ],
-                       'password' => [
-                               ApiBase::PARAM_TYPE => 'password',
-                       ],
-                       'domain' => null,
-                       'token' => [
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => false, // for BC
-                               ApiBase::PARAM_HELP_MSG => [ 'api-help-param-token', 'createaccount' ],
-                       ],
-                       'email' => [
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => $this->getConfig()->get( 'EmailConfirmToEdit' ),
-                       ],
-                       'realname' => null,
-                       'mailpassword' => [
-                               ApiBase::PARAM_TYPE => 'boolean',
-                               ApiBase::PARAM_DFLT => false
-                       ],
-                       'reason' => null,
-                       'language' => null
-               ];
-       }
-
-       protected function getExamplesMessages() {
-               return [
-                       'action=createaccount&name=testuser&password=test123'
-                               => 'apihelp-createaccount-example-pass',
-                       'action=createaccount&name=testmailuser&mailpassword=true&reason=MyReason'
-                               => 'apihelp-createaccount-example-mail',
-               ];
-       }
-
-       public function getHelpUrls() {
-               return 'https://www.mediawiki.org/wiki/API:Account_creation';
-       }
-}
index 1dadc07..b9f65b3 100644 (file)
@@ -42,9 +42,7 @@ class ApiLogin extends ApiBase {
        }
 
        protected function getDescriptionMessage() {
-               if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                       return 'apihelp-login-description-nonauthmanager';
-               } elseif ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+               if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
                        return 'apihelp-login-description';
                } else {
                        return 'apihelp-login-description-nobotpasswords';
@@ -124,85 +122,52 @@ class ApiLogin extends ApiBase {
                }
 
                if ( $authRes === false ) {
-                       if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                               // Non-AuthManager login
-                               $context->setRequest( new DerivativeRequest(
-                                       $this->getContext()->getRequest(),
-                                       [
-                                               'wpName' => $params['name'],
-                                               'wpPassword' => $params['password'],
-                                               'wpDomain' => $params['domain'],
-                                               'wpLoginToken' => $params['token'],
-                                               'wpRemember' => ''
-                                       ]
-                               ) );
-                               $loginForm = new LoginForm();
-                               $loginForm->setContext( $context );
-                               $authRes = $loginForm->authenticateUserData();
-                               $loginType = 'LoginForm';
-
-                               switch ( $authRes ) {
-                                       case LoginForm::SUCCESS:
-                                               $authRes = 'Success';
-                                               break;
-                                       case LoginForm::NEED_TOKEN:
-                                               $authRes = 'NeedToken';
-                                               break;
-                               }
-                       } else {
-                               // Simplified AuthManager login, for backwards compatibility
-                               $manager = AuthManager::singleton();
-                               $reqs = AuthenticationRequest::loadRequestsFromSubmission(
-                                       $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
-                                       [
-                                               'username' => $params['name'],
-                                               'password' => $params['password'],
-                                               'domain' => $params['domain'],
-                                               'rememberMe' => true,
-                                       ]
-                               );
-                               $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
-                               switch ( $res->status ) {
-                                       case AuthenticationResponse::PASS:
-                                               if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
-                                                       $warn = 'Main-account login via action=login is deprecated and may stop working ' .
-                                                               'without warning.';
-                                                       $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
-                                                       $warn .= ' To safely continue using main-account login, see action=clientlogin.';
-                                               } else {
-                                                       $warn = 'Login via action=login is deprecated and may stop working without warning.';
-                                                       $warn .= ' To safely log in, see action=clientlogin.';
-                                               }
-                                               $this->setWarning( $warn );
-                                               $authRes = 'Success';
-                                               $loginType = 'AuthManager';
-                                               break;
-
-                                       case AuthenticationResponse::FAIL:
-                                               // Hope it's not a PreAuthenticationProvider that failed...
-                                               $authRes = 'Failed';
-                                               $message = $res->message;
-                                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                                       ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
-                                               break;
-
-                                       default:
-                                               $authRes = 'Aborted';
-                                               break;
-                               }
+                       // Simplified AuthManager login, for backwards compatibility
+                       $manager = AuthManager::singleton();
+                       $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+                               $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
+                               [
+                                       'username' => $params['name'],
+                                       'password' => $params['password'],
+                                       'domain' => $params['domain'],
+                                       'rememberMe' => true,
+                               ]
+                       );
+                       $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+                       switch ( $res->status ) {
+                               case AuthenticationResponse::PASS:
+                                       if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+                                               $warn = 'Main-account login via action=login is deprecated and may stop working ' .
+                                                       'without warning.';
+                                               $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
+                                               $warn .= ' To safely continue using main-account login, see action=clientlogin.';
+                                       } else {
+                                               $warn = 'Login via action=login is deprecated and may stop working without warning.';
+                                               $warn .= ' To safely log in, see action=clientlogin.';
+                                       }
+                                       $this->setWarning( $warn );
+                                       $authRes = 'Success';
+                                       $loginType = 'AuthManager';
+                                       break;
+
+                               case AuthenticationResponse::FAIL:
+                                       // Hope it's not a PreAuthenticationProvider that failed...
+                                       $authRes = 'Failed';
+                                       $message = $res->message;
+                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                               ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
+                                       break;
+
+                               default:
+                                       $authRes = 'Aborted';
+                                       break;
                        }
                }
 
                $result['result'] = $authRes;
                switch ( $authRes ) {
                        case 'Success':
-                               if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                                       $user = $context->getUser();
-                                       $this->getContext()->setUser( $user );
-                                       $user->setCookies( $this->getRequest(), null, true );
-                               } else {
-                                       $user = $session->getUser();
-                               }
+                               $user = $session->getUser();
 
                                ApiQueryInfo::resetTokenCache();
 
@@ -212,6 +177,15 @@ class ApiLogin extends ApiBase {
 
                                $result['lguserid'] = intval( $user->getId() );
                                $result['lgusername'] = $user->getName();
+
+                               // @todo: These are deprecated, and should be removed at some
+                               // point (1.28 at the earliest, and see T121527). They were ok
+                               // when the core cookie-based login was the only thing, but
+                               // CentralAuth broke that a while back and
+                               // SessionManager/AuthManager *really* break it.
+                               $result['lgtoken'] = $user->getToken();
+                               $result['cookieprefix'] = $this->getConfig()->get( 'CookiePrefix' );
+                               $result['sessionid'] = $session->getId();
                                break;
 
                        case 'NeedToken':
@@ -219,6 +193,10 @@ class ApiLogin extends ApiBase {
                                $this->setWarning( 'Fetching a token via action=login is deprecated. ' .
                                   'Use action=query&meta=tokens&type=login instead.' );
                                $this->logFeatureUsage( 'action=login&!lgtoken' );
+
+                               // @todo: See above about deprecation
+                               $result['cookieprefix'] = $this->getConfig()->get( 'CookiePrefix' );
+                               $result['sessionid'] = $session->getId();
                                break;
 
                        case 'WrongToken':
@@ -239,65 +217,6 @@ class ApiLogin extends ApiBase {
                                }
                                break;
 
-                       // Results from LoginForm for when $wgDisableAuthManager is true
-                       case LoginForm::WRONG_TOKEN:
-                               $result['result'] = 'WrongToken';
-                               break;
-
-                       case LoginForm::NO_NAME:
-                               $result['result'] = 'NoName';
-                               break;
-
-                       case LoginForm::ILLEGAL:
-                               $result['result'] = 'Illegal';
-                               break;
-
-                       case LoginForm::WRONG_PLUGIN_PASS:
-                               $result['result'] = 'WrongPluginPass';
-                               break;
-
-                       case LoginForm::NOT_EXISTS:
-                               $result['result'] = 'NotExists';
-                               break;
-
-                       // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
-                       // The e-mailed temporary password should not be used for actual logins.
-                       case LoginForm::RESET_PASS:
-                       case LoginForm::WRONG_PASS:
-                               $result['result'] = 'WrongPass';
-                               break;
-
-                       case LoginForm::EMPTY_PASS:
-                               $result['result'] = 'EmptyPass';
-                               break;
-
-                       case LoginForm::CREATE_BLOCKED:
-                               $result['result'] = 'CreateBlocked';
-                               $result['details'] = 'Your IP address is blocked from account creation';
-                               $block = $context->getUser()->getBlock();
-                               if ( $block ) {
-                                       $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
-                               }
-                               break;
-
-                       case LoginForm::THROTTLED:
-                               $result['result'] = 'Throttled';
-                               $result['wait'] = intval( $loginForm->mThrottleWait );
-                               break;
-
-                       case LoginForm::USER_BLOCKED:
-                               $result['result'] = 'Blocked';
-                               $block = User::newFromName( $params['name'] )->getBlock();
-                               if ( $block ) {
-                                       $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
-                               }
-                               break;
-
-                       case LoginForm::ABORTED:
-                               $result['result'] = 'Aborted';
-                               $result['reason'] = $loginForm->mAbortLoginErrorMsg;
-                               break;
-
                        default:
                                ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
                }
@@ -316,8 +235,7 @@ class ApiLogin extends ApiBase {
        }
 
        public function isDeprecated() {
-               return !$this->getConfig()->get( 'DisableAuthManager' ) &&
-                       !$this->getConfig()->get( 'EnableBotPasswords' );
+               return !$this->getConfig()->get( 'EnableBotPasswords' );
        }
 
        public function mustBePosted() {
index 8045447..90438d4 100644 (file)
@@ -1002,7 +1002,7 @@ class ApiPageSet extends ApiBase {
                                // Get pageIDs data from the `page` table
                                $res = $db->select( 'page', $pageFlds, $set, __METHOD__ );
 
-                               // Hack: get the ns:titles stored in array(ns => array(titles)) format
+                               // Hack: get the ns:titles stored in [ns => array(titles)] format
                                $this->initFromQueryResult( $res, $linkBatch->data, true );
                        }
                }
index 5afb66f..cfc1e46 100644 (file)
@@ -261,7 +261,7 @@ class ApiQueryUsers extends ApiQueryBase {
                                        }
                                } else {
                                        $data[$u]['missing'] = true;
-                                       if ( isset( $this->prop['cancreate'] ) && !$this->getConfig()->get( 'DisableAuthManager' ) ) {
+                                       if ( isset( $this->prop['cancreate'] ) ) {
                                                $status = MediaWiki\Auth\AuthManager::singleton()->canCreateAccount( $u );
                                                $data[$u]['cancreate'] = $status->isGood();
                                                if ( !$status->isGood() ) {
@@ -307,7 +307,7 @@ class ApiQueryUsers extends ApiQueryBase {
        }
 
        public function getAllowedParams() {
-               $ret = [
+               return [
                        'prop' => [
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => [
@@ -320,6 +320,7 @@ class ApiQueryUsers extends ApiQueryBase {
                                        'emailable',
                                        'gender',
                                        'centralids',
+                                       'cancreate',
                                        // When adding a prop, consider whether it should be added
                                        // to self::$publicProps
                                ],
@@ -336,10 +337,6 @@ class ApiQueryUsers extends ApiQueryBase {
                                ApiBase::PARAM_ISMULTI => true
                        ],
                ];
-               if ( !$this->getConfig()->get( 'DisableAuthManager' ) ) {
-                       $ret['prop'][ApiBase::PARAM_TYPE][] = 'cancreate';
-               }
-               return $ret;
        }
 
        protected function getExamplesMessages() {
index 3a4b012..00846f5 100644 (file)
@@ -20,7 +20,7 @@
 
 /**
  * This class represents the result of the API operations.
- * It simply wraps a nested array() structure, adding some functions to simplify
+ * It simply wraps a nested array structure, adding some functions to simplify
  * array's modifications. As various modules execute, they add different pieces
  * of information to this result, structuring it as it will be given to the client.
  *
index f09fdcb..3a7a082 100644 (file)
@@ -110,14 +110,16 @@ class ApiWatch extends ApiBase {
                        $status = UnwatchAction::doUnwatch( $title, $user );
                        $res['unwatched'] = $status->isOK();
                        if ( $status->isOK() ) {
-                               $res['message'] = $this->msg( 'removedwatchtext', $title->getPrefixedText() )
+                               $msgKey = $title->isTalkPage() ? 'removedwatchtext-talk' : 'removedwatchtext';
+                               $res['message'] = $this->msg( $msgKey, $title->getPrefixedText() )
                                        ->title( $title )->parseAsBlock();
                        }
                } else {
                        $status = WatchAction::doWatch( $title, $user );
                        $res['watched'] = $status->isOK();
                        if ( $status->isOK() ) {
-                               $res['message'] = $this->msg( 'addedwatchtext', $title->getPrefixedText() )
+                               $msgKey = $title->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
+                               $res['message'] = $this->msg( $msgKey, $title->getPrefixedText() )
                                        ->title( $title )->parseAsBlock();
                        }
                }
index 7dcc4fd..2107e89 100644 (file)
        "apihelp-parse-paramvalue-prop-displaytitle": "Вики-текстың синтаксик анализына исем ҡуя.",
        "apihelp-parse-paramvalue-prop-headitems": "<код> & ЛТ -ҡа һалыу өсөн элементтар бирә; башы & GT; биттең </ код>",
        "apihelp-parse-paramvalue-prop-headhtml": "Айырылған <код> & лт бирә; & баштары GТ; биттең </ код>.",
-       "apihelp-parse-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле  JavaScript үҙгәреүсән конфигурациялар бирә.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле JavaScript үҙгәреүсән конфигурациялар бирә. Ҡулланыр өсөн, <code>mw.config.set()</code> ҡабыҙырға.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "JavaScriptтың JSON юлы һымаҡ үҙенсәлекле биттәренә  алышына торған конфигурация бирә.",
        "apihelp-parse-paramvalue-prop-iwlinks": "Вики-текстың синтаксик анализында интервиктарға һылтанма бирә.",
        "apihelp-parse-paramvalue-prop-wikitext": "Һығымта яҺау өсөн тәүге вики-тексты күрһәтә",
        "apihelp-protect-param-tags": "Юйҙырылғандар журналындағы яҙмаларға  мөрәжәғәт итер өсөн, билдәләрҙе үҙгәртергә.",
        "apihelp-protect-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмаҫҡа.",
        "apihelp-protect-example-protect": "Битте һаҡларға.",
-       "apihelp-protect-example-unprotect": "<kbd>всех</kbd> өсөн сикләүҙәр ҡуйып,биттән һаҡлауҙы алырға.",
+       "apihelp-protect-example-unprotect": "<kbd>all</kbd> сикләүҙәрен (йәғни һәр береһе эшләй ала) ҡуйып, бит һағын асырға.",
        "apihelp-protect-example-unprotect2": "Бер ниндәй сикләүҙәр ҡуймай биттән һаҡлауҙы алырға.",
        "apihelp-purge-param-forcelinkupdate": "Таблицалар бәйләнешен яңыртыу.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Һылтанманы һәм таблицаны яңыртығыҙ һәм был битте шаблон итеп ҡулланған башҡа биттәр өсөн һылтанмаларҙы ла яңыртығыҙ.",
index 7f30ef8..2f46e71 100644 (file)
 
        "apihelp-login-description": "Log in and get authentication cookies.\n\nThis action should only be used in combination with [[Special:BotPasswords]]; use for main-account login is deprecated and may fail without warning. To safely log in to the main account, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-description-nobotpasswords": "Log in and get authentication cookies.\n\nThis action is deprecated and may fail without warning. To safely log in, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
-       "apihelp-login-description-nonauthmanager": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
        "apihelp-login-param-name": "User name.",
        "apihelp-login-param-password": "Password.",
        "apihelp-login-param-domain": "Domain (optional).",
index 289aa78..c5aef1d 100644 (file)
        "apihelp-parse-paramvalue-prop-sections": "Devolve as seccións do texto wiki analizado.",
        "apihelp-parse-paramvalue-prop-revid": "Engade o identificador de edición do texto wiki analizado.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Engade o título do texto wiki analizado.",
-       "apihelp-parse-paramvalue-prop-headitems": "Devolve os elementos a poñer na <code>&lt;cabeceira&gt;</code> da páxina.",
+       "apihelp-parse-paramvalue-prop-headitems": "<span class=\"apihelp-deprecated\">Obsoleto.</span> Devolve os elementos a poñer na <code>&lt;cabeceira&gt;</code> da páxina.",
        "apihelp-parse-paramvalue-prop-headhtml": "Devolve <code>&lt;cabeceira&gt;</code> analizada da páxina.",
-       "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitados xunto con <kbd>modules</kbd>.",
-       "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina.",
+       "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina. Para cargar, use <code>mw.loader.using()</code>. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitados xunto con <kbd>modules</kbd>.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina. Para aplicalo, use <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina como unha cadea de texto JSON.",
        "apihelp-parse-paramvalue-prop-indicators": "Devolve o HTML dos indicadores de estado de páxina usados na páxina.",
        "apihelp-parse-paramvalue-prop-iwlinks": "Devolve as ligazóns interwiki do texto wiki analizado.",
        "apihelp-protect-description": "Cambiar o nivel de protección dunha páxina.",
        "apihelp-protect-param-title": "Título da páxina que quere (des)protexer. Non pode usarse xunto con $1pageid.",
        "apihelp-protect-param-pageid": "Identificador da páxina que quere (des)protexer. Non pode usarse xunto con $1title.",
-       "apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>).\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
+       "apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>). Un nivel de <kbd>all</kbd> quere dicir que todo o mundo ten permiso para realizar a acción, sen restricións.\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
        "apihelp-protect-param-expiry": "Selos de tempo de caducidade. Se só se indica un selo de tempo, usarase para todas as proteccións. Use <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, ou <kbd>never</kbd>, para unha protección sen caducidade.",
        "apihelp-protect-param-reason": "Razón para (des)protexer.",
        "apihelp-protect-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de protección.",
        "apihelp-protect-param-watch": "Se se define este parámetro, engadir a páxina que se (des)protexe á lista de vixilancia do usuario actual.",
        "apihelp-protect-param-watchlist": "Engadir ou eliminar sen condicións a páxina da lista de vixiancia do usuario actual, use as preferencias ou non cambie a vixiancia.",
        "apihelp-protect-example-protect": "Protexer unha páxina",
-       "apihelp-protect-example-unprotect": "Desprotexer unha páxina poñendo as restricións a <kbd>all</kbd>.",
+       "apihelp-protect-example-unprotect": "Desprotexer unha páxina poñendo as restricións a <kbd>all</kbd>. (isto quere dicir que todo o mundo pode realizar a acción).",
        "apihelp-protect-example-unprotect2": "Desprotexer unha páxina quitando as restricións.",
        "apihelp-purge-description": "Borrar a caché para os títulos indicados.\n\nPrecisa dunha petición POST se o usuario non está conectado.",
        "apihelp-purge-param-forcelinkupdate": "Actualizar as táboas de ligazóns.",
index 57e124c..e02abe0 100644 (file)
        "apihelp-protect-param-pageid": "ID della pagina da (s)proteggere. Non può essere usato insieme con $1title.",
        "apihelp-protect-param-tags": "Modifica etichette da applicare all'elemento del registro delle protezioni.",
        "apihelp-protect-example-protect": "Proteggi una pagina.",
-       "apihelp-protect-example-unprotect": "Sproteggi una pagina impostando restrizione su <kbd>all</kbd>.",
+       "apihelp-protect-example-unprotect": "Sproteggi una pagina impostando restrizione su <kbd>all</kbd> (cioè a tutti è consentito intraprendere l'azione).",
        "apihelp-protect-example-unprotect2": "Sproteggi una pagina impostando nessuna restrizione.",
        "apihelp-purge-param-forcelinkupdate": "Aggiorna la tabella dei collegamenti.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Aggiorna la tabella dei collegamenti per questa pagina, e per ogni pagina che usa questa pagina come template.",
index 1ec5b50..bad4a12 100644 (file)
        "apihelp-parse-paramvalue-prop-sections": "구문 분석된 위키텍스트의 문단을 제공합니다.",
        "apihelp-parse-paramvalue-prop-revid": "구문 분석된 페이지의 판 ID를 추가합니다.",
        "apihelp-parse-paramvalue-prop-displaytitle": "구문 분석된 위키텍스트의 제목을 추가합니다.",
-       "apihelp-parse-paramvalue-prop-headitems": "문서의 <code>&lt;head&gt;</code> 안에 넣을 항목을 제공합니다.",
+       "apihelp-parse-paramvalue-prop-headitems": "<span class=\"apihelp-deprecated\">사용되지 않습니다.</span> 문서의 <code>&lt;head&gt;</code> 안에 넣을 항목을 제공합니다.",
        "apihelp-parse-paramvalue-prop-headhtml": "문서의 구문 분석된 <code>&lt;head&gt;</code>를 제공합니다.",
+       "apihelp-parse-paramvalue-prop-modules": "문서에 사용되는 ResourceLoader 모듈을 제공합니다. 불러오려면, <code>mw.loader.using()</code>을 사용하세요. <kbd>jsconfigvars</kbd> 또는 <kbd>encodedjsconfigvars</kbd>는 <kbd>modules</kbd>와 함께 요청해야 합니다.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "문서에 특화된 자바스크립트 구성 변수를 제공합니다. 적용하려면 <code>mw.config.set()</code>을 사용하세요.",
        "apihelp-parse-paramvalue-prop-iwlinks": "구문 분석된 위키텍스트의 인터위키 링크를 제공합니다.",
        "apihelp-parse-paramvalue-prop-wikitext": "구문 분석된 위키텍스트 원문을 제공합니다.",
        "apihelp-parse-paramvalue-prop-properties": "구문 분석된 위키텍스트에 정의된 다양한 속성을 제공합니다.",
        "api-help-license-noname": "라이선스: [[$1|링크 참조]]",
        "api-help-license-unknown": "라이선스: <span class=\"apihelp-unknown\">알 수 없음</span>",
        "api-help-parameters": "{{PLURAL:$1|변수}}:",
-       "api-help-param-deprecated": "사용 중지됨.",
+       "api-help-param-deprecated": "사용되지 않습니다.",
        "api-help-param-required": "이 변수는 필수 입력 사항입니다.",
        "api-help-datatypes-header": "데이터 유형",
        "api-help-datatypes": "API 요청 내 몇몇 매개변수형에 대해 더 자세히 설명해보겠습니다:\n;boolean\n:Boolean 매개변수들은 HTML 체크박스처럼 동작합니다: 만약 매개변수가 지정되었다면, 값에 상관없이 참의 값으로 여겨집니다. 거짓값은 매개변수 전체를 생략하세요.\n;timestamp\n:타임스탬프들은 여러 형식으로 표현될 수 있으나 ISO 8601 날짜와 시간이 추천됩니다. 모든 시간은 UTC이어야 하며, 포함된 시간대는 모두 무시됩니다.\n:* ISO 8601 날짜와 시간, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (구두점과 <kbd>Z</kbd>는 선택입니다.)\n:* ISO 8601 날짜와 시간과 (무시되는) 소수 초, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (대시, 콜론과 <kbd>Z</kbd>는 선택입니다.)\n:* 미디어위키 형식, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* 일반적인 수 형식 <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (<kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, 또는 <kbd>-<var>##</var></kbd>와 같은 선택적 시간대는 무시됩니다)\n:*RFC 2822 형식 (시간대는 생략될 수 있음), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850 형식 (시간대는 생략될 수 있음), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime 형식, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* 1부터 13자리까지의 숫자로 표현된 1970-01-01T00:00:00Z 부터 흐른 시간(초) (<kbd>0</kbd>을 제외)\n:* 문자열 <kbd>now</kbd>",
        "api-help-param-type-limit": "유형: 정수 또는 <kbd>max</kbd>",
        "api-help-param-type-integer": "유형: {{PLURAL:$1|1=정수|2=정수 목록}}",
        "api-help-param-type-boolean": "유형: 부울 ([[Special:ApiHelp/main#main/datatypes|자세한 정보]])",
-       "api-help-param-list": "{{PLURAL:$1|1=하나의 값|2=값 (\"{{!}}\"로 구분)}}: $2",
+       "api-help-param-list": "{{PLURAL:$1|1=다음 값 중 하나|2=값 (<kbd>{{!}}</kbd>로 구분)}}: $2",
        "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=비어 있어야 함|비어 있을 수 있거나 $2}}",
        "api-help-param-limit": "$1 초과는 허용되지 않습니다.",
        "api-help-param-limit2": "$1 초과는 허용되지 않습니다. (봇의 경우 $2)",
index 96fe70e..6023be0 100644 (file)
        "apihelp-protect-param-reason": "Powód zabezpieczania/odbezpieczania.",
        "apihelp-protect-param-cascade": "Włącz ochronę kaskadową (chronione są wszystkie osadzone szablony i obrazki na tej stronie). Ignorowane, jeśli żaden z danych poziomów ochrony nie wspiera kaskadowania.",
        "apihelp-protect-example-protect": "Zabezpiecz stronę",
-       "apihelp-protect-example-unprotect": "Odbezpiecz stronę ustawiając ograniczenia na <kbd>all</kbd>.",
+       "apihelp-protect-example-unprotect": "Odbezpiecz stronę ustawiając ograniczenia na <kbd>all</kbd> (czyli każdy może wykonać działanie).",
        "apihelp-protect-example-unprotect2": "Odbezpiecz stronę ustawiając brak ograniczeń.",
        "apihelp-purge-param-forcelinkupdate": "Uaktualnij tabele linków.",
        "apihelp-purge-example-generator": "Przeczyść pierwsze 10 stron w przestrzeni głównej.",
index 6c47aa4..cbd9fb8 100644 (file)
        "apihelp-linkaccount-example-link": "{{doc-apihelp-example|linkaccount}}",
        "apihelp-login-description": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is true.|seealso=* {{msg-mw|apihelp-login-description-nobotpasswords}}}}",
        "apihelp-login-description-nobotpasswords": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is false.|seealso=* {{msg-mw|apihelp-login-description}}}}",
-       "apihelp-login-description-nonauthmanager": "{{doc-apihelp-description|login|info=This message is used when <code>$wgDisableAuthManager</code> is true.|seealso=* {{msg-mw|apihelp-login-description}}}}",
        "apihelp-login-param-name": "{{doc-apihelp-param|login|name}}\n{{Identical|Username}}",
        "apihelp-login-param-password": "{{doc-apihelp-param|login|password}}\n{{Identical|Password}}",
        "apihelp-login-param-domain": "{{doc-apihelp-param|login|domain}}",
index 517496f..9e5d754 100644 (file)
@@ -75,6 +75,8 @@
        "apihelp-createaccount-example-pass": "Створити користувача <kbd>testuser</kbd> з паролем <kbd>test123</kbd>.",
        "apihelp-createaccount-example-mail": "Створити користувача <kbd>testmailuser</kbd> і надіслати на електронну пошту випадково-згенерований пароль.",
        "apihelp-cspreport-description": "Використовується браузерами для повідомлення порушень Правил безпеки контенту (Content Security Policy). Цей модуль не повинен використовуватися, окрім випадків автоматичного використання веб-браузером для CSP-скарги.",
+       "apihelp-cspreport-param-reportonly": "Позначити як доповідь із моніторингової політики, не примусової політики",
+       "apihelp-cspreport-param-source": "Що згенерувало CSP-заголовок, який запустив цю доповідь",
        "apihelp-delete-description": "Вилучити сторінку.",
        "apihelp-delete-param-title": "Назва сторінки для вилучення. Не можна використати разом з <var>$1pageid</var>.",
        "apihelp-delete-param-pageid": "ID-сторінки на вилучення. Не можна використати разом з <var>$1title</var>.",
        "apihelp-parse-paramvalue-prop-sections": "Дає розділи в аналізованому вікітексті.",
        "apihelp-parse-paramvalue-prop-revid": "Додає ідентифікатор версії аналізованої сторінки.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Додає заголовок аналізованого вікітексту.",
-       "apihelp-parse-paramvalue-prop-headitems": "Дає елементи для вставки в <code>&lt;head&gt;</code> сторінки.",
+       "apihelp-parse-paramvalue-prop-headitems": "<span class=\"apihelp-deprecated\">Застаріло.</span> Дає елементи для вставки в <code>&lt;head&gt;</code> сторінки.",
        "apihelp-parse-paramvalue-prop-headhtml": "Дає проаналізований <code>&lt;head&gt;</code> сторінки.",
-       "apihelp-parse-paramvalue-prop-modules": "Дає модулі ResourceLoader, використані на сторінці. Чи <kbd>jsconfigvars</kbd>, чи <kbd>encodedjsconfigvars</kbd> має бути запитано разом з <kbd>modules</kbd>.",
-       "apihelp-parse-paramvalue-prop-jsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки.",
+       "apihelp-parse-paramvalue-prop-modules": "Ð\94аÑ\94 Ð¼Ð¾Ð´Ñ\83лÑ\96 ResourceLoader, Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82анÑ\96 Ð½Ð° Ñ\81Ñ\82оÑ\80Ñ\96нÑ\86Ñ\96. Ð©Ð¾Ð± Ð·Ð°Ð²Ð°Ð½Ñ\82ажиÑ\82и, Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82овÑ\83йÑ\82е <code>mw.loader.using()</code>. Ð§Ð¸ <kbd>jsconfigvars</kbd>, Ñ\87и <kbd>encodedjsconfigvars</kbd> Ð¼Ð°Ñ\94 Ð±Ñ\83Ñ\82и Ð·Ð°Ð¿Ð¸Ñ\82ано Ñ\80азом Ð· <kbd>modules</kbd>.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки. Щоб застосувати, використайте <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки, як рядок JSON.",
        "apihelp-parse-paramvalue-prop-indicators": "Дає HTML індикаторів стану сторінки, використаних на сторінці.",
        "apihelp-parse-paramvalue-prop-iwlinks": "Дає інтервікі-посилання в аналізованому вікітексті.",
        "apihelp-protect-description": "Змінити рівень захисту сторінки.",
        "apihelp-protect-param-title": "Заголовок сторінки для (зняття) захисту. Не може використовуватися разом із $1pageid.",
        "apihelp-protect-param-pageid": "ID сторінки для (зняття) захисту. Не може використовуватися разом з $1title.",
-       "apihelp-protect-param-protections": "Список рівнів захисту у форматі <kbd>action=level</kbd> (напр., <kbd>edit=sysop</kbd>).\n\n<strong>Примітка:</strong> Обмеження на дії, яких нема в списку, буде знято.",
+       "apihelp-protect-param-protections": "Список рівнів захисту у форматі <kbd>action=level</kbd> (напр., <kbd>edit=sysop</kbd>). Рівень <kbd>all</kbd> означає, що будь-хто може робити дію, тобто обмежень немає.\n\n<strong>Примітка:</strong> Обмеження на дії, яких нема в списку, буде знято.",
        "apihelp-protect-param-expiry": "Часові мітки закінчення. Якщо встановлена лише одна мітка, її буде використано для усіх захистів. Для безстрокового захисту використовуйте <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd> або <kbd>never</kbd>.",
        "apihelp-protect-param-reason": "Причина для (зняття) захисту.",
        "apihelp-protect-param-tags": "Змінити теги, що мають бути застосовані до запису в журналі захисту.",
        "apihelp-protect-param-watch": "Якщо вказано, додати сторінку, де додається/знімається захист, до списку спостереження поточного користувача.",
        "apihelp-protect-param-watchlist": "Беззастережно додати або вилучити сторінку зі списку спостереження поточного користувача, використати налаштування або не змінювати спостереження.",
        "apihelp-protect-example-protect": "Захистити сторінку.",
-       "apihelp-protect-example-unprotect": "Зняти захист зі сторінки, встановивши обмеження для <kbd>all</kbd>.",
+       "apihelp-protect-example-unprotect": "Зняти захист зі сторінки, встановивши обмеження для <kbd>all</kbd> (тобто будь-хто зможе робити дії).",
        "apihelp-protect-example-unprotect2": "Зняти захист з сторінки, встановивши відсутність обмежень.",
        "apihelp-purge-description": "Очистити кеш для вказаних заголовків.\n\nВимагає запиту POST, якщо користувач не ввійшов у систему.",
        "apihelp-purge-param-forcelinkupdate": "Оновити таблиці посилань.",
        "apihelp-undelete-example-page": "Відновити сторінку <kbd>Main Page</kbd>.",
        "apihelp-undelete-example-revisions": "Відновити дві версії сторінки <kbd>Main Page</kbd>.",
        "apihelp-unlinkaccount-description": "Вилучити пов'язаний обліковий запис третьої сторони з поточного користувача.",
+       "apihelp-unlinkaccount-example-simple": "Здійснити спробу вилучити посилання поточного користувача для провайдера, асоційованого з <kbd>FooAuthenticationRequest</kbd>.",
        "apihelp-upload-description": "Завантажити файл, або отримати статус завантажень у процесі.\n\nДоступні декілька методів:\n* Завантажити вміст файлу напряму, використовуючи параметр <var>$1file</var>.\n* Завантажити файл шматками, використовуючи параметри <var>$1filesize</var>, <var>$1chunk</var>, та <var>$1offset</var>.\n* Змусити сервер Медіавікі отримати файл за URL, використовуючи параметр <var>$1url</var>.\n* Завершити раніше розпочате завантаження, яке не вдалось через попередження, використовуючи параметр <var>$1filekey</var>.\nЗауважте, що HTTP POST повинен бути здійснений як завантаження файлу (наприклад, використовуючи <code>multipart/form-data</code>)",
        "apihelp-upload-param-filename": "Цільова назва файлу.",
        "apihelp-upload-param-comment": "Коментар завантаження. Також використовується як початковий текст сторінок для нових файлів, якщо <var>$1text</var> не вказано.",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Надано|Надані}}: $2",
        "api-help-right-apihighlimits": "Використовувати вищі ліміти у запитах API (повільні запити: $1; швидкі запити: $2). Ліміти для повільних запитів також застосовуються до багатозначних параметрів.",
        "api-help-open-in-apisandbox": "<small>[відкрити в пісочниці]</small>",
+       "api-help-authmanager-general-usage": "Загальна процедура використання цього модуля така:\n# Отримайте доступні поля зі <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$4</kbd>, а також токен  <kbd>$5</kbd> зі <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Передайте ці поля користувачеві, і отримайте інформацію, якою він їх заповнить.\n# Напишіть до цього модуля, заповнивши <var>$1returnurl</var> та всі релевантні поля.\n# Перевірте <samp>status</samp> у відповіді.\n#* Якщо Ви отримали <samp>PASS</samp> або <samp>FAIL</samp>, роботу завершено. Операція або була успішною, або провалилася.\n#* Якщо Ви отримали <samp>UI</samp>, надішліть нові поля користувачеві й отримайте інформацію, якою він їх заповнить. Далі напишіть до цього модуля із <var>$1continue</var> та заповніть всі реелевантні поля, після чого повторіть крок 4.\n#* Якщо Ви отримали <samp>REDIRECT</samp>, направте користувача до <samp>redirecttarget</samp> і дочекайтеся повернення до <var>$1returnurl</var>. Тоді напишіть до цього модуля із <var>$1continue</var>, та з усіма полями, що були передані до повернутої URL-адреси, після чого повторіть крок 4.\n#* Якщо Ви отримали <samp>RESTART</samp>, це означає, що автентифікація спрацювала, але ми не маємо пов'язаного облікового запису користувача. Ви можете розцінити це як <samp>UI</samp>, або як <samp>FAIL</samp>.",
+       "api-help-authmanagerhelper-requests": "Використовувати ці автентифікаційні запити через <samp>id</samp>, що повертається з <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$1</kbd>, або з попередньої відповіді з цього модуля.",
+       "api-help-authmanagerhelper-request": "Використовувати цей автентифікаційний запит через <samp>id</samp>, що повертається з <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$1</kbd>.",
        "api-help-authmanagerhelper-messageformat": "Формат до використання для повернення повідомлень.",
        "api-help-authmanagerhelper-mergerequestfields": "Об'єднати інформацію всіх автентифікаційних запитів у один масив.",
        "api-help-authmanagerhelper-preservestate": "Зберегти статус з попередньої спроби входу, що не вдалась, якщо можливо.",
+       "api-help-authmanagerhelper-returnurl": "URL-адреса повернення для сторонніх автентифікаційних потоків повинна бути абсолютною. Обов'язковим є це, або <var>$1continue</var>. \n\nПри отриманні відповіді <samp>REDIRECT</samp>, найбільш звичною Вашою дією буде відкриття браузерного чи іншого веб-перегляду вказаного URL-посилання для стороннього потоку автентифікації. Коли ця операція буде завершена, стороння програма перенаправить веб-переглядач на цю URL-адресу. Ви повинні видобувати будь-які параметри запитів або POST-параметри із цієї URL-адреси, і передавати їх як запит <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> (або попередню відповідь від цього модуля, якщо це застосовно), аби визначити доступні запити та поля, які вони використовують.",
        "api-credits-header": "Автор(и)",
        "api-credits": "Розробники API:\n* Roan Kattouw (головний розробник вер. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (творець, головний розробник вер. 2006 – вер. 2007)\n* Brad Jorsch (головний розробник 2013 – тепер)\n\nБудь ласка, надсилайте свої коментарі, пропозиції та запитання на mediawiki-api@lists.wikimedia.org\nабо зафайліть звіт про баґ на https://phabricator.wikimedia.org/."
 }
index 1bf80a2..5c85832 100644 (file)
@@ -20,7 +20,8 @@
                        "Hzy980512",
                        "PhiLiP",
                        "Arthur2e5",
-                       "損齋"
+                       "損齋",
+                       "Myy730"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|文档]]\n* [[mw: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>本页所展示的所有特性都应正常工作,但是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:API:Errors_and_warnings|API: 错误与警告]]。\n\n<strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。",
@@ -85,6 +86,7 @@
        "apihelp-createaccount-example-mail": "创建用户<kbd>testmailuser</kbd>并电邮发送一个随机生成的密码。",
        "apihelp-cspreport-description": "由浏览器使用以报告违反内容安全方针的内容。此模块应永不使用,除了在被CSP兼容的浏览器自动使用时。",
        "apihelp-cspreport-param-reportonly": "标记作为来自监视方针的报告,而不是执行方针的报告",
+       "apihelp-cspreport-param-source": "生成引发此报告的CSP标头的事物",
        "apihelp-delete-description": "删除一个页面。",
        "apihelp-delete-param-title": "要删除的页面标题。不能与<var>$1pageid</var>一起使用。",
        "apihelp-delete-param-pageid": "要删除的页面的页面 ID。不能与<var>$1title</var>一起使用。",
        "apihelp-query+recentchanges-paramvalue-prop-sizes": "添加新旧页面长度(字节)。",
        "apihelp-query+recentchanges-paramvalue-prop-redirect": "如果页面是重定向的话,标记编辑。",
        "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Tags patrollable edits as being patrolled or unpatrolled.",
-       "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Adds log information (log ID, log type, etc) to log entries.",
+       "apihelp-query+recentchanges-paramvalue-prop-loginfo": "添加日志信息(日志ID、日志类型等)至日志记录。",
        "apihelp-query+recentchanges-paramvalue-prop-tags": "列举条目的标签。",
        "apihelp-query+recentchanges-paramvalue-prop-sha1": "Adds the content checksum for entries associated with a revision.",
        "apihelp-query+recentchanges-param-token": "请改用<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>。",
index 82eeff0..eab5068 100644 (file)
@@ -105,12 +105,6 @@ class AuthManager implements LoggerAwareInterface {
         * @return AuthManager
         */
        public static function singleton() {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       throw new \BadMethodCallException( '$wgDisableAuthManager is set' );
-               }
-
                if ( self::$instance === null ) {
                        self::$instance = new self(
                                \RequestContext::getMain()->getRequest(),
index 5f5ef79..bbc6e8d 100644 (file)
@@ -110,7 +110,7 @@ class LocalPasswordPrimaryAuthenticationProvider
                }
 
                $status = $this->checkPasswordValidity( $username, $req->password );
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        // Fatal, can't log in
                        return AuthenticationResponse::newFail( $status->getMessage() );
                }
index f5d3c33..530fc76 100644 (file)
@@ -150,7 +150,7 @@ class IcuCollation extends Collation {
                'la' => [],
                'lb' => [],
                'lt' => [ "Č", "Š", "Ž" ],
-               'mk' => [],
+               'mk' => [ "Ѓ", "Ќ" ],
                'mo' => [ "Ă", "Â", "Î", "Ş", "Ţ" ],
                'mt' => [ "Ċ", "Ġ", "Għ", "Ħ", "Ż" ],
                'nl' => [],
index 1ecd614..7184980 100644 (file)
@@ -1270,4 +1270,69 @@ abstract class ContentHandler {
                 */
                return [];
        }
+
+       /**
+        * Add new field definition to array.
+        * @param SearchIndexField[] $fields
+        * @param SearchEngine       $engine
+        * @param string             $name
+        * @param int                $type
+        * @return SearchIndexField[] new field defs
+        * @since 1.28
+        */
+       protected function addSearchField( &$fields, SearchEngine $engine, $name, $type ) {
+               $fields[$name] = $engine->makeSearchFieldMapping( $name, $type );
+               return $fields;
+       }
+
+       /**
+        * Return fields to be indexed by search engine
+        * as representation of this document.
+        * Overriding class should call parent function or take care of calling
+        * the SearchDataForIndex hook.
+        * @param WikiPage     $page Page to index
+        * @param ParserOutput $output
+        * @param SearchEngine $engine Search engine for which we are indexing
+        * @return array Map of name=>value for fields
+        * @since 1.28
+        */
+       public function getDataForSearchIndex( WikiPage $page, ParserOutput $output,
+                                              SearchEngine $engine ) {
+               $fields = [];
+               $content = $page->getContent();
+               if ( $content ) {
+                       $text = $content->getTextForSearchIndex();
+                       $fields['text'] = $text;
+                       $fields['source_text'] = $text;
+                       $fields['text_bytes'] = $content->getSize();
+               }
+               Hooks::run( 'SearchDataForIndex', [ &$fields, $this, $page, $output, $engine ] );
+               return $fields;
+       }
+
+       /**
+        * Produce page output suitable for indexing.
+        *
+        * Specific content handlers may override it if they need different content handling.
+        *
+        * @param WikiPage    $page
+        * @param ParserCache $cache
+        * @return ParserOutput
+        */
+       public function getParserOutputForIndexing( WikiPage $page, ParserCache $cache = null ) {
+               $parserOptions = $page->makeParserOptions( 'canonical' );
+               $revId = $page->getRevision()->getId();
+               if ( $cache ) {
+                       $parserOutput = $cache->get( $page, $parserOptions );
+               }
+               if ( empty( $parserOutput ) ) {
+                       $parserOutput =
+                               $page->getContent()->getParserOutput( $page->getTitle(), $revId, $parserOptions );
+                       if ( $cache ) {
+                               $cache->save( $parserOutput, $page, $parserOptions );
+                       }
+               }
+               return $parserOutput;
+       }
+
 }
index 748c810..d4fad44 100644 (file)
@@ -148,4 +148,13 @@ class TextContentHandler extends ContentHandler {
                        $engine->makeSearchFieldMapping( 'language', SearchIndexField::INDEX_TYPE_KEYWORD );
                return $fields;
        }
+
+       public function getDataForSearchIndex( WikiPage $page, ParserOutput $output,
+                                              SearchEngine $engine ) {
+               $fields = parent::getDataForSearchIndex( $page, $output, $engine );
+               $fields['language'] =
+                       $this->getPageLanguage( $page->getTitle(), $page->getContent() )->getCode();
+               return $fields;
+       }
+
 }
diff --git a/includes/content/WikiTextStructure.php b/includes/content/WikiTextStructure.php
new file mode 100644 (file)
index 0000000..e83c213
--- /dev/null
@@ -0,0 +1,280 @@
+<?php
+
+use HtmlFormatter\HtmlFormatter;
+use MediaWiki\Logger\LoggerFactory;
+
+/**
+ * Class allowing to explore structure of parsed wikitext.
+ */
+class WikiTextStructure {
+       /**
+        * @var string
+        */
+       private $openingText;
+       /**
+        * @var string
+        */
+       private $allText;
+       /**
+        * @var string[]
+        */
+       private $auxText = [];
+       /**
+        * @var ParserOutput
+        */
+       private $parserOutput;
+
+       /**
+        * @var string[] selectors to elements that are excluded entirely from search
+        */
+       private $excludedElementSelectors = [
+               'audio', 'video',       // "it looks like you don't have javascript enabled..."
+                                       // do not need to index
+               'sup.reference',        // The [1] for references
+               '.mw-cite-backlink',    // The ↑ next to references in the references section
+               'h1', 'h2', 'h3',       // Headings are already indexed in their own field.
+               'h5', 'h6', 'h4',
+               '.autocollapse',        // Collapsed fields are hidden by default so we don't want them
+                                                               // showing up.
+       ];
+
+       /**
+        * @var string[] selectors to elements that are considered auxiliary to article text for search
+        */
+       private $auxiliaryElementSelectors = [
+               '.thumbcaption',        // Thumbnail captions aren't really part of the text proper
+               'table',                // Neither are tables
+               '.rellink',             // Common style for "See also:".
+               '.dablink',             // Common style for calling out helpful links at the top
+                                                               // of the article.
+               '.searchaux',           // New class users can use to mark stuff as auxiliary to searches.
+       ];
+
+       /**
+        * WikiTextStructure constructor.
+        * @param ParserOutput $parserOutput
+        */
+       public function __construct( ParserOutput $parserOutput ) {
+               $this->parserOutput = $parserOutput;
+       }
+
+       /**
+        * Get categories in the text.
+        * @return string[]
+        */
+       public function categories() {
+               $categories = [];
+               foreach ( array_keys( $this->parserOutput->getCategories() ) as $key ) {
+                       $categories[] = Category::newFromName( $key )->getTitle()->getText();
+               }
+               return $categories;
+       }
+
+       /**
+        * Get outgoing links.
+        * @return string[]
+        */
+       public function outgoingLinks() {
+               $outgoingLinks = [];
+               foreach ( $this->parserOutput->getLinks() as $linkedNamespace => $namespaceLinks ) {
+                       foreach ( array_keys( $namespaceLinks ) as $linkedDbKey ) {
+                               $outgoingLinks[] =
+                                       Title::makeTitle( $linkedNamespace, $linkedDbKey )->getPrefixedDBkey();
+                       }
+               }
+               return $outgoingLinks;
+       }
+
+       /**
+        * Get templates in the text.
+        * @return string[]
+        */
+       public function templates() {
+               $templates = [];
+               foreach ( $this->parserOutput->getTemplates() as $tNS => $templatesInNS ) {
+                       foreach ( array_keys( $templatesInNS ) as $tDbKey ) {
+                               $templateTitle = Title::makeTitleSafe( $tNS, $tDbKey );
+                               if ( $templateTitle && $templateTitle->exists() ) {
+                                       $templates[] = $templateTitle->getPrefixedText();
+                               }
+                       }
+               }
+               return $templates;
+       }
+
+       /**
+        * Get headings on the page.
+        * @return string[]
+        * First strip out things that look like references.  We can't use HTML filtering because
+        * the references come back as <sup> tags without a class.  To keep from breaking stuff like
+        *  ==Applicability of the strict mass–energy equivalence formula, ''E'' = ''mc''<sup>2</sup>==
+        * we don't remove the whole <sup> tag.  We also don't want to strip the <sup> tag and remove
+        * everything that looks like [2] because, I dunno, maybe there is a band named Word [2] Foo
+        * or something.  Whatever.  So we only strip things that look like <sup> tags wrapping a
+        * reference.  And since the data looks like:
+        *      Reference in heading <sup>&#91;1&#93;</sup><sup>&#91;2&#93;</sup>
+        * we can not really use HtmlFormatter as we have no suitable selector.
+        */
+       public function headings() {
+               $headings = [];
+               $ignoredHeadings = $this->getIgnoredHeadings();
+               foreach ( $this->parserOutput->getSections() as $heading ) {
+                       $heading = $heading[ 'line' ];
+
+                       // Some wikis wrap the brackets in a span:
+                       // http://en.wikipedia.org/wiki/MediaWiki:Cite_reference_link
+                       $heading = preg_replace( '/<\/?span>/', '', $heading );
+                       // Normalize [] so the following regexp would work.
+                       $heading = preg_replace( [ '/&#91;/', '/&#93;/' ], [ '[', ']' ], $heading );
+                       $heading = preg_replace( '/<sup>\s*\[\s*\d+\s*\]\s*<\/sup>/is', '', $heading );
+
+                       // Strip tags from the heading or else we'll display them (escaped) in search results
+                       $heading = trim( Sanitizer::stripAllTags( $heading ) );
+
+                       // Note that we don't take the level of the heading into account - all headings are equal.
+                       // Except the ones we ignore.
+                       if ( !in_array( $heading, $ignoredHeadings ) ) {
+                               $headings[] = $heading;
+                       }
+               }
+               return $headings;
+       }
+
+       /**
+        * Parse a message content into an array. This function is generally used to
+        * parse settings stored as i18n messages (see search-ignored-headings).
+        *
+        * @param string $message
+        * @return string[]
+        */
+       public static function parseSettingsInMessage( $message ) {
+               $lines = explode( "\n", $message );
+               $lines = preg_replace( '/#.*$/', '', $lines ); // Remove comments
+               $lines = array_map( 'trim', $lines );          // Remove extra spaces
+               $lines = array_filter( $lines );               // Remove empty lines
+               return $lines;
+       }
+
+       /**
+        * Get list of heading to ignore.
+        * @return string[]
+        */
+       private function getIgnoredHeadings() {
+               static $ignoredHeadings = null;
+               if ( $ignoredHeadings === null ) {
+                       $ignoredHeadings = [];
+                       $source = wfMessage( 'search-ignored-headings' )->inContentLanguage();
+                       if ( $source->isBlank() ) {
+                               // Try old version too, just in case
+                               $source = wfMessage( 'cirrussearch-ignored-headings' )->inContentLanguage();
+                       }
+                       if ( !$source->isDisabled() ) {
+                               $lines = self::parseSettingsInMessage( $source->plain() );
+                               $ignoredHeadings = $lines;               // Now we just have headings!
+                       }
+               }
+               return $ignoredHeadings;
+       }
+
+       /**
+        * Extract parts of the text - opening, main and auxiliary.
+        */
+       private function extractWikitextParts() {
+               if ( !is_null( $this->allText ) ) {
+                       return;
+               }
+               $this->parserOutput->setEditSectionTokens( false );
+               $this->parserOutput->setTOCEnabled( false );
+               $text = $this->parserOutput->getText();
+               if ( strlen( $text ) == 0 ) {
+                       $this->allText = "";
+                       // empty text - nothing to seek here
+                       return;
+               }
+               $opening = null;
+
+               $this->openingText = $this->extractHeadingBeforeFirstHeading( $text );
+
+               // Add extra spacing around break tags so text crammed together like<br>this
+               // doesn't make one word.
+               $text = str_replace( '<br', "\n<br", $text );
+
+               $formatter = new HtmlFormatter( $text );
+
+               // Strip elements from the page that we never want in the search text.
+               $formatter->remove( $this->excludedElementSelectors );
+               $formatter->filterContent();
+
+               // Strip elements from the page that are auxiliary text.  These will still be
+               // searched but matches will be ranked lower and non-auxiliary matches will be
+               // preferred in highlighting.
+               $formatter->remove( $this->auxiliaryElementSelectors );
+               $auxiliaryElements = $formatter->filterContent();
+               $this->allText = trim( Sanitizer::stripAllTags( $formatter->getText() ) );
+               foreach ( $auxiliaryElements as $auxiliaryElement ) {
+                       $this->auxText[] =
+                               trim( Sanitizer::stripAllTags( $formatter->getText( $auxiliaryElement ) ) );
+               }
+       }
+
+       /**
+        * Get text before first heading.
+        * @param string $text
+        * @return string|null
+        */
+       private function extractHeadingBeforeFirstHeading( $text ) {
+               $matches = [];
+               if ( !preg_match( '/<h[123456]>/', $text, $matches, PREG_OFFSET_CAPTURE ) ) {
+                       // There isn't a first heading so we interpret this as the article
+                       // being entirely without heading.
+                       return null;
+               }
+               $text = substr( $text, 0, $matches[ 0 ][ 1 ] );
+               if ( !$text ) {
+                       // There isn't any text before the first heading so we declare there isn't
+                       // a first heading.
+                       return null;
+               }
+
+               $formatter = new HtmlFormatter( $text );
+               $formatter->remove( $this->excludedElementSelectors );
+               $formatter->remove( $this->auxiliaryElementSelectors );
+               $formatter->filterContent();
+               $text = trim( Sanitizer::stripAllTags( $formatter->getText() ) );
+
+               if ( !$text ) {
+                       // There isn't any text after filtering before the first heading so we declare
+                       // that there isn't a first heading.
+                       return null;
+               }
+
+               return $text;
+       }
+
+       /**
+        * Get opening text
+        * @return string
+        */
+       public function getOpeningText() {
+               $this->extractWikitextParts();
+               return $this->openingText;
+       }
+
+       /**
+        * Get main text
+        * @return string
+        */
+       public function getMainText() {
+               $this->extractWikitextParts();
+               return $this->allText;
+       }
+
+       /**
+        * Get auxiliary text
+        * @return string[]
+        */
+       public function getAuxiliaryText() {
+               $this->extractWikitextParts();
+               return $this->auxText;
+       }
+}
index 4e8f0df..5c0a9c8 100644 (file)
@@ -145,4 +145,44 @@ class WikitextContentHandler extends TextContentHandler {
                return $fields;
        }
 
+       /**
+        * Extract text of the file
+        * TODO: probably should go to file handler?
+        * @param Title $title
+        * @return string|null
+        */
+       protected function getFileText( Title $title ) {
+               $file = wfLocalFile( $title );
+               if ( $file && $file->exists() ) {
+                       return $file->getHandler()->getEntireText( $file );
+               }
+
+               return null;
+       }
+
+       public function getDataForSearchIndex( WikiPage $page, ParserOutput $parserOutput,
+                                              SearchEngine $engine ) {
+               $fields = parent::getDataForSearchIndex( $page, $parserOutput, $engine );
+
+               $structure = new WikiTextStructure( $parserOutput );
+               $fields['external_link'] = array_keys( $parserOutput->getExternalLinks() );
+               $fields['category'] = $structure->categories();
+               $fields['heading'] = $structure->headings();
+               $fields['outgoing_link'] = $structure->outgoingLinks();
+               $fields['template'] = $structure->templates();
+               // text fields
+               $fields['opening_text'] = $structure->getOpeningText();
+               $fields['text'] = $structure->getMainText(); // overwrites one from ContentHandler
+               $fields['auxiliary_text'] = $structure->getAuxiliaryText();
+
+               $title = $page->getTitle();
+               if ( NS_FILE == $title->getNamespace() ) {
+                       $fileText = $this->getFileText( $title );
+                       if ( $fileText ) {
+                               $fields['file_text'] = $fileText;
+                       }
+               }
+               return $fields;
+       }
+
 }
index 33f8162..5e0365a 100644 (file)
@@ -378,10 +378,10 @@ class DatabaseMssql extends Database {
         * @param mixed $conds Array or string, condition(s) for WHERE
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
         * @param array $options Associative array of options (e.g.
-        *   array('GROUP BY' => 'page_title')), see Database::makeSelectOptions
+        *   [ 'GROUP BY' => 'page_title' ]), see Database::makeSelectOptions
         *   code for list of supported stuff
         * @param array $join_conds Associative array of table join conditions
-        *   (optional) (e.g. array( 'page' => array('LEFT JOIN','page_latest=rev_id') )
+        *   (optional) (e.g. [ 'page' => [ 'LEFT JOIN','page_latest=rev_id' ] ]
         * @return mixed Database result resource (feed to Database::fetchObject
         *   or whatever), or false on failure
         * @throws DBQueryError
@@ -434,10 +434,10 @@ class DatabaseMssql extends Database {
         * @param mixed $vars Array or string, field name(s) to be retrieved
         * @param mixed $conds Array or string, condition(s) for WHERE
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
-        * @param array $options Associative array of options (e.g. array('GROUP BY' => 'page_title')),
+        * @param array $options Associative array of options (e.g. [ 'GROUP BY' => 'page_title' ]),
         *   see Database::makeSelectOptions code for list of supported stuff
         * @param array $join_conds Associative array of table join conditions (optional)
-        *    (e.g. array( 'page' => array('LEFT JOIN','page_latest=rev_id') )
+        *    (e.g. [ 'page' => [ 'LEFT JOIN','page_latest=rev_id' ] ]
         * @return string The SQL text
         */
        public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
@@ -717,7 +717,7 @@ class DatabaseMssql extends Database {
 
        /**
         * INSERT SELECT wrapper
-        * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
+        * $varMap must be an associative array of the form [ 'dest1' => 'source1', ... ]
         * Source items may be literals rather than field names, but strings should
         * be quoted with Database::addQuotes().
         * @param string $destTable
index a6f8c31..798815d 100644 (file)
@@ -798,7 +798,7 @@ abstract class DatabaseMysqlBase extends Database {
                // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
                if ( $this->useGTIDs && $pos->gtids ) {
                        // Wait on the GTID set (MariaDB only)
-                       $gtidArg = implode( ',', $pos->gtids );
+                       $gtidArg = $this->addQuotes( implode( ',', $pos->gtids ) );
                        $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
                } else {
                        // Wait on the binlog coordinates
@@ -1186,12 +1186,6 @@ abstract class DatabaseMysqlBase extends Database {
                return $this->lastErrno() == 1205;
        }
 
-       /**
-        * Determines if the last query error was something that should be dealt
-        * with by pinging the connection and reissuing the query
-        *
-        * @return bool
-        */
        function wasErrorReissuable() {
                return $this->lastErrno() == 2013 || $this->lastErrno() == 2006;
        }
index c9127ff..867aeb8 100644 (file)
@@ -888,7 +888,7 @@ __INDEXATTR__;
 
        /**
         * INSERT SELECT wrapper
-        * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
+        * $varMap must be an associative array of the form [ 'dest1' => 'source1', ... ]
         * Source items may be literals rather then field names, but strings should
         * be quoted with Database::addQuotes()
         * $conds may be "*" to copy the whole table
index 41b131f..43592e2 100644 (file)
@@ -329,7 +329,7 @@ interface IDatabase {
         *
         * Example:
         * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
-        * $dbw->insert( 'page', array( 'page_id' => $id ) );
+        * $dbw->insert( 'page', [ 'page_id' => $id ] );
         * $id = $dbw->insertId();
         *
         * @return int
@@ -519,7 +519,7 @@ interface IDatabase {
         * May be either an array of table names, or a single string holding a table
         * name. If an array is given, table aliases can be specified, for example:
         *
-        *    array( 'a' => 'user' )
+        *    [ 'a' => 'user' ]
         *
         * This includes the user table in the query, with the alias "a" available
         * for use in field names (e.g. a.user_name).
@@ -537,7 +537,7 @@ interface IDatabase {
         * can be complete fragments of SQL, for direct inclusion into the SELECT
         * query. If an array is given, field aliases can be specified, for example:
         *
-        *   array( 'maxrev' => 'MAX(rev_id)' )
+        *   [ 'maxrev' => 'MAX(rev_id)' ]
         *
         * This includes an expression with the alias "maxrev" in the query.
         *
@@ -582,7 +582,7 @@ interface IDatabase {
         * including them in the array as a string value with a numeric key, for
         * example:
         *
-        *    array( 'FOR UPDATE' )
+        *    [ 'FOR UPDATE' ]
         *
         * The supported options are:
         *
@@ -644,7 +644,7 @@ interface IDatabase {
         * an SQL fragment, or an array where the string keys are equality and the
         * numeric keys are SQL fragments all AND'd together. For example:
         *
-        *    array( 'page' => array( 'LEFT JOIN', 'page_latest=rev_id' ) )
+        *    [ 'page' => [ 'LEFT JOIN', 'page_latest=rev_id' ] ]
         *
         * @return ResultWrapper|bool If the query returned no rows, a ResultWrapper
         *   with no rows in it will be returned. If there was a query error, a
@@ -857,7 +857,7 @@ interface IDatabase {
         * The keys on each level may be either integers or strings.
         *
         * @param array $data Organized as 2-d
-        *    array(baseKeyVal => array(subKeyVal => [ignored], ...), ...)
+        *    [ baseKeyVal => [ subKeyVal => [ignored], ... ], ... ]
         * @param string $baseKey Field name to match the base-level keys to (eg 'pl_namespace')
         * @param string $subKey Field name to match the sub-level keys to (eg 'pl_title')
         * @return string|bool SQL fragment, or false if no items in array
@@ -950,7 +950,7 @@ interface IDatabase {
         * Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns
         * a LIKE clause that searches for subpages of 'My page title'.
         * Alternatively:
-        *   $pattern = array( 'My_page_title/', $dbr->anyString() );
+        *   $pattern = [ 'My_page_title/', $dbr->anyString() ];
         *   $query .= $dbr->buildLike( $pattern );
         *
         * @since 1.16
@@ -1092,7 +1092,7 @@ interface IDatabase {
         *    to include in a join.
         *
         * @param array $varMap Must be an associative array of the form
-        *    array( 'dest1' => 'source1', ...). Source items may be literals
+        *    [ 'dest1' => 'source1', ... ]. Source items may be literals
         *    rather than field names, but strings should be quoted with
         *    IDatabase::addQuotes()
         *
@@ -1156,7 +1156,6 @@ interface IDatabase {
 
        /**
         * Determines how long the server has been up
-        * STUB
         *
         * @return int
         */
@@ -1164,7 +1163,6 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to a deadlock
-        * STUB
         *
         * @return bool
         */
@@ -1172,16 +1170,14 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to a lock timeout
-        * STUB
         *
         * @return bool
         */
        public function wasLockTimeout();
 
        /**
-        * Determines if the last query error was something that should be dealt
-        * with by pinging the connection and reissuing the query.
-        * STUB
+        * Determines if the last query error was due to a dropped connection and should
+        * be dealt with by pinging the connection and reissuing the query.
         *
         * @return bool
         */
@@ -1189,7 +1185,6 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to the database being read-only.
-        * STUB
         *
         * @return bool
         */
index 3a543ac..32b1a0f 100644 (file)
  *
  *     sectionLoads                A 2-d map. For each section, gives a map of server names to
  *                                 load ratios. For example:
- *                                 array(
- *                                     'section1' => array(
+ *                                 [
+ *                                     'section1' => [
  *                                         'db1' => 100,
  *                                         'db2' => 100
- *                                     )
- *                                 )
+ *                                     ]
+ *                                 ]
  *
  *     serverTemplate              A server info associative array as documented for $wgDBservers.
  *                                 The host, hostName and load entries will be overridden.
  *
  *     groupLoadsBySection         A 3-d map giving server load ratios for each section and group.
  *                                 For example:
- *                                 array(
- *                                     'section1' => array(
- *                                         'group1' => array(
+ *                                 [
+ *                                     'section1' => [
+ *                                         'group1' => [
  *                                             'db1' => 100,
  *                                             'db2' => 100
- *                                         )
- *                                     )
- *                                 )
+ *                                         ]
+ *                                     ]
+ *                                 ]
  *
  *     groupLoadsByDB              A 3-d map giving server load ratios by DB name.
  *
index 2543958..1269c3e 100644 (file)
@@ -138,8 +138,20 @@ class LoadBalancer {
                        }
                }
 
-               $this->srvCache = ObjectCache::getLocalServerInstance();
-               $this->wanCache = ObjectCache::getMainWANInstance();
+               // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
+               // @TODO: inject these in via LBFactory at some point
+               $cache = ObjectCache::getLocalServerInstance();
+               if ( $cache->getQoS( $cache::ATTR_EMULATION ) > $cache::QOS_EMULATION_SQL ) {
+                       $this->srvCache = $cache;
+               } else {
+                       $this->srvCache = new EmptyBagOStuff();
+               }
+               $wCache = ObjectCache::getMainWANInstance();
+               if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
+                       $this->wanCache = $wCache;
+               } else {
+                       $this->wanCache = WANObjectCache::newEmpty();
+               }
 
                if ( isset( $params['trxProfiler'] ) ) {
                        $this->trxProfiler = $params['trxProfiler'];
@@ -605,7 +617,7 @@ class LoadBalancer {
                        /**
                         * This can happen in code like:
                         *   foreach ( $dbs as $db ) {
-                        *     $conn = $lb->getConnection( DB_SLAVE, array(), $db );
+                        *     $conn = $lb->getConnection( DB_SLAVE, [], $db );
                         *     ...
                         *     $lb->reuseConnection( $conn );
                         *   }
@@ -1314,12 +1326,15 @@ class LoadBalancer {
                        $cache->makeGlobalKey( __CLASS__, 'server-read-only', $masterServer ),
                        self::TTL_CACHE_READONLY,
                        function () use ( $wiki, $conn ) {
+                               $this->trxProfiler->setSilenced( true );
                                try {
                                        $dbw = $conn ?: $this->getConnection( DB_MASTER, [], $wiki );
-                                       return (int)$dbw->serverIsReadOnly();
+                                       $readOnly = (int)$dbw->serverIsReadOnly();
                                } catch ( DBError $e ) {
-                                       return 0;
+                                       $readOnly = 0;
                                }
+                               $this->trxProfiler->setSilenced( false );
+                               return $readOnly;
                        },
                        [ 'pcTTL' => $cache::TTL_PROC_LONG, 'busyValue' => 0 ]
                );
index 4ce9e62..470086a 100644 (file)
@@ -65,7 +65,7 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate {
        /**
         * @param Title $title
         * @return CdnCacheUpdate
-        * @deprecated 1.27
+        * @deprecated since 1.27
         */
        public static function newSimplePurge( Title $title ) {
                return new CdnCacheUpdate( $title->getCdnUrls() );
index 949a0ac..4a6ac8e 100644 (file)
@@ -238,12 +238,14 @@ class DifferenceEngine extends ContextSource {
        }
 
        public function showDiffPage( $diffOnly = false ) {
-
                # Allow frames except in certain special cases
                $out = $this->getOutput();
                $out->allowClickjacking();
                $out->setRobotPolicy( 'noindex,nofollow' );
 
+               // Allow extensions to add any extra output here
+               Hooks::run( 'DifferenceEngineShowDiffPage', [ $out ] );
+
                if ( !$this->loadRevisionData() ) {
                        $this->showMissingRevision();
 
@@ -285,6 +287,8 @@ class DifferenceEngine extends ContextSource {
                        $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
                        $samePage = true;
                        $oldHeader = '';
+                       // Allow extensions to change the $oldHeader variable
+                       Hooks::run( 'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] );
                } else {
                        Hooks::run( 'DiffViewHeader', [ $this, $this->mOldRev, $this->mNewRev ] );
 
@@ -354,6 +358,10 @@ class DifferenceEngine extends ContextSource {
                                '<div id="mw-diff-otitle5">' . $oldChangeTags[0] . '</div>' .
                                '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
 
+                       // Allow extensions to change the $oldHeader variable
+                       Hooks::run( 'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink, $oldminor,
+                               $diffOnly, $ldel, $this->unhide ] );
+
                        if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
                                $deleted = true; // old revisions text is hidden
                                if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
@@ -415,6 +423,10 @@ class DifferenceEngine extends ContextSource {
                        '<div id="mw-diff-ntitle5">' . $newChangeTags[0] . '</div>' .
                        '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
 
+               // Allow extensions to change the $newHeader variable
+               Hooks::run( 'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools,
+                       $nextlink, $rollback, $newminor, $diffOnly, $rdel, $this->unhide ] );
+
                if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
                        $deleted = true; // new revisions text is hidden
                        if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
@@ -487,6 +499,9 @@ class DifferenceEngine extends ContextSource {
                                                        'token' => $linkInfo['token'],
                                                ]
                                        ) . ']</span>';
+                               // Allow extensions to change the markpatrolled link
+                               Hooks::run( 'DifferenceEngineMarkPatrolledLink', [ $this,
+                                       &$this->mMarkPatrolledLink, $linkInfo['rcid'], $linkInfo['token'] ] );
                        }
                }
                return $this->mMarkPatrolledLink;
@@ -530,9 +545,17 @@ class DifferenceEngine extends ContextSource {
                                // If the user could patrol this it already would be patrolled
                                $rcid = 0;
                        }
+
+                       // Allow extensions to possibly change the rcid here
+                       // For example the rcid might be set to zero due to the user
+                       // being the same as the performer of the change but an extension
+                       // might still want to show it under certain conditions
+                       Hooks::run( 'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] );
+
                        // Build the link
                        if ( $rcid ) {
                                $this->getOutput()->preventClickjacking();
+                               $this->getOutput()->addModuleStyles( 'mediawiki.page.patrol' );
                                if ( $wgEnableAPI && $wgEnableWriteAPI
                                        && $user->isAllowed( 'writeapi' )
                                ) {
@@ -617,15 +640,20 @@ class DifferenceEngine extends ContextSource {
 
                                # WikiPage::getParserOutput() should not return false, but just in case
                                if ( $parserOutput ) {
-                                       $out->addParserOutput( $parserOutput );
+                                       // Allow extensions to change parser output here
+                                       if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput', [ $this, $out, $parserOutput, $wikiPage ] ) ) {
+                                               $out->addParserOutput( $parserOutput );
+                                       }
                                }
                        }
                }
                # @codingStandardsIgnoreEnd
 
-               # Add redundant patrol link on bottom...
-               $out->addHTML( $this->markPatrolledLink() );
-
+               // Allow extensions to optionally not show the final patrolled link
+               if ( Hooks::run( 'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) {
+                       # Add redundant patrol link on bottom...
+                       $out->addHTML( $this->markPatrolledLink() );
+               }
        }
 
        protected function getParserOutput( WikiPage $page, Revision $rev ) {
@@ -651,6 +679,9 @@ class DifferenceEngine extends ContextSource {
         * @return bool
         */
        public function showDiff( $otitle, $ntitle, $notice = '' ) {
+               // Allow extensions to affect the output here
+               Hooks::run( 'DifferenceEngineShowDiff', [ $this ] );
+
                $diff = $this->getDiff( $otitle, $ntitle, $notice );
                if ( $diff === false ) {
                        $this->showMissingRevision();
@@ -720,7 +751,9 @@ class DifferenceEngine extends ContextSource {
                if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
                        && $this->mOldRev->getId() == $this->mNewRev->getId() )
                ) {
-                       return '';
+                       if ( Hooks::run( 'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) {
+                               return '';
+                       }
                }
                // Cacheable?
                $key = false;
@@ -819,21 +852,6 @@ class DifferenceEngine extends ContextSource {
                return $this->generateTextDiffBody( $otext, $ntext );
        }
 
-       /**
-        * Generate a diff, no caching
-        *
-        * @param string $otext Old text, must be already segmented
-        * @param string $ntext New text, must be already segmented
-        *
-        * @return bool|string
-        * @deprecated since 1.21, use generateContentDiffBody() instead!
-        */
-       public function generateDiffBody( $otext, $ntext ) {
-               ContentHandler::deprecated( __METHOD__, "1.21" );
-
-               return $this->generateTextDiffBody( $otext, $ntext );
-       }
-
        /**
         * Generate a diff, no caching
         *
index 67080b6..538e9bc 100644 (file)
@@ -24,7 +24,7 @@
 /**
  * Generic operation result class for FileRepo-related operations
  * @ingroup FileRepo
- * @deprecated 1.25
+ * @deprecated since 1.25
  */
 class FileRepoStatus extends Status {
 }
index 8175b58..425a08c 100644 (file)
@@ -1028,7 +1028,7 @@ abstract class File implements IDBAccessObject {
         * @param array $params An associative array of handler-specific parameters.
         *   Typical keys are width, height and page.
         * @param int $flags A bitfield, may contain self::RENDER_NOW to force rendering
-        * @return MediaTransformOutput|bool False on failure
+        * @return ThumbnailImage|MediaTransformOutput|bool False on failure
         */
        function transform( $params, $flags = 0 ) {
                global $wgThumbnailEpoch;
@@ -1324,7 +1324,7 @@ abstract class File implements IDBAccessObject {
        /**
         * Creates a temp FS file with the same extension and the thumbnail
         * @param string $thumbPath Thumbnail path
-        * @return TempFSFile
+        * @return TempFSFile|null
         */
        protected function makeTransformTmpFile( $thumbPath ) {
                $thumbExt = FileBackend::extensionFromPath( $thumbPath );
index a7f6e6f..b8be4ea 100644 (file)
@@ -1517,7 +1517,8 @@ class LocalFile extends File {
                                                LinksUpdate::queueRecursiveJobsForTable( $this->getTitle(), 'imagelinks' );
                                        }
                                }
-                       )
+                       ),
+                       DeferredUpdates::PRESEND
                );
 
                if ( !$reupload ) {
diff --git a/includes/htmlform/HTMLApiField.php b/includes/htmlform/HTMLApiField.php
deleted file mode 100644 (file)
index 24a253e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-class HTMLApiField extends HTMLFormField {
-       public function getTableRow( $value ) {
-               return '';
-       }
-
-       public function getDiv( $value ) {
-               return $this->getTableRow( $value );
-       }
-
-       public function getRaw( $value ) {
-               return $this->getTableRow( $value );
-       }
-
-       public function getInputHTML( $value ) {
-               return '';
-       }
-
-       public function hasVisibleOutput() {
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLAutoCompleteSelectField.php b/includes/htmlform/HTMLAutoCompleteSelectField.php
deleted file mode 100644 (file)
index 76a88d5..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-<?php
-
-/**
- * Text field for selecting a value from a large list of possible values, with
- * auto-completion and optionally with a select dropdown for selecting common
- * options.
- *
- * HTMLComboboxField implements most of the same functionality and should be
- * used instead, if possible.
- *
- * If one of 'options-messages', 'options', or 'options-message' is provided
- * and non-empty, the select dropdown will be shown. An 'other' key will be
- * appended using message 'htmlform-selectorother-other' if not already
- * present.
- *
- * Besides the parameters recognized by HTMLTextField, the following are
- * recognized:
- *   options-messages - As for HTMLSelectField
- *   options - As for HTMLSelectField
- *   options-message - As for HTMLSelectField
- *   autocomplete - Associative array mapping display text to values.
- *   autocomplete-messages - Like autocomplete, but keys are message names.
- *   require-match - Boolean, if true the value must be in the options or the
- *     autocomplete.
- *   other-message - Message to use instead of htmlform-selectorother-other for
- *      the 'other' message.
- *   other - Raw text to use for the 'other' message
- */
-class HTMLAutoCompleteSelectField extends HTMLTextField {
-       protected $autocomplete = [];
-
-       function __construct( $params ) {
-               $params += [
-                       'require-match' => false,
-               ];
-
-               parent::__construct( $params );
-
-               if ( array_key_exists( 'autocomplete-messages', $this->mParams ) ) {
-                       foreach ( $this->mParams['autocomplete-messages'] as $key => $value ) {
-                               $key = $this->msg( $key )->plain();
-                               $this->autocomplete[$key] = strval( $value );
-                       }
-               } elseif ( array_key_exists( 'autocomplete', $this->mParams ) ) {
-                       foreach ( $this->mParams['autocomplete'] as $key => $value ) {
-                               $this->autocomplete[$key] = strval( $value );
-                       }
-               }
-               if ( !is_array( $this->autocomplete ) || !$this->autocomplete ) {
-                       throw new MWException( 'HTMLAutoCompleteSelectField called without any autocompletions' );
-               }
-
-               $this->getOptions();
-               if ( $this->mOptions && !in_array( 'other', $this->mOptions, true ) ) {
-                       if ( isset( $params['other-message'] ) ) {
-                               $msg = $this->getMessage( $params['other-message'] )->text();
-                       } elseif ( isset( $params['other'] ) ) {
-                               $msg = $params['other'];
-                       } else {
-                               $msg = wfMessage( 'htmlform-selectorother-other' )->text();
-                       }
-                       $this->mOptions[$msg] = 'other';
-               }
-       }
-
-       function loadDataFromRequest( $request ) {
-               if ( $request->getCheck( $this->mName ) ) {
-                       $val = $request->getText( $this->mName . '-select', 'other' );
-
-                       if ( $val === 'other' ) {
-                               $val = $request->getText( $this->mName );
-                               if ( isset( $this->autocomplete[$val] ) ) {
-                                       $val = $this->autocomplete[$val];
-                               }
-                       }
-
-                       return $val;
-               } else {
-                       return $this->getDefault();
-               }
-       }
-
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
-
-               if ( in_array( strval( $value ), $validOptions, true ) ) {
-                       return true;
-               } elseif ( in_array( strval( $value ), $this->autocomplete, true ) ) {
-                       return true;
-               } elseif ( $this->mParams['require-match'] ) {
-                       return $this->msg( 'htmlform-select-badoption' )->parse();
-               }
-
-               return true;
-       }
-
-       // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
-       public function getAttributes( array $list ) {
-               $attribs = [
-                       'type' => 'text',
-                       'data-autocomplete' => FormatJson::encode( array_keys( $this->autocomplete ) ),
-               ] + parent::getAttributes( $list );
-
-               if ( $this->getOptions() ) {
-                       $attribs['data-hide-if'] = FormatJson::encode(
-                               [ '!==', $this->mName . '-select', 'other' ]
-                       );
-               }
-
-               return $attribs;
-       }
-
-       function getInputHTML( $value ) {
-               $oldClass = $this->mClass;
-               $this->mClass = (array)$this->mClass;
-
-               $valInSelect = false;
-               $ret = '';
-
-               if ( $this->getOptions() ) {
-                       if ( $value !== false ) {
-                               $value = strval( $value );
-                               $valInSelect = in_array(
-                                       $value, HTMLFormField::flattenOptions( $this->getOptions() ), true
-                               );
-                       }
-
-                       $selected = $valInSelect ? $value : 'other';
-                       $select = new XmlSelect( $this->mName . '-select', $this->mID . '-select', $selected );
-                       $select->addOptions( $this->getOptions() );
-                       $select->setAttribute( 'class', 'mw-htmlform-select-or-other' );
-
-                       if ( !empty( $this->mParams['disabled'] ) ) {
-                               $select->setAttribute( 'disabled', 'disabled' );
-                       }
-
-                       if ( isset( $this->mParams['tabindex'] ) ) {
-                               $select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
-                       }
-
-                       $ret = $select->getHTML() . "<br />\n";
-
-                       $this->mClass[] = 'mw-htmlform-hide-if';
-               }
-
-               if ( $valInSelect ) {
-                       $value = '';
-               } else {
-                       $key = array_search( strval( $value ), $this->autocomplete, true );
-                       if ( $key !== false ) {
-                               $value = $key;
-                       }
-               }
-
-               $this->mClass[] = 'mw-htmlform-autocomplete';
-               $ret .= parent::getInputHTML( $valInSelect ? '' : $value );
-               $this->mClass = $oldClass;
-
-               return $ret;
-       }
-
-       /**
-        * Get the OOUI version of this input.
-        * @param string $value
-        * @return false
-        */
-       function getInputOOUI( $value ) {
-               // To be implemented, for now override the function from HTMLTextField
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLButtonField.php b/includes/htmlform/HTMLButtonField.php
deleted file mode 100644 (file)
index 64fe7ed..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-
-/**
- * Adds a generic button inline to the form. Does not do anything, you must add
- * click handling code in JavaScript. Use a HTMLSubmitField if you merely
- * wish to add a submit button to a form.
- *
- * Additional recognized configuration parameters include:
- * - flags: OOUI flags for the button, see OOUI\FlaggedElement
- * - buttonlabel-message: Message to use for the button display text, instead
- *   of the value from 'default'. Overrides 'buttonlabel' and 'buttonlabel-raw'.
- * - buttonlabel: Text to display for the button display text, instead
- *   of the value from 'default'. Overrides 'buttonlabel-raw'.
- * - buttonlabel-raw: HTMLto display for the button display text, instead
- *   of the value from 'default'.
- *
- * Note that the buttonlabel parameters are not supported on IE6 and IE7 due to
- * bugs in those browsers. If detected, they will be served buttons using the
- * value of 'default' as the button label.
- *
- * @since 1.22
- */
-class HTMLButtonField extends HTMLFormField {
-       protected $buttonType = 'button';
-       protected $buttonLabel = null;
-
-       /** @var array $mFlags Flags to add to OOUI Button widget */
-       protected $mFlags = [];
-
-       public function __construct( $info ) {
-               $info['nodata'] = true;
-               if ( isset( $info['flags'] ) ) {
-                       $this->mFlags = $info['flags'];
-               }
-
-               # Generate the label from a message, if possible
-               if ( isset( $info['buttonlabel-message'] ) ) {
-                       $this->buttonLabel = $this->getMessage( $info['buttonlabel-message'] )->parse();
-               } elseif ( isset( $info['buttonlabel'] ) ) {
-                       if ( $info['buttonlabel'] === '&#160;' ) {
-                               // Apparently some things set &nbsp directly and in an odd format
-                               $this->buttonLabel = '&#160;';
-                       } else {
-                               $this->buttonLabel = htmlspecialchars( $info['buttonlabel'] );
-                       }
-               } elseif ( isset( $info['buttonlabel-raw'] ) ) {
-                       $this->buttonLabel = $info['buttonlabel-raw'];
-               }
-
-               $this->setShowEmptyLabel( false );
-
-               parent::__construct( $info );
-       }
-
-       public function getInputHTML( $value ) {
-               $flags = '';
-               $prefix = 'mw-htmlform-';
-               if ( $this->mParent instanceof VFormHTMLForm ||
-                       $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' )
-               ) {
-                       $prefix = 'mw-ui-';
-                       // add mw-ui-button separately, so the descriptor doesn't need to set it
-                       $flags .= ' ' . $prefix . 'button';
-               }
-               foreach ( $this->mFlags as $flag ) {
-                       $flags .= ' ' . $prefix . $flag;
-               }
-               $attr = [
-                       'class' => 'mw-htmlform-submit ' . $this->mClass . $flags,
-                       'id' => $this->mID,
-                       'type' => $this->buttonType,
-                       'name' => $this->mName,
-                       'value' => $this->getDefault(),
-               ] + $this->getAttributes( [ 'disabled', 'tabindex' ] );
-
-               if ( $this->isBadIE() ) {
-                       return Html::element( 'input', $attr );
-               } else {
-                       return Html::rawElement( 'button', $attr,
-                               $this->buttonLabel ?: htmlspecialchars( $this->getDefault() ) );
-               }
-       }
-
-       /**
-        * Get the OOUI widget for this field.
-        * @param string $value
-        * @return OOUI\ButtonInputWidget
-        */
-       public function getInputOOUI( $value ) {
-               return new OOUI\ButtonInputWidget( [
-                       'name' => $this->mName,
-                       'value' => $this->getDefault(),
-                       'label' => !$this->isBadIE() && $this->buttonLabel
-                               ? new OOUI\HtmlSnippet( $this->buttonLabel )
-                               : $this->getDefault(),
-                       'type' => $this->buttonType,
-                       'classes' => [ 'mw-htmlform-submit', $this->mClass ],
-                       'id' => $this->mID,
-                       'flags' => $this->mFlags,
-                       'useInputTag' => $this->isBadIE(),
-               ] + OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
-               ) );
-       }
-
-       protected function needsLabel() {
-               return false;
-       }
-
-       /**
-        * Button cannot be invalid
-        *
-        * @param string $value
-        * @param array $alldata
-        *
-        * @return bool
-        */
-       public function validate( $value, $alldata ) {
-               return true;
-       }
-
-       /**
-        * IE<8 has bugs with <button>, so we'll need to avoid them.
-        * @return bool Whether the request is from a bad version of IE
-        */
-       private function isBadIE() {
-               $request = $this->mParent
-                       ? $this->mParent->getRequest()
-                       : RequestContext::getMain()->getRequest();
-               return preg_match( '/MSIE [1-7]\./i', $request->getHeader( 'User-Agent' ) );
-       }
-}
diff --git a/includes/htmlform/HTMLCheckField.php b/includes/htmlform/HTMLCheckField.php
deleted file mode 100644 (file)
index a553839..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-
-/**
- * A checkbox field
- */
-class HTMLCheckField extends HTMLFormField {
-       function getInputHTML( $value ) {
-               global $wgUseMediaWikiUIEverywhere;
-
-               if ( !empty( $this->mParams['invert'] ) ) {
-                       $value = !$value;
-               }
-
-               $attr = $this->getTooltipAndAccessKey();
-               $attr['id'] = $this->mID;
-
-               $attr += $this->getAttributes( [ 'disabled', 'tabindex' ] );
-
-               if ( $this->mClass !== '' ) {
-                       $attr['class'] = $this->mClass;
-               }
-
-               $attrLabel = [ 'for' => $this->mID ];
-               if ( isset( $attr['title'] ) ) {
-                       // propagate tooltip to label
-                       $attrLabel['title'] = $attr['title'];
-               }
-
-               $chkLabel = Xml::check( $this->mName, $value, $attr ) .
-                       '&#160;' .
-                       Html::rawElement( 'label', $attrLabel, $this->mLabel );
-
-               if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
-                       $chkLabel = Html::rawElement(
-                               'div',
-                               [ 'class' => 'mw-ui-checkbox' ],
-                               $chkLabel
-                       );
-               }
-
-               return $chkLabel;
-       }
-
-       /**
-        * Get the OOUI version of this field.
-        * @since 1.26
-        * @param string $value
-        * @return OOUI\CheckboxInputWidget The checkbox widget.
-        */
-       public function getInputOOUI( $value ) {
-               if ( !empty( $this->mParams['invert'] ) ) {
-                       $value = !$value;
-               }
-
-               $attr = $this->getTooltipAndAccessKey();
-               $attr['id'] = $this->mID;
-               $attr['name'] = $this->mName;
-
-               $attr += OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
-               );
-
-               if ( $this->mClass !== '' ) {
-                       $attr['classes'] = [ $this->mClass ];
-               }
-
-               $attr['selected'] = $value;
-               $attr['value'] = '1'; // Nasty hack, but needed to make this work
-
-               return new OOUI\CheckboxInputWidget( $attr );
-       }
-
-       /**
-        * For a checkbox, the label goes on the right hand side, and is
-        * added in getInputHTML(), rather than HTMLFormField::getRow()
-        *
-        * ...unless OOUI is being used, in which case we actually return
-        * the label here.
-        *
-        * @return string
-        */
-       function getLabel() {
-               if ( $this->mParent instanceof OOUIHTMLForm ) {
-                       return $this->mLabel;
-               } elseif (
-                       $this->mParent instanceof HTMLForm &&
-                       $this->mParent->getDisplayFormat() === 'div'
-               ) {
-                       return '';
-               } else {
-                       return '&#160;';
-               }
-       }
-
-       /**
-        * Get label alignment when generating field for OOUI.
-        * @return string 'left', 'right', 'top' or 'inline'
-        */
-       protected function getLabelAlignOOUI() {
-               return 'inline';
-       }
-
-       /**
-        * checkboxes don't need a label.
-        * @return bool
-        */
-       protected function needsLabel() {
-               return false;
-       }
-
-       /**
-        * @param WebRequest $request
-        *
-        * @return bool
-        */
-       function loadDataFromRequest( $request ) {
-               $invert = isset( $this->mParams['invert'] ) && $this->mParams['invert'];
-
-               // GetCheck won't work like we want for checks.
-               // Fetch the value in either one of the two following case:
-               // - we have a valid submit attempt (form was just submitted, or a GET URL forged by the user)
-               // - checkbox name has a value (false or true), ie is not null
-               if ( $this->isSubmitAttempt( $request ) || $request->getVal( $this->mName ) !== null ) {
-                       return $invert
-                               ? !$request->getBool( $this->mName )
-                               : $request->getBool( $this->mName );
-               } else {
-                       return (bool)$this->getDefault();
-               }
-       }
-}
diff --git a/includes/htmlform/HTMLCheckMatrix.php b/includes/htmlform/HTMLCheckMatrix.php
deleted file mode 100644 (file)
index b324fb6..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-<?php
-
-/**
- * A checkbox matrix
- * Operates similarly to HTMLMultiSelectField, but instead of using an array of
- * options, uses an array of rows and an array of columns to dynamically
- * construct a matrix of options. The tags used to identify a particular cell
- * are of the form "columnName-rowName"
- *
- * Options:
- *   - columns
- *     - Required list of columns in the matrix.
- *   - rows
- *     - Required list of rows in the matrix.
- *   - force-options-on
- *     - Accepts array of column-row tags to be displayed as enabled but unavailable to change
- *   - force-options-off
- *     - Accepts array of column-row tags to be displayed as disabled but unavailable to change.
- *   - tooltips
- *     - Optional array mapping row label to tooltip content
- *   - tooltip-class
- *     - Optional CSS class used on tooltip container span. Defaults to mw-icon-question.
- */
-class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
-       static private $requiredParams = [
-               // Required by underlying HTMLFormField
-               'fieldname',
-               // Required by HTMLCheckMatrix
-               'rows',
-               'columns'
-       ];
-
-       public function __construct( $params ) {
-               $missing = array_diff( self::$requiredParams, array_keys( $params ) );
-               if ( $missing ) {
-                       throw new HTMLFormFieldRequiredOptionsException( $this, $missing );
-               }
-               parent::__construct( $params );
-       }
-
-       function validate( $value, $alldata ) {
-               $rows = $this->mParams['rows'];
-               $columns = $this->mParams['columns'];
-
-               // Make sure user-defined validation callback is run
-               $p = parent::validate( $value, $alldata );
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               // Make sure submitted value is an array
-               if ( !is_array( $value ) ) {
-                       return false;
-               }
-
-               // If all options are valid, array_intersect of the valid options
-               // and the provided options will return the provided options.
-               $validOptions = [];
-               foreach ( $rows as $rowTag ) {
-                       foreach ( $columns as $columnTag ) {
-                               $validOptions[] = $columnTag . '-' . $rowTag;
-                       }
-               }
-               $validValues = array_intersect( $value, $validOptions );
-               if ( count( $validValues ) == count( $value ) ) {
-                       return true;
-               } else {
-                       return $this->msg( 'htmlform-select-badoption' )->parse();
-               }
-       }
-
-       /**
-        * Build a table containing a matrix of checkbox options.
-        * The value of each option is a combination of the row tag and column tag.
-        * mParams['rows'] is an array with row labels as keys and row tags as values.
-        * mParams['columns'] is an array with column labels as keys and column tags as values.
-        *
-        * @param array $value Array of the options that should be checked
-        *
-        * @return string
-        */
-       function getInputHTML( $value ) {
-               $html = '';
-               $tableContents = '';
-               $rows = $this->mParams['rows'];
-               $columns = $this->mParams['columns'];
-
-               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
-
-               // Build the column headers
-               $headerContents = Html::rawElement( 'td', [], '&#160;' );
-               foreach ( $columns as $columnLabel => $columnTag ) {
-                       $headerContents .= Html::rawElement( 'td', [], $columnLabel );
-               }
-               $tableContents .= Html::rawElement( 'tr', [], "\n$headerContents\n" );
-
-               $tooltipClass = 'mw-icon-question';
-               if ( isset( $this->mParams['tooltip-class'] ) ) {
-                       $tooltipClass = $this->mParams['tooltip-class'];
-               }
-
-               // Build the options matrix
-               foreach ( $rows as $rowLabel => $rowTag ) {
-                       // Append tooltip if configured
-                       if ( isset( $this->mParams['tooltips'][$rowLabel] ) ) {
-                               $tooltipAttribs = [
-                                       'class' => "mw-htmlform-tooltip $tooltipClass",
-                                       'title' => $this->mParams['tooltips'][$rowLabel],
-                               ];
-                               $rowLabel .= ' ' . Html::element( 'span', $tooltipAttribs, '' );
-                       }
-                       $rowContents = Html::rawElement( 'td', [], $rowLabel );
-                       foreach ( $columns as $columnTag ) {
-                               $thisTag = "$columnTag-$rowTag";
-                               // Construct the checkbox
-                               $thisAttribs = [
-                                       'id' => "{$this->mID}-$thisTag",
-                                       'value' => $thisTag,
-                               ];
-                               $checked = in_array( $thisTag, (array)$value, true );
-                               if ( $this->isTagForcedOff( $thisTag ) ) {
-                                       $checked = false;
-                                       $thisAttribs['disabled'] = 1;
-                               } elseif ( $this->isTagForcedOn( $thisTag ) ) {
-                                       $checked = true;
-                                       $thisAttribs['disabled'] = 1;
-                               }
-
-                               $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs );
-
-                               $rowContents .= Html::rawElement(
-                                       'td',
-                                       [],
-                                       $checkbox
-                               );
-                       }
-                       $tableContents .= Html::rawElement( 'tr', [], "\n$rowContents\n" );
-               }
-
-               // Put it all in a table
-               $html .= Html::rawElement( 'table',
-                               [ 'class' => 'mw-htmlform-matrix' ],
-                               Html::rawElement( 'tbody', [], "\n$tableContents\n" ) ) . "\n";
-
-               return $html;
-       }
-
-       protected function getOneCheckbox( $checked, $attribs ) {
-               if ( $this->mParent instanceof OOUIHTMLForm ) {
-                       return new OOUI\CheckboxInputWidget( [
-                               'name' => "{$this->mName}[]",
-                               'selected' => $checked,
-                       ] + OOUI\Element::configFromHtmlAttributes(
-                               $attribs
-                       ) );
-               } else {
-                       $checkbox = Xml::check( "{$this->mName}[]", $checked, $attribs );
-                       if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
-                               $checkbox = Html::openElement( 'div', [ 'class' => 'mw-ui-checkbox' ] ) .
-                                       $checkbox .
-                                       Html::element( 'label', [ 'for' => $attribs['id'] ] ) .
-                                       Html::closeElement( 'div' );
-                       }
-                       return $checkbox;
-               }
-       }
-
-       protected function isTagForcedOff( $tag ) {
-               return isset( $this->mParams['force-options-off'] )
-                       && in_array( $tag, $this->mParams['force-options-off'] );
-       }
-
-       protected function isTagForcedOn( $tag ) {
-               return isset( $this->mParams['force-options-on'] )
-                       && in_array( $tag, $this->mParams['force-options-on'] );
-       }
-
-       /**
-        * Get the complete table row for the input, including help text,
-        * labels, and whatever.
-        * We override this function since the label should always be on a separate
-        * line above the options in the case of a checkbox matrix, i.e. it's always
-        * a "vertical-label".
-        *
-        * @param string $value The value to set the input to
-        *
-        * @return string Complete HTML table row
-        */
-       function getTableRow( $value ) {
-               list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
-               $inputHtml = $this->getInputHTML( $value );
-               $fieldType = get_class( $this );
-               $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
-               $cellAttributes = [ 'colspan' => 2 ];
-
-               $hideClass = '';
-               $hideAttributes = [];
-               if ( $this->mHideIf ) {
-                       $hideAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
-                       $hideClass = 'mw-htmlform-hide-if';
-               }
-
-               $label = $this->getLabelHtml( $cellAttributes );
-
-               $field = Html::rawElement(
-                       'td',
-                       [ 'class' => 'mw-input' ] + $cellAttributes,
-                       $inputHtml . "\n$errors"
-               );
-
-               $html = Html::rawElement( 'tr',
-                       [ 'class' => "mw-htmlform-vertical-label $hideClass" ] + $hideAttributes,
-                       $label );
-               $html .= Html::rawElement( 'tr',
-                       [ 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $hideClass" ] +
-                               $hideAttributes,
-                       $field );
-
-               return $html . $helptext;
-       }
-
-       /**
-        * @param WebRequest $request
-        *
-        * @return array
-        */
-       function loadDataFromRequest( $request ) {
-               if ( $this->isSubmitAttempt( $request ) ) {
-                       // Checkboxes are just not added to the request arrays if they're not checked,
-                       // so it's perfectly possible for there not to be an entry at all
-                       return $request->getArray( $this->mName, [] );
-               } else {
-                       // That's ok, the user has not yet submitted the form, so show the defaults
-                       return $this->getDefault();
-               }
-       }
-
-       function getDefault() {
-               if ( isset( $this->mDefault ) ) {
-                       return $this->mDefault;
-               } else {
-                       return [];
-               }
-       }
-
-       function filterDataForSubmit( $data ) {
-               $columns = HTMLFormField::flattenOptions( $this->mParams['columns'] );
-               $rows = HTMLFormField::flattenOptions( $this->mParams['rows'] );
-               $res = [];
-               foreach ( $columns as $column ) {
-                       foreach ( $rows as $row ) {
-                               // Make sure option hasn't been forced
-                               $thisTag = "$column-$row";
-                               if ( $this->isTagForcedOff( $thisTag ) ) {
-                                       $res[$thisTag] = false;
-                               } elseif ( $this->isTagForcedOn( $thisTag ) ) {
-                                       $res[$thisTag] = true;
-                               } else {
-                                       $res[$thisTag] = in_array( $thisTag, $data );
-                               }
-                       }
-               }
-
-               return $res;
-       }
-}
diff --git a/includes/htmlform/HTMLComboboxField.php b/includes/htmlform/HTMLComboboxField.php
deleted file mode 100644 (file)
index 778aedb..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-/**
- * A combo box field.
- *
- * You can think of it as a dropdown select with the ability to add custom options,
- * or as a text field with input suggestions (autocompletion).
- *
- * When JavaScript is not supported or enabled, it uses HTML5 `<datalist>` element.
- *
- * Besides the parameters recognized by HTMLTextField, the following are
- * recognized:
- *   options-messages - As for HTMLSelectField
- *   options - As for HTMLSelectField
- *   options-message - As for HTMLSelectField
- */
-class HTMLComboboxField extends HTMLTextField {
-       // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
-       public function getAttributes( array $list ) {
-               $attribs = [
-                       'type' => 'text',
-                       'list' => $this->mName . '-datalist',
-               ] + parent::getAttributes( $list );
-
-               return $attribs;
-       }
-
-       function getInputHTML( $value ) {
-               $datalist = new XmlSelect( false, $this->mName . '-datalist' );
-               $datalist->setTagName( 'datalist' );
-               $datalist->addOptions( $this->getOptions() );
-
-               return parent::getInputHTML( $value ) . $datalist->getHTML();
-       }
-
-       function getInputOOUI( $value ) {
-               $disabled = false;
-               $allowedParams = [ 'tabindex' ];
-               $attribs = OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( $allowedParams )
-               );
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['classes'] = [ $this->mClass ];
-               }
-
-               if ( !empty( $this->mParams['disabled'] ) ) {
-                       $disabled = true;
-               }
-
-               return new OOUI\ComboBoxInputWidget( [
-                       'name' => $this->mName,
-                       'id' => $this->mID,
-                       'options' => $this->getOptionsOOUI(),
-                       'value' => strval( $value ),
-                       'disabled' => $disabled,
-               ] + $attribs );
-       }
-}
diff --git a/includes/htmlform/HTMLEditTools.php b/includes/htmlform/HTMLEditTools.php
deleted file mode 100644 (file)
index 1b5d1fb..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-class HTMLEditTools extends HTMLFormField {
-       public function getInputHTML( $value ) {
-               return '';
-       }
-
-       public function getTableRow( $value ) {
-               $msg = $this->formatMsg();
-
-               return
-                       '<tr><td></td><td class="mw-input">' .
-                       '<div class="mw-editTools">' .
-                       $msg->parseAsBlock() .
-                       "</div></td></tr>\n";
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getDiv( $value ) {
-               $msg = $this->formatMsg();
-
-               return '<div class="mw-editTools">' . $msg->parseAsBlock() . '</div>';
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getRaw( $value ) {
-               return $this->getDiv( $value );
-       }
-
-       protected function formatMsg() {
-               if ( empty( $this->mParams['message'] ) ) {
-                       $msg = $this->msg( 'edittools' );
-               } else {
-                       $msg = $this->getMessage( $this->mParams['message'] );
-                       if ( $msg->isDisabled() ) {
-                               $msg = $this->msg( 'edittools' );
-                       }
-               }
-               $msg->inContentLanguage();
-
-               return $msg;
-       }
-}
diff --git a/includes/htmlform/HTMLFloatField.php b/includes/htmlform/HTMLFloatField.php
deleted file mode 100644 (file)
index 2ef4978..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/**
- * A field that will contain a numeric value
- */
-class HTMLFloatField extends HTMLTextField {
-       function getSize() {
-               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 20;
-       }
-
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               $value = trim( $value );
-
-               # http://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers
-               # with the addition that a leading '+' sign is ok.
-               if ( !preg_match( '/^((\+|\-)?\d+(\.\d+)?(E(\+|\-)?\d+)?)?$/i', $value ) ) {
-                       return $this->msg( 'htmlform-float-invalid' )->parseAsBlock();
-               }
-
-               # The "int" part of these message names is rather confusing.
-               # They make equal sense for all numbers.
-               if ( isset( $this->mParams['min'] ) ) {
-                       $min = $this->mParams['min'];
-
-                       if ( $min > $value ) {
-                               return $this->msg( 'htmlform-int-toolow', $min )->parseAsBlock();
-                       }
-               }
-
-               if ( isset( $this->mParams['max'] ) ) {
-                       $max = $this->mParams['max'];
-
-                       if ( $max < $value ) {
-                               return $this->msg( 'htmlform-int-toohigh', $max )->parseAsBlock();
-                       }
-               }
-
-               return true;
-       }
-}
diff --git a/includes/htmlform/HTMLFormFieldCloner.php b/includes/htmlform/HTMLFormFieldCloner.php
deleted file mode 100644 (file)
index ec1bd84..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-<?php
-
-/**
- * A container for HTMLFormFields that allows for multiple copies of the set of
- * fields to be displayed to and entered by the user.
- *
- * Recognized parameters, besides the general ones, include:
- *   fields - HTMLFormField descriptors for the subfields this cloner manages.
- *     The format is just like for the HTMLForm. A field with key 'delete' is
- *     special: it must have type = submit and will serve to delete the group
- *     of fields.
- *   required - If specified, at least one group of fields must be submitted.
- *   format - HTMLForm display format to use when displaying the subfields:
- *     'table', 'div', or 'raw'.
- *   row-legend - If non-empty, each group of subfields will be enclosed in a
- *     fieldset. The value is the name of a message key to use as the legend.
- *   create-button-message - Message to use as the text of the button to
- *     add an additional group of fields.
- *   delete-button-message - Message to use as the text of automatically-
- *     generated 'delete' button. Ignored if 'delete' is included in 'fields'.
- *
- * In the generated HTML, the subfields will be named along the lines of
- * "clonerName[index][fieldname]", with ids "clonerId--index--fieldid". 'index'
- * may be a number or an arbitrary string, and may likely change when the page
- * is resubmitted. Cloners may be nested, resulting in field names along the
- * lines of "cloner1Name[index1][cloner2Name][index2][fieldname]" and
- * corresponding ids.
- *
- * Use of cloner may result in submissions of the page that are not submissions
- * of the HTMLForm, when non-JavaScript clients use the create or remove buttons.
- *
- * The result is an array, with values being arrays mapping subfield names to
- * their values. On non-HTMLForm-submission page loads, there may also be
- * additional (string) keys present with other types of values.
- *
- * @since 1.23
- */
-class HTMLFormFieldCloner extends HTMLFormField {
-       private static $counter = 0;
-
-       /**
-        * @var string String uniquely identifying this cloner instance and
-        * unlikely to exist otherwise in the generated HTML, while still being
-        * valid as part of an HTML id.
-        */
-       protected $uniqueId;
-
-       public function __construct( $params ) {
-               $this->uniqueId = get_class( $this ) . ++self::$counter . 'x';
-               parent::__construct( $params );
-
-               if ( empty( $this->mParams['fields'] ) || !is_array( $this->mParams['fields'] ) ) {
-                       throw new MWException( 'HTMLFormFieldCloner called without any fields' );
-               }
-
-               // Make sure the delete button, if explicitly specified, is sane
-               if ( isset( $this->mParams['fields']['delete'] ) ) {
-                       $class = 'mw-htmlform-cloner-delete-button';
-                       $info = $this->mParams['fields']['delete'] + [
-                               'cssclass' => $class
-                       ];
-                       unset( $info['name'], $info['class'] );
-
-                       if ( !isset( $info['type'] ) || $info['type'] !== 'submit' ) {
-                               throw new MWException(
-                                       'HTMLFormFieldCloner delete field, if specified, must be of type "submit"'
-                               );
-                       }
-
-                       if ( !in_array( $class, explode( ' ', $info['cssclass'] ) ) ) {
-                               $info['cssclass'] .= " $class";
-                       }
-
-                       $this->mParams['fields']['delete'] = $info;
-               }
-       }
-
-       /**
-        * Create the HTMLFormFields that go inside this element, using the
-        * specified key.
-        *
-        * @param string $key Array key under which these fields should be named
-        * @return HTMLFormField[]
-        */
-       protected function createFieldsForKey( $key ) {
-               $fields = [];
-               foreach ( $this->mParams['fields'] as $fieldname => $info ) {
-                       $name = "{$this->mName}[$key][$fieldname]";
-                       if ( isset( $info['name'] ) ) {
-                               $info['name'] = "{$this->mName}[$key][{$info['name']}]";
-                       } else {
-                               $info['name'] = $name;
-                       }
-                       if ( isset( $info['id'] ) ) {
-                               $info['id'] = Sanitizer::escapeId( "{$this->mID}--$key--{$info['id']}" );
-                       } else {
-                               $info['id'] = Sanitizer::escapeId( "{$this->mID}--$key--$fieldname" );
-                       }
-                       $field = HTMLForm::loadInputFromParameters( $name, $info, $this->mParent );
-                       $fields[$fieldname] = $field;
-               }
-               return $fields;
-       }
-
-       /**
-        * Re-key the specified values array to match the names applied by
-        * createFieldsForKey().
-        *
-        * @param string $key Array key under which these fields should be named
-        * @param array $values Values array from the request
-        * @return array
-        */
-       protected function rekeyValuesArray( $key, $values ) {
-               $data = [];
-               foreach ( $values as $fieldname => $value ) {
-                       $name = "{$this->mName}[$key][$fieldname]";
-                       $data[$name] = $value;
-               }
-               return $data;
-       }
-
-       protected function needsLabel() {
-               return false;
-       }
-
-       public function loadDataFromRequest( $request ) {
-               // It's possible that this might be posted with no fields. Detect that
-               // by looking for an edit token.
-               if ( !$request->getCheck( 'wpEditToken' ) && $request->getArray( $this->mName ) === null ) {
-                       return $this->getDefault();
-               }
-
-               $values = $request->getArray( $this->mName );
-               if ( $values === null ) {
-                       $values = [];
-               }
-
-               $ret = [];
-               foreach ( $values as $key => $value ) {
-                       if ( $key === 'create' || isset( $value['delete'] ) ) {
-                               $ret['nonjs'] = 1;
-                               continue;
-                       }
-
-                       // Add back in $request->getValues() so things that look for e.g.
-                       // wpEditToken don't fail.
-                       $data = $this->rekeyValuesArray( $key, $value ) + $request->getValues();
-
-                       $fields = $this->createFieldsForKey( $key );
-                       $subrequest = new DerivativeRequest( $request, $data, $request->wasPosted() );
-                       $row = [];
-                       foreach ( $fields as $fieldname => $field ) {
-                               if ( $field->skipLoadData( $subrequest ) ) {
-                                       continue;
-                               } elseif ( !empty( $field->mParams['disabled'] ) ) {
-                                       $row[$fieldname] = $field->getDefault();
-                               } else {
-                                       $row[$fieldname] = $field->loadDataFromRequest( $subrequest );
-                               }
-                       }
-                       $ret[] = $row;
-               }
-
-               if ( isset( $values['create'] ) ) {
-                       // Non-JS client clicked the "create" button.
-                       $fields = $this->createFieldsForKey( $this->uniqueId );
-                       $row = [];
-                       foreach ( $fields as $fieldname => $field ) {
-                               if ( !empty( $field->mParams['nodata'] ) ) {
-                                       continue;
-                               } else {
-                                       $row[$fieldname] = $field->getDefault();
-                               }
-                       }
-                       $ret[] = $row;
-               }
-
-               return $ret;
-       }
-
-       public function getDefault() {
-               $ret = parent::getDefault();
-
-               // The default default is one entry with all subfields at their
-               // defaults.
-               if ( $ret === null ) {
-                       $fields = $this->createFieldsForKey( $this->uniqueId );
-                       $row = [];
-                       foreach ( $fields as $fieldname => $field ) {
-                               if ( !empty( $field->mParams['nodata'] ) ) {
-                                       continue;
-                               } else {
-                                       $row[$fieldname] = $field->getDefault();
-                               }
-                       }
-                       $ret = [ $row ];
-               }
-
-               return $ret;
-       }
-
-       public function cancelSubmit( $values, $alldata ) {
-               if ( isset( $values['nonjs'] ) ) {
-                       return true;
-               }
-
-               foreach ( $values as $key => $value ) {
-                       $fields = $this->createFieldsForKey( $key );
-                       foreach ( $fields as $fieldname => $field ) {
-                               if ( !array_key_exists( $fieldname, $value ) ) {
-                                       continue;
-                               }
-                               if ( $field->cancelSubmit( $value[$fieldname], $alldata ) ) {
-                                       return true;
-                               }
-                       }
-               }
-
-               return parent::cancelSubmit( $values, $alldata );
-       }
-
-       public function validate( $values, $alldata ) {
-               if ( isset( $this->mParams['required'] )
-                       && $this->mParams['required'] !== false
-                       && !$values
-               ) {
-                       return $this->msg( 'htmlform-cloner-required' )->parseAsBlock();
-               }
-
-               if ( isset( $values['nonjs'] ) ) {
-                       // The submission was a non-JS create/delete click, so fail
-                       // validation in case cancelSubmit() somehow didn't already handle
-                       // it.
-                       return false;
-               }
-
-               foreach ( $values as $key => $value ) {
-                       $fields = $this->createFieldsForKey( $key );
-                       foreach ( $fields as $fieldname => $field ) {
-                               if ( !array_key_exists( $fieldname, $value ) ) {
-                                       continue;
-                               }
-                               $ok = $field->validate( $value[$fieldname], $alldata );
-                               if ( $ok !== true ) {
-                                       return false;
-                               }
-                       }
-               }
-
-               return parent::validate( $values, $alldata );
-       }
-
-       /**
-        * Get the input HTML for the specified key.
-        *
-        * @param string $key Array key under which the fields should be named
-        * @param array $values
-        * @return string
-        */
-       protected function getInputHTMLForKey( $key, $values ) {
-               $displayFormat = isset( $this->mParams['format'] )
-                       ? $this->mParams['format']
-                       : $this->mParent->getDisplayFormat();
-
-               // Conveniently, PHP method names are case-insensitive.
-               $getFieldHtmlMethod = $displayFormat == 'table' ? 'getTableRow' : ( 'get' . $displayFormat );
-
-               $html = '';
-               $hidden = '';
-               $hasLabel = false;
-
-               $fields = $this->createFieldsForKey( $key );
-               foreach ( $fields as $fieldname => $field ) {
-                       $v = array_key_exists( $fieldname, $values )
-                               ? $values[$fieldname]
-                               : $field->getDefault();
-
-                       if ( $field instanceof HTMLHiddenField ) {
-                               // HTMLHiddenField doesn't generate its own HTML
-                               list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
-                               $hidden .= Html::hidden( $name, $value, $params ) . "\n";
-                       } else {
-                               $html .= $field->$getFieldHtmlMethod( $v );
-
-                               $labelValue = trim( $field->getLabel() );
-                               if ( $labelValue != '&#160;' && $labelValue !== '' ) {
-                                       $hasLabel = true;
-                               }
-                       }
-               }
-
-               if ( !isset( $fields['delete'] ) ) {
-                       $name = "{$this->mName}[$key][delete]";
-                       $label = isset( $this->mParams['delete-button-message'] )
-                               ? $this->mParams['delete-button-message']
-                               : 'htmlform-cloner-delete';
-                       $field = HTMLForm::loadInputFromParameters( $name, [
-                               'type' => 'submit',
-                               'name' => $name,
-                               'id' => Sanitizer::escapeId( "{$this->mID}--$key--delete" ),
-                               'cssclass' => 'mw-htmlform-cloner-delete-button',
-                               'default' => $this->getMessage( $label )->text(),
-                       ], $this->mParent );
-                       $v = $field->getDefault();
-
-                       if ( $displayFormat === 'table' ) {
-                               $html .= $field->$getFieldHtmlMethod( $v );
-                       } else {
-                               $html .= $field->getInputHTML( $v );
-                       }
-               }
-
-               if ( $displayFormat !== 'raw' ) {
-                       $classes = [
-                               'mw-htmlform-cloner-row',
-                       ];
-
-                       if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
-                               $classes[] = 'mw-htmlform-nolabel';
-                       }
-
-                       $attribs = [
-                               'class' => implode( ' ', $classes ),
-                       ];
-
-                       if ( $displayFormat === 'table' ) {
-                               $html = Html::rawElement( 'table',
-                                       $attribs,
-                                       Html::rawElement( 'tbody', [], "\n$html\n" ) ) . "\n";
-                       } else {
-                               $html = Html::rawElement( 'div', $attribs, "\n$html\n" );
-                       }
-               }
-
-               $html .= $hidden;
-
-               if ( !empty( $this->mParams['row-legend'] ) ) {
-                       $legend = $this->msg( $this->mParams['row-legend'] )->text();
-                       $html = Xml::fieldset( $legend, $html );
-               }
-
-               return $html;
-       }
-
-       public function getInputHTML( $values ) {
-               $html = '';
-
-               foreach ( (array)$values as $key => $value ) {
-                       if ( $key === 'nonjs' ) {
-                               continue;
-                       }
-                       $html .= Html::rawElement( 'li', [ 'class' => 'mw-htmlform-cloner-li' ],
-                               $this->getInputHTMLForKey( $key, $value )
-                       );
-               }
-
-               $template = $this->getInputHTMLForKey( $this->uniqueId, null );
-               $html = Html::rawElement( 'ul', [
-                       'id' => "mw-htmlform-cloner-list-{$this->mID}",
-                       'class' => 'mw-htmlform-cloner-ul',
-                       'data-template' => $template,
-                       'data-unique-id' => $this->uniqueId,
-               ], $html );
-
-               $name = "{$this->mName}[create]";
-               $label = isset( $this->mParams['create-button-message'] )
-                       ? $this->mParams['create-button-message']
-                       : 'htmlform-cloner-create';
-               $field = HTMLForm::loadInputFromParameters( $name, [
-                       'type' => 'submit',
-                       'name' => $name,
-                       'id' => Sanitizer::escapeId( "{$this->mID}--create" ),
-                       'cssclass' => 'mw-htmlform-cloner-create-button',
-                       'default' => $this->getMessage( $label )->text(),
-               ], $this->mParent );
-               $html .= $field->getInputHTML( $field->getDefault() );
-
-               return $html;
-       }
-}
diff --git a/includes/htmlform/HTMLFormFieldWithButton.php b/includes/htmlform/HTMLFormFieldWithButton.php
deleted file mode 100644 (file)
index bcb07bd..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * Enables HTMLFormField elements to be build with a button.
- */
-class HTMLFormFieldWithButton extends HTMLFormField {
-       /** @var string $mButtonClass CSS class for the button in this field */
-       protected $mButtonClass = '';
-
-       /** @var string|integer $mButtonId Element ID for the button in this field */
-       protected $mButtonId = '';
-
-       /** @var string $mButtonName Name the button in this field */
-       protected $mButtonName = '';
-
-       /** @var string $mButtonType Type of the button in this field (e.g. button or submit) */
-       protected $mButtonType = 'submit';
-
-       /** @var string $mButtonType Value for the button in this field */
-       protected $mButtonValue;
-
-       /** @var string $mButtonType Value for the button in this field */
-       protected $mButtonFlags = [ 'progressive' ];
-
-       public function __construct( $info ) {
-               if ( isset( $info['buttonclass'] ) ) {
-                       $this->mButtonClass = $info['buttonclass'];
-               }
-               if ( isset( $info['buttonid'] ) ) {
-                       $this->mButtonId = $info['buttonid'];
-               }
-               if ( isset( $info['buttonname'] ) ) {
-                       $this->mButtonName = $info['buttonname'];
-               }
-               if ( isset( $info['buttondefault'] ) ) {
-                       $this->mButtonValue = $info['buttondefault'];
-               }
-               if ( isset( $info['buttontype'] ) ) {
-                       $this->mButtonType = $info['buttontype'];
-               }
-               if ( isset( $info['buttonflags'] ) ) {
-                       $this->mButtonFlags = $info['buttonflags'];
-               }
-               parent::__construct( $info );
-       }
-
-       public function getInputHTML( $value ) {
-               $attr = [
-                       'class' => 'mw-htmlform-submit ' . $this->mButtonClass,
-                       'id' => $this->mButtonId,
-               ] + $this->getAttributes( [ 'disabled', 'tabindex' ] );
-
-               return Html::input( $this->mButtonName, $this->mButtonValue, $this->mButtonType, $attr );
-       }
-
-       public function getInputOOUI( $value ) {
-               return new OOUI\ButtonInputWidget( [
-                       'name' => $this->mButtonName,
-                       'value' => $this->mButtonValue,
-                       'type' => $this->mButtonType,
-                       'label' => $this->mButtonValue,
-                       'flags' => $this->mButtonFlags,
-               ] + OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
-               ) );
-       }
-
-       /**
-        * Combines the passed element with a button.
-        * @param String $element Element to combine the button with.
-        * @return String
-        */
-       public function getElement( $element ) {
-               return $element . '&#160;' . $this->getInputHTML( '' );
-       }
-}
diff --git a/includes/htmlform/HTMLHiddenField.php b/includes/htmlform/HTMLHiddenField.php
deleted file mode 100644 (file)
index c0fce2b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-class HTMLHiddenField extends HTMLFormField {
-       protected $outputAsDefault = true;
-
-       public function __construct( $params ) {
-               parent::__construct( $params );
-
-               if ( isset( $this->mParams['output-as-default'] ) ) {
-                       $this->outputAsDefault = (bool)$this->mParams['output-as-default'];
-               }
-
-               # Per HTML5 spec, hidden fields cannot be 'required'
-               # http://www.w3.org/TR/html5/forms.html#hidden-state-%28type=hidden%29
-               unset( $this->mParams['required'] );
-       }
-
-       public function getHiddenFieldData( $value ) {
-               $params = [];
-               if ( $this->mID ) {
-                       $params['id'] = $this->mID;
-               }
-
-               if ( $this->outputAsDefault ) {
-                       $value = $this->mDefault;
-               }
-
-               return [ $this->mName, $value, $params ];
-       }
-
-       public function getTableRow( $value ) {
-               list( $name, $value, $params ) = $this->getHiddenFieldData( $value );
-               $this->mParent->addHiddenField( $name, $value, $params );
-               return '';
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getDiv( $value ) {
-               return $this->getTableRow( $value );
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getRaw( $value ) {
-               return $this->getTableRow( $value );
-       }
-
-       public function getInputHTML( $value ) {
-               return '';
-       }
-
-       public function canDisplayErrors() {
-               return false;
-       }
-
-       public function hasVisibleOutput() {
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLInfoField.php b/includes/htmlform/HTMLInfoField.php
deleted file mode 100644 (file)
index ada4fb6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-/**
- * An information field (text blob), not a proper input.
- */
-class HTMLInfoField extends HTMLFormField {
-       public function __construct( $info ) {
-               $info['nodata'] = true;
-
-               parent::__construct( $info );
-       }
-
-       public function getInputHTML( $value ) {
-               return !empty( $this->mParams['raw'] ) ? $value : htmlspecialchars( $value );
-       }
-
-       public function getInputOOUI( $value ) {
-               if ( !empty( $this->mParams['raw'] ) ) {
-                       $value = new OOUI\HtmlSnippet( $value );
-               }
-
-               return new OOUI\LabelWidget( [
-                       'label' => $value,
-               ] );
-       }
-
-       public function getTableRow( $value ) {
-               if ( !empty( $this->mParams['rawrow'] ) ) {
-                       return $value;
-               }
-
-               return parent::getTableRow( $value );
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getDiv( $value ) {
-               if ( !empty( $this->mParams['rawrow'] ) ) {
-                       return $value;
-               }
-
-               return parent::getDiv( $value );
-       }
-
-       /**
-        * @param string $value
-        * @return string
-        * @since 1.20
-        */
-       public function getRaw( $value ) {
-               if ( !empty( $this->mParams['rawrow'] ) ) {
-                       return $value;
-               }
-
-               return parent::getRaw( $value );
-       }
-
-       protected function needsLabel() {
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLIntField.php b/includes/htmlform/HTMLIntField.php
deleted file mode 100644 (file)
index b0148d9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * A field that must contain a number
- */
-class HTMLIntField extends HTMLFloatField {
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               # http://www.w3.org/TR/html5/infrastructure.html#signed-integers
-               # with the addition that a leading '+' sign is ok. Note that leading zeros
-               # are fine, and will be left in the input, which is useful for things like
-               # phone numbers when you know that they are integers (the HTML5 type=tel
-               # input does not require its value to be numeric).  If you want a tidier
-               # value to, eg, save in the DB, clean it up with intval().
-               if ( !preg_match( '/^((\+|\-)?\d+)?$/', trim( $value ) ) ) {
-                       return $this->msg( 'htmlform-int-invalid' )->parseAsBlock();
-               }
-
-               return true;
-       }
-}
diff --git a/includes/htmlform/HTMLMultiSelectField.php b/includes/htmlform/HTMLMultiSelectField.php
deleted file mode 100644 (file)
index a231b2f..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-
-/**
- * Multi-select field
- */
-class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable {
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               if ( !is_array( $value ) ) {
-                       return false;
-               }
-
-               # If all options are valid, array_intersect of the valid options
-               # and the provided options will return the provided options.
-               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
-
-               $validValues = array_intersect( $value, $validOptions );
-               if ( count( $validValues ) == count( $value ) ) {
-                       return true;
-               } else {
-                       return $this->msg( 'htmlform-select-badoption' )->parse();
-               }
-       }
-
-       function getInputHTML( $value ) {
-               $value = HTMLFormField::forceToStringRecursive( $value );
-               $html = $this->formatOptions( $this->getOptions(), $value );
-
-               return $html;
-       }
-
-       function formatOptions( $options, $value ) {
-               $html = '';
-
-               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
-
-               foreach ( $options as $label => $info ) {
-                       if ( is_array( $info ) ) {
-                               $html .= Html::rawElement( 'h1', [], $label ) . "\n";
-                               $html .= $this->formatOptions( $info, $value );
-                       } else {
-                               $thisAttribs = [
-                                       'id' => "{$this->mID}-$info",
-                                       'value' => $info,
-                               ];
-                               $checked = in_array( $info, $value, true );
-
-                               $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs, $label );
-
-                               $html .= ' ' . Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'mw-htmlform-flatlist-item' ],
-                                       $checkbox
-                               );
-                       }
-               }
-
-               return $html;
-       }
-
-       protected function getOneCheckbox( $checked, $attribs, $label ) {
-               if ( $this->mParent instanceof OOUIHTMLForm ) {
-                       throw new MWException( 'HTMLMultiSelectField#getOneCheckbox() is not supported' );
-               } else {
-                       $elementFunc = [ 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' ];
-                       $checkbox =
-                               Xml::check( "{$this->mName}[]", $checked, $attribs ) .
-                               '&#160;' .
-                               call_user_func( $elementFunc,
-                                       'label',
-                                       [ 'for' => $attribs['id'] ],
-                                       $label
-                               );
-                       if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
-                               $checkbox = Html::openElement( 'div', [ 'class' => 'mw-ui-checkbox' ] ) .
-                                       $checkbox .
-                                       Html::closeElement( 'div' );
-                       }
-                       return $checkbox;
-               }
-       }
-
-       /**
-        * Get the OOUI version of this field.
-        *
-        * @since 1.28
-        * @param string[] $value
-        * @return OOUI\CheckboxMultiselectInputWidget
-        */
-       public function getInputOOUI( $value ) {
-               $attr = $this->getTooltipAndAccessKey();
-               $attr['id'] = $this->mID;
-               $attr['name'] = "{$this->mName}[]";
-
-               $attr['value'] = $value;
-               $attr['options'] = $this->getOptionsOOUI();
-
-               if ( $this->mOptionsLabelsNotFromMessage ) {
-                       foreach ( $attr['options'] as &$option ) {
-                               $option['label'] = new OOUI\HtmlSnippet( $option['label'] );
-                       }
-               }
-
-               $attr += OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
-               );
-
-               if ( $this->mClass !== '' ) {
-                       $attr['classes'] = [ $this->mClass ];
-               }
-
-               return new OOUI\CheckboxMultiselectInputWidget( $attr );
-       }
-
-       /**
-        * @param WebRequest $request
-        *
-        * @return string
-        */
-       function loadDataFromRequest( $request ) {
-               if ( $this->isSubmitAttempt( $request ) ) {
-                       // Checkboxes are just not added to the request arrays if they're not checked,
-                       // so it's perfectly possible for there not to be an entry at all
-                       return $request->getArray( $this->mName, [] );
-               } else {
-                       // That's ok, the user has not yet submitted the form, so show the defaults
-                       return $this->getDefault();
-               }
-       }
-
-       function getDefault() {
-               if ( isset( $this->mDefault ) ) {
-                       return $this->mDefault;
-               } else {
-                       return [];
-               }
-       }
-
-       function filterDataForSubmit( $data ) {
-               $data = HTMLFormField::forceToStringRecursive( $data );
-               $options = HTMLFormField::flattenOptions( $this->getOptions() );
-
-               $res = [];
-               foreach ( $options as $opt ) {
-                       $res["$opt"] = in_array( $opt, $data, true );
-               }
-
-               return $res;
-       }
-
-       protected function needsLabel() {
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLRadioField.php b/includes/htmlform/HTMLRadioField.php
deleted file mode 100644 (file)
index e5b5e68..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-
-/**
- * Radio checkbox fields.
- */
-class HTMLRadioField extends HTMLFormField {
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               if ( !is_string( $value ) && !is_int( $value ) ) {
-                       return false;
-               }
-
-               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
-
-               if ( in_array( strval( $value ), $validOptions, true ) ) {
-                       return true;
-               } else {
-                       return $this->msg( 'htmlform-select-badoption' )->parse();
-               }
-       }
-
-       /**
-        * This returns a block of all the radio options, in one cell.
-        * @see includes/HTMLFormField#getInputHTML()
-        *
-        * @param string $value
-        *
-        * @return string
-        */
-       function getInputHTML( $value ) {
-               $html = $this->formatOptions( $this->getOptions(), strval( $value ) );
-
-               return $html;
-       }
-
-       function getInputOOUI( $value ) {
-               $options = [];
-               foreach ( $this->getOptions() as $label => $data ) {
-                       $options[] = [
-                               'data' => $data,
-                               'label' => $this->mOptionsLabelsNotFromMessage ? new OOUI\HtmlSnippet( $label ) : $label,
-                       ];
-               }
-
-               return new OOUI\RadioSelectInputWidget( [
-                       'name' => $this->mName,
-                       'id' => $this->mID,
-                       'value' => $value,
-                       'options' => $options,
-               ] + OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
-               ) );
-       }
-
-       function formatOptions( $options, $value ) {
-               global $wgUseMediaWikiUIEverywhere;
-
-               $html = '';
-
-               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
-               $elementFunc = [ 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' ];
-
-               # @todo Should this produce an unordered list perhaps?
-               foreach ( $options as $label => $info ) {
-                       if ( is_array( $info ) ) {
-                               $html .= Html::rawElement( 'h1', [], $label ) . "\n";
-                               $html .= $this->formatOptions( $info, $value );
-                       } else {
-                               $id = Sanitizer::escapeId( $this->mID . "-$info" );
-                               $classes = [ 'mw-htmlform-flatlist-item' ];
-                               if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
-                                       $classes[] = 'mw-ui-radio';
-                               }
-                               $radio = Xml::radio( $this->mName, $info, $info === $value, $attribs + [ 'id' => $id ] );
-                               $radio .= '&#160;' . call_user_func( $elementFunc, 'label', [ 'for' => $id ], $label );
-
-                               $html .= ' ' . Html::rawElement(
-                                       'div',
-                                       [ 'class' => $classes ],
-                                       $radio
-                               );
-                       }
-               }
-
-               return $html;
-       }
-
-       protected function needsLabel() {
-               return false;
-       }
-}
diff --git a/includes/htmlform/HTMLSelectAndOtherField.php b/includes/htmlform/HTMLSelectAndOtherField.php
deleted file mode 100644 (file)
index e75c2b2..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-<?php
-
-/**
- * Double field with a dropdown list constructed from a system message in the format
- *     * Optgroup header
- *     ** <option value>
- *     * New Optgroup header
- * Plus a text field underneath for an additional reason.  The 'value' of the field is
- * "<select>: <extra reason>", or "<extra reason>" if nothing has been selected in the
- * select dropdown.
- * @todo FIXME: If made 'required', only the text field should be compulsory.
- */
-class HTMLSelectAndOtherField extends HTMLSelectField {
-       function __construct( $params ) {
-               if ( array_key_exists( 'other', $params ) ) {
-                       // Do nothing
-               } elseif ( array_key_exists( 'other-message', $params ) ) {
-                       $params['other'] = $this->getMessage( $params['other-message'] )->plain();
-               } else {
-                       $params['other'] = $this->msg( 'htmlform-selectorother-other' )->plain();
-               }
-
-               parent::__construct( $params );
-
-               if ( $this->getOptions() === null ) {
-                       // Sulk
-                       throw new MWException( 'HTMLSelectAndOtherField called without any options' );
-               }
-               if ( !in_array( 'other', $this->mOptions, true ) ) {
-                       // Have 'other' always as first element
-                       $this->mOptions = [ $params['other'] => 'other' ] + $this->mOptions;
-               }
-               $this->mFlatOptions = self::flattenOptions( $this->getOptions() );
-
-       }
-
-       function getInputHTML( $value ) {
-               $select = parent::getInputHTML( $value[1] );
-
-               $textAttribs = [
-                       'id' => $this->mID . '-other',
-                       'size' => $this->getSize(),
-                       'class' => [ 'mw-htmlform-select-and-other-field' ],
-                       'data-id-select' => $this->mID,
-               ];
-
-               if ( $this->mClass !== '' ) {
-                       $textAttribs['class'][] = $this->mClass;
-               }
-
-               $allowedParams = [
-                       'required',
-                       'autofocus',
-                       'multiple',
-                       'disabled',
-                       'tabindex',
-                       'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
-               ];
-
-               $textAttribs += $this->getAttributes( $allowedParams );
-
-               $textbox = Html::input( $this->mName . '-other', $value[2], 'text', $textAttribs );
-
-               return "$select<br />\n$textbox";
-       }
-
-       function getInputOOUI( $value ) {
-               return false;
-       }
-
-       /**
-        * @param WebRequest $request
-        *
-        * @return array("<overall message>","<select value>","<text field value>")
-        */
-       function loadDataFromRequest( $request ) {
-               if ( $request->getCheck( $this->mName ) ) {
-                       $list = $request->getText( $this->mName );
-                       $text = $request->getText( $this->mName . '-other' );
-
-                       // Should be built the same as in mediawiki.htmlform.js
-                       if ( $list == 'other' ) {
-                               $final = $text;
-                       } elseif ( !in_array( $list, $this->mFlatOptions, true ) ) {
-                               # User has spoofed the select form to give an option which wasn't
-                               # in the original offer.  Sulk...
-                               $final = $text;
-                       } elseif ( $text == '' ) {
-                               $final = $list;
-                       } else {
-                               $final = $list . $this->msg( 'colon-separator' )->inContentLanguage()->text() . $text;
-                       }
-               } else {
-                       $final = $this->getDefault();
-
-                       $list = 'other';
-                       $text = $final;
-                       foreach ( $this->mFlatOptions as $option ) {
-                               $match = $option . $this->msg( 'colon-separator' )->inContentLanguage()->text();
-                               if ( strpos( $text, $match ) === 0 ) {
-                                       $list = $option;
-                                       $text = substr( $text, strlen( $match ) );
-                                       break;
-                               }
-                       }
-               }
-
-               return [ $final, $list, $text ];
-       }
-
-       function getSize() {
-               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
-       }
-
-       function validate( $value, $alldata ) {
-               # HTMLSelectField forces $value to be one of the options in the select
-               # field, which is not useful here.  But we do want the validation further up
-               # the chain
-               $p = parent::validate( $value[1], $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               if ( isset( $this->mParams['required'] )
-                       && $this->mParams['required'] !== false
-                       && $value[1] === ''
-               ) {
-                       return $this->msg( 'htmlform-required' )->parse();
-               }
-
-               return true;
-       }
-}
diff --git a/includes/htmlform/HTMLSelectField.php b/includes/htmlform/HTMLSelectField.php
deleted file mode 100644 (file)
index b6ad46c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-/**
- * A select dropdown field.  Basically a wrapper for Xmlselect class
- */
-class HTMLSelectField extends HTMLFormField {
-       function validate( $value, $alldata ) {
-               $p = parent::validate( $value, $alldata );
-
-               if ( $p !== true ) {
-                       return $p;
-               }
-
-               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
-
-               if ( in_array( strval( $value ), $validOptions, true ) ) {
-                       return true;
-               } else {
-                       return $this->msg( 'htmlform-select-badoption' )->parse();
-               }
-       }
-
-       function getInputHTML( $value ) {
-               $select = new XmlSelect( $this->mName, $this->mID, strval( $value ) );
-
-               if ( !empty( $this->mParams['disabled'] ) ) {
-                       $select->setAttribute( 'disabled', 'disabled' );
-               }
-
-               $allowedParams = [ 'tabindex', 'size' ];
-               $customParams = $this->getAttributes( $allowedParams );
-               foreach ( $customParams as $name => $value ) {
-                       $select->setAttribute( $name, $value );
-               }
-
-               if ( $this->mClass !== '' ) {
-                       $select->setAttribute( 'class', $this->mClass );
-               }
-
-               $select->addOptions( $this->getOptions() );
-
-               return $select->getHTML();
-       }
-
-       function getInputOOUI( $value ) {
-               $disabled = false;
-               $allowedParams = [ 'tabindex' ];
-               $attribs = OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( $allowedParams )
-               );
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['classes'] = [ $this->mClass ];
-               }
-
-               if ( !empty( $this->mParams['disabled'] ) ) {
-                       $disabled = true;
-               }
-
-               return new OOUI\DropdownInputWidget( [
-                       'name' => $this->mName,
-                       'id' => $this->mID,
-                       'options' => $this->getOptionsOOUI(),
-                       'value' => strval( $value ),
-                       'disabled' => $disabled,
-               ] + $attribs );
-       }
-}
diff --git a/includes/htmlform/HTMLSelectLimitField.php b/includes/htmlform/HTMLSelectLimitField.php
deleted file mode 100644 (file)
index e7f1c04..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-/**
- * A limit dropdown, which accepts any valid number
- */
-class HTMLSelectLimitField extends HTMLSelectField {
-       /**
-        * Basically don't do any validation. If it's a number that's fine. Also,
-        * add it to the list if it's not there already
-        *
-        * @param string $value
-        * @param array $alldata
-        * @return bool
-        */
-       function validate( $value, $alldata ) {
-               if ( $value == '' ) {
-                       return true;
-               }
-
-               // Let folks pick an explicit limit not from our list, as long as it's a real numbr.
-               if ( !in_array( $value, $this->mParams['options'] )
-                       && $value == intval( $value )
-                       && $value > 0
-               ) {
-                       // This adds the explicitly requested limit value to the drop-down,
-                       // then makes sure it's sorted correctly so when we output the list
-                       // later, the custom option doesn't just show up last.
-                       $this->mParams['options'][$this->mParent->getLanguage()->formatNum( $value )] =
-                               intval( $value );
-                       asort( $this->mParams['options'] );
-               }
-
-               return true;
-       }
-}
diff --git a/includes/htmlform/HTMLSelectNamespace.php b/includes/htmlform/HTMLSelectNamespace.php
deleted file mode 100644 (file)
index ef21969..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/**
- * Wrapper for Html::namespaceSelector to use in HTMLForm
- */
-class HTMLSelectNamespace extends HTMLFormField {
-       public function __construct( $params ) {
-               parent::__construct( $params );
-
-               $this->mAllValue = array_key_exists( 'all', $params )
-                       ? $params['all']
-                       : 'all';
-
-       }
-
-       function getInputHTML( $value ) {
-               return Html::namespaceSelector(
-                       [
-                               'selected' => $value,
-                               'all' => $this->mAllValue
-                       ], [
-                               'name' => $this->mName,
-                               'id' => $this->mID,
-                               'class' => 'namespaceselector',
-                       ]
-               );
-       }
-
-       public function getInputOOUI( $value ) {
-               return new MediaWiki\Widget\NamespaceInputWidget( [
-                       'value' => $value,
-                       'name' => $this->mName,
-                       'id' => $this->mID,
-                       'includeAllValue' => $this->mAllValue,
-               ] );
-       }
-}
diff --git a/includes/htmlform/HTMLSelectNamespaceWithButton.php b/includes/htmlform/HTMLSelectNamespaceWithButton.php
deleted file mode 100644 (file)
index 5225983..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Creates a Html::namespaceSelector input field with a button assigned to the input field.
- */
-class HTMLSelectNamespaceWithButton extends HTMLSelectNamespace {
-       /** @var HTMLFormFieldWithButton $mClassWithButton */
-       protected $mClassWithButton = null;
-
-       public function __construct( $info ) {
-               $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
-               parent::__construct( $info );
-       }
-
-       public function getInputHTML( $value ) {
-               return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
-       }
-}
diff --git a/includes/htmlform/HTMLSelectOrOtherField.php b/includes/htmlform/HTMLSelectOrOtherField.php
deleted file mode 100644 (file)
index 8f7750c..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-
-/**
- * Select dropdown field, with an additional "other" textbox.
- *
- * HTMLComboboxField implements the same functionality using a single form field
- * and should be used instead.
- */
-class HTMLSelectOrOtherField extends HTMLTextField {
-       function __construct( $params ) {
-               parent::__construct( $params );
-               $this->getOptions();
-               if ( !in_array( 'other', $this->mOptions, true ) ) {
-                       $msg =
-                               isset( $params['other'] )
-                                       ? $params['other']
-                                       : wfMessage( 'htmlform-selectorother-other' )->text();
-                       // Have 'other' always as first element
-                       $this->mOptions = [ $msg => 'other' ] + $this->mOptions;
-               }
-
-       }
-
-       function getInputHTML( $value ) {
-               $valInSelect = false;
-
-               if ( $value !== false ) {
-                       $value = strval( $value );
-                       $valInSelect = in_array(
-                               $value, HTMLFormField::flattenOptions( $this->getOptions() ), true
-                       );
-               }
-
-               $selected = $valInSelect ? $value : 'other';
-
-               $select = new XmlSelect( $this->mName, $this->mID, $selected );
-               $select->addOptions( $this->getOptions() );
-
-               $select->setAttribute( 'class', 'mw-htmlform-select-or-other' );
-
-               $tbAttribs = [ 'id' => $this->mID . '-other', 'size' => $this->getSize() ];
-
-               if ( !empty( $this->mParams['disabled'] ) ) {
-                       $select->setAttribute( 'disabled', 'disabled' );
-                       $tbAttribs['disabled'] = 'disabled';
-               }
-
-               if ( isset( $this->mParams['tabindex'] ) ) {
-                       $select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
-                       $tbAttribs['tabindex'] = $this->mParams['tabindex'];
-               }
-
-               $select = $select->getHTML();
-
-               if ( isset( $this->mParams['maxlength'] ) ) {
-                       $tbAttribs['maxlength'] = $this->mParams['maxlength'];
-               }
-
-               if ( $this->mClass !== '' ) {
-                       $tbAttribs['class'] = $this->mClass;
-               }
-
-               $textbox = Html::input( $this->mName . '-other', $valInSelect ? '' : $value, 'text', $tbAttribs );
-
-               return "$select<br />\n$textbox";
-       }
-
-       function getInputOOUI( $value ) {
-               return false;
-       }
-
-       /**
-        * @param WebRequest $request
-        *
-        * @return string
-        */
-       function loadDataFromRequest( $request ) {
-               if ( $request->getCheck( $this->mName ) ) {
-                       $val = $request->getText( $this->mName );
-
-                       if ( $val === 'other' ) {
-                               $val = $request->getText( $this->mName . '-other' );
-                       }
-
-                       return $val;
-               } else {
-                       return $this->getDefault();
-               }
-       }
-}
diff --git a/includes/htmlform/HTMLSubmitField.php b/includes/htmlform/HTMLSubmitField.php
deleted file mode 100644 (file)
index cb98549..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-/**
- * Add a submit button inline in the form (as opposed to
- * HTMLForm::addButton(), which will add it at the end).
- */
-class HTMLSubmitField extends HTMLButtonField {
-       protected $buttonType = 'submit';
-
-       protected $mFlags = [ 'primary', 'constructive' ];
-
-       public function skipLoadData( $request ) {
-               return !$request->getCheck( $this->mName );
-       }
-
-       public function loadDataFromRequest( $request ) {
-               return $request->getCheck( $this->mName );
-       }
-}
diff --git a/includes/htmlform/HTMLTagFilter.php b/includes/htmlform/HTMLTagFilter.php
deleted file mode 100644 (file)
index 8075de5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-/**
- * Wrapper for ChangeTags::buildTagFilterSelector to use in HTMLForm
- */
-class HTMLTagFilter extends HTMLFormField {
-       protected $tagFilter;
-
-       function getTableRow( $value ) {
-               $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
-               if ( $this->tagFilter ) {
-                       return parent::getTableRow( $value );
-               }
-               return '';
-       }
-
-       function getDiv( $value ) {
-               $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
-               if ( $this->tagFilter ) {
-                       return parent::getDiv( $value );
-               }
-               return '';
-       }
-
-       function getInputHTML( $value ) {
-               if ( $this->tagFilter ) {
-                       // we only need the select field, HTMLForm should handle the label
-                       return $this->tagFilter[1];
-               }
-               return '';
-       }
-}
diff --git a/includes/htmlform/HTMLTextAreaField.php b/includes/htmlform/HTMLTextAreaField.php
deleted file mode 100644 (file)
index 8ffff43..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-class HTMLTextAreaField extends HTMLFormField {
-       const DEFAULT_COLS = 80;
-       const DEFAULT_ROWS = 25;
-
-       protected $mPlaceholder = '';
-
-       /**
-        * @param array $params
-        *   - cols, rows: textarea size
-        *   - placeholder/placeholder-message: set HTML placeholder attribute
-        *   - spellcheck: set HTML spellcheck attribute
-        */
-       public function __construct( $params ) {
-               parent::__construct( $params );
-
-               if ( isset( $params['placeholder-message'] ) ) {
-                       $this->mPlaceholder = $this->getMessage( $params['placeholder-message'] )->parse();
-               } elseif ( isset( $params['placeholder'] ) ) {
-                       $this->mPlaceholder = $params['placeholder'];
-               }
-       }
-
-       function getCols() {
-               return isset( $this->mParams['cols'] ) ? $this->mParams['cols'] : static::DEFAULT_COLS;
-       }
-
-       function getRows() {
-               return isset( $this->mParams['rows'] ) ? $this->mParams['rows'] : static::DEFAULT_ROWS;
-       }
-
-       function getSpellCheck() {
-               $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
-               if ( is_bool( $val ) ) {
-                       // "spellcheck" attribute literally requires "true" or "false" to work.
-                       return $val === true ? 'true' : 'false';
-               }
-               return null;
-       }
-
-       function getInputHTML( $value ) {
-               $attribs = [
-                               'id' => $this->mID,
-                               'cols' => $this->getCols(),
-                               'rows' => $this->getRows(),
-                               'spellcheck' => $this->getSpellCheck(),
-                       ] + $this->getTooltipAndAccessKey();
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['class'] = $this->mClass;
-               }
-               if ( $this->mPlaceholder !== '' ) {
-                       $attribs['placeholder'] = $this->mPlaceholder;
-               }
-
-               $allowedParams = [
-                       'tabindex',
-                       'disabled',
-                       'readonly',
-                       'required',
-                       'autofocus'
-               ];
-
-               $attribs += $this->getAttributes( $allowedParams );
-               return Html::textarea( $this->mName, $value, $attribs );
-       }
-
-       function getInputOOUI( $value ) {
-               if ( isset( $this->mParams['cols'] ) ) {
-                       throw new Exception( "OOUIHTMLForm does not support the 'cols' parameter for textareas" );
-               }
-
-               $attribs = $this->getTooltipAndAccessKey();
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['classes'] = [ $this->mClass ];
-               }
-               if ( $this->mPlaceholder !== '' ) {
-                       $attribs['placeholder'] = $this->mPlaceholder;
-               }
-
-               $allowedParams = [
-                       'tabindex',
-                       'disabled',
-                       'readonly',
-                       'required',
-                       'autofocus',
-               ];
-
-               $attribs += OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( $allowedParams )
-               );
-
-               return new OOUI\TextInputWidget( [
-                       'id' => $this->mID,
-                       'name' => $this->mName,
-                       'multiline' => true,
-                       'value' => $value,
-                       'rows' => $this->getRows(),
-               ] + $attribs );
-       }
-}
diff --git a/includes/htmlform/HTMLTextField.php b/includes/htmlform/HTMLTextField.php
deleted file mode 100644 (file)
index 3ab7176..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-<?php
-
-class HTMLTextField extends HTMLFormField {
-       protected $mPlaceholder = '';
-
-       /**
-        * @param array $params
-        *   - type: HTML textfield type
-        *   - size: field size in characters (defaults to 45)
-        *   - placeholder/placeholder-message: set HTML placeholder attribute
-        *   - spellcheck: set HTML spellcheck attribute
-        *   - persistent: upon unsuccessful requests, retain the value (defaults to true, except
-        *     for password fields)
-        */
-       public function __construct( $params ) {
-               parent::__construct( $params );
-
-               if ( isset( $params['placeholder-message'] ) ) {
-                       $this->mPlaceholder = $this->getMessage( $params['placeholder-message'] )->parse();
-               } elseif ( isset( $params['placeholder'] ) ) {
-                       $this->mPlaceholder = $params['placeholder'];
-               }
-       }
-
-       function getSize() {
-               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
-       }
-
-       function getSpellCheck() {
-               $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
-               if ( is_bool( $val ) ) {
-                       // "spellcheck" attribute literally requires "true" or "false" to work.
-                       return $val === true ? 'true' : 'false';
-               }
-               return null;
-       }
-
-       public function isPersistent() {
-               if ( isset( $this->mParams['persistent'] ) ) {
-                       return $this->mParams['persistent'];
-               }
-               // don't put passwords into the HTML body, they could get cached or otherwise leaked
-               return !( isset( $this->mParams['type'] ) && $this->mParams['type'] === 'password' );
-       }
-
-       function getInputHTML( $value ) {
-               if ( !$this->isPersistent() ) {
-                       $value = '';
-               }
-
-               $attribs = [
-                               'id' => $this->mID,
-                               'name' => $this->mName,
-                               'size' => $this->getSize(),
-                               'value' => $value,
-                               'dir' => $this->mDir,
-                               'spellcheck' => $this->getSpellCheck(),
-                       ] + $this->getTooltipAndAccessKey() + $this->getDataAttribs();
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['class'] = $this->mClass;
-               }
-               if ( $this->mPlaceholder !== '' ) {
-                       $attribs['placeholder'] = $this->mPlaceholder;
-               }
-
-               # @todo Enforce pattern, step, required, readonly on the server side as
-               # well
-               $allowedParams = [
-                       'type',
-                       'min',
-                       'max',
-                       'pattern',
-                       'title',
-                       'step',
-                       'list',
-                       'maxlength',
-                       'tabindex',
-                       'disabled',
-                       'required',
-                       'autofocus',
-                       'multiple',
-                       'readonly'
-               ];
-
-               $attribs += $this->getAttributes( $allowedParams );
-
-               # Extract 'type'
-               $type = $this->getType( $attribs );
-               return Html::input( $this->mName, $value, $type, $attribs );
-       }
-
-       protected function getType( &$attribs ) {
-               $type = isset( $attribs['type'] ) ? $attribs['type'] : 'text';
-               unset( $attribs['type'] );
-
-               # Implement tiny differences between some field variants
-               # here, rather than creating a new class for each one which
-               # is essentially just a clone of this one.
-               if ( isset( $this->mParams['type'] ) ) {
-                       switch ( $this->mParams['type'] ) {
-                               case 'int':
-                                       $type = 'number';
-                                       break;
-                               case 'float':
-                                       $type = 'number';
-                                       $attribs['step'] = 'any';
-                                       break;
-                               # Pass through
-                               case 'email':
-                               case 'password':
-                               case 'file':
-                               case 'url':
-                                       $type = $this->mParams['type'];
-                                       break;
-                       }
-               }
-
-               return $type;
-       }
-
-       function getInputOOUI( $value ) {
-               if ( !$this->isPersistent() ) {
-                       $value = '';
-               }
-
-               $attribs = $this->getTooltipAndAccessKey();
-
-               if ( $this->mClass !== '' ) {
-                       $attribs['classes'] = [ $this->mClass ];
-               }
-               if ( $this->mPlaceholder !== '' ) {
-                       $attribs['placeholder'] = $this->mPlaceholder;
-               }
-
-               # @todo Enforce pattern, step, required, readonly on the server side as
-               # well
-               $allowedParams = [
-                       'autofocus',
-                       'autosize',
-                       'disabled',
-                       'flags',
-                       'indicator',
-                       'maxlength',
-                       'readonly',
-                       'required',
-                       'tabindex',
-                       'type',
-               ];
-
-               $attribs += OOUI\Element::configFromHtmlAttributes(
-                       $this->getAttributes( $allowedParams )
-               );
-
-               $type = $this->getType( $attribs );
-
-               return $this->getInputWidget( [
-                       'id' => $this->mID,
-                       'name' => $this->mName,
-                       'value' => $value,
-                       'type' => $type,
-               ] + $attribs );
-       }
-
-       protected function getInputWidget( $params ) {
-               return new OOUI\TextInputWidget( $params );
-       }
-
-       /**
-        * Returns an array of data-* attributes to add to the field.
-        *
-        * @return array
-        */
-       protected function getDataAttribs() {
-               return [];
-       }
-}
diff --git a/includes/htmlform/HTMLTextFieldWithButton.php b/includes/htmlform/HTMLTextFieldWithButton.php
deleted file mode 100644 (file)
index 7c1c673..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Creates a text input field with a button assigned to the input field.
- */
-class HTMLTextFieldWithButton extends HTMLTextField {
-       /** @var HTMLFormFieldWithButton $mClassWithButton */
-       protected $mClassWithButton = null;
-
-       public function __construct( $info ) {
-               $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
-               parent::__construct( $info );
-       }
-
-       public function getInputHTML( $value ) {
-               return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
-       }
-}
diff --git a/includes/htmlform/HTMLTitleTextField.php b/includes/htmlform/HTMLTitleTextField.php
deleted file mode 100644 (file)
index fcf721a..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-use MediaWiki\Widget\TitleInputWidget;
-
-/**
- * Implements a text input field for page titles.
- * Automatically does validation that the title is valid,
- * as well as autocompletion if using the OOUI display format.
- *
- * Note: Forms using GET requests will need to make sure the title value is not
- * an empty string.
- *
- * Optional parameters:
- * 'namespace' - Namespace the page must be in
- * 'relative' - If true and 'namespace' given, strip/add the namespace from/to the title as needed
- * 'creatable' - Whether to validate the title is creatable (not a special page)
- * 'exists' - Whether to validate that the title already exists
- *
- * @since 1.26
- */
-class HTMLTitleTextField extends HTMLTextField {
-       public function __construct( $params ) {
-               $params += [
-                       'namespace' => false,
-                       'relative' => false,
-                       'creatable' => false,
-                       'exists' => false,
-               ];
-
-               parent::__construct( $params );
-       }
-
-       public function validate( $value, $alldata ) {
-               if ( $this->mParent->getMethod() === 'get' && $value === '' ) {
-                       // If the form is a GET form and has no value, assume it hasn't been
-                       // submitted yet, and skip validation
-                       return parent::validate( $value, $alldata );
-               }
-               try {
-                       if ( !$this->mParams['relative'] ) {
-                               $title = Title::newFromTextThrow( $value );
-                       } else {
-                               // Can't use Title::makeTitleSafe(), because it doesn't throw useful exceptions
-                               global $wgContLang;
-                               $namespaceName = $wgContLang->getNsText( $this->mParams['namespace'] );
-                               $title = Title::newFromTextThrow( $namespaceName . ':' . $value );
-                       }
-               } catch ( MalformedTitleException $e ) {
-                       $msg = $this->msg( $e->getErrorMessage() );
-                       $params = $e->getErrorMessageParameters();
-                       if ( $params ) {
-                               $msg->params( $params );
-                       }
-                       return $msg->parse();
-               }
-
-               $text = $title->getPrefixedText();
-               if ( $this->mParams['namespace'] !== false &&
-                       !$title->inNamespace( $this->mParams['namespace'] )
-               ) {
-                       return $this->msg( 'htmlform-title-badnamespace', $this->mParams['namespace'], $text )->parse();
-               }
-
-               if ( $this->mParams['creatable'] && !$title->canExist() ) {
-                       return $this->msg( 'htmlform-title-not-creatable', $text )->escaped();
-               }
-
-               if ( $this->mParams['exists'] && !$title->exists() ) {
-                       return $this->msg( 'htmlform-title-not-exists', $text )->parse();
-               }
-
-               return parent::validate( $value, $alldata );
-       }
-
-       protected function getInputWidget( $params ) {
-               $this->mParent->getOutput()->addModules( 'mediawiki.widgets' );
-               if ( $this->mParams['namespace'] !== false ) {
-                       $params['namespace'] = $this->mParams['namespace'];
-               }
-               $params['relative'] = $this->mParams['relative'];
-               return new TitleInputWidget( $params );
-       }
-
-       public function getInputHtml( $value ) {
-               // add mw-searchInput class to enable search suggestions for non-OOUI, too
-               $this->mClass .= 'mw-searchInput';
-
-               // return the HTMLTextField html
-               return parent::getInputHTML( $value );
-       }
-
-       protected function getDataAttribs() {
-               return [
-                       'data-mw-searchsuggest' => FormatJson::encode( [
-                               'wrapAsLink' => false,
-                       ] ),
-               ];
-       }
-}
diff --git a/includes/htmlform/HTMLUserTextField.php b/includes/htmlform/HTMLUserTextField.php
deleted file mode 100644 (file)
index 5a7e0b9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-
-use MediaWiki\Widget\UserInputWidget;
-
-/**
- * Implements a text input field for user names.
- * Automatically auto-completes if using the OOUI display format.
- *
- * FIXME: Does not work for forms that support GET requests.
- *
- * Optional parameters:
- * 'exists' - Whether to validate that the user already exists
- *
- * @since 1.26
- */
-class HTMLUserTextField extends HTMLTextField {
-       public function __construct( $params ) {
-               $params += [
-                       'exists' => false,
-                       'ipallowed' => false,
-               ];
-
-               parent::__construct( $params );
-       }
-
-       public function validate( $value, $alldata ) {
-               // check, if a user exists with the given username
-               $user = User::newFromName( $value, false );
-
-               if ( !$user ) {
-                       return $this->msg( 'htmlform-user-not-valid', $value )->parse();
-               } elseif (
-                       ( $this->mParams['exists'] && $user->getId() === 0 ) &&
-                       !( $this->mParams['ipallowed'] && User::isIP( $value ) )
-               ) {
-                       return $this->msg( 'htmlform-user-not-exists', $user->getName() )->parse();
-               }
-
-               return parent::validate( $value, $alldata );
-       }
-
-       protected function getInputWidget( $params ) {
-               $this->mParent->getOutput()->addModules( 'mediawiki.widgets.UserInputWidget' );
-
-               return new UserInputWidget( $params );
-       }
-
-       public function getInputHtml( $value ) {
-               // add the required module and css class for user suggestions in non-OOUI mode
-               $this->mParent->getOutput()->addModules( 'mediawiki.userSuggest' );
-               $this->mClass .= ' mw-autocomplete-user';
-
-               // return parent html
-               return parent::getInputHTML( $value );
-       }
-}
diff --git a/includes/htmlform/fields/HTMLApiField.php b/includes/htmlform/fields/HTMLApiField.php
new file mode 100644 (file)
index 0000000..24a253e
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+class HTMLApiField extends HTMLFormField {
+       public function getTableRow( $value ) {
+               return '';
+       }
+
+       public function getDiv( $value ) {
+               return $this->getTableRow( $value );
+       }
+
+       public function getRaw( $value ) {
+               return $this->getTableRow( $value );
+       }
+
+       public function getInputHTML( $value ) {
+               return '';
+       }
+
+       public function hasVisibleOutput() {
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLAutoCompleteSelectField.php b/includes/htmlform/fields/HTMLAutoCompleteSelectField.php
new file mode 100644 (file)
index 0000000..76a88d5
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * Text field for selecting a value from a large list of possible values, with
+ * auto-completion and optionally with a select dropdown for selecting common
+ * options.
+ *
+ * HTMLComboboxField implements most of the same functionality and should be
+ * used instead, if possible.
+ *
+ * If one of 'options-messages', 'options', or 'options-message' is provided
+ * and non-empty, the select dropdown will be shown. An 'other' key will be
+ * appended using message 'htmlform-selectorother-other' if not already
+ * present.
+ *
+ * Besides the parameters recognized by HTMLTextField, the following are
+ * recognized:
+ *   options-messages - As for HTMLSelectField
+ *   options - As for HTMLSelectField
+ *   options-message - As for HTMLSelectField
+ *   autocomplete - Associative array mapping display text to values.
+ *   autocomplete-messages - Like autocomplete, but keys are message names.
+ *   require-match - Boolean, if true the value must be in the options or the
+ *     autocomplete.
+ *   other-message - Message to use instead of htmlform-selectorother-other for
+ *      the 'other' message.
+ *   other - Raw text to use for the 'other' message
+ */
+class HTMLAutoCompleteSelectField extends HTMLTextField {
+       protected $autocomplete = [];
+
+       function __construct( $params ) {
+               $params += [
+                       'require-match' => false,
+               ];
+
+               parent::__construct( $params );
+
+               if ( array_key_exists( 'autocomplete-messages', $this->mParams ) ) {
+                       foreach ( $this->mParams['autocomplete-messages'] as $key => $value ) {
+                               $key = $this->msg( $key )->plain();
+                               $this->autocomplete[$key] = strval( $value );
+                       }
+               } elseif ( array_key_exists( 'autocomplete', $this->mParams ) ) {
+                       foreach ( $this->mParams['autocomplete'] as $key => $value ) {
+                               $this->autocomplete[$key] = strval( $value );
+                       }
+               }
+               if ( !is_array( $this->autocomplete ) || !$this->autocomplete ) {
+                       throw new MWException( 'HTMLAutoCompleteSelectField called without any autocompletions' );
+               }
+
+               $this->getOptions();
+               if ( $this->mOptions && !in_array( 'other', $this->mOptions, true ) ) {
+                       if ( isset( $params['other-message'] ) ) {
+                               $msg = $this->getMessage( $params['other-message'] )->text();
+                       } elseif ( isset( $params['other'] ) ) {
+                               $msg = $params['other'];
+                       } else {
+                               $msg = wfMessage( 'htmlform-selectorother-other' )->text();
+                       }
+                       $this->mOptions[$msg] = 'other';
+               }
+       }
+
+       function loadDataFromRequest( $request ) {
+               if ( $request->getCheck( $this->mName ) ) {
+                       $val = $request->getText( $this->mName . '-select', 'other' );
+
+                       if ( $val === 'other' ) {
+                               $val = $request->getText( $this->mName );
+                               if ( isset( $this->autocomplete[$val] ) ) {
+                                       $val = $this->autocomplete[$val];
+                               }
+                       }
+
+                       return $val;
+               } else {
+                       return $this->getDefault();
+               }
+       }
+
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
+
+               if ( in_array( strval( $value ), $validOptions, true ) ) {
+                       return true;
+               } elseif ( in_array( strval( $value ), $this->autocomplete, true ) ) {
+                       return true;
+               } elseif ( $this->mParams['require-match'] ) {
+                       return $this->msg( 'htmlform-select-badoption' )->parse();
+               }
+
+               return true;
+       }
+
+       // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
+       public function getAttributes( array $list ) {
+               $attribs = [
+                       'type' => 'text',
+                       'data-autocomplete' => FormatJson::encode( array_keys( $this->autocomplete ) ),
+               ] + parent::getAttributes( $list );
+
+               if ( $this->getOptions() ) {
+                       $attribs['data-hide-if'] = FormatJson::encode(
+                               [ '!==', $this->mName . '-select', 'other' ]
+                       );
+               }
+
+               return $attribs;
+       }
+
+       function getInputHTML( $value ) {
+               $oldClass = $this->mClass;
+               $this->mClass = (array)$this->mClass;
+
+               $valInSelect = false;
+               $ret = '';
+
+               if ( $this->getOptions() ) {
+                       if ( $value !== false ) {
+                               $value = strval( $value );
+                               $valInSelect = in_array(
+                                       $value, HTMLFormField::flattenOptions( $this->getOptions() ), true
+                               );
+                       }
+
+                       $selected = $valInSelect ? $value : 'other';
+                       $select = new XmlSelect( $this->mName . '-select', $this->mID . '-select', $selected );
+                       $select->addOptions( $this->getOptions() );
+                       $select->setAttribute( 'class', 'mw-htmlform-select-or-other' );
+
+                       if ( !empty( $this->mParams['disabled'] ) ) {
+                               $select->setAttribute( 'disabled', 'disabled' );
+                       }
+
+                       if ( isset( $this->mParams['tabindex'] ) ) {
+                               $select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
+                       }
+
+                       $ret = $select->getHTML() . "<br />\n";
+
+                       $this->mClass[] = 'mw-htmlform-hide-if';
+               }
+
+               if ( $valInSelect ) {
+                       $value = '';
+               } else {
+                       $key = array_search( strval( $value ), $this->autocomplete, true );
+                       if ( $key !== false ) {
+                               $value = $key;
+                       }
+               }
+
+               $this->mClass[] = 'mw-htmlform-autocomplete';
+               $ret .= parent::getInputHTML( $valInSelect ? '' : $value );
+               $this->mClass = $oldClass;
+
+               return $ret;
+       }
+
+       /**
+        * Get the OOUI version of this input.
+        * @param string $value
+        * @return false
+        */
+       function getInputOOUI( $value ) {
+               // To be implemented, for now override the function from HTMLTextField
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLButtonField.php b/includes/htmlform/fields/HTMLButtonField.php
new file mode 100644 (file)
index 0000000..64fe7ed
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * Adds a generic button inline to the form. Does not do anything, you must add
+ * click handling code in JavaScript. Use a HTMLSubmitField if you merely
+ * wish to add a submit button to a form.
+ *
+ * Additional recognized configuration parameters include:
+ * - flags: OOUI flags for the button, see OOUI\FlaggedElement
+ * - buttonlabel-message: Message to use for the button display text, instead
+ *   of the value from 'default'. Overrides 'buttonlabel' and 'buttonlabel-raw'.
+ * - buttonlabel: Text to display for the button display text, instead
+ *   of the value from 'default'. Overrides 'buttonlabel-raw'.
+ * - buttonlabel-raw: HTMLto display for the button display text, instead
+ *   of the value from 'default'.
+ *
+ * Note that the buttonlabel parameters are not supported on IE6 and IE7 due to
+ * bugs in those browsers. If detected, they will be served buttons using the
+ * value of 'default' as the button label.
+ *
+ * @since 1.22
+ */
+class HTMLButtonField extends HTMLFormField {
+       protected $buttonType = 'button';
+       protected $buttonLabel = null;
+
+       /** @var array $mFlags Flags to add to OOUI Button widget */
+       protected $mFlags = [];
+
+       public function __construct( $info ) {
+               $info['nodata'] = true;
+               if ( isset( $info['flags'] ) ) {
+                       $this->mFlags = $info['flags'];
+               }
+
+               # Generate the label from a message, if possible
+               if ( isset( $info['buttonlabel-message'] ) ) {
+                       $this->buttonLabel = $this->getMessage( $info['buttonlabel-message'] )->parse();
+               } elseif ( isset( $info['buttonlabel'] ) ) {
+                       if ( $info['buttonlabel'] === '&#160;' ) {
+                               // Apparently some things set &nbsp directly and in an odd format
+                               $this->buttonLabel = '&#160;';
+                       } else {
+                               $this->buttonLabel = htmlspecialchars( $info['buttonlabel'] );
+                       }
+               } elseif ( isset( $info['buttonlabel-raw'] ) ) {
+                       $this->buttonLabel = $info['buttonlabel-raw'];
+               }
+
+               $this->setShowEmptyLabel( false );
+
+               parent::__construct( $info );
+       }
+
+       public function getInputHTML( $value ) {
+               $flags = '';
+               $prefix = 'mw-htmlform-';
+               if ( $this->mParent instanceof VFormHTMLForm ||
+                       $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' )
+               ) {
+                       $prefix = 'mw-ui-';
+                       // add mw-ui-button separately, so the descriptor doesn't need to set it
+                       $flags .= ' ' . $prefix . 'button';
+               }
+               foreach ( $this->mFlags as $flag ) {
+                       $flags .= ' ' . $prefix . $flag;
+               }
+               $attr = [
+                       'class' => 'mw-htmlform-submit ' . $this->mClass . $flags,
+                       'id' => $this->mID,
+                       'type' => $this->buttonType,
+                       'name' => $this->mName,
+                       'value' => $this->getDefault(),
+               ] + $this->getAttributes( [ 'disabled', 'tabindex' ] );
+
+               if ( $this->isBadIE() ) {
+                       return Html::element( 'input', $attr );
+               } else {
+                       return Html::rawElement( 'button', $attr,
+                               $this->buttonLabel ?: htmlspecialchars( $this->getDefault() ) );
+               }
+       }
+
+       /**
+        * Get the OOUI widget for this field.
+        * @param string $value
+        * @return OOUI\ButtonInputWidget
+        */
+       public function getInputOOUI( $value ) {
+               return new OOUI\ButtonInputWidget( [
+                       'name' => $this->mName,
+                       'value' => $this->getDefault(),
+                       'label' => !$this->isBadIE() && $this->buttonLabel
+                               ? new OOUI\HtmlSnippet( $this->buttonLabel )
+                               : $this->getDefault(),
+                       'type' => $this->buttonType,
+                       'classes' => [ 'mw-htmlform-submit', $this->mClass ],
+                       'id' => $this->mID,
+                       'flags' => $this->mFlags,
+                       'useInputTag' => $this->isBadIE(),
+               ] + OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
+               ) );
+       }
+
+       protected function needsLabel() {
+               return false;
+       }
+
+       /**
+        * Button cannot be invalid
+        *
+        * @param string $value
+        * @param array $alldata
+        *
+        * @return bool
+        */
+       public function validate( $value, $alldata ) {
+               return true;
+       }
+
+       /**
+        * IE<8 has bugs with <button>, so we'll need to avoid them.
+        * @return bool Whether the request is from a bad version of IE
+        */
+       private function isBadIE() {
+               $request = $this->mParent
+                       ? $this->mParent->getRequest()
+                       : RequestContext::getMain()->getRequest();
+               return preg_match( '/MSIE [1-7]\./i', $request->getHeader( 'User-Agent' ) );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLCheckField.php b/includes/htmlform/fields/HTMLCheckField.php
new file mode 100644 (file)
index 0000000..a553839
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+
+/**
+ * A checkbox field
+ */
+class HTMLCheckField extends HTMLFormField {
+       function getInputHTML( $value ) {
+               global $wgUseMediaWikiUIEverywhere;
+
+               if ( !empty( $this->mParams['invert'] ) ) {
+                       $value = !$value;
+               }
+
+               $attr = $this->getTooltipAndAccessKey();
+               $attr['id'] = $this->mID;
+
+               $attr += $this->getAttributes( [ 'disabled', 'tabindex' ] );
+
+               if ( $this->mClass !== '' ) {
+                       $attr['class'] = $this->mClass;
+               }
+
+               $attrLabel = [ 'for' => $this->mID ];
+               if ( isset( $attr['title'] ) ) {
+                       // propagate tooltip to label
+                       $attrLabel['title'] = $attr['title'];
+               }
+
+               $chkLabel = Xml::check( $this->mName, $value, $attr ) .
+                       '&#160;' .
+                       Html::rawElement( 'label', $attrLabel, $this->mLabel );
+
+               if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
+                       $chkLabel = Html::rawElement(
+                               'div',
+                               [ 'class' => 'mw-ui-checkbox' ],
+                               $chkLabel
+                       );
+               }
+
+               return $chkLabel;
+       }
+
+       /**
+        * Get the OOUI version of this field.
+        * @since 1.26
+        * @param string $value
+        * @return OOUI\CheckboxInputWidget The checkbox widget.
+        */
+       public function getInputOOUI( $value ) {
+               if ( !empty( $this->mParams['invert'] ) ) {
+                       $value = !$value;
+               }
+
+               $attr = $this->getTooltipAndAccessKey();
+               $attr['id'] = $this->mID;
+               $attr['name'] = $this->mName;
+
+               $attr += OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
+               );
+
+               if ( $this->mClass !== '' ) {
+                       $attr['classes'] = [ $this->mClass ];
+               }
+
+               $attr['selected'] = $value;
+               $attr['value'] = '1'; // Nasty hack, but needed to make this work
+
+               return new OOUI\CheckboxInputWidget( $attr );
+       }
+
+       /**
+        * For a checkbox, the label goes on the right hand side, and is
+        * added in getInputHTML(), rather than HTMLFormField::getRow()
+        *
+        * ...unless OOUI is being used, in which case we actually return
+        * the label here.
+        *
+        * @return string
+        */
+       function getLabel() {
+               if ( $this->mParent instanceof OOUIHTMLForm ) {
+                       return $this->mLabel;
+               } elseif (
+                       $this->mParent instanceof HTMLForm &&
+                       $this->mParent->getDisplayFormat() === 'div'
+               ) {
+                       return '';
+               } else {
+                       return '&#160;';
+               }
+       }
+
+       /**
+        * Get label alignment when generating field for OOUI.
+        * @return string 'left', 'right', 'top' or 'inline'
+        */
+       protected function getLabelAlignOOUI() {
+               return 'inline';
+       }
+
+       /**
+        * checkboxes don't need a label.
+        * @return bool
+        */
+       protected function needsLabel() {
+               return false;
+       }
+
+       /**
+        * @param WebRequest $request
+        *
+        * @return bool
+        */
+       function loadDataFromRequest( $request ) {
+               $invert = isset( $this->mParams['invert'] ) && $this->mParams['invert'];
+
+               // GetCheck won't work like we want for checks.
+               // Fetch the value in either one of the two following case:
+               // - we have a valid submit attempt (form was just submitted, or a GET URL forged by the user)
+               // - checkbox name has a value (false or true), ie is not null
+               if ( $this->isSubmitAttempt( $request ) || $request->getVal( $this->mName ) !== null ) {
+                       return $invert
+                               ? !$request->getBool( $this->mName )
+                               : $request->getBool( $this->mName );
+               } else {
+                       return (bool)$this->getDefault();
+               }
+       }
+}
diff --git a/includes/htmlform/fields/HTMLCheckMatrix.php b/includes/htmlform/fields/HTMLCheckMatrix.php
new file mode 100644 (file)
index 0000000..b324fb6
--- /dev/null
@@ -0,0 +1,266 @@
+<?php
+
+/**
+ * A checkbox matrix
+ * Operates similarly to HTMLMultiSelectField, but instead of using an array of
+ * options, uses an array of rows and an array of columns to dynamically
+ * construct a matrix of options. The tags used to identify a particular cell
+ * are of the form "columnName-rowName"
+ *
+ * Options:
+ *   - columns
+ *     - Required list of columns in the matrix.
+ *   - rows
+ *     - Required list of rows in the matrix.
+ *   - force-options-on
+ *     - Accepts array of column-row tags to be displayed as enabled but unavailable to change
+ *   - force-options-off
+ *     - Accepts array of column-row tags to be displayed as disabled but unavailable to change.
+ *   - tooltips
+ *     - Optional array mapping row label to tooltip content
+ *   - tooltip-class
+ *     - Optional CSS class used on tooltip container span. Defaults to mw-icon-question.
+ */
+class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
+       static private $requiredParams = [
+               // Required by underlying HTMLFormField
+               'fieldname',
+               // Required by HTMLCheckMatrix
+               'rows',
+               'columns'
+       ];
+
+       public function __construct( $params ) {
+               $missing = array_diff( self::$requiredParams, array_keys( $params ) );
+               if ( $missing ) {
+                       throw new HTMLFormFieldRequiredOptionsException( $this, $missing );
+               }
+               parent::__construct( $params );
+       }
+
+       function validate( $value, $alldata ) {
+               $rows = $this->mParams['rows'];
+               $columns = $this->mParams['columns'];
+
+               // Make sure user-defined validation callback is run
+               $p = parent::validate( $value, $alldata );
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               // Make sure submitted value is an array
+               if ( !is_array( $value ) ) {
+                       return false;
+               }
+
+               // If all options are valid, array_intersect of the valid options
+               // and the provided options will return the provided options.
+               $validOptions = [];
+               foreach ( $rows as $rowTag ) {
+                       foreach ( $columns as $columnTag ) {
+                               $validOptions[] = $columnTag . '-' . $rowTag;
+                       }
+               }
+               $validValues = array_intersect( $value, $validOptions );
+               if ( count( $validValues ) == count( $value ) ) {
+                       return true;
+               } else {
+                       return $this->msg( 'htmlform-select-badoption' )->parse();
+               }
+       }
+
+       /**
+        * Build a table containing a matrix of checkbox options.
+        * The value of each option is a combination of the row tag and column tag.
+        * mParams['rows'] is an array with row labels as keys and row tags as values.
+        * mParams['columns'] is an array with column labels as keys and column tags as values.
+        *
+        * @param array $value Array of the options that should be checked
+        *
+        * @return string
+        */
+       function getInputHTML( $value ) {
+               $html = '';
+               $tableContents = '';
+               $rows = $this->mParams['rows'];
+               $columns = $this->mParams['columns'];
+
+               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
+
+               // Build the column headers
+               $headerContents = Html::rawElement( 'td', [], '&#160;' );
+               foreach ( $columns as $columnLabel => $columnTag ) {
+                       $headerContents .= Html::rawElement( 'td', [], $columnLabel );
+               }
+               $tableContents .= Html::rawElement( 'tr', [], "\n$headerContents\n" );
+
+               $tooltipClass = 'mw-icon-question';
+               if ( isset( $this->mParams['tooltip-class'] ) ) {
+                       $tooltipClass = $this->mParams['tooltip-class'];
+               }
+
+               // Build the options matrix
+               foreach ( $rows as $rowLabel => $rowTag ) {
+                       // Append tooltip if configured
+                       if ( isset( $this->mParams['tooltips'][$rowLabel] ) ) {
+                               $tooltipAttribs = [
+                                       'class' => "mw-htmlform-tooltip $tooltipClass",
+                                       'title' => $this->mParams['tooltips'][$rowLabel],
+                               ];
+                               $rowLabel .= ' ' . Html::element( 'span', $tooltipAttribs, '' );
+                       }
+                       $rowContents = Html::rawElement( 'td', [], $rowLabel );
+                       foreach ( $columns as $columnTag ) {
+                               $thisTag = "$columnTag-$rowTag";
+                               // Construct the checkbox
+                               $thisAttribs = [
+                                       'id' => "{$this->mID}-$thisTag",
+                                       'value' => $thisTag,
+                               ];
+                               $checked = in_array( $thisTag, (array)$value, true );
+                               if ( $this->isTagForcedOff( $thisTag ) ) {
+                                       $checked = false;
+                                       $thisAttribs['disabled'] = 1;
+                               } elseif ( $this->isTagForcedOn( $thisTag ) ) {
+                                       $checked = true;
+                                       $thisAttribs['disabled'] = 1;
+                               }
+
+                               $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs );
+
+                               $rowContents .= Html::rawElement(
+                                       'td',
+                                       [],
+                                       $checkbox
+                               );
+                       }
+                       $tableContents .= Html::rawElement( 'tr', [], "\n$rowContents\n" );
+               }
+
+               // Put it all in a table
+               $html .= Html::rawElement( 'table',
+                               [ 'class' => 'mw-htmlform-matrix' ],
+                               Html::rawElement( 'tbody', [], "\n$tableContents\n" ) ) . "\n";
+
+               return $html;
+       }
+
+       protected function getOneCheckbox( $checked, $attribs ) {
+               if ( $this->mParent instanceof OOUIHTMLForm ) {
+                       return new OOUI\CheckboxInputWidget( [
+                               'name' => "{$this->mName}[]",
+                               'selected' => $checked,
+                       ] + OOUI\Element::configFromHtmlAttributes(
+                               $attribs
+                       ) );
+               } else {
+                       $checkbox = Xml::check( "{$this->mName}[]", $checked, $attribs );
+                       if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+                               $checkbox = Html::openElement( 'div', [ 'class' => 'mw-ui-checkbox' ] ) .
+                                       $checkbox .
+                                       Html::element( 'label', [ 'for' => $attribs['id'] ] ) .
+                                       Html::closeElement( 'div' );
+                       }
+                       return $checkbox;
+               }
+       }
+
+       protected function isTagForcedOff( $tag ) {
+               return isset( $this->mParams['force-options-off'] )
+                       && in_array( $tag, $this->mParams['force-options-off'] );
+       }
+
+       protected function isTagForcedOn( $tag ) {
+               return isset( $this->mParams['force-options-on'] )
+                       && in_array( $tag, $this->mParams['force-options-on'] );
+       }
+
+       /**
+        * Get the complete table row for the input, including help text,
+        * labels, and whatever.
+        * We override this function since the label should always be on a separate
+        * line above the options in the case of a checkbox matrix, i.e. it's always
+        * a "vertical-label".
+        *
+        * @param string $value The value to set the input to
+        *
+        * @return string Complete HTML table row
+        */
+       function getTableRow( $value ) {
+               list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
+               $inputHtml = $this->getInputHTML( $value );
+               $fieldType = get_class( $this );
+               $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
+               $cellAttributes = [ 'colspan' => 2 ];
+
+               $hideClass = '';
+               $hideAttributes = [];
+               if ( $this->mHideIf ) {
+                       $hideAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
+                       $hideClass = 'mw-htmlform-hide-if';
+               }
+
+               $label = $this->getLabelHtml( $cellAttributes );
+
+               $field = Html::rawElement(
+                       'td',
+                       [ 'class' => 'mw-input' ] + $cellAttributes,
+                       $inputHtml . "\n$errors"
+               );
+
+               $html = Html::rawElement( 'tr',
+                       [ 'class' => "mw-htmlform-vertical-label $hideClass" ] + $hideAttributes,
+                       $label );
+               $html .= Html::rawElement( 'tr',
+                       [ 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $hideClass" ] +
+                               $hideAttributes,
+                       $field );
+
+               return $html . $helptext;
+       }
+
+       /**
+        * @param WebRequest $request
+        *
+        * @return array
+        */
+       function loadDataFromRequest( $request ) {
+               if ( $this->isSubmitAttempt( $request ) ) {
+                       // Checkboxes are just not added to the request arrays if they're not checked,
+                       // so it's perfectly possible for there not to be an entry at all
+                       return $request->getArray( $this->mName, [] );
+               } else {
+                       // That's ok, the user has not yet submitted the form, so show the defaults
+                       return $this->getDefault();
+               }
+       }
+
+       function getDefault() {
+               if ( isset( $this->mDefault ) ) {
+                       return $this->mDefault;
+               } else {
+                       return [];
+               }
+       }
+
+       function filterDataForSubmit( $data ) {
+               $columns = HTMLFormField::flattenOptions( $this->mParams['columns'] );
+               $rows = HTMLFormField::flattenOptions( $this->mParams['rows'] );
+               $res = [];
+               foreach ( $columns as $column ) {
+                       foreach ( $rows as $row ) {
+                               // Make sure option hasn't been forced
+                               $thisTag = "$column-$row";
+                               if ( $this->isTagForcedOff( $thisTag ) ) {
+                                       $res[$thisTag] = false;
+                               } elseif ( $this->isTagForcedOn( $thisTag ) ) {
+                                       $res[$thisTag] = true;
+                               } else {
+                                       $res[$thisTag] = in_array( $thisTag, $data );
+                               }
+                       }
+               }
+
+               return $res;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLComboboxField.php b/includes/htmlform/fields/HTMLComboboxField.php
new file mode 100644 (file)
index 0000000..778aedb
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * A combo box field.
+ *
+ * You can think of it as a dropdown select with the ability to add custom options,
+ * or as a text field with input suggestions (autocompletion).
+ *
+ * When JavaScript is not supported or enabled, it uses HTML5 `<datalist>` element.
+ *
+ * Besides the parameters recognized by HTMLTextField, the following are
+ * recognized:
+ *   options-messages - As for HTMLSelectField
+ *   options - As for HTMLSelectField
+ *   options-message - As for HTMLSelectField
+ */
+class HTMLComboboxField extends HTMLTextField {
+       // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
+       public function getAttributes( array $list ) {
+               $attribs = [
+                       'type' => 'text',
+                       'list' => $this->mName . '-datalist',
+               ] + parent::getAttributes( $list );
+
+               return $attribs;
+       }
+
+       function getInputHTML( $value ) {
+               $datalist = new XmlSelect( false, $this->mName . '-datalist' );
+               $datalist->setTagName( 'datalist' );
+               $datalist->addOptions( $this->getOptions() );
+
+               return parent::getInputHTML( $value ) . $datalist->getHTML();
+       }
+
+       function getInputOOUI( $value ) {
+               $disabled = false;
+               $allowedParams = [ 'tabindex' ];
+               $attribs = OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( $allowedParams )
+               );
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['classes'] = [ $this->mClass ];
+               }
+
+               if ( !empty( $this->mParams['disabled'] ) ) {
+                       $disabled = true;
+               }
+
+               return new OOUI\ComboBoxInputWidget( [
+                       'name' => $this->mName,
+                       'id' => $this->mID,
+                       'options' => $this->getOptionsOOUI(),
+                       'value' => strval( $value ),
+                       'disabled' => $disabled,
+               ] + $attribs );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLEditTools.php b/includes/htmlform/fields/HTMLEditTools.php
new file mode 100644 (file)
index 0000000..1b5d1fb
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+class HTMLEditTools extends HTMLFormField {
+       public function getInputHTML( $value ) {
+               return '';
+       }
+
+       public function getTableRow( $value ) {
+               $msg = $this->formatMsg();
+
+               return
+                       '<tr><td></td><td class="mw-input">' .
+                       '<div class="mw-editTools">' .
+                       $msg->parseAsBlock() .
+                       "</div></td></tr>\n";
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getDiv( $value ) {
+               $msg = $this->formatMsg();
+
+               return '<div class="mw-editTools">' . $msg->parseAsBlock() . '</div>';
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getRaw( $value ) {
+               return $this->getDiv( $value );
+       }
+
+       protected function formatMsg() {
+               if ( empty( $this->mParams['message'] ) ) {
+                       $msg = $this->msg( 'edittools' );
+               } else {
+                       $msg = $this->getMessage( $this->mParams['message'] );
+                       if ( $msg->isDisabled() ) {
+                               $msg = $this->msg( 'edittools' );
+                       }
+               }
+               $msg->inContentLanguage();
+
+               return $msg;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLFloatField.php b/includes/htmlform/fields/HTMLFloatField.php
new file mode 100644 (file)
index 0000000..2ef4978
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * A field that will contain a numeric value
+ */
+class HTMLFloatField extends HTMLTextField {
+       function getSize() {
+               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 20;
+       }
+
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               $value = trim( $value );
+
+               # http://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers
+               # with the addition that a leading '+' sign is ok.
+               if ( !preg_match( '/^((\+|\-)?\d+(\.\d+)?(E(\+|\-)?\d+)?)?$/i', $value ) ) {
+                       return $this->msg( 'htmlform-float-invalid' )->parseAsBlock();
+               }
+
+               # The "int" part of these message names is rather confusing.
+               # They make equal sense for all numbers.
+               if ( isset( $this->mParams['min'] ) ) {
+                       $min = $this->mParams['min'];
+
+                       if ( $min > $value ) {
+                               return $this->msg( 'htmlform-int-toolow', $min )->parseAsBlock();
+                       }
+               }
+
+               if ( isset( $this->mParams['max'] ) ) {
+                       $max = $this->mParams['max'];
+
+                       if ( $max < $value ) {
+                               return $this->msg( 'htmlform-int-toohigh', $max )->parseAsBlock();
+                       }
+               }
+
+               return true;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLFormFieldCloner.php b/includes/htmlform/fields/HTMLFormFieldCloner.php
new file mode 100644 (file)
index 0000000..ec1bd84
--- /dev/null
@@ -0,0 +1,380 @@
+<?php
+
+/**
+ * A container for HTMLFormFields that allows for multiple copies of the set of
+ * fields to be displayed to and entered by the user.
+ *
+ * Recognized parameters, besides the general ones, include:
+ *   fields - HTMLFormField descriptors for the subfields this cloner manages.
+ *     The format is just like for the HTMLForm. A field with key 'delete' is
+ *     special: it must have type = submit and will serve to delete the group
+ *     of fields.
+ *   required - If specified, at least one group of fields must be submitted.
+ *   format - HTMLForm display format to use when displaying the subfields:
+ *     'table', 'div', or 'raw'.
+ *   row-legend - If non-empty, each group of subfields will be enclosed in a
+ *     fieldset. The value is the name of a message key to use as the legend.
+ *   create-button-message - Message to use as the text of the button to
+ *     add an additional group of fields.
+ *   delete-button-message - Message to use as the text of automatically-
+ *     generated 'delete' button. Ignored if 'delete' is included in 'fields'.
+ *
+ * In the generated HTML, the subfields will be named along the lines of
+ * "clonerName[index][fieldname]", with ids "clonerId--index--fieldid". 'index'
+ * may be a number or an arbitrary string, and may likely change when the page
+ * is resubmitted. Cloners may be nested, resulting in field names along the
+ * lines of "cloner1Name[index1][cloner2Name][index2][fieldname]" and
+ * corresponding ids.
+ *
+ * Use of cloner may result in submissions of the page that are not submissions
+ * of the HTMLForm, when non-JavaScript clients use the create or remove buttons.
+ *
+ * The result is an array, with values being arrays mapping subfield names to
+ * their values. On non-HTMLForm-submission page loads, there may also be
+ * additional (string) keys present with other types of values.
+ *
+ * @since 1.23
+ */
+class HTMLFormFieldCloner extends HTMLFormField {
+       private static $counter = 0;
+
+       /**
+        * @var string String uniquely identifying this cloner instance and
+        * unlikely to exist otherwise in the generated HTML, while still being
+        * valid as part of an HTML id.
+        */
+       protected $uniqueId;
+
+       public function __construct( $params ) {
+               $this->uniqueId = get_class( $this ) . ++self::$counter . 'x';
+               parent::__construct( $params );
+
+               if ( empty( $this->mParams['fields'] ) || !is_array( $this->mParams['fields'] ) ) {
+                       throw new MWException( 'HTMLFormFieldCloner called without any fields' );
+               }
+
+               // Make sure the delete button, if explicitly specified, is sane
+               if ( isset( $this->mParams['fields']['delete'] ) ) {
+                       $class = 'mw-htmlform-cloner-delete-button';
+                       $info = $this->mParams['fields']['delete'] + [
+                               'cssclass' => $class
+                       ];
+                       unset( $info['name'], $info['class'] );
+
+                       if ( !isset( $info['type'] ) || $info['type'] !== 'submit' ) {
+                               throw new MWException(
+                                       'HTMLFormFieldCloner delete field, if specified, must be of type "submit"'
+                               );
+                       }
+
+                       if ( !in_array( $class, explode( ' ', $info['cssclass'] ) ) ) {
+                               $info['cssclass'] .= " $class";
+                       }
+
+                       $this->mParams['fields']['delete'] = $info;
+               }
+       }
+
+       /**
+        * Create the HTMLFormFields that go inside this element, using the
+        * specified key.
+        *
+        * @param string $key Array key under which these fields should be named
+        * @return HTMLFormField[]
+        */
+       protected function createFieldsForKey( $key ) {
+               $fields = [];
+               foreach ( $this->mParams['fields'] as $fieldname => $info ) {
+                       $name = "{$this->mName}[$key][$fieldname]";
+                       if ( isset( $info['name'] ) ) {
+                               $info['name'] = "{$this->mName}[$key][{$info['name']}]";
+                       } else {
+                               $info['name'] = $name;
+                       }
+                       if ( isset( $info['id'] ) ) {
+                               $info['id'] = Sanitizer::escapeId( "{$this->mID}--$key--{$info['id']}" );
+                       } else {
+                               $info['id'] = Sanitizer::escapeId( "{$this->mID}--$key--$fieldname" );
+                       }
+                       $field = HTMLForm::loadInputFromParameters( $name, $info, $this->mParent );
+                       $fields[$fieldname] = $field;
+               }
+               return $fields;
+       }
+
+       /**
+        * Re-key the specified values array to match the names applied by
+        * createFieldsForKey().
+        *
+        * @param string $key Array key under which these fields should be named
+        * @param array $values Values array from the request
+        * @return array
+        */
+       protected function rekeyValuesArray( $key, $values ) {
+               $data = [];
+               foreach ( $values as $fieldname => $value ) {
+                       $name = "{$this->mName}[$key][$fieldname]";
+                       $data[$name] = $value;
+               }
+               return $data;
+       }
+
+       protected function needsLabel() {
+               return false;
+       }
+
+       public function loadDataFromRequest( $request ) {
+               // It's possible that this might be posted with no fields. Detect that
+               // by looking for an edit token.
+               if ( !$request->getCheck( 'wpEditToken' ) && $request->getArray( $this->mName ) === null ) {
+                       return $this->getDefault();
+               }
+
+               $values = $request->getArray( $this->mName );
+               if ( $values === null ) {
+                       $values = [];
+               }
+
+               $ret = [];
+               foreach ( $values as $key => $value ) {
+                       if ( $key === 'create' || isset( $value['delete'] ) ) {
+                               $ret['nonjs'] = 1;
+                               continue;
+                       }
+
+                       // Add back in $request->getValues() so things that look for e.g.
+                       // wpEditToken don't fail.
+                       $data = $this->rekeyValuesArray( $key, $value ) + $request->getValues();
+
+                       $fields = $this->createFieldsForKey( $key );
+                       $subrequest = new DerivativeRequest( $request, $data, $request->wasPosted() );
+                       $row = [];
+                       foreach ( $fields as $fieldname => $field ) {
+                               if ( $field->skipLoadData( $subrequest ) ) {
+                                       continue;
+                               } elseif ( !empty( $field->mParams['disabled'] ) ) {
+                                       $row[$fieldname] = $field->getDefault();
+                               } else {
+                                       $row[$fieldname] = $field->loadDataFromRequest( $subrequest );
+                               }
+                       }
+                       $ret[] = $row;
+               }
+
+               if ( isset( $values['create'] ) ) {
+                       // Non-JS client clicked the "create" button.
+                       $fields = $this->createFieldsForKey( $this->uniqueId );
+                       $row = [];
+                       foreach ( $fields as $fieldname => $field ) {
+                               if ( !empty( $field->mParams['nodata'] ) ) {
+                                       continue;
+                               } else {
+                                       $row[$fieldname] = $field->getDefault();
+                               }
+                       }
+                       $ret[] = $row;
+               }
+
+               return $ret;
+       }
+
+       public function getDefault() {
+               $ret = parent::getDefault();
+
+               // The default default is one entry with all subfields at their
+               // defaults.
+               if ( $ret === null ) {
+                       $fields = $this->createFieldsForKey( $this->uniqueId );
+                       $row = [];
+                       foreach ( $fields as $fieldname => $field ) {
+                               if ( !empty( $field->mParams['nodata'] ) ) {
+                                       continue;
+                               } else {
+                                       $row[$fieldname] = $field->getDefault();
+                               }
+                       }
+                       $ret = [ $row ];
+               }
+
+               return $ret;
+       }
+
+       public function cancelSubmit( $values, $alldata ) {
+               if ( isset( $values['nonjs'] ) ) {
+                       return true;
+               }
+
+               foreach ( $values as $key => $value ) {
+                       $fields = $this->createFieldsForKey( $key );
+                       foreach ( $fields as $fieldname => $field ) {
+                               if ( !array_key_exists( $fieldname, $value ) ) {
+                                       continue;
+                               }
+                               if ( $field->cancelSubmit( $value[$fieldname], $alldata ) ) {
+                                       return true;
+                               }
+                       }
+               }
+
+               return parent::cancelSubmit( $values, $alldata );
+       }
+
+       public function validate( $values, $alldata ) {
+               if ( isset( $this->mParams['required'] )
+                       && $this->mParams['required'] !== false
+                       && !$values
+               ) {
+                       return $this->msg( 'htmlform-cloner-required' )->parseAsBlock();
+               }
+
+               if ( isset( $values['nonjs'] ) ) {
+                       // The submission was a non-JS create/delete click, so fail
+                       // validation in case cancelSubmit() somehow didn't already handle
+                       // it.
+                       return false;
+               }
+
+               foreach ( $values as $key => $value ) {
+                       $fields = $this->createFieldsForKey( $key );
+                       foreach ( $fields as $fieldname => $field ) {
+                               if ( !array_key_exists( $fieldname, $value ) ) {
+                                       continue;
+                               }
+                               $ok = $field->validate( $value[$fieldname], $alldata );
+                               if ( $ok !== true ) {
+                                       return false;
+                               }
+                       }
+               }
+
+               return parent::validate( $values, $alldata );
+       }
+
+       /**
+        * Get the input HTML for the specified key.
+        *
+        * @param string $key Array key under which the fields should be named
+        * @param array $values
+        * @return string
+        */
+       protected function getInputHTMLForKey( $key, $values ) {
+               $displayFormat = isset( $this->mParams['format'] )
+                       ? $this->mParams['format']
+                       : $this->mParent->getDisplayFormat();
+
+               // Conveniently, PHP method names are case-insensitive.
+               $getFieldHtmlMethod = $displayFormat == 'table' ? 'getTableRow' : ( 'get' . $displayFormat );
+
+               $html = '';
+               $hidden = '';
+               $hasLabel = false;
+
+               $fields = $this->createFieldsForKey( $key );
+               foreach ( $fields as $fieldname => $field ) {
+                       $v = array_key_exists( $fieldname, $values )
+                               ? $values[$fieldname]
+                               : $field->getDefault();
+
+                       if ( $field instanceof HTMLHiddenField ) {
+                               // HTMLHiddenField doesn't generate its own HTML
+                               list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
+                               $hidden .= Html::hidden( $name, $value, $params ) . "\n";
+                       } else {
+                               $html .= $field->$getFieldHtmlMethod( $v );
+
+                               $labelValue = trim( $field->getLabel() );
+                               if ( $labelValue != '&#160;' && $labelValue !== '' ) {
+                                       $hasLabel = true;
+                               }
+                       }
+               }
+
+               if ( !isset( $fields['delete'] ) ) {
+                       $name = "{$this->mName}[$key][delete]";
+                       $label = isset( $this->mParams['delete-button-message'] )
+                               ? $this->mParams['delete-button-message']
+                               : 'htmlform-cloner-delete';
+                       $field = HTMLForm::loadInputFromParameters( $name, [
+                               'type' => 'submit',
+                               'name' => $name,
+                               'id' => Sanitizer::escapeId( "{$this->mID}--$key--delete" ),
+                               'cssclass' => 'mw-htmlform-cloner-delete-button',
+                               'default' => $this->getMessage( $label )->text(),
+                       ], $this->mParent );
+                       $v = $field->getDefault();
+
+                       if ( $displayFormat === 'table' ) {
+                               $html .= $field->$getFieldHtmlMethod( $v );
+                       } else {
+                               $html .= $field->getInputHTML( $v );
+                       }
+               }
+
+               if ( $displayFormat !== 'raw' ) {
+                       $classes = [
+                               'mw-htmlform-cloner-row',
+                       ];
+
+                       if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
+                               $classes[] = 'mw-htmlform-nolabel';
+                       }
+
+                       $attribs = [
+                               'class' => implode( ' ', $classes ),
+                       ];
+
+                       if ( $displayFormat === 'table' ) {
+                               $html = Html::rawElement( 'table',
+                                       $attribs,
+                                       Html::rawElement( 'tbody', [], "\n$html\n" ) ) . "\n";
+                       } else {
+                               $html = Html::rawElement( 'div', $attribs, "\n$html\n" );
+                       }
+               }
+
+               $html .= $hidden;
+
+               if ( !empty( $this->mParams['row-legend'] ) ) {
+                       $legend = $this->msg( $this->mParams['row-legend'] )->text();
+                       $html = Xml::fieldset( $legend, $html );
+               }
+
+               return $html;
+       }
+
+       public function getInputHTML( $values ) {
+               $html = '';
+
+               foreach ( (array)$values as $key => $value ) {
+                       if ( $key === 'nonjs' ) {
+                               continue;
+                       }
+                       $html .= Html::rawElement( 'li', [ 'class' => 'mw-htmlform-cloner-li' ],
+                               $this->getInputHTMLForKey( $key, $value )
+                       );
+               }
+
+               $template = $this->getInputHTMLForKey( $this->uniqueId, null );
+               $html = Html::rawElement( 'ul', [
+                       'id' => "mw-htmlform-cloner-list-{$this->mID}",
+                       'class' => 'mw-htmlform-cloner-ul',
+                       'data-template' => $template,
+                       'data-unique-id' => $this->uniqueId,
+               ], $html );
+
+               $name = "{$this->mName}[create]";
+               $label = isset( $this->mParams['create-button-message'] )
+                       ? $this->mParams['create-button-message']
+                       : 'htmlform-cloner-create';
+               $field = HTMLForm::loadInputFromParameters( $name, [
+                       'type' => 'submit',
+                       'name' => $name,
+                       'id' => Sanitizer::escapeId( "{$this->mID}--create" ),
+                       'cssclass' => 'mw-htmlform-cloner-create-button',
+                       'default' => $this->getMessage( $label )->text(),
+               ], $this->mParent );
+               $html .= $field->getInputHTML( $field->getDefault() );
+
+               return $html;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLFormFieldWithButton.php b/includes/htmlform/fields/HTMLFormFieldWithButton.php
new file mode 100644 (file)
index 0000000..bcb07bd
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Enables HTMLFormField elements to be build with a button.
+ */
+class HTMLFormFieldWithButton extends HTMLFormField {
+       /** @var string $mButtonClass CSS class for the button in this field */
+       protected $mButtonClass = '';
+
+       /** @var string|integer $mButtonId Element ID for the button in this field */
+       protected $mButtonId = '';
+
+       /** @var string $mButtonName Name the button in this field */
+       protected $mButtonName = '';
+
+       /** @var string $mButtonType Type of the button in this field (e.g. button or submit) */
+       protected $mButtonType = 'submit';
+
+       /** @var string $mButtonType Value for the button in this field */
+       protected $mButtonValue;
+
+       /** @var string $mButtonType Value for the button in this field */
+       protected $mButtonFlags = [ 'progressive' ];
+
+       public function __construct( $info ) {
+               if ( isset( $info['buttonclass'] ) ) {
+                       $this->mButtonClass = $info['buttonclass'];
+               }
+               if ( isset( $info['buttonid'] ) ) {
+                       $this->mButtonId = $info['buttonid'];
+               }
+               if ( isset( $info['buttonname'] ) ) {
+                       $this->mButtonName = $info['buttonname'];
+               }
+               if ( isset( $info['buttondefault'] ) ) {
+                       $this->mButtonValue = $info['buttondefault'];
+               }
+               if ( isset( $info['buttontype'] ) ) {
+                       $this->mButtonType = $info['buttontype'];
+               }
+               if ( isset( $info['buttonflags'] ) ) {
+                       $this->mButtonFlags = $info['buttonflags'];
+               }
+               parent::__construct( $info );
+       }
+
+       public function getInputHTML( $value ) {
+               $attr = [
+                       'class' => 'mw-htmlform-submit ' . $this->mButtonClass,
+                       'id' => $this->mButtonId,
+               ] + $this->getAttributes( [ 'disabled', 'tabindex' ] );
+
+               return Html::input( $this->mButtonName, $this->mButtonValue, $this->mButtonType, $attr );
+       }
+
+       public function getInputOOUI( $value ) {
+               return new OOUI\ButtonInputWidget( [
+                       'name' => $this->mButtonName,
+                       'value' => $this->mButtonValue,
+                       'type' => $this->mButtonType,
+                       'label' => $this->mButtonValue,
+                       'flags' => $this->mButtonFlags,
+               ] + OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
+               ) );
+       }
+
+       /**
+        * Combines the passed element with a button.
+        * @param String $element Element to combine the button with.
+        * @return String
+        */
+       public function getElement( $element ) {
+               return $element . '&#160;' . $this->getInputHTML( '' );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLHiddenField.php b/includes/htmlform/fields/HTMLHiddenField.php
new file mode 100644 (file)
index 0000000..c0fce2b
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+
+class HTMLHiddenField extends HTMLFormField {
+       protected $outputAsDefault = true;
+
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               if ( isset( $this->mParams['output-as-default'] ) ) {
+                       $this->outputAsDefault = (bool)$this->mParams['output-as-default'];
+               }
+
+               # Per HTML5 spec, hidden fields cannot be 'required'
+               # http://www.w3.org/TR/html5/forms.html#hidden-state-%28type=hidden%29
+               unset( $this->mParams['required'] );
+       }
+
+       public function getHiddenFieldData( $value ) {
+               $params = [];
+               if ( $this->mID ) {
+                       $params['id'] = $this->mID;
+               }
+
+               if ( $this->outputAsDefault ) {
+                       $value = $this->mDefault;
+               }
+
+               return [ $this->mName, $value, $params ];
+       }
+
+       public function getTableRow( $value ) {
+               list( $name, $value, $params ) = $this->getHiddenFieldData( $value );
+               $this->mParent->addHiddenField( $name, $value, $params );
+               return '';
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getDiv( $value ) {
+               return $this->getTableRow( $value );
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getRaw( $value ) {
+               return $this->getTableRow( $value );
+       }
+
+       public function getInputHTML( $value ) {
+               return '';
+       }
+
+       public function canDisplayErrors() {
+               return false;
+       }
+
+       public function hasVisibleOutput() {
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLInfoField.php b/includes/htmlform/fields/HTMLInfoField.php
new file mode 100644 (file)
index 0000000..6dc5d08
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * An information field (text blob), not a proper input.
+ */
+class HTMLInfoField extends HTMLFormField {
+       /**
+        * @param array $info
+        *   In adition to the usual HTMLFormField parameters, this can take the following fields:
+        *   - default: the value (text) of the field. Unlike other form field types, HTMLInfoField can
+        *     take a closure as a default value, which will be evaluated with $info as its only parameter.
+        *   - raw: if true, the value won't be escaped.
+        *   - rawrow: if true, the usual wrapping of form fields (e.g. into a table row + cell when
+        *     display mode is table) will not happen and the value must contain it already.
+        */
+       public function __construct( $info ) {
+               $info['nodata'] = true;
+
+               parent::__construct( $info );
+       }
+
+       function getDefault() {
+               $default = parent::getDefault();
+               if ( $default instanceof Closure ) {
+                       $default = call_user_func( $default, $this->mParams );
+               }
+               return $default;
+       }
+
+       public function getInputHTML( $value ) {
+               return !empty( $this->mParams['raw'] ) ? $value : htmlspecialchars( $value );
+       }
+
+       public function getInputOOUI( $value ) {
+               if ( !empty( $this->mParams['raw'] ) ) {
+                       $value = new OOUI\HtmlSnippet( $value );
+               }
+
+               return new OOUI\LabelWidget( [
+                       'label' => $value,
+               ] );
+       }
+
+       public function getTableRow( $value ) {
+               if ( !empty( $this->mParams['rawrow'] ) ) {
+                       return $value;
+               }
+
+               return parent::getTableRow( $value );
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getDiv( $value ) {
+               if ( !empty( $this->mParams['rawrow'] ) ) {
+                       return $value;
+               }
+
+               return parent::getDiv( $value );
+       }
+
+       /**
+        * @param string $value
+        * @return string
+        * @since 1.20
+        */
+       public function getRaw( $value ) {
+               if ( !empty( $this->mParams['rawrow'] ) ) {
+                       return $value;
+               }
+
+               return parent::getRaw( $value );
+       }
+
+       protected function needsLabel() {
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLIntField.php b/includes/htmlform/fields/HTMLIntField.php
new file mode 100644 (file)
index 0000000..b0148d9
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * A field that must contain a number
+ */
+class HTMLIntField extends HTMLFloatField {
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               # http://www.w3.org/TR/html5/infrastructure.html#signed-integers
+               # with the addition that a leading '+' sign is ok. Note that leading zeros
+               # are fine, and will be left in the input, which is useful for things like
+               # phone numbers when you know that they are integers (the HTML5 type=tel
+               # input does not require its value to be numeric).  If you want a tidier
+               # value to, eg, save in the DB, clean it up with intval().
+               if ( !preg_match( '/^((\+|\-)?\d+)?$/', trim( $value ) ) ) {
+                       return $this->msg( 'htmlform-int-invalid' )->parseAsBlock();
+               }
+
+               return true;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLMultiSelectField.php b/includes/htmlform/fields/HTMLMultiSelectField.php
new file mode 100644 (file)
index 0000000..a231b2f
--- /dev/null
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * Multi-select field
+ */
+class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable {
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               if ( !is_array( $value ) ) {
+                       return false;
+               }
+
+               # If all options are valid, array_intersect of the valid options
+               # and the provided options will return the provided options.
+               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
+
+               $validValues = array_intersect( $value, $validOptions );
+               if ( count( $validValues ) == count( $value ) ) {
+                       return true;
+               } else {
+                       return $this->msg( 'htmlform-select-badoption' )->parse();
+               }
+       }
+
+       function getInputHTML( $value ) {
+               $value = HTMLFormField::forceToStringRecursive( $value );
+               $html = $this->formatOptions( $this->getOptions(), $value );
+
+               return $html;
+       }
+
+       function formatOptions( $options, $value ) {
+               $html = '';
+
+               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
+
+               foreach ( $options as $label => $info ) {
+                       if ( is_array( $info ) ) {
+                               $html .= Html::rawElement( 'h1', [], $label ) . "\n";
+                               $html .= $this->formatOptions( $info, $value );
+                       } else {
+                               $thisAttribs = [
+                                       'id' => "{$this->mID}-$info",
+                                       'value' => $info,
+                               ];
+                               $checked = in_array( $info, $value, true );
+
+                               $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs, $label );
+
+                               $html .= ' ' . Html::rawElement(
+                                       'div',
+                                       [ 'class' => 'mw-htmlform-flatlist-item' ],
+                                       $checkbox
+                               );
+                       }
+               }
+
+               return $html;
+       }
+
+       protected function getOneCheckbox( $checked, $attribs, $label ) {
+               if ( $this->mParent instanceof OOUIHTMLForm ) {
+                       throw new MWException( 'HTMLMultiSelectField#getOneCheckbox() is not supported' );
+               } else {
+                       $elementFunc = [ 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' ];
+                       $checkbox =
+                               Xml::check( "{$this->mName}[]", $checked, $attribs ) .
+                               '&#160;' .
+                               call_user_func( $elementFunc,
+                                       'label',
+                                       [ 'for' => $attribs['id'] ],
+                                       $label
+                               );
+                       if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+                               $checkbox = Html::openElement( 'div', [ 'class' => 'mw-ui-checkbox' ] ) .
+                                       $checkbox .
+                                       Html::closeElement( 'div' );
+                       }
+                       return $checkbox;
+               }
+       }
+
+       /**
+        * Get the OOUI version of this field.
+        *
+        * @since 1.28
+        * @param string[] $value
+        * @return OOUI\CheckboxMultiselectInputWidget
+        */
+       public function getInputOOUI( $value ) {
+               $attr = $this->getTooltipAndAccessKey();
+               $attr['id'] = $this->mID;
+               $attr['name'] = "{$this->mName}[]";
+
+               $attr['value'] = $value;
+               $attr['options'] = $this->getOptionsOOUI();
+
+               if ( $this->mOptionsLabelsNotFromMessage ) {
+                       foreach ( $attr['options'] as &$option ) {
+                               $option['label'] = new OOUI\HtmlSnippet( $option['label'] );
+                       }
+               }
+
+               $attr += OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
+               );
+
+               if ( $this->mClass !== '' ) {
+                       $attr['classes'] = [ $this->mClass ];
+               }
+
+               return new OOUI\CheckboxMultiselectInputWidget( $attr );
+       }
+
+       /**
+        * @param WebRequest $request
+        *
+        * @return string
+        */
+       function loadDataFromRequest( $request ) {
+               if ( $this->isSubmitAttempt( $request ) ) {
+                       // Checkboxes are just not added to the request arrays if they're not checked,
+                       // so it's perfectly possible for there not to be an entry at all
+                       return $request->getArray( $this->mName, [] );
+               } else {
+                       // That's ok, the user has not yet submitted the form, so show the defaults
+                       return $this->getDefault();
+               }
+       }
+
+       function getDefault() {
+               if ( isset( $this->mDefault ) ) {
+                       return $this->mDefault;
+               } else {
+                       return [];
+               }
+       }
+
+       function filterDataForSubmit( $data ) {
+               $data = HTMLFormField::forceToStringRecursive( $data );
+               $options = HTMLFormField::flattenOptions( $this->getOptions() );
+
+               $res = [];
+               foreach ( $options as $opt ) {
+                       $res["$opt"] = in_array( $opt, $data, true );
+               }
+
+               return $res;
+       }
+
+       protected function needsLabel() {
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLRadioField.php b/includes/htmlform/fields/HTMLRadioField.php
new file mode 100644 (file)
index 0000000..e5b5e68
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * Radio checkbox fields.
+ */
+class HTMLRadioField extends HTMLFormField {
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               if ( !is_string( $value ) && !is_int( $value ) ) {
+                       return false;
+               }
+
+               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
+
+               if ( in_array( strval( $value ), $validOptions, true ) ) {
+                       return true;
+               } else {
+                       return $this->msg( 'htmlform-select-badoption' )->parse();
+               }
+       }
+
+       /**
+        * This returns a block of all the radio options, in one cell.
+        * @see includes/HTMLFormField#getInputHTML()
+        *
+        * @param string $value
+        *
+        * @return string
+        */
+       function getInputHTML( $value ) {
+               $html = $this->formatOptions( $this->getOptions(), strval( $value ) );
+
+               return $html;
+       }
+
+       function getInputOOUI( $value ) {
+               $options = [];
+               foreach ( $this->getOptions() as $label => $data ) {
+                       $options[] = [
+                               'data' => $data,
+                               'label' => $this->mOptionsLabelsNotFromMessage ? new OOUI\HtmlSnippet( $label ) : $label,
+                       ];
+               }
+
+               return new OOUI\RadioSelectInputWidget( [
+                       'name' => $this->mName,
+                       'id' => $this->mID,
+                       'value' => $value,
+                       'options' => $options,
+               ] + OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( [ 'disabled', 'tabindex' ] )
+               ) );
+       }
+
+       function formatOptions( $options, $value ) {
+               global $wgUseMediaWikiUIEverywhere;
+
+               $html = '';
+
+               $attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
+               $elementFunc = [ 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' ];
+
+               # @todo Should this produce an unordered list perhaps?
+               foreach ( $options as $label => $info ) {
+                       if ( is_array( $info ) ) {
+                               $html .= Html::rawElement( 'h1', [], $label ) . "\n";
+                               $html .= $this->formatOptions( $info, $value );
+                       } else {
+                               $id = Sanitizer::escapeId( $this->mID . "-$info" );
+                               $classes = [ 'mw-htmlform-flatlist-item' ];
+                               if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
+                                       $classes[] = 'mw-ui-radio';
+                               }
+                               $radio = Xml::radio( $this->mName, $info, $info === $value, $attribs + [ 'id' => $id ] );
+                               $radio .= '&#160;' . call_user_func( $elementFunc, 'label', [ 'for' => $id ], $label );
+
+                               $html .= ' ' . Html::rawElement(
+                                       'div',
+                                       [ 'class' => $classes ],
+                                       $radio
+                               );
+                       }
+               }
+
+               return $html;
+       }
+
+       protected function needsLabel() {
+               return false;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectAndOtherField.php b/includes/htmlform/fields/HTMLSelectAndOtherField.php
new file mode 100644 (file)
index 0000000..e75c2b2
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * Double field with a dropdown list constructed from a system message in the format
+ *     * Optgroup header
+ *     ** <option value>
+ *     * New Optgroup header
+ * Plus a text field underneath for an additional reason.  The 'value' of the field is
+ * "<select>: <extra reason>", or "<extra reason>" if nothing has been selected in the
+ * select dropdown.
+ * @todo FIXME: If made 'required', only the text field should be compulsory.
+ */
+class HTMLSelectAndOtherField extends HTMLSelectField {
+       function __construct( $params ) {
+               if ( array_key_exists( 'other', $params ) ) {
+                       // Do nothing
+               } elseif ( array_key_exists( 'other-message', $params ) ) {
+                       $params['other'] = $this->getMessage( $params['other-message'] )->plain();
+               } else {
+                       $params['other'] = $this->msg( 'htmlform-selectorother-other' )->plain();
+               }
+
+               parent::__construct( $params );
+
+               if ( $this->getOptions() === null ) {
+                       // Sulk
+                       throw new MWException( 'HTMLSelectAndOtherField called without any options' );
+               }
+               if ( !in_array( 'other', $this->mOptions, true ) ) {
+                       // Have 'other' always as first element
+                       $this->mOptions = [ $params['other'] => 'other' ] + $this->mOptions;
+               }
+               $this->mFlatOptions = self::flattenOptions( $this->getOptions() );
+
+       }
+
+       function getInputHTML( $value ) {
+               $select = parent::getInputHTML( $value[1] );
+
+               $textAttribs = [
+                       'id' => $this->mID . '-other',
+                       'size' => $this->getSize(),
+                       'class' => [ 'mw-htmlform-select-and-other-field' ],
+                       'data-id-select' => $this->mID,
+               ];
+
+               if ( $this->mClass !== '' ) {
+                       $textAttribs['class'][] = $this->mClass;
+               }
+
+               $allowedParams = [
+                       'required',
+                       'autofocus',
+                       'multiple',
+                       'disabled',
+                       'tabindex',
+                       'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
+               ];
+
+               $textAttribs += $this->getAttributes( $allowedParams );
+
+               $textbox = Html::input( $this->mName . '-other', $value[2], 'text', $textAttribs );
+
+               return "$select<br />\n$textbox";
+       }
+
+       function getInputOOUI( $value ) {
+               return false;
+       }
+
+       /**
+        * @param WebRequest $request
+        *
+        * @return array("<overall message>","<select value>","<text field value>")
+        */
+       function loadDataFromRequest( $request ) {
+               if ( $request->getCheck( $this->mName ) ) {
+                       $list = $request->getText( $this->mName );
+                       $text = $request->getText( $this->mName . '-other' );
+
+                       // Should be built the same as in mediawiki.htmlform.js
+                       if ( $list == 'other' ) {
+                               $final = $text;
+                       } elseif ( !in_array( $list, $this->mFlatOptions, true ) ) {
+                               # User has spoofed the select form to give an option which wasn't
+                               # in the original offer.  Sulk...
+                               $final = $text;
+                       } elseif ( $text == '' ) {
+                               $final = $list;
+                       } else {
+                               $final = $list . $this->msg( 'colon-separator' )->inContentLanguage()->text() . $text;
+                       }
+               } else {
+                       $final = $this->getDefault();
+
+                       $list = 'other';
+                       $text = $final;
+                       foreach ( $this->mFlatOptions as $option ) {
+                               $match = $option . $this->msg( 'colon-separator' )->inContentLanguage()->text();
+                               if ( strpos( $text, $match ) === 0 ) {
+                                       $list = $option;
+                                       $text = substr( $text, strlen( $match ) );
+                                       break;
+                               }
+                       }
+               }
+
+               return [ $final, $list, $text ];
+       }
+
+       function getSize() {
+               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
+       }
+
+       function validate( $value, $alldata ) {
+               # HTMLSelectField forces $value to be one of the options in the select
+               # field, which is not useful here.  But we do want the validation further up
+               # the chain
+               $p = parent::validate( $value[1], $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               if ( isset( $this->mParams['required'] )
+                       && $this->mParams['required'] !== false
+                       && $value[1] === ''
+               ) {
+                       return $this->msg( 'htmlform-required' )->parse();
+               }
+
+               return true;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectField.php b/includes/htmlform/fields/HTMLSelectField.php
new file mode 100644 (file)
index 0000000..b6ad46c
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * A select dropdown field.  Basically a wrapper for Xmlselect class
+ */
+class HTMLSelectField extends HTMLFormField {
+       function validate( $value, $alldata ) {
+               $p = parent::validate( $value, $alldata );
+
+               if ( $p !== true ) {
+                       return $p;
+               }
+
+               $validOptions = HTMLFormField::flattenOptions( $this->getOptions() );
+
+               if ( in_array( strval( $value ), $validOptions, true ) ) {
+                       return true;
+               } else {
+                       return $this->msg( 'htmlform-select-badoption' )->parse();
+               }
+       }
+
+       function getInputHTML( $value ) {
+               $select = new XmlSelect( $this->mName, $this->mID, strval( $value ) );
+
+               if ( !empty( $this->mParams['disabled'] ) ) {
+                       $select->setAttribute( 'disabled', 'disabled' );
+               }
+
+               $allowedParams = [ 'tabindex', 'size' ];
+               $customParams = $this->getAttributes( $allowedParams );
+               foreach ( $customParams as $name => $value ) {
+                       $select->setAttribute( $name, $value );
+               }
+
+               if ( $this->mClass !== '' ) {
+                       $select->setAttribute( 'class', $this->mClass );
+               }
+
+               $select->addOptions( $this->getOptions() );
+
+               return $select->getHTML();
+       }
+
+       function getInputOOUI( $value ) {
+               $disabled = false;
+               $allowedParams = [ 'tabindex' ];
+               $attribs = OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( $allowedParams )
+               );
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['classes'] = [ $this->mClass ];
+               }
+
+               if ( !empty( $this->mParams['disabled'] ) ) {
+                       $disabled = true;
+               }
+
+               return new OOUI\DropdownInputWidget( [
+                       'name' => $this->mName,
+                       'id' => $this->mID,
+                       'options' => $this->getOptionsOOUI(),
+                       'value' => strval( $value ),
+                       'disabled' => $disabled,
+               ] + $attribs );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectLimitField.php b/includes/htmlform/fields/HTMLSelectLimitField.php
new file mode 100644 (file)
index 0000000..e7f1c04
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * A limit dropdown, which accepts any valid number
+ */
+class HTMLSelectLimitField extends HTMLSelectField {
+       /**
+        * Basically don't do any validation. If it's a number that's fine. Also,
+        * add it to the list if it's not there already
+        *
+        * @param string $value
+        * @param array $alldata
+        * @return bool
+        */
+       function validate( $value, $alldata ) {
+               if ( $value == '' ) {
+                       return true;
+               }
+
+               // Let folks pick an explicit limit not from our list, as long as it's a real numbr.
+               if ( !in_array( $value, $this->mParams['options'] )
+                       && $value == intval( $value )
+                       && $value > 0
+               ) {
+                       // This adds the explicitly requested limit value to the drop-down,
+                       // then makes sure it's sorted correctly so when we output the list
+                       // later, the custom option doesn't just show up last.
+                       $this->mParams['options'][$this->mParent->getLanguage()->formatNum( $value )] =
+                               intval( $value );
+                       asort( $this->mParams['options'] );
+               }
+
+               return true;
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectNamespace.php b/includes/htmlform/fields/HTMLSelectNamespace.php
new file mode 100644 (file)
index 0000000..ef21969
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Wrapper for Html::namespaceSelector to use in HTMLForm
+ */
+class HTMLSelectNamespace extends HTMLFormField {
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               $this->mAllValue = array_key_exists( 'all', $params )
+                       ? $params['all']
+                       : 'all';
+
+       }
+
+       function getInputHTML( $value ) {
+               return Html::namespaceSelector(
+                       [
+                               'selected' => $value,
+                               'all' => $this->mAllValue
+                       ], [
+                               'name' => $this->mName,
+                               'id' => $this->mID,
+                               'class' => 'namespaceselector',
+                       ]
+               );
+       }
+
+       public function getInputOOUI( $value ) {
+               return new MediaWiki\Widget\NamespaceInputWidget( [
+                       'value' => $value,
+                       'name' => $this->mName,
+                       'id' => $this->mID,
+                       'includeAllValue' => $this->mAllValue,
+               ] );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectNamespaceWithButton.php b/includes/htmlform/fields/HTMLSelectNamespaceWithButton.php
new file mode 100644 (file)
index 0000000..5225983
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Creates a Html::namespaceSelector input field with a button assigned to the input field.
+ */
+class HTMLSelectNamespaceWithButton extends HTMLSelectNamespace {
+       /** @var HTMLFormFieldWithButton $mClassWithButton */
+       protected $mClassWithButton = null;
+
+       public function __construct( $info ) {
+               $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
+               parent::__construct( $info );
+       }
+
+       public function getInputHTML( $value ) {
+               return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSelectOrOtherField.php b/includes/htmlform/fields/HTMLSelectOrOtherField.php
new file mode 100644 (file)
index 0000000..8f7750c
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Select dropdown field, with an additional "other" textbox.
+ *
+ * HTMLComboboxField implements the same functionality using a single form field
+ * and should be used instead.
+ */
+class HTMLSelectOrOtherField extends HTMLTextField {
+       function __construct( $params ) {
+               parent::__construct( $params );
+               $this->getOptions();
+               if ( !in_array( 'other', $this->mOptions, true ) ) {
+                       $msg =
+                               isset( $params['other'] )
+                                       ? $params['other']
+                                       : wfMessage( 'htmlform-selectorother-other' )->text();
+                       // Have 'other' always as first element
+                       $this->mOptions = [ $msg => 'other' ] + $this->mOptions;
+               }
+
+       }
+
+       function getInputHTML( $value ) {
+               $valInSelect = false;
+
+               if ( $value !== false ) {
+                       $value = strval( $value );
+                       $valInSelect = in_array(
+                               $value, HTMLFormField::flattenOptions( $this->getOptions() ), true
+                       );
+               }
+
+               $selected = $valInSelect ? $value : 'other';
+
+               $select = new XmlSelect( $this->mName, $this->mID, $selected );
+               $select->addOptions( $this->getOptions() );
+
+               $select->setAttribute( 'class', 'mw-htmlform-select-or-other' );
+
+               $tbAttribs = [ 'id' => $this->mID . '-other', 'size' => $this->getSize() ];
+
+               if ( !empty( $this->mParams['disabled'] ) ) {
+                       $select->setAttribute( 'disabled', 'disabled' );
+                       $tbAttribs['disabled'] = 'disabled';
+               }
+
+               if ( isset( $this->mParams['tabindex'] ) ) {
+                       $select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
+                       $tbAttribs['tabindex'] = $this->mParams['tabindex'];
+               }
+
+               $select = $select->getHTML();
+
+               if ( isset( $this->mParams['maxlength'] ) ) {
+                       $tbAttribs['maxlength'] = $this->mParams['maxlength'];
+               }
+
+               if ( $this->mClass !== '' ) {
+                       $tbAttribs['class'] = $this->mClass;
+               }
+
+               $textbox = Html::input( $this->mName . '-other', $valInSelect ? '' : $value, 'text', $tbAttribs );
+
+               return "$select<br />\n$textbox";
+       }
+
+       function getInputOOUI( $value ) {
+               return false;
+       }
+
+       /**
+        * @param WebRequest $request
+        *
+        * @return string
+        */
+       function loadDataFromRequest( $request ) {
+               if ( $request->getCheck( $this->mName ) ) {
+                       $val = $request->getText( $this->mName );
+
+                       if ( $val === 'other' ) {
+                               $val = $request->getText( $this->mName . '-other' );
+                       }
+
+                       return $val;
+               } else {
+                       return $this->getDefault();
+               }
+       }
+}
diff --git a/includes/htmlform/fields/HTMLSubmitField.php b/includes/htmlform/fields/HTMLSubmitField.php
new file mode 100644 (file)
index 0000000..cb98549
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * Add a submit button inline in the form (as opposed to
+ * HTMLForm::addButton(), which will add it at the end).
+ */
+class HTMLSubmitField extends HTMLButtonField {
+       protected $buttonType = 'submit';
+
+       protected $mFlags = [ 'primary', 'constructive' ];
+
+       public function skipLoadData( $request ) {
+               return !$request->getCheck( $this->mName );
+       }
+
+       public function loadDataFromRequest( $request ) {
+               return $request->getCheck( $this->mName );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLTagFilter.php b/includes/htmlform/fields/HTMLTagFilter.php
new file mode 100644 (file)
index 0000000..8075de5
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Wrapper for ChangeTags::buildTagFilterSelector to use in HTMLForm
+ */
+class HTMLTagFilter extends HTMLFormField {
+       protected $tagFilter;
+
+       function getTableRow( $value ) {
+               $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
+               if ( $this->tagFilter ) {
+                       return parent::getTableRow( $value );
+               }
+               return '';
+       }
+
+       function getDiv( $value ) {
+               $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
+               if ( $this->tagFilter ) {
+                       return parent::getDiv( $value );
+               }
+               return '';
+       }
+
+       function getInputHTML( $value ) {
+               if ( $this->tagFilter ) {
+                       // we only need the select field, HTMLForm should handle the label
+                       return $this->tagFilter[1];
+               }
+               return '';
+       }
+}
diff --git a/includes/htmlform/fields/HTMLTextAreaField.php b/includes/htmlform/fields/HTMLTextAreaField.php
new file mode 100644 (file)
index 0000000..8ffff43
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+class HTMLTextAreaField extends HTMLFormField {
+       const DEFAULT_COLS = 80;
+       const DEFAULT_ROWS = 25;
+
+       protected $mPlaceholder = '';
+
+       /**
+        * @param array $params
+        *   - cols, rows: textarea size
+        *   - placeholder/placeholder-message: set HTML placeholder attribute
+        *   - spellcheck: set HTML spellcheck attribute
+        */
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               if ( isset( $params['placeholder-message'] ) ) {
+                       $this->mPlaceholder = $this->getMessage( $params['placeholder-message'] )->parse();
+               } elseif ( isset( $params['placeholder'] ) ) {
+                       $this->mPlaceholder = $params['placeholder'];
+               }
+       }
+
+       function getCols() {
+               return isset( $this->mParams['cols'] ) ? $this->mParams['cols'] : static::DEFAULT_COLS;
+       }
+
+       function getRows() {
+               return isset( $this->mParams['rows'] ) ? $this->mParams['rows'] : static::DEFAULT_ROWS;
+       }
+
+       function getSpellCheck() {
+               $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+               if ( is_bool( $val ) ) {
+                       // "spellcheck" attribute literally requires "true" or "false" to work.
+                       return $val === true ? 'true' : 'false';
+               }
+               return null;
+       }
+
+       function getInputHTML( $value ) {
+               $attribs = [
+                               'id' => $this->mID,
+                               'cols' => $this->getCols(),
+                               'rows' => $this->getRows(),
+                               'spellcheck' => $this->getSpellCheck(),
+                       ] + $this->getTooltipAndAccessKey();
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['class'] = $this->mClass;
+               }
+               if ( $this->mPlaceholder !== '' ) {
+                       $attribs['placeholder'] = $this->mPlaceholder;
+               }
+
+               $allowedParams = [
+                       'tabindex',
+                       'disabled',
+                       'readonly',
+                       'required',
+                       'autofocus'
+               ];
+
+               $attribs += $this->getAttributes( $allowedParams );
+               return Html::textarea( $this->mName, $value, $attribs );
+       }
+
+       function getInputOOUI( $value ) {
+               if ( isset( $this->mParams['cols'] ) ) {
+                       throw new Exception( "OOUIHTMLForm does not support the 'cols' parameter for textareas" );
+               }
+
+               $attribs = $this->getTooltipAndAccessKey();
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['classes'] = [ $this->mClass ];
+               }
+               if ( $this->mPlaceholder !== '' ) {
+                       $attribs['placeholder'] = $this->mPlaceholder;
+               }
+
+               $allowedParams = [
+                       'tabindex',
+                       'disabled',
+                       'readonly',
+                       'required',
+                       'autofocus',
+               ];
+
+               $attribs += OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( $allowedParams )
+               );
+
+               return new OOUI\TextInputWidget( [
+                       'id' => $this->mID,
+                       'name' => $this->mName,
+                       'multiline' => true,
+                       'value' => $value,
+                       'rows' => $this->getRows(),
+               ] + $attribs );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLTextField.php b/includes/htmlform/fields/HTMLTextField.php
new file mode 100644 (file)
index 0000000..3ab7176
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+
+class HTMLTextField extends HTMLFormField {
+       protected $mPlaceholder = '';
+
+       /**
+        * @param array $params
+        *   - type: HTML textfield type
+        *   - size: field size in characters (defaults to 45)
+        *   - placeholder/placeholder-message: set HTML placeholder attribute
+        *   - spellcheck: set HTML spellcheck attribute
+        *   - persistent: upon unsuccessful requests, retain the value (defaults to true, except
+        *     for password fields)
+        */
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               if ( isset( $params['placeholder-message'] ) ) {
+                       $this->mPlaceholder = $this->getMessage( $params['placeholder-message'] )->parse();
+               } elseif ( isset( $params['placeholder'] ) ) {
+                       $this->mPlaceholder = $params['placeholder'];
+               }
+       }
+
+       function getSize() {
+               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
+       }
+
+       function getSpellCheck() {
+               $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+               if ( is_bool( $val ) ) {
+                       // "spellcheck" attribute literally requires "true" or "false" to work.
+                       return $val === true ? 'true' : 'false';
+               }
+               return null;
+       }
+
+       public function isPersistent() {
+               if ( isset( $this->mParams['persistent'] ) ) {
+                       return $this->mParams['persistent'];
+               }
+               // don't put passwords into the HTML body, they could get cached or otherwise leaked
+               return !( isset( $this->mParams['type'] ) && $this->mParams['type'] === 'password' );
+       }
+
+       function getInputHTML( $value ) {
+               if ( !$this->isPersistent() ) {
+                       $value = '';
+               }
+
+               $attribs = [
+                               'id' => $this->mID,
+                               'name' => $this->mName,
+                               'size' => $this->getSize(),
+                               'value' => $value,
+                               'dir' => $this->mDir,
+                               'spellcheck' => $this->getSpellCheck(),
+                       ] + $this->getTooltipAndAccessKey() + $this->getDataAttribs();
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['class'] = $this->mClass;
+               }
+               if ( $this->mPlaceholder !== '' ) {
+                       $attribs['placeholder'] = $this->mPlaceholder;
+               }
+
+               # @todo Enforce pattern, step, required, readonly on the server side as
+               # well
+               $allowedParams = [
+                       'type',
+                       'min',
+                       'max',
+                       'pattern',
+                       'title',
+                       'step',
+                       'list',
+                       'maxlength',
+                       'tabindex',
+                       'disabled',
+                       'required',
+                       'autofocus',
+                       'multiple',
+                       'readonly'
+               ];
+
+               $attribs += $this->getAttributes( $allowedParams );
+
+               # Extract 'type'
+               $type = $this->getType( $attribs );
+               return Html::input( $this->mName, $value, $type, $attribs );
+       }
+
+       protected function getType( &$attribs ) {
+               $type = isset( $attribs['type'] ) ? $attribs['type'] : 'text';
+               unset( $attribs['type'] );
+
+               # Implement tiny differences between some field variants
+               # here, rather than creating a new class for each one which
+               # is essentially just a clone of this one.
+               if ( isset( $this->mParams['type'] ) ) {
+                       switch ( $this->mParams['type'] ) {
+                               case 'int':
+                                       $type = 'number';
+                                       break;
+                               case 'float':
+                                       $type = 'number';
+                                       $attribs['step'] = 'any';
+                                       break;
+                               # Pass through
+                               case 'email':
+                               case 'password':
+                               case 'file':
+                               case 'url':
+                                       $type = $this->mParams['type'];
+                                       break;
+                       }
+               }
+
+               return $type;
+       }
+
+       function getInputOOUI( $value ) {
+               if ( !$this->isPersistent() ) {
+                       $value = '';
+               }
+
+               $attribs = $this->getTooltipAndAccessKey();
+
+               if ( $this->mClass !== '' ) {
+                       $attribs['classes'] = [ $this->mClass ];
+               }
+               if ( $this->mPlaceholder !== '' ) {
+                       $attribs['placeholder'] = $this->mPlaceholder;
+               }
+
+               # @todo Enforce pattern, step, required, readonly on the server side as
+               # well
+               $allowedParams = [
+                       'autofocus',
+                       'autosize',
+                       'disabled',
+                       'flags',
+                       'indicator',
+                       'maxlength',
+                       'readonly',
+                       'required',
+                       'tabindex',
+                       'type',
+               ];
+
+               $attribs += OOUI\Element::configFromHtmlAttributes(
+                       $this->getAttributes( $allowedParams )
+               );
+
+               $type = $this->getType( $attribs );
+
+               return $this->getInputWidget( [
+                       'id' => $this->mID,
+                       'name' => $this->mName,
+                       'value' => $value,
+                       'type' => $type,
+               ] + $attribs );
+       }
+
+       protected function getInputWidget( $params ) {
+               return new OOUI\TextInputWidget( $params );
+       }
+
+       /**
+        * Returns an array of data-* attributes to add to the field.
+        *
+        * @return array
+        */
+       protected function getDataAttribs() {
+               return [];
+       }
+}
diff --git a/includes/htmlform/fields/HTMLTextFieldWithButton.php b/includes/htmlform/fields/HTMLTextFieldWithButton.php
new file mode 100644 (file)
index 0000000..7c1c673
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Creates a text input field with a button assigned to the input field.
+ */
+class HTMLTextFieldWithButton extends HTMLTextField {
+       /** @var HTMLFormFieldWithButton $mClassWithButton */
+       protected $mClassWithButton = null;
+
+       public function __construct( $info ) {
+               $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
+               parent::__construct( $info );
+       }
+
+       public function getInputHTML( $value ) {
+               return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
+       }
+}
diff --git a/includes/htmlform/fields/HTMLTitleTextField.php b/includes/htmlform/fields/HTMLTitleTextField.php
new file mode 100644 (file)
index 0000000..fcf721a
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+
+use MediaWiki\Widget\TitleInputWidget;
+
+/**
+ * Implements a text input field for page titles.
+ * Automatically does validation that the title is valid,
+ * as well as autocompletion if using the OOUI display format.
+ *
+ * Note: Forms using GET requests will need to make sure the title value is not
+ * an empty string.
+ *
+ * Optional parameters:
+ * 'namespace' - Namespace the page must be in
+ * 'relative' - If true and 'namespace' given, strip/add the namespace from/to the title as needed
+ * 'creatable' - Whether to validate the title is creatable (not a special page)
+ * 'exists' - Whether to validate that the title already exists
+ *
+ * @since 1.26
+ */
+class HTMLTitleTextField extends HTMLTextField {
+       public function __construct( $params ) {
+               $params += [
+                       'namespace' => false,
+                       'relative' => false,
+                       'creatable' => false,
+                       'exists' => false,
+               ];
+
+               parent::__construct( $params );
+       }
+
+       public function validate( $value, $alldata ) {
+               if ( $this->mParent->getMethod() === 'get' && $value === '' ) {
+                       // If the form is a GET form and has no value, assume it hasn't been
+                       // submitted yet, and skip validation
+                       return parent::validate( $value, $alldata );
+               }
+               try {
+                       if ( !$this->mParams['relative'] ) {
+                               $title = Title::newFromTextThrow( $value );
+                       } else {
+                               // Can't use Title::makeTitleSafe(), because it doesn't throw useful exceptions
+                               global $wgContLang;
+                               $namespaceName = $wgContLang->getNsText( $this->mParams['namespace'] );
+                               $title = Title::newFromTextThrow( $namespaceName . ':' . $value );
+                       }
+               } catch ( MalformedTitleException $e ) {
+                       $msg = $this->msg( $e->getErrorMessage() );
+                       $params = $e->getErrorMessageParameters();
+                       if ( $params ) {
+                               $msg->params( $params );
+                       }
+                       return $msg->parse();
+               }
+
+               $text = $title->getPrefixedText();
+               if ( $this->mParams['namespace'] !== false &&
+                       !$title->inNamespace( $this->mParams['namespace'] )
+               ) {
+                       return $this->msg( 'htmlform-title-badnamespace', $this->mParams['namespace'], $text )->parse();
+               }
+
+               if ( $this->mParams['creatable'] && !$title->canExist() ) {
+                       return $this->msg( 'htmlform-title-not-creatable', $text )->escaped();
+               }
+
+               if ( $this->mParams['exists'] && !$title->exists() ) {
+                       return $this->msg( 'htmlform-title-not-exists', $text )->parse();
+               }
+
+               return parent::validate( $value, $alldata );
+       }
+
+       protected function getInputWidget( $params ) {
+               $this->mParent->getOutput()->addModules( 'mediawiki.widgets' );
+               if ( $this->mParams['namespace'] !== false ) {
+                       $params['namespace'] = $this->mParams['namespace'];
+               }
+               $params['relative'] = $this->mParams['relative'];
+               return new TitleInputWidget( $params );
+       }
+
+       public function getInputHtml( $value ) {
+               // add mw-searchInput class to enable search suggestions for non-OOUI, too
+               $this->mClass .= 'mw-searchInput';
+
+               // return the HTMLTextField html
+               return parent::getInputHTML( $value );
+       }
+
+       protected function getDataAttribs() {
+               return [
+                       'data-mw-searchsuggest' => FormatJson::encode( [
+                               'wrapAsLink' => false,
+                       ] ),
+               ];
+       }
+}
diff --git a/includes/htmlform/fields/HTMLUserTextField.php b/includes/htmlform/fields/HTMLUserTextField.php
new file mode 100644 (file)
index 0000000..5a7e0b9
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+
+use MediaWiki\Widget\UserInputWidget;
+
+/**
+ * Implements a text input field for user names.
+ * Automatically auto-completes if using the OOUI display format.
+ *
+ * FIXME: Does not work for forms that support GET requests.
+ *
+ * Optional parameters:
+ * 'exists' - Whether to validate that the user already exists
+ *
+ * @since 1.26
+ */
+class HTMLUserTextField extends HTMLTextField {
+       public function __construct( $params ) {
+               $params += [
+                       'exists' => false,
+                       'ipallowed' => false,
+               ];
+
+               parent::__construct( $params );
+       }
+
+       public function validate( $value, $alldata ) {
+               // check, if a user exists with the given username
+               $user = User::newFromName( $value, false );
+
+               if ( !$user ) {
+                       return $this->msg( 'htmlform-user-not-valid', $value )->parse();
+               } elseif (
+                       ( $this->mParams['exists'] && $user->getId() === 0 ) &&
+                       !( $this->mParams['ipallowed'] && User::isIP( $value ) )
+               ) {
+                       return $this->msg( 'htmlform-user-not-exists', $user->getName() )->parse();
+               }
+
+               return parent::validate( $value, $alldata );
+       }
+
+       protected function getInputWidget( $params ) {
+               $this->mParent->getOutput()->addModules( 'mediawiki.widgets.UserInputWidget' );
+
+               return new UserInputWidget( $params );
+       }
+
+       public function getInputHtml( $value ) {
+               // add the required module and css class for user suggestions in non-OOUI mode
+               $this->mParent->getOutput()->addModules( 'mediawiki.userSuggest' );
+               $this->mClass .= ' mw-autocomplete-user';
+
+               // return parent html
+               return parent::getInputHTML( $value );
+       }
+}
index f8d26a7..b29e3bd 100644 (file)
        "config-env-php": "PHP $1 i biyo saz.",
        "config-db-type": "Database tipe:",
        "config-db-host": "Database host:",
+       "config-db-host-oracle": "Database TNS:",
        "config-db-name": "Database name:",
+       "config-db-username": "Database nameykarberi:",
+       "config-db-password": "Database parola :",
        "config-db-port": "Portê database:",
        "config-type-mssql": "Microsoft SQL Server",
        "config-header-mysql": "Eyarê MySQL",
diff --git a/includes/installer/i18n/dty.json b/includes/installer/i18n/dty.json
new file mode 100644 (file)
index 0000000..a986e00
--- /dev/null
@@ -0,0 +1,52 @@
+{
+       "@metadata": {
+               "authors": [
+                       "राम प्रसाद जोशी"
+               ]
+       },
+       "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": "An existing installation of MediaWiki has been detected.\nTo upgrade this installation, please put the following line at the bottom of your <code>LocalSettings.php</code>:\n\n$1",
+       "config-localsettings-incomplete": "The existing <code>LocalSettings.php</code> appears to be incomplete.\nThe $1 variable is not set.\nPlease change <code>LocalSettings.php</code> so that this variable is set, and click \"{{int:Config-continue}}\".",
+       "config-localsettings-connection-error": "An error was encountered when connecting to the database using the settings specified in <code>LocalSettings.php</code>. Please fix these settings and try again.\n\n$1",
+       "config-session-error": "Error starting session: $1",
+       "config-session-expired": "Your session data seems to have expired.\nSessions are configured for a lifetime of $1.\nYou can increase this by setting <code>session.gc_maxlifetime</code> in php.ini.\nRestart the installation process.",
+       "config-no-session": "तमरो सेसन डाटा मेटिया छ!\nतमरो php चेक गर। ini र make sure <code>session.save_path</code> is set to an appropriate directory.",
+       "config-your-language": "तमरो भाषा:",
+       "config-your-language-help": "इन्स्टाल गर्दा उपयोग गद्दे भाषा छान ।",
+       "config-wiki-language": "विकि भाषाहरू",
+       "config-wiki-language-help": "Select the language that the wiki will predominantly be written in.",
+       "config-back": "← पछाडी",
+       "config-continue": "जारी राख्या",
+       "config-page-language": "भाषा",
+       "config-page-welcome": "मिडीयाविकिमी तमलाई स्वागत छ!",
+       "config-page-dbconnect": "डेटाबेससँग सम्बन्ध बनाउन्या",
+       "config-page-upgrade": "मौजूदा स्थापनाको नवीनीकरण",
+       "config-page-dbsettings": "डेटावेस सेटिङ",
+       "config-page-name": "नाऊ",
+       "config-page-options": "विकल्पहरू",
+       "config-page-install": "स्थापना गद्दे",
+       "config-page-complete": "पूरा भयो !",
+       "config-page-restart": "स्थापना फेरि सुरु गद्दे",
+       "config-page-readme": "थप पड्डे",
+       "config-page-releasenotes": "प्रकाशन टिप्पणी",
+       "config-page-copying": "कपि हून लाग्याको छ",
+       "config-page-upgradedoc": "अद्यावधिक गरिदै",
+       "config-page-existingwiki": "विकि बन्द हुँदै",
+       "config-help-restart": "Do you want to clear all saved data that you have entered and restart the installation process?",
+       "config-restart": "हुन्छ, पुनः सुचारू गद्दे",
+       "config-welcome": "=== Environmental checks ===\nBasic checks will now be performed to see if this environment is suitable for MediaWiki installation.\nRemember to include this information if you seek support on how to complete the installation.",
+       "config-copyright": "=== Copyright and Terms ===\n\n$1\n\nThis 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.\n\nThis program is distributed in the hope that it will be useful, but <strong>without any warranty</strong>; without even the implied warranty of <strong>merchantability</strong> or <strong>fitness for a particular purpose</strong>.\nSee the GNU General Public License for more details.\n\nYou should have received <doclink href=Copying>a copy of the GNU General Public License</doclink> along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, or [http://www.gnu.org/copyleft/gpl.html read it online].",
+       "config-sidebar": "* [https://www.mediawiki.org MediaWiki home]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Administrator's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Read me</doclink>\n* <doclink href=ReleaseNotes>Release notes</doclink>\n* <doclink href=Copying>Copying</doclink>\n* <doclink href=UpgradeDoc>Upgrading</doclink>",
+       "config-env-good": "The environment has been checked.\nYou can install MediaWiki.",
+       "config-env-bad": "The environment has been checked.\nYou cannot install MediaWiki.",
+       "config-env-php": "PHP $1 is installed.",
+       "config-env-hhvm": "HHVM $1 स्थापना गरिएको छ ।",
+       "config-unicode-using-intl": "Using the [http://pecl.php.net/intl intl PECL extension] for Unicode normalization.",
+       "config-unicode-pure-php-warning": "<strong>Warning:</strong> The [http://pecl.php.net/intl intl PECL extension] is not available to handle Unicode normalization, falling back to slow pure-PHP implementation.\nIf you run a high-traffic site, you should read a little on [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization]."
+}
index 1158193..f812471 100644 (file)
@@ -63,6 +63,7 @@
        "config-header-oracle": "Oracle hobespenak",
        "config-header-mssql": "Microsoft SQL Server-en ezarpenak",
        "config-invalid-db-type": "Datu-base mota baliogabea.",
+       "config-db-sys-user-exists-oracle": "$1 erabiltzaile kontua dagoeneko existitzen da. SYSDBA kontu berri bat sortzeko erabili daiteke soilik!",
        "config-mysql-innodb": "InnoDB",
        "config-mysql-myisam": "MyISAM",
        "config-mysql-binary": "Bitarra",
index e22317c..dae9f2a 100644 (file)
        "config-subscribe": "عضویت در [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce release announcements mailing list].",
        "config-subscribe-help": "این یک میلینگ لیست کم حجم است که برای اطلاع‌رسانی کاربرد دارد و شامل اطلاعیه‌های امنیتی می‌شود.\nشما باید در آن ثبت نام کنید و زمانی که نسخهٔ جدید مدیاویکی ارائه شد آن را به‌روز نمائید.",
        "config-subscribe-noemail": "شما بدون ثبت نشانی پست الکترونیکی قصد داشتید در فهرست اطلاع‌رسانی پخش نرم‌افزار ثبت‌نام کنید.\nاگر قصد ثبت‌نام دارید لطفاً یک نشانی پست الکترونیکی مشخص کنید.",
+       "config-pingback": "اشتراک گذاری داده‌های نصب با توسعه‌دهندگان مدیاویکی",
+       "config-pingback-help": "اگر این گزینه را انتخاب کنید، ویکی‌مدیا به صورت مداوم به وب‌گاه https://www.mediawiki.org برای ارسال اطلاعات ابتدایی نصب این مدیاویکی ارتباط برقرار می‌کند. اطلاعات شامل نوع سامانه، نسخهٔ پی‌اچ‌پی، دیتابیس انتخاب شده می‌باشد. بنیاد مدیاویکی برای توسعه‌های آینده نرم‌افزار اطلاعات را با توسعه دهندگان مدیاویکی به اشتراک می‌گذارد. اطلاعاتی که از سامانه شما ارسال خواهد شد موارد زیر هستند:\n<pre>$1</pre>",
        "config-almost-done": "شما تقریباً عملیات را کامل کرده‌اید.\nاکنون می‌توانید پیکربندی باقیمانده را نخوانده رها کنید و درحال‌حاضر ویکی را نصب کنید.",
        "config-optional-continue": "سوال‌های بیشتری از من بپرسید.",
        "config-optional-skip": "درحال‌حاضر خسته‌ام،سریعاً ویکی را نصب کنید.",
index 326f947..e9e757a 100644 (file)
        "config-subscribe-help": "Esta é unha lista de correos de baixo volume usada para anuncios sobre lanzamentos de novas versións, incluíndo avisos de seguridade importantes.\nDebería subscribirse a ela e actualizar a súa instalación MediaWiki cando saian as novas versións.",
        "config-subscribe-noemail": "Intentou subscribirse á lista de correo dos anuncios de novos lanzamentos sen proporcionar o enderezo de correo electrónico.\nDea un enderezo de correo electrónico se quere efectuar a subscrición á lista de correo.",
        "config-pingback": "Compartir datos de esta instalación cos desenvolvedores de MediaWiki",
-       "config-pingback-help": "Se seleccionas esta opción, MediaWiki enviará periodicamente unha mensaxe a https://www.mediawiki.org con datos básicos sobre esta instancia Mediawiki. Estos datos inclúen, por exemplo, o tipo de sistema, versión de PHP e a base de datos escollida. A Fundación Wikimedia comparte estos datos cos desenvolvedores de MediaWiki para axudar a guiar o traballo futuro de desenvolvemento.",
+       "config-pingback-help": "Se seleccionas esta opción, MediaWiki enviará periodicamente unha mensaxe a https://www.mediawiki.org con datos básicos sobre esta instancia Mediawiki. Estos datos inclúen, por exemplo, o tipo de sistema, versión de PHP e a base de datos escollida. A Fundación Wikimedia comparte estos datos cos desenvolvedores de MediaWiki para axudar a guiar o traballo futuro de desenvolvemento. Serán enviados os seguintes datos do seu sistemaː\n<pre>$1</pre>",
        "config-almost-done": "Xa case rematou!\nNeste paso pode saltar o resto da configuración e instalar o wiki agora mesmo.",
        "config-optional-continue": "Facédeme máis preguntas.",
        "config-optional-skip": "Xa estou canso. Instalade o wiki.",
index f156a00..ac67394 100644 (file)
        "config-subscribe-help": "זוהי רשימת תפוצה עם הודעות מעטות שמשמשת להודעות על הוצאת גרסאות, כולל עדכוני אבטחה חשובים.\nמומלץ להירשם אליה ולעדכן את מדיה־ויקי כאשר יוצאות גרסאות חדשות.",
        "config-subscribe-noemail": "ניסית להירשם לרשימת תפוצה של הודעות בלי לתת כתובת דוא\"ל.\nנא לתת כתובת דוא\"ל אם ברצונך להירשם לרשימת התפוצה.",
        "config-pingback": "לשתף נתונים אודות ההתקנה הזו עם מפתחי מדיה־ויקי.",
+       "config-pingback-help": "אם האפשרות הזאת תיבחר, מדיה־ויקי תודיע לאתר https://www.mediawiki.org נתונים בסיסיים על מופע המדיה־ויקי הזה. הנתונים האלה כוללים, למשל, את סוג המערכת, גרסת ה־PHP, ושרת מסד הנתונים שבחרת. קרן ויקימדיה משתפת את הנתונים האלה עם מפתחי מדיה־ויקי כדי לעזור למאמצי הפיתוח העתידיים. הנתונים הבאים יישלחו מהמערכת שלך:\n<pre>$1</pre>",
        "config-almost-done": "כמעט סיימת!\nאפשר לדלג על שאר ההגדרות ולהתקין את הוויקי כבר עכשיו.",
        "config-optional-continue": "הצגת שאלות נוספות.",
        "config-optional-skip": "משעמם לי, תתקינו לי כבר את הוויקי הזה.",
index 423926b..8d54c98 100644 (file)
        "config-subscribe": "Zapisz się na [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce listę pocztową z ogłoszeniami o nowych wersjach].",
        "config-subscribe-help": "Jest to lista o małej liczbie wiadomości, wykorzystywana do przesyłania informacji o udostępnieniu nowej wersji oraz istotnych sprawach dotyczących bezpieczeństwa.\nPowinieneś zapisać się na tę listę i aktualizować zainstalowane oprogramowanie MediaWiki gdy pojawia się nowa wersja.",
        "config-subscribe-noemail": "Próbowano subskrybować listę mailingową ogłoszeń wersji bez podania adresu e-mail.\nProszę podać adres e-mail, jeśli chcesz subskrybować listę wysyłkową.",
+       "config-pingback": "Udostępnij dane o instalacji twórcom MediaWiki.",
+       "config-pingback-help": "Jeżeli wybierzesz tę opcję, MediaWiki będzie okresowo wysyłać na https://www.mediawiki.org podstawowe dane na temat tej instancji MediaWiki. Te dane zawierają np. typ systemu, wersję PHP i wybrany silnik bazy danych. Fundacja Wikimedia dzieli się tymi danymi z twórcami MediaWiki, aby pomóc w podejmowaniu dalszych wysiłków co do rozwoju. Poniższe dane o Twoim systemie zostaną wysłane:\n<pre>$1</pre>",
        "config-almost-done": "To już prawie koniec!\nMożesz pominąć pozostałe czynności konfiguracyjne i zainstalować wiki.",
        "config-optional-continue": "Zadaj mi więcej pytań.",
        "config-optional-skip": "Jestem już znudzony, po prostu zainstaluj wiki.",
index 8bc18b0..5240f13 100644 (file)
        "config-subscribe": "Підписатися на [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce розсилку анонсів нових версій MediaWiki].",
        "config-subscribe-help": "Це список розсилки з малим обсягом повідомлень, що використовується для анонсування релізів, а також важливих повідомлень про безпеку.\nВам варто підписати і оновлювати інсталяцію MediaWiki, коли з'являтимуться нові версії.",
        "config-subscribe-noemail": "Ви намагались підписатись на розсилку анонсів релізів, не вказавши адреси електронної пошти.\nБудь ласка, вкажіть адресу електронної пошти, якщо хочете підписатись на розсилку.",
+       "config-pingback": "Поділитися даними про цю інсталяцію з розробниками MediaWiki.",
+       "config-pingback-help": "Якщо Ви обираєте цю опцію, MediaWiki періодично пінгуватиме https://www.mediawiki.org базовими даними про цю інсталяцію MediaWiki. Дані включають, наприклад, тип системи, версію PHP, обраний бекенд бази даних. Фонд Вікімедіа ділиться цими даними з розробниками MediaWiki, щоб допомогти спрямувати подальні розробки. Від Вашої системи надсилатимуться такі дані:\n<pre>$1</pre>",
        "config-almost-done": "Майже готово!\nВи можете зараз пропустити налаштування, що залишилось, і встановити вікі прямо зараз.",
        "config-optional-continue": "Запитуйте ще.",
        "config-optional-skip": "Це вже втомлює, просто встановити вікі.",
index dab2f26..ab21779 100644 (file)
        "config-ns-site-name": "同 Wiki 名稱:$1",
        "config-ns-other": "其他 (請註明)",
        "config-ns-other-default": "我的 wiki",
-       "config-project-namespace-help": "許多 Wiki 以維基百科(Wikipedia)做為範例將政策頁面從內容頁面抽離,放置在 \"'''專案命名空間'''\" 中。\n所有在此命名空間裡的頁面都會有特定的字首,您可以在此處設定。\n通常這些字首是由該 Wiki 的名稱所衍伸出來,但無法使用標點符號,如 \"#\" 或 \":\"。",
+       "config-project-namespace-help": "許多 Wiki 以維基百科 (Wikipedia) 做為範例將政策頁面從內容頁面抽離,放置在 \"'''專案命名空間'''\" 中。\n所有在此命名空間裡的頁面都會有特定的字首,您可以在此處設定。\n通常這些字首是由該 Wiki 的名稱所衍伸出來,但無法使用標點符號,如 \"#\" 或 \":\"。",
        "config-ns-invalid": "您指定的命名空間 \"<nowiki>$1</nowiki>\" 無效,\n請指定另一個專案命名空間。",
        "config-ns-conflict": "您指定的命名空間 \"<nowiki>$1</nowiki>\" 與 MediaWiki 預設的命名空間衝突。\n請指定另一個專案命名空間。",
        "config-admin-box": "管理員帳號",
index 1350958..98d7d12 100644 (file)
@@ -307,7 +307,7 @@ class JobRunner implements LoggerAwareInterface {
                $stats->timing( "jobqueue.run.$jType", $timeMs );
                // Track RSS increases for jobs (in case of memory leaks)
                if ( $rssStart && $rssEnd ) {
-                       $stats->increment( "jobqueue.rss_delta.$jType", $rssEnd - $rssStart );
+                       $stats->updateCount( "jobqueue.rss_delta.$jType", $rssEnd - $rssStart );
                }
 
                if ( $status === false ) {
index 511e1c9..4ba1bc3 100644 (file)
@@ -50,7 +50,7 @@ class HtmlArmor {
                if ( $input instanceof HtmlArmor ) {
                        return $input->value;
                } else {
-                       return htmlspecialchars( $input );
+                       return htmlspecialchars( $input, ENT_QUOTES );
                }
        }
 }
index 1a2711a..25a5a26 100644 (file)
@@ -46,7 +46,7 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        /** @var array[] Lock tracking */
        protected $locks = [];
 
-       /** @var integer */
+       /** @var integer ERR_* class constant */
        protected $lastError = self::ERR_NONE;
 
        /** @var string */
@@ -70,6 +70,9 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        /** @var bool */
        private $dupeTrackScheduled = false;
 
+       /** @var integer[] Map of (ATTR_* class constant => QOS_* class constant) */
+       protected $attrMap = [];
+
        /** Possible values for getLastError() */
        const ERR_NONE = 0; // no error
        const ERR_NO_RESPONSE = 1; // no response
@@ -734,4 +737,34 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        public function makeKey() {
                return $this->makeKeyInternal( $this->keyspace, func_get_args() );
        }
+
+       /**
+        * @param integer $flag ATTR_* class constant
+        * @return integer QOS_* class constant
+        * @since 1.28
+        */
+       public function getQoS( $flag ) {
+               return isset( $this->attrMap[$flag] ) ? $this->attrMap[$flag] : self::QOS_UNKNOWN;
+       }
+
+       /**
+        * Merge the flag maps of one or more BagOStuff objects into a "lowest common denominator" map
+        *
+        * @param BagOStuff[] $bags
+        * @return integer[] Resulting flag map (class ATTR_* constant => class QOS_* constant)
+        */
+       protected function mergeFlagMaps( array $bags ) {
+               $map = [];
+               foreach ( $bags as $bag ) {
+                       foreach ( $bag->attrMap as $attr => $rank ) {
+                               if ( isset( $map[$attr] ) ) {
+                                       $map[$attr] = min( $map[$attr], $rank );
+                               } else {
+                                       $map[$attr] = $rank;
+                               }
+                       }
+               }
+
+               return $map;
+       }
 }
index 60ec922..e70a51f 100644 (file)
@@ -42,8 +42,10 @@ class CachedBagOStuff extends HashBagOStuff {
         * @param array $params Parameters for HashBagOStuff
         */
        function __construct( BagOStuff $backend, $params = [] ) {
-               $this->backend = $backend;
                parent::__construct( $params );
+
+               $this->backend = $backend;
+               $this->attrMap = $backend->attrMap;
        }
 
        protected function doGet( $key, $flags = 0 ) {
index 91e7934..62c4fa5 100644 (file)
@@ -42,4 +42,11 @@ interface IExpiringStore {
        const TTL_PROC_LONG = 30; // loose cache time that can survive slow web requests
 
        const TTL_INDEFINITE = 0;
+
+       // Attribute and QoS constants; higher QOS values with the same prefix rank higher...
+       // Medium attributes constants related to emulation or media type
+       const ATTR_EMULATION = 1;
+       const QOS_EMULATION_SQL = 1;
+       // Generic "unknown" value that is useful for comparisons (e.g. always good enough)
+       const QOS_UNKNOWN = INF;
 }
index fe61470..9dcfa7c 100644 (file)
@@ -83,6 +83,7 @@ class MultiWriteBagOStuff extends BagOStuff {
                                $this->caches[] = ObjectFactory::getObjectFromSpec( $cacheInfo );
                        }
                }
+               $this->mergeFlagMaps( $this->caches );
 
                $this->asyncWrites = (
                        isset( $params['replication'] ) &&
index 5f2c509..f2ba9de 100644 (file)
@@ -65,6 +65,7 @@ class ReplicatedBagOStuff extends BagOStuff {
                $this->readStore = ( $params['readFactory'] instanceof BagOStuff )
                        ? $params['readFactory']
                        : ObjectFactory::getObjectFromSpec( $params['readFactory'] );
+               $this->attrMap = $this->mergeFlagMaps( [ $this->readStore, $this->writeStore ] );
        }
 
        public function setDebug( $debug ) {
index b5d014f..4fd40e2 100644 (file)
@@ -977,7 +977,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
 
        /**
         * Get the "last error" registered; clearLastError() should be called manually
-        * @return int ERR_* constant for the "last error" registry
+        * @return int ERR_* class constant for the "last error" registry
         */
        final public function getLastError() {
                if ( $this->lastRelayError ) {
@@ -1019,6 +1019,15 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $this->procCache->clear();
        }
 
+       /**
+        * @param integer $flag ATTR_* class constant
+        * @return integer QOS_* class constant
+        * @since 1.28
+        */
+       public function getQoS( $flag ) {
+               return $this->cache->getQoS( $flag );
+       }
+
        /**
         * Do the actual async bus purge of a key
         *
index 0ebfab7..70a43f2 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup Media
  */
+use MediaWiki\MediaWikiServices;
 
 /**
  * Base media handler class
@@ -36,9 +37,6 @@ abstract class MediaHandler {
         */
        const MAX_ERR_LOG_SIZE = 65535;
 
-       /** @var MediaHandler[] Instance cache with array of MediaHandler */
-       protected static $handlers = [];
-
        /**
         * Get a MediaHandler for a given MIME type from the instance cache
         *
@@ -46,29 +44,8 @@ abstract class MediaHandler {
         * @return MediaHandler|bool
         */
        static function getHandler( $type ) {
-               global $wgMediaHandlers;
-               if ( !isset( $wgMediaHandlers[$type] ) ) {
-                       wfDebug( __METHOD__ . ": no handler found for $type.\n" );
-
-                       return false;
-               }
-               $class = $wgMediaHandlers[$type];
-               if ( !isset( self::$handlers[$class] ) ) {
-                       self::$handlers[$class] = new $class;
-                       if ( !self::$handlers[$class]->isEnabled() ) {
-                               wfDebug( __METHOD__ . ": $class is not enabled\n" );
-                               self::$handlers[$class] = false;
-                       }
-               }
-
-               return self::$handlers[$class];
-       }
-
-       /**
-        * Resets all static caches
-        */
-       public static function resetCache() {
-               self::$handlers = [];
+               return MediaWikiServices::getInstance()
+                       ->getMediaHandlerFactory()->getHandler( $type );
        }
 
        /**
diff --git a/includes/media/MediaHandlerFactory.php b/includes/media/MediaHandlerFactory.php
new file mode 100644 (file)
index 0000000..543dc80
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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
+ * @ingroup Media
+ */
+
+/**
+ * Class to construct MediaHandler objects
+ *
+ * @since 1.28
+ */
+class MediaHandlerFactory {
+
+       /**
+        * Default, MediaWiki core media handlers
+        *
+        * @var array
+        */
+       private static $coreHandlers = [
+               'image/jpeg' => JpegHandler::class,
+               'image/png' => PNGHandler::class,
+               'image/gif' => GIFHandler::class,
+               'image/tiff' => TiffHandler::class,
+               'image/webp' => WebPHandler::class,
+               'image/x-ms-bmp' => BmpHandler::class,
+               'image/x-bmp' => BmpHandler::class,
+               'image/x-xcf' => XCFHandler::class,
+               'image/svg+xml' => SvgHandler::class, // official
+               'image/svg' => SvgHandler::class, // compat
+               'image/vnd.djvu' => DjVuHandler::class, // official
+               'image/x.djvu' => DjVuHandler::class, // compat
+               'image/x-djvu' => DjVuHandler::class, // compat
+       ];
+
+       /**
+        * @var array
+        */
+       private $registry;
+
+       /**
+        * Instance cache of MediaHandler objects by mimetype
+        *
+        * @var MediaHandler[]
+        */
+       private $handlers;
+
+       public function __construct( array $registry ) {
+               $this->registry = $registry + self::$coreHandlers;
+       }
+
+       protected function getHandlerClass( $type ) {
+               if ( isset( $this->registry[$type] ) ) {
+                       return $this->registry[$type];
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * @param string $type mimetype
+        * @return bool|MediaHandler
+        */
+       public function getHandler( $type ) {
+               if ( isset( $this->handlers[$type] ) ) {
+                       return $this->handlers[$type];
+               }
+
+               $class = $this->getHandlerClass( $type );
+               if ( $class !== false ) {
+                       /** @var MediaHandler $handler */
+                       $handler = new $class;
+                       if ( !$handler->isEnabled() ) {
+                               wfDebug( __METHOD__ . ": $class is not enabled\n" );
+                               $handler = false;
+                       }
+               } else {
+                       wfDebug( __METHOD__ . ": no handler found for $type.\n" );
+                       $handler = false;
+               }
+
+               $this->handlers[$type] = $handler;
+               return $handler;
+       }
+}
index e1bb2db..1083393 100644 (file)
@@ -228,14 +228,12 @@ class ObjectCache {
                        }
                }
 
-               try {
-                       // Make sure we actually have a DB backend before falling back to CACHE_DB
-                       MediaWikiServices::getInstance()->getDBLoadBalancer();
-                       $candidate = CACHE_DB;
-               } catch ( ServiceDisabledException $e ) {
+               if ( MediaWikiServices::getInstance()->isServiceDisabled( 'DBLoadBalancer' ) ) {
                        // The LoadBalancer is disabled, probably because
                        // MediaWikiServices::disableStorageBackend was called.
                        $candidate = CACHE_NONE;
+               } else {
+                       $candidate = CACHE_DB;
                }
 
                return self::getInstance( $candidate );
@@ -280,7 +278,7 @@ class ObjectCache {
         * @param array $params [optional] Array key 'fallback' for $fallback.
         * @param int|string $fallback Fallback cache, e.g. (CACHE_NONE, "hash") (since 1.24)
         * @return BagOStuff
-        * @deprecated 1.27
+        * @deprecated since 1.27
         */
        public static function newAccelerator( $params = [], $fallback = null ) {
                if ( $fallback === null ) {
index 98b6eb9..c48880f 100644 (file)
@@ -91,6 +91,9 @@ class SqlBagOStuff extends BagOStuff {
         */
        public function __construct( $params ) {
                parent::__construct( $params );
+
+               $this->attrMap[self::ATTR_EMULATION] = self::QOS_EMULATION_SQL;
+
                if ( isset( $params['servers'] ) ) {
                        $this->serverInfos = [];
                        $this->serverTags = [];
index 2a6f88c..f5a860e 100644 (file)
@@ -1196,6 +1196,7 @@ class Article implements Page {
                $token = $user->getEditToken( $rcid );
 
                $outputPage->preventClickjacking();
+               $outputPage->addModuleStyles( 'mediawiki.page.patrol' );
                if ( $wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed( 'writeapi' ) ) {
                        $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
                }
@@ -1438,14 +1439,13 @@ class Article implements Page {
                        : 'revision-info';
 
                $outputPage = $context->getOutput();
-               $outputPage->addSubtitle( "<div id=\"mw-{$infomsg}\">" .
+               $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
                        $context->msg( $infomsg, $td )
                                ->rawParams( $userlinks )
                                ->params( $revision->getId(), $tddate, $tdtime, $revision->getUserText() )
                                ->rawParams( Linker::revComment( $revision, true, true ) )
                                ->parse() .
-                       "</div>"
-               );
+                       "</div>";
 
                $lnk = $current
                        ? $context->msg( 'currentrevisionlink' )->escaped()
@@ -1517,10 +1517,12 @@ class Article implements Page {
                        $cdel .= ' ';
                }
 
-               $outputPage->addSubtitle( "<div id=\"mw-revision-nav\">" . $cdel .
+               // the outer div is need for styling the revision info and nav in MobileFrontend
+               $outputPage->addSubtitle( "<div class=\"mw-revision\">" . $revisionInfo .
+                       "<div id=\"mw-revision-nav\">" . $cdel .
                        $context->msg( 'revision-nav' )->rawParams(
                                $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
-                       )->escaped() . "</div>" );
+                       )->escaped() . "</div></div>" );
        }
 
        /**
index 46fef10..bded84d 100644 (file)
@@ -1043,14 +1043,16 @@ class WikiPage implements Page, IDBAccessObject {
         *
         * @since 1.19
         * @param ParserOptions $parserOptions ParserOptions to use for the parse operation
-        * @param null|int $oldid Revision ID to get the text from, passing null or 0 will
-        *   get the current revision (default value)
-        *
-        * @return ParserOutput|bool ParserOutput or false if the revision was not found
+        * @param null|int      $oldid Revision ID to get the text from, passing null or 0 will
+        *                             get the current revision (default value)
+        * @param bool          $forceParse Force reindexing, regardless of cache settings
+        * @return bool|ParserOutput ParserOutput or false if the revision was not found
         */
-       public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
+       public function getParserOutput( ParserOptions $parserOptions, $oldid = null,
+                                        $forceParse = false ) {
 
-               $useParserCache = $this->shouldCheckParserCache( $parserOptions, $oldid );
+               $useParserCache =
+                       ( !$forceParse ) && $this->shouldCheckParserCache( $parserOptions, $oldid );
                wfDebug( __METHOD__ .
                        ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
                if ( $parserOptions->getStubThreshold() ) {
@@ -1834,7 +1836,8 @@ class WikiPage implements Page, IDBAccessObject {
                                        ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $params );
                                        Hooks::run( 'PageContentSaveComplete', $params );
                                }
-                       )
+                       ),
+                       DeferredUpdates::PRESEND
                );
 
                return $status;
@@ -1959,7 +1962,8 @@ class WikiPage implements Page, IDBAccessObject {
                                        Hooks::run( 'PageContentSaveComplete', $params );
 
                                }
-                       )
+                       ),
+                       DeferredUpdates::PRESEND
                );
 
                return $status;
@@ -2925,6 +2929,8 @@ class WikiPage implements Page, IDBAccessObject {
                        ],
                        __METHOD__
                );
+               // Save this so we can pass it to the ArticleDeleteComplete hook.
+               $archivedRevisionCount = $dbw->affectedRows();
 
                // Now that it's safely backed up, delete it
                $dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
@@ -2955,7 +2961,7 @@ class WikiPage implements Page, IDBAccessObject {
                $this->doDeleteUpdates( $id, $content );
 
                Hooks::run( 'ArticleDeleteComplete',
-                       [ &$this, &$user, $reason, $id, $content, $logEntry ] );
+                       [ &$this, &$user, $reason, $id, $content, $logEntry, $archivedRevisionCount ] );
                $status->value = $logid;
 
                // Show log excerpt on 404 pages rather than just a link
index d787edb..32daeed 100644 (file)
@@ -25,7 +25,7 @@
  * Class for handling function-scope profiling
  *
  * @since 1.22
- * @deprecated 1.25 No-op now
+ * @deprecated since 1.25 No-op now
  */
 class ProfileSection {
        /**
index 50a77ec..cc71630 100644 (file)
@@ -42,7 +42,7 @@ function wfGetRusage() {
 /**
  * Begin profiling of a function
  * @param string $functionname Name of the function we will profile
- * @deprecated 1.25
+ * @deprecated since 1.25
  */
 function wfProfileIn( $functionname ) {
 }
@@ -50,7 +50,7 @@ function wfProfileIn( $functionname ) {
 /**
  * Stop profiling of a function
  * @param string $functionname Name of the function we have profiled
- * @deprecated 1.25
+ * @deprecated since 1.25
  */
 function wfProfileOut( $functionname = 'missing' ) {
 }
index 1aba71c..bf26573 100644 (file)
@@ -38,6 +38,8 @@ class TransactionProfiler implements LoggerAwareInterface {
        protected $dbLockThreshold = 3.0;
        /** @var float Seconds */
        protected $eventThreshold = .25;
+       /** @var bool */
+       protected $silenced = false;
 
        /** @var array transaction ID => (write start time, list of DBs involved) */
        protected $dbTrxHoldingLocks = [];
@@ -77,6 +79,14 @@ class TransactionProfiler implements LoggerAwareInterface {
                $this->logger = $logger;
        }
 
+       /**
+        * @param bool $value
+        * @since 1.28
+        */
+       public function setSilenced( $value ) {
+               $this->silenced = $value;
+       }
+
        /**
         * Set performance expectations
         *
@@ -302,6 +312,10 @@ class TransactionProfiler implements LoggerAwareInterface {
         * @param string|float|int $actual [optional]
         */
        protected function reportExpectationViolated( $expect, $query, $actual = null ) {
+               if ( $this->silenced ) {
+                       return;
+               }
+
                $n = $this->expect[$expect];
                $by = $this->expectBy[$expect];
                $actual = ( $actual !== null ) ? " (actual: $actual)" : "";
index 1a93f6e..85a6954 100644 (file)
@@ -1578,7 +1578,6 @@ MESSAGE;
                        array_fill_keys( $this->config->get( 'ResourceLoaderLESSImportPaths' ), '' )
                );
                $parser->SetOption( 'relativeUrls', false );
-               $parser->SetCacheDir( $this->config->get( 'CacheDirectory' ) ?: wfTempDir() );
 
                return $parser;
        }
index 6b755d7..2816126 100644 (file)
@@ -255,6 +255,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                                                $this->{$member}[$key] = (array)$value;
                                        }
                                        break;
+                               case 'deprecated':
+                                       $this->deprecated = $option;
+                                       break;
                                // Lists of strings
                                case 'dependencies':
                                case 'messages':
@@ -352,7 +355,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         */
        public function getScript( ResourceLoaderContext $context ) {
                $files = $this->getScriptFiles( $context );
-               return $this->readScriptFiles( $files );
+               return $this->getDeprecationInformation() . $this->readScriptFiles( $files );
        }
 
        /**
index 59f9a63..48e7937 100644 (file)
@@ -82,6 +82,11 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         */
        protected $config;
 
+       /**
+        * @var array|bool
+        */
+       protected $deprecated = false;
+
        /**
         * @var LoggerInterface
         */
@@ -130,6 +135,28 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                return $wgContLang->getDir() !== $context->getDirection();
        }
 
+       /**
+        * Get JS representing deprecation information for the current module if available
+        *
+        * @return string JavaScript code
+        */
+       protected function getDeprecationInformation() {
+               $deprecationInfo = $this->deprecated;
+               if ( $deprecationInfo ) {
+                       $name = $this->getName();
+                       $warning = 'This page is using the deprecated ResourceLoader module "' . $name . '".';
+                       if ( !is_bool( $deprecationInfo ) && isset( $deprecationInfo['message'] ) ) {
+                               $warning .= "\n" . $deprecationInfo['message'];
+                       }
+                       return Xml::encodeJsCall(
+                               'mw.log.warn',
+                               [ $warning ]
+                       );
+               } else {
+                       return '';
+               }
+       }
+
        /**
         * Get all JS for this module for a given language and skin.
         * Includes all relevant JS except loader scripts.
index e01d0a1..7401d58 100644 (file)
@@ -39,12 +39,13 @@ class ResourceLoaderSiteModule extends ResourceLoaderWikiModule {
                        $pages['MediaWiki:Common.js'] = [ 'type' => 'script' ];
                        $pages['MediaWiki:' . ucfirst( $context->getSkin() ) . '.js'] = [ 'type' => 'script' ];
                }
-               if ( $this->getConfig()->get( 'UseSiteCss' ) ) {
-                       $pages['MediaWiki:Common.css'] = [ 'type' => 'style' ];
-                       $pages['MediaWiki:' . ucfirst( $context->getSkin() ) . '.css'] = [ 'type' => 'style' ];
-                       $pages['MediaWiki:Print.css'] = [ 'type' => 'style', 'media' => 'print' ];
-
-               }
                return $pages;
        }
+
+       /*
+        * @return array
+        */
+       public function getDependencies( ResourceLoaderContext $context = null ) {
+               return [ 'site.styles' ];
+       }
 }
index 7b2d532..eb9788c 100644 (file)
@@ -66,6 +66,8 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        }
                }
 
+               $illegalFileChars = $conf->get( 'IllegalFileChars' );
+
                // Build list of variables
                $vars = [
                        'wgLoadScript' => wfScript( 'load' ),
@@ -107,6 +109,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        'wgResourceLoaderMaxQueryLength' => $conf->get( 'ResourceLoaderMaxQueryLength' ),
                        'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces,
                        'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass( Title::legalChars() ),
+                       'wgIllegalFileChars' => Title::convertByteClassToUnicodeClass( $illegalFileChars ),
                        'wgResourceLoaderStorageVersion' => $conf->get( 'ResourceLoaderStorageVersion' ),
                        'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
                        'wgResourceLoaderLegacyModules' => self::getLegacyModules(),
index 8d4f263..8f58040 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 /**
- * ResourceLoader module for user customizations.
- *
  * 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
@@ -23,7 +21,7 @@
  */
 
 /**
- * Module for user customizations
+ * Module for user customizations scripts
  */
 class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
 
@@ -31,8 +29,6 @@ class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
        protected $targets = [ 'desktop', 'mobile' ];
 
        /**
-        * Get list of pages used by this module
-        *
         * @param ResourceLoaderContext $context
         * @return array List of pages
         */
@@ -52,35 +48,20 @@ class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
                        $pages["$userPage/" . $context->getSkin() . '.js'] = [ 'type' => 'script' ];
                }
 
-               if ( $config->get( 'AllowUserCss' ) ) {
-                       $pages["$userPage/common.css"] = [ 'type' => 'style' ];
-                       $pages["$userPage/" . $context->getSkin() . '.css'] = [ 'type' => 'style' ];
-               }
-
-               $useSiteJs = $config->get( 'UseSiteJs' );
-               $useSiteCss = $config->get( 'UseSiteCss' );
                // User group pages are maintained site-wide and enabled with site JS/CSS.
-               if ( $useSiteJs || $useSiteCss ) {
+               if ( $config->get( 'UseSiteJs' ) ) {
                        foreach ( $user->getEffectiveGroups() as $group ) {
                                if ( $group == '*' ) {
                                        continue;
                                }
-                               if ( $useSiteJs ) {
-                                       $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
-                               }
-                               if ( $useSiteCss ) {
-                                       $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
-                               }
+                               $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
                        }
                }
 
-               // Hack for bug 26283: if we're on a preview page for a CSS/JS page,
-               // we need to exclude that page from this module. In that case, the excludepage
-               // parameter will be set to the name of the page we need to exclude.
+               // Hack for T28283: Allow excluding pages for preview on a CSS/JS page.
+               // The excludepage parameter is set by OutputPage.
                $excludepage = $context->getRequest()->getVal( 'excludepage' );
                if ( isset( $pages[$excludepage] ) ) {
-                       // This works because $excludepage is generated with getPrefixedDBkey(),
-                       // just like the keys in $pages[] above
                        unset( $pages[$excludepage] );
                }
 
@@ -95,4 +76,11 @@ class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
        public function getGroup() {
                return 'user';
        }
+
+       /**
+        * @return array
+        */
+       public function getDependencies( ResourceLoaderContext $context = null ) {
+               return [ 'user.styles' ];
+       }
 }
diff --git a/includes/resourceloader/ResourceLoaderUserStylesModule.php b/includes/resourceloader/ResourceLoaderUserStylesModule.php
new file mode 100644 (file)
index 0000000..8d8e008
--- /dev/null
@@ -0,0 +1,86 @@
+<?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
+ * @author Trevor Parscal
+ * @author Roan Kattouw
+ */
+
+/**
+ * Module for user customizations styles
+ */
+class ResourceLoaderUserStylesModule extends ResourceLoaderWikiModule {
+
+       protected $origin = self::ORIGIN_USER_INDIVIDUAL;
+       protected $targets = [ 'desktop', 'mobile' ];
+
+       /**
+        * @param ResourceLoaderContext $context
+        * @return array List of pages
+        */
+       protected function getPages( ResourceLoaderContext $context ) {
+               $config = $this->getConfig();
+               $user = $context->getUserObj();
+               if ( $user->isAnon() ) {
+                       return [];
+               }
+
+               // Use localised/normalised variant to ensure $excludepage matches
+               $userPage = $user->getUserPage()->getPrefixedDBkey();
+               $pages = [];
+
+               if ( $config->get( 'AllowUserCss' ) ) {
+                       $pages["$userPage/common.css"] = [ 'type' => 'style' ];
+                       $pages["$userPage/" . $context->getSkin() . '.css'] = [ 'type' => 'style' ];
+               }
+
+               // User group pages are maintained site-wide and enabled with site JS/CSS.
+               if ( $config->get( 'UseSiteCss' ) ) {
+                       foreach ( $user->getEffectiveGroups() as $group ) {
+                               if ( $group == '*' ) {
+                                       continue;
+                               }
+                               $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
+                       }
+               }
+
+               // Hack for T28283: Allow excluding pages for preview on a CSS/JS page.
+               // The excludepage parameter is set by OutputPage.
+               $excludepage = $context->getRequest()->getVal( 'excludepage' );
+               if ( isset( $pages[$excludepage] ) ) {
+                       unset( $pages[$excludepage] );
+               }
+
+               return $pages;
+       }
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return self::LOAD_STYLES;
+       }
+
+       /**
+        * Get group name
+        *
+        * @return string
+        */
+       public function getGroup() {
+               return 'user';
+       }
+}
index 39fb8ef..52df2e3 100644 (file)
  * Item class for a filearchive table row
  */
 class RevDelArchivedFileItem extends RevDelFileItem {
-       /** @var RevDelArchivedFileList */
-       protected $list;
-       /** @var ArchivedFile */
-       protected $file;
+       /** @var $list RevDelArchivedFileList */
+       /** @var $file ArchivedFile */
        /** @var LocalFile */
        protected $lockFile;
 
index 3a3b467..ff01cee 100644 (file)
  * Item class for an oldimage table row
  */
 class RevDelFileItem extends RevDelItem {
-       /** @var OldLocalFile */
-       public $file;
        /** @var RevDelFileList */
        protected $list;
+       /** @var OldLocalFile */
+       protected $file;
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
index 9168d64..c2ccca0 100644 (file)
@@ -659,7 +659,7 @@ abstract class SearchEngine {
         * Create a search field definition.
         * Specific search engines should override this method to create search fields.
         * @param string $name
-        * @param int    $type
+        * @param int    $type One of the types in SearchIndexField::INDEX_TYPE_*
         * @return SearchIndexField
         * @since 1.28
         */
index 3e5ef3b..8ccb6d1 100644 (file)
@@ -374,202 +374,15 @@ final class SessionManager implements SessionManagerInterface {
         * @deprecated since 1.27, use MediaWiki\Auth\AuthManager::autoCreateUser instead
         * @param User $user User to auto-create
         * @return bool Success
+        * @codeCoverageIgnore
         */
        public static function autoCreateUser( User $user ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               // @codeCoverageIgnoreStart
-               if ( !$wgDisableAuthManager ) {
-                       wfDeprecated( __METHOD__, '1.27' );
-                       return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
-                               $user,
-                               \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
-                               false
-                       )->isGood();
-               }
-               // @codeCoverageIgnoreEnd
-
-               $logger = self::singleton()->logger;
-
-               // Much of this code is based on that in CentralAuth
-
-               // Try the local user from the slave DB
-               $localId = User::idFromName( $user->getName() );
-               $flags = 0;
-
-               // Fetch the user ID from the master, so that we don't try to create the user
-               // when they already exist, due to replication lag
-               // @codeCoverageIgnoreStart
-               if ( !$localId && wfGetLB()->getReaderIndex() != 0 ) {
-                       $localId = User::idFromName( $user->getName(), User::READ_LATEST );
-                       $flags = User::READ_LATEST;
-               }
-               // @codeCoverageIgnoreEnd
-
-               if ( $localId ) {
-                       // User exists after all.
-                       $user->setId( $localId );
-                       $user->loadFromId( $flags );
-                       return false;
-               }
-
-               // Denied by AuthPlugin? But ignore AuthPlugin itself.
-               if ( get_class( $wgAuth ) !== 'AuthPlugin' && !$wgAuth->autoCreate() ) {
-                       $logger->debug( __METHOD__ . ': denied by AuthPlugin' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Wiki is read-only?
-               if ( wfReadOnly() ) {
-                       $logger->debug( __METHOD__ . ': denied by wfReadOnly()' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               $userName = $user->getName();
-
-               // Check the session, if we tried to create this user already there's
-               // no point in retrying.
-               $session = self::getGlobalSession();
-               $reason = $session->get( 'MWSession::AutoCreateBlacklist' );
-               if ( $reason ) {
-                       $logger->debug( __METHOD__ . ": blacklisted in session ($reason)" );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Is the IP user able to create accounts?
-               $anon = new User;
-               if ( !$anon->isAllowedAny( 'createaccount', 'autocreateaccount' )
-                       || $anon->isBlockedFromCreateAccount()
-               ) {
-                       // Blacklist the user to avoid repeated DB queries subsequently
-                       $logger->debug( __METHOD__ . ': user is blocked from this wiki, blacklisting' );
-                       $session->set( 'MWSession::AutoCreateBlacklist', 'blocked', 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Check for validity of username
-               if ( !User::isCreatableName( $userName ) ) {
-                       $logger->debug( __METHOD__ . ': Invalid username, blacklisting' );
-                       $session->set( 'MWSession::AutoCreateBlacklist', 'invalid username', 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Give other extensions a chance to stop auto creation.
-               $user->loadDefaults( $userName );
-               $abortMessage = '';
-               if ( !\Hooks::run( 'AbortAutoAccount', [ $user, &$abortMessage ] ) ) {
-                       // In this case we have no way to return the message to the user,
-                       // but we can log it.
-                       $logger->debug( __METHOD__ . ": denied by hook: $abortMessage" );
-                       $session->set( 'MWSession::AutoCreateBlacklist', "hook aborted: $abortMessage", 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Make sure the name has not been changed
-               if ( $user->getName() !== $userName ) {
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       throw new \UnexpectedValueException(
-                               'AbortAutoAccount hook tried to change the user name'
-                       );
-               }
-
-               // Ignore warnings about master connections/writes...hard to avoid here
-               \Profiler::instance()->getTransactionProfiler()->resetExpectations();
-
-               $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'MWSession', 'autocreate-failed', md5( $userName ) );
-               if ( $cache->get( $backoffKey ) ) {
-                       $logger->debug( __METHOD__ . ': denied by prior creation attempt failures' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Checks passed, create the user...
-               $from = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : 'CLI';
-               $logger->info( __METHOD__ . ': creating new user ({username}) - from: {url}',
-                       [
-                               'username' => $userName,
-                               'url' => $from,
-               ] );
-
-               try {
-                       // Insert the user into the local DB master
-                       $status = $user->addToDatabase();
-                       if ( !$status->isOK() ) {
-                               // @codeCoverageIgnoreStart
-                               // double-check for a race condition (T70012)
-                               $id = User::idFromName( $user->getName(), User::READ_LATEST );
-                               if ( $id ) {
-                                       $logger->info( __METHOD__ . ': tried to autocreate existing user',
-                                               [
-                                                       'username' => $userName,
-                                               ] );
-                               } else {
-                                       $logger->error(
-                                               __METHOD__ . ': failed with message ' . $status->getWikiText( false, false, 'en' ),
-                                               [
-                                                       'username' => $userName,
-                                               ]
-                                       );
-                               }
-                               $user->setId( $id );
-                               $user->loadFromId( User::READ_LATEST );
-                               return false;
-                               // @codeCoverageIgnoreEnd
-                       }
-               } catch ( \Exception $ex ) {
-                       // @codeCoverageIgnoreStart
-                       $logger->error( __METHOD__ . ': failed with exception {exception}', [
-                               'exception' => $ex,
-                               'username' => $userName,
-                       ] );
-                       // Do not keep throwing errors for a while
-                       $cache->set( $backoffKey, 1, 600 );
-                       // Bubble up error; which should normally trigger DB rollbacks
-                       throw $ex;
-                       // @codeCoverageIgnoreEnd
-               }
-
-               # Notify AuthPlugin
-               // @codeCoverageIgnoreStart
-               $tmpUser = $user;
-               $wgAuth->initUser( $tmpUser, true );
-               if ( $tmpUser !== $user ) {
-                       $logger->warning( __METHOD__ . ': ' .
-                               get_class( $wgAuth ) . '::initUser() replaced the user object' );
-               }
-               // @codeCoverageIgnoreEnd
-
-               # Notify hooks (e.g. Newuserlog)
-               \Hooks::run( 'AuthPluginAutoCreate', [ $user ] );
-               \Hooks::run( 'LocalUserCreated', [ $user, true ] );
-
-               $user->saveSettings();
-
-               # Update user count
-               \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
-               # Watch user's userpage and talk page
-               $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
-
-               return true;
+               wfDeprecated( __METHOD__, '1.27' );
+               return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+                       $user,
+                       \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+                       false
+               )->isGood();
        }
 
        /**
index a4116ae..2f8a113 100644 (file)
@@ -35,8 +35,8 @@ class SiteSQLStore {
         * @note This does not return an instance of SiteSQLStore!
         *
         * @since 1.21
-        * @deprecated 1.27 use MediaWikiServices::getSiteStore() or MediaWikiServices::getSiteLookup()
-        *             instead.
+        * @deprecated since 1.27 use MediaWikiServices::getSiteStore()
+        *             or MediaWikiServices::getSiteLookup() instead.
         *
         * @param null $sitesTable IGNORED
         * @param null $cache IGNORED
index 64d2f8b..d473251 100644 (file)
@@ -1566,56 +1566,4 @@ abstract class Skin extends ContextSource {
                return $result;
        }
 
-       /** @deprecated in 1.21 */
-       public function commentBlock( $comment, $title = null, $local = false, $wikiId = null ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::commentBlock( $comment, $title, $local, $wikiId );
-       }
-
-       /** @deprecated in 1.21 */
-       public function generateRollback(
-               $rev,
-               IContextSource $context = null,
-               $options = [ 'verify' ]
-       ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::generateRollback( $rev, $context, $options );
-       }
-
-       /** @deprecated in 1.21 */
-       public function link( $target, $html = null, $customAttribs = [], $query = [], $options = [] ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::link( $target, $html, $customAttribs, $query, $options );
-       }
-
-       /** @deprecated in 1.21 */
-       public function linkKnown(
-               $target,
-               $html = null,
-               $customAttribs = [],
-               $query = [],
-               $options = [ 'known', 'noclasses' ]
-       ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::linkKnown( $target, $html, $customAttribs, $query, $options );
-       }
-
-       /** @deprecated in 1.21 */
-       public function userLink( $userId, $userName, $altUserName = false ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::userLink( $userId, $userName, $altUserName );
-       }
-
-       /** @deprecated in 1.21 */
-       public function userToolLinks(
-               $userId,
-               $userText,
-               $redContribsWhenNoEdits = false,
-               $flags = 0,
-               $edits = null
-       ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               return Linker::userToolLinks( $userId, $userText, $redContribsWhenNoEdits, $flags, $edits );
-       }
-
 }
index 69e2e8b..22413b9 100644 (file)
@@ -665,34 +665,17 @@ class SkinTemplate extends Skin {
                                ? 'nav-login-createaccount'
                                : 'pt-login';
 
-                       // TODO remove this after AuthManager is stable
-                       global $wgDisableAuthManager;
-                       if ( $wgDisableAuthManager ) {
-                               $is_signup = $request->getText( 'type' ) == 'signup';
-                               $login_url = [
-                                       'text' => $this->msg( $loginlink )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' )
-                                               && ( $loginlink == 'nav-login-createaccount' || !$is_signup ),
-                               ];
-                               $createaccount_url = [
-                                       'text' => $this->msg( 'pt-createaccount' )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
-                                       'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
-                               ];
-                       } else {
-                               $login_url = [
-                                       'text' => $this->msg( $loginlink )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' ) ||
-                                               $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
-                               ];
-                               $createaccount_url = [
-                                       'text' => $this->msg( 'pt-createaccount' )->text(),
-                                       'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
-                                       'active' => $title->isSpecial( 'CreateAccount' ),
-                               ];
-                       }
+                       $login_url = [
+                               'text' => $this->msg( $loginlink )->text(),
+                               'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
+                               'active' => $title->isSpecial( 'Userlogin' )
+                                       || $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
+                       ];
+                       $createaccount_url = [
+                               'text' => $this->msg( 'pt-createaccount' )->text(),
+                               'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
+                               'active' => $title->isSpecial( 'CreateAccount' ),
+                       ];
 
                        // No need to show Talk and Contributions to anons if they can't contribute!
                        if ( User::groupHasPermission( '*', 'edit' ) ) {
index 5dab221..8a2e0d6 100644 (file)
@@ -1342,196 +1342,12 @@ class FakeAuthTemplate extends BaseTemplate {
        }
 }
 
-/**
- * A horrible hack to handle AuthManager's feature flag. For other special pages this is done in
- * SpecialPageFactory, but LoginForm is used directly by some extensions. Will be killed as soon
- * as AuthManager is stable.
- */
-class LoginForm extends SpecialPage {
-       private $realLoginForm;
-
-       public function __construct( $request = null ) {
-               global $wgDisableAuthManager;
-               if ( $wgDisableAuthManager ) {
-                       $this->realLoginForm = new LoginFormPreAuthManager( $request );
-               } else {
-                       $this->realLoginForm = new LoginFormAuthManager( $request );
-               }
-       }
-
-       // proxy everything
-
-       public function __get( $name ) {
-               return $this->realLoginForm->$name;
-       }
-
-       public function __set( $name, $value ) {
-               $this->realLoginForm->$name = $value;
-       }
-
-       public function __call( $name, $args ) {
-               return call_user_func_array( [ $this->realLoginForm, $name ], $args );
-       }
-
-       public static function __callStatic( $name, $args ) {
-               global $wgDisableAuthManager;
-               return call_user_func_array( [ $wgDisableAuthManager ? LoginFormPreAuthManager::class
-                       : LoginFormAuthManager::class, $name ], $args );
-       }
-
-       // all public SpecialPage methods need to be proxied explicitly
-
-       public function getName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getRestriction() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isListed() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function setListed( $listed ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function listed( $x = null ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isIncludable() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function including( $x = null ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getLocalName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isExpensive() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isCached() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isRestricted() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function userCanExecute( User $user ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function displayRestrictionError() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function checkPermissions() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function checkReadOnly() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function requireLogin(
-               $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin'
-       ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function execute( $subPage ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getDescription() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       function getTitle( $subpage = false ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       function getPageTitle( $subpage = false ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function setContext( $context ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getContext() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getRequest() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getOutput() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getUser() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getSkin() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getLanguage() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getConfig() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getFullTitle() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getFinalGroupName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function doesWrites() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-
-       // no way to proxy constants and static properties
-
-       const SUCCESS = 0;
-       const NO_NAME = 1;
-       const ILLEGAL = 2;
-       const WRONG_PLUGIN_PASS = 3;
-       const NOT_EXISTS = 4;
-       const WRONG_PASS = 5;
-       const EMPTY_PASS = 6;
-       const RESET_PASS = 7;
-       const ABORTED = 8;
-       const CREATE_BLOCKED = 9;
-       const THROTTLED = 10;
-       const USER_BLOCKED = 11;
-       const NEED_TOKEN = 12;
-       const WRONG_TOKEN = 13;
-       const USER_MIGRATED = 14;
-
-       public static $statusCodes = [
-               self::SUCCESS => 'success',
-               self::NO_NAME => 'no_name',
-               self::ILLEGAL => 'illegal',
-               self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
-               self::NOT_EXISTS => 'not_exists',
-               self::WRONG_PASS => 'wrong_pass',
-               self::EMPTY_PASS => 'empty_pass',
-               self::RESET_PASS => 'reset_pass',
-               self::ABORTED => 'aborted',
-               self::CREATE_BLOCKED => 'create_blocked',
-               self::THROTTLED => 'throttled',
-               self::USER_BLOCKED => 'user_blocked',
-               self::NEED_TOKEN => 'need_token',
-               self::WRONG_TOKEN => 'wrong_token',
-               self::USER_MIGRATED => 'user_migrated',
-       ];
-
-       public static $validErrorMessages = [
-               'exception-nologin-text',
-               'watchlistanontext',
-               'changeemail-no-info',
-               'resetpass-no-info',
-               'confirmemail_needlogin',
-               'prefsnologintext2',
-       ];
-}
-
 /**
  * LoginForm as a special page has been replaced by SpecialUserLogin and SpecialCreateAccount,
  * but some extensions called its public methods directly, so the class is retained as a
  * B/C wrapper. Anything that used it before should use AuthManager instead.
  */
-class LoginFormAuthManager extends SpecialPage {
+class LoginForm extends SpecialPage {
        const SUCCESS = 0;
        const NO_NAME = 1;
        const ILLEGAL = 2;
index b69b28a..030a903 100644 (file)
@@ -84,8 +84,8 @@ class SpecialPageFactory {
 
                // Authentication
                'Userlogin' => 'SpecialUserLogin',
-               'Userlogout' => 'SpecialUserlogoutPreAuthManager',
-               'CreateAccount' => 'SpecialCreateAccountPreAuthManager',
+               'Userlogout' => 'SpecialUserLogout',
+               'CreateAccount' => 'SpecialCreateAccount',
                'LinkAccounts' => 'SpecialLinkAccounts',
                'UnlinkAccounts' => 'SpecialUnlinkAccounts',
                'ChangeCredentials' => 'SpecialChangeCredentials',
@@ -96,9 +96,9 @@ class SpecialPageFactory {
                'Block' => 'SpecialBlock',
                'Unblock' => 'SpecialUnblock',
                'BlockList' => 'SpecialBlockList',
-               'ChangePassword' => 'SpecialChangePasswordPreAuthManager',
+               'ChangePassword' => 'SpecialChangePassword',
                'BotPasswords' => 'SpecialBotPasswords',
-               'PasswordReset' => 'SpecialPasswordResetPreAuthManager',
+               'PasswordReset' => 'SpecialPasswordReset',
                'DeletedContributions' => 'DeletedContributionsPage',
                'Preferences' => 'SpecialPreferences',
                'ResetTokens' => 'SpecialResetTokens',
@@ -231,7 +231,6 @@ class SpecialPageFactory {
                global $wgDisableInternalSearch, $wgEmailAuthentication;
                global $wgEnableEmail, $wgEnableJavaScriptTest;
                global $wgPageLanguageUseDB, $wgContentHandlerUseDB;
-               global $wgDisableAuthManager;
 
                if ( !is_array( self::$list ) ) {
 
@@ -247,7 +246,7 @@ class SpecialPageFactory {
                        }
 
                        if ( $wgEnableEmail ) {
-                               self::$list['ChangeEmail'] = 'SpecialChangeEmailPreAuthManager';
+                               self::$list['ChangeEmail'] = 'SpecialChangeEmail';
                        }
 
                        if ( $wgEnableJavaScriptTest ) {
@@ -261,20 +260,6 @@ class SpecialPageFactory {
                                self::$list['ChangeContentModel'] = 'SpecialChangeContentModel';
                        }
 
-                       // horrible hack to allow selection between old and new classes via a feature flag - T110756
-                       // will be removed once AuthManager is stable
-                       if ( !$wgDisableAuthManager ) {
-                               self::$list = array_map( function ( $class ) {
-                                       return preg_replace( '/PreAuthManager$/', '', $class );
-                               }, self::$list );
-                               self::$list['Userlogout'] = 'SpecialUserLogout'; // case matters
-                       } else {
-                               self::$list['Userlogin'] = 'LoginForm';
-                               self::$list = array_diff_key( self::$list, array_fill_keys( [
-                                       'LinkAccounts', 'UnlinkAccounts', 'ChangeCredentials', 'RemoveCredentials',
-                               ], true ) );
-                       }
-
                        // Add extension special pages
                        self::$list = array_merge( self::$list, $wgSpecialPages );
 
index 4da8049..d98504d 100644 (file)
@@ -184,6 +184,7 @@ class SpecialChangeCredentials extends AuthManagerSpecialPage {
                        $groupedRequests[(string)$info['provider']][] = $req;
                }
 
+               $linkRenderer = $this->getLinkRenderer();
                $out->addHTML( Html::openElement( 'dl' ) );
                foreach ( $groupedRequests as $group => $members ) {
                        $out->addHTML( Html::element( 'dt', [], $group ) );
@@ -191,8 +192,10 @@ class SpecialChangeCredentials extends AuthManagerSpecialPage {
                                /** @var AuthenticationRequest $req */
                                $info = $req->describeCredentials();
                                $out->addHTML( Html::rawElement( 'dd', [],
-                                       Linker::link( $this->getPageTitle( $req->getUniqueId() ),
-                                               htmlspecialchars( $info['account'], ENT_QUOTES ) )
+                                       $linkRenderer->makeLink(
+                                               $this->getPageTitle( $req->getUniqueId() ),
+                                               $info['account']
+                                       )
                                ) );
                        }
                }
index cce88b9..0a98721 100644 (file)
@@ -267,13 +267,13 @@ class SpecialContributions extends IncludableSpecialPage {
                        }
                        $user = htmlspecialchars( $userObj->getName() );
                } else {
-                       $user = Linker::link( $userObj->getUserPage(), htmlspecialchars( $userObj->getName() ) );
+                       $user = $this->getLinkRenderer()->makeLink( $userObj->getUserPage(), $userObj->getName() );
                }
                $nt = $userObj->getUserPage();
                $talk = $userObj->getTalkPage();
                $links = '';
                if ( $talk ) {
-                       $tools = $this->getUserLinks( $nt, $talk, $userObj );
+                       $tools = self::getUserLinks( $this, $userObj );
                        $links = $this->getLanguage()->pipeList( $tools );
 
                        // Show a note if the user is blocked and display the last block log entry.
@@ -313,86 +313,93 @@ class SpecialContributions extends IncludableSpecialPage {
 
        /**
         * Links to different places.
-        * @param Title $userpage Target user page
-        * @param Title $talkpage Talk page
+        *
+        * @note This function is also called in DeletedContributionsPage
+        * @param SpecialPage $sp SpecialPage instance, for context
         * @param User $target Target user object
         * @return array
         */
-       public function getUserLinks( Title $userpage, Title $talkpage, User $target ) {
+       public static function getUserLinks( SpecialPage $sp, User $target ) {
 
                $id = $target->getId();
                $username = $target->getName();
+               $userpage = $target->getUserPage();
+               $talkpage = $target->getTalkPage();
 
-               $tools[] = Linker::link( $talkpage, $this->msg( 'sp-contributions-talk' )->escaped() );
+               $linkRenderer = $sp->getLinkRenderer();
+               $tools['user-talk'] = $linkRenderer->makeLink(
+                       $talkpage,
+                       $sp->msg( 'sp-contributions-talk' )->text()
+               );
 
                if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) {
-                       if ( $this->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
+                       if ( $sp->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
                                if ( $target->isBlocked() && $target->getBlock()->getType() != Block::TYPE_AUTO ) {
-                                       $tools[] = Linker::linkKnown( # Change block link
+                                       $tools['block'] = $linkRenderer->makeKnownLink( # Change block link
                                                SpecialPage::getTitleFor( 'Block', $username ),
-                                               $this->msg( 'change-blocklink' )->escaped()
+                                               $sp->msg( 'change-blocklink' )->text()
                                        );
-                                       $tools[] = Linker::linkKnown( # Unblock link
+                                       $tools['unblock'] = $linkRenderer->makeKnownLink( # Unblock link
                                                SpecialPage::getTitleFor( 'Unblock', $username ),
-                                               $this->msg( 'unblocklink' )->escaped()
+                                               $sp->msg( 'unblocklink' )->text()
                                        );
                                } else { # User is not blocked
-                                       $tools[] = Linker::linkKnown( # Block link
+                                       $tools['block'] = $linkRenderer->makeKnownLink( # Block link
                                                SpecialPage::getTitleFor( 'Block', $username ),
-                                               $this->msg( 'blocklink' )->escaped()
+                                               $sp->msg( 'blocklink' )->text()
                                        );
                                }
                        }
 
                        # Block log link
-                       $tools[] = Linker::linkKnown(
+                       $tools['log-block'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Log', 'block' ),
-                               $this->msg( 'sp-contributions-blocklog' )->escaped(),
+                               $sp->msg( 'sp-contributions-blocklog' )->text(),
                                [],
                                [ 'page' => $userpage->getPrefixedText() ]
                        );
 
                        # Suppression log link (bug 59120)
-                       if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
-                               $tools[] = Linker::linkKnown(
+                       if ( $sp->getUser()->isAllowed( 'suppressionlog' ) ) {
+                               $tools['log-suppression'] = $linkRenderer->makeKnownLink(
                                        SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                       $this->msg( 'sp-contributions-suppresslog' )->escaped(),
+                                       $sp->msg( 'sp-contributions-suppresslog' )->text(),
                                        [],
                                        [ 'offender' => $username ]
                                );
                        }
                }
                # Uploads
-               $tools[] = Linker::linkKnown(
+               $tools['uploads'] = $linkRenderer->makeKnownLink(
                        SpecialPage::getTitleFor( 'Listfiles', $username ),
-                       $this->msg( 'sp-contributions-uploads' )->escaped()
+                       $sp->msg( 'sp-contributions-uploads' )->text()
                );
 
                # Other logs link
-               $tools[] = Linker::linkKnown(
+               $tools['logs'] = $linkRenderer->makeKnownLink(
                        SpecialPage::getTitleFor( 'Log', $username ),
-                       $this->msg( 'sp-contributions-logs' )->escaped()
+                       $sp->msg( 'sp-contributions-logs' )->text()
                );
 
                # Add link to deleted user contributions for priviledged users
-               if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
-                       $tools[] = Linker::linkKnown(
+               if ( $sp->getUser()->isAllowed( 'deletedhistory' ) ) {
+                       $tools['deletedcontribs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'DeletedContributions', $username ),
-                               $this->msg( 'sp-contributions-deleted' )->escaped()
+                               $sp->msg( 'sp-contributions-deleted' )->text()
                        );
                }
 
                # Add a link to change user rights for privileged users
                $userrightsPage = new UserrightsPage();
-               $userrightsPage->setContext( $this->getContext() );
+               $userrightsPage->setContext( $sp->getContext() );
                if ( $userrightsPage->userCanChangeRights( $target ) ) {
-                       $tools[] = Linker::linkKnown(
+                       $tools['userrights'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Userrights', $username ),
-                               $this->msg( 'sp-contributions-userrights' )->escaped()
+                               $sp->msg( 'sp-contributions-userrights' )->text()
                        );
                }
 
-               Hooks::run( 'ContributionsToolLinks', [ $id, $userpage, &$tools ] );
+               Hooks::run( 'ContributionsToolLinks', [ $id, $userpage, &$tools, $sp ] );
 
                return $tools;
        }
index 190bf9f..8e168b2 100644 (file)
@@ -129,97 +129,29 @@ class DeletedContributionsPage extends SpecialPage {
         * Generates the subheading with links
         * @param User $userObj User object for the target
         * @return string Appropriately-escaped HTML to be output literally
-        * @todo FIXME: Almost the same as contributionsSub in SpecialContributions.php. Could be combined.
         */
        function getSubTitle( $userObj ) {
+               $linkRenderer = $this->getLinkRenderer();
                if ( $userObj->isAnon() ) {
                        $user = htmlspecialchars( $userObj->getName() );
                } else {
-                       $user = Linker::link( $userObj->getUserPage(), htmlspecialchars( $userObj->getName() ) );
+                       $user = $linkRenderer->makeKnownLink( $userObj->getUserPage(), $userObj->getName() );
                }
                $links = '';
                $nt = $userObj->getUserPage();
-               $id = $userObj->getId();
                $talk = $nt->getTalkPage();
                if ( $talk ) {
-                       # Talk page link
-                       $tools[] = Linker::link( $talk, $this->msg( 'sp-contributions-talk' )->escaped() );
-                       if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) {
-                               # Block / Change block / Unblock links
-                               if ( $this->getUser()->isAllowed( 'block' ) ) {
-                                       if ( $userObj->isBlocked() && $userObj->getBlock()->getType() !== Block::TYPE_AUTO ) {
-                                               $tools[] = Linker::linkKnown( # Change block link
-                                                       SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
-                                                       $this->msg( 'change-blocklink' )->escaped()
-                                               );
-                                               $tools[] = Linker::linkKnown( # Unblock link
-                                                       SpecialPage::getTitleFor( 'BlockList' ),
-                                                       $this->msg( 'unblocklink' )->escaped(),
-                                                       [],
-                                                       [
-                                                               'action' => 'unblock',
-                                                               'ip' => $nt->getDBkey()
-                                                       ]
-                                               );
-                                       } else {
-                                               # User is not blocked
-                                               $tools[] = Linker::linkKnown( # Block link
-                                                       SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
-                                                       $this->msg( 'blocklink' )->escaped()
-                                               );
-                                       }
-                               }
-                               # Block log link
-                               $tools[] = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Log' ),
-                                       $this->msg( 'sp-contributions-blocklog' )->escaped(),
-                                       [],
-                                       [
-                                               'type' => 'block',
-                                               'page' => $nt->getPrefixedText()
-                                       ]
-                               );
-                               # Suppression log link (bug 59120)
-                               if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
-                                       $tools[] = Linker::linkKnown(
-                                               SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                               $this->msg( 'sp-contributions-suppresslog' )->escaped(),
-                                               [],
-                                               [ 'offender' => $userObj->getName() ]
-                                       );
-                               }
-                       }
+                       $tools = SpecialContributions::getUserLinks( $this, $userObj );
 
-                       # Uploads
-                       $tools[] = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Listfiles', $userObj->getName() ),
-                               $this->msg( 'sp-contributions-uploads' )->escaped()
-                       );
-
-                       # Other logs link
-                       $tools[] = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Log' ),
-                               $this->msg( 'sp-contributions-logs' )->escaped(),
-                               [],
-                               [ 'user' => $nt->getText() ]
-                       );
                        # Link to contributions
-                       $tools[] = Linker::linkKnown(
+                       $insert['contribs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Contributions', $nt->getDBkey() ),
-                               $this->msg( 'sp-deletedcontributions-contribs' )->escaped()
+                               $this->msg( 'sp-deletedcontributions-contribs' )->text()
                        );
 
-                       # Add a link to change user rights for privileged users
-                       $userrightsPage = new UserrightsPage();
-                       $userrightsPage->setContext( $this->getContext() );
-                       if ( $userrightsPage->userCanChangeRights( $userObj ) ) {
-                               $tools[] = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Userrights', $nt->getDBkey() ),
-                                       $this->msg( 'sp-contributions-userrights' )->escaped()
-                               );
-                       }
-
-                       Hooks::run( 'ContributionsToolLinks', [ $id, $nt, &$tools ] );
+                       // Swap out the deletedcontribs link for our contribs one
+                       $tools = wfArrayInsertAfter( $tools, $insert, 'deletedcontribs' );
+                       unset( $tools['deletedcontribs'] );
 
                        $links = $this->getLanguage()->pipeList( $tools );
 
index 627dd2c..a5a45d5 100644 (file)
@@ -2,7 +2,6 @@
 /**
  * @defgroup Watchlist Users watchlist handling
  */
-use MediaWiki\Linker\LinkTarget;
 
 /**
  * Implements Special:EditWatchlist
@@ -27,6 +26,8 @@ use MediaWiki\Linker\LinkTarget;
  * @ingroup Watchlist
  */
 
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
 
 /**
@@ -138,7 +139,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        protected function outputSubtitle() {
                $out = $this->getOutput();
                $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() )
-                       ->rawParams( SpecialEditWatchlist::buildTools( null ) ) );
+                       ->rawParams(
+                               self::buildTools(
+                                       $this->getLanguage(),
+                                       $this->getLinkRenderer()
+                               )
+                       )
+               );
        }
 
        /**
@@ -277,7 +284,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * @param string $output
         */
        private function showTitles( $titles, &$output ) {
-               $talk = $this->msg( 'talkpagelinktext' )->escaped();
+               $talk = $this->msg( 'talkpagelinktext' )->text();
                // Do a batch existence check
                $batch = new LinkBatch();
                if ( count( $titles ) >= 100 ) {
@@ -300,6 +307,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                // Print out the list
                $output .= "<ul>\n";
 
+               $linkRenderer = $this->getLinkRenderer();
                foreach ( $titles as $title ) {
                        if ( !$title instanceof Title ) {
                                $title = Title::newFromText( $title );
@@ -307,9 +315,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                        if ( $title instanceof Title ) {
                                $output .= '<li>' .
-                                       Linker::link( $title ) . ' ' .
+                                       $linkRenderer->makeLink( $title ) . ' ' .
                                        $this->msg( 'parentheses' )->rawParams(
-                                               Linker::link( $title->getTalkPage(), $talk )
+                                               $linkRenderer->makeLink( $title->getTalkPage(), $talk )
                                        )->escaped() .
                                        "</li>\n";
                        }
@@ -610,26 +618,27 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * @return string
         */
        private function buildRemoveLine( $title ) {
-               $link = Linker::link( $title );
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeLink( $title );
 
-               $tools['talk'] = Linker::link(
+               $tools['talk'] = $linkRenderer->makeLink(
                        $title->getTalkPage(),
-                       $this->msg( 'talkpagelinktext' )->escaped()
+                       $this->msg( 'talkpagelinktext' )->text()
                );
 
                if ( $title->exists() ) {
-                       $tools['history'] = Linker::linkKnown(
+                       $tools['history'] = $linkRenderer->makeKnownLink(
                                $title,
-                               $this->msg( 'history_short' )->escaped(),
+                               $this->msg( 'history_short' )->text(),
                                [],
                                [ 'action' => 'history' ]
                        );
                }
 
                if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) {
-                       $tools['contributions'] = Linker::linkKnown(
+                       $tools['contributions'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
-                               $this->msg( 'contributions' )->escaped()
+                               $this->msg( 'contributions' )->text()
                        );
                }
 
@@ -724,11 +733,19 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * Build a set of links for convenient navigation
         * between watchlist viewing and editing modes
         *
-        * @param null $unused
+        * @param Language $lang
+        * @param LinkRenderer|null $linkRenderer
         * @return string
         */
-       public static function buildTools( $unused ) {
-               global $wgLang;
+       public static function buildTools( $lang, LinkRenderer $linkRenderer = null ) {
+               if ( !$lang instanceof Language ) {
+                       // back-compat where the first parameter was $unused
+                       global $wgLang;
+                       $lang = $wgLang;
+               }
+               if ( !$linkRenderer ) {
+                       $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               }
 
                $tools = [];
                $modes = [
@@ -740,16 +757,16 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                foreach ( $modes as $mode => $arr ) {
                        // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
-                       $tools[] = Linker::linkKnown(
+                       $tools[] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( $arr[0], $arr[1] ),
-                               wfMessage( "watchlisttools-{$mode}" )->escaped()
+                               wfMessage( "watchlisttools-{$mode}" )->text()
                        );
                }
 
                return Html::rawElement(
                        'span',
                        [ 'class' => 'mw-watchlist-toollinks' ],
-                       wfMessage( 'parentheses' )->rawParams( $wgLang->pipeList( $tools ) )->escaped()
+                       wfMessage( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped()
                );
        }
 }
index b8316f3..3ead08a 100644 (file)
@@ -94,7 +94,7 @@ class MostlinkedCategoriesPage extends QueryPage {
                }
 
                $text = $wgContLang->convert( $nt->getText() );
-               $plink = Linker::link( $nt, htmlspecialchars( $text ) );
+               $plink = $this->getLinkRenderer()->makeLink( $nt, $text );
                $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
 
                return $this->getLanguage()->specialList( $plink, $nlinks );
index 14391d2..077a5d2 100644 (file)
@@ -22,6 +22,9 @@
  */
 
 class SpecialNewFiles extends IncludableSpecialPage {
+       /** @var FormOptions */
+       protected $opts;
+
        public function __construct() {
                parent::__construct( 'Newimages' );
        }
@@ -33,21 +36,86 @@ class SpecialNewFiles extends IncludableSpecialPage {
                $out = $this->getOutput();
                $this->addHelpLink( 'Help:New images' );
 
-               $pager = new NewFilesPager( $this->getContext(), $par );
+               $opts = new FormOptions();
+
+               $opts->add( 'like', '' );
+               $opts->add( 'showbots', false );
+               $opts->add( 'hidepatrolled', false );
+               $opts->add( 'limit', 50 );
+               $opts->add( 'offset', '' );
+
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               if ( $par !== null ) {
+                       $opts->setValue( is_numeric( $par ) ? 'limit' : 'like', $par );
+               }
+
+               $opts->validateIntBounds( 'limit', 0, 500 );
+
+               $this->opts = $opts;
 
                if ( !$this->including() ) {
                        $this->setTopText();
-                       $form = $pager->getForm();
-                       $form->prepareForm();
-                       $form->displayForm( '' );
+                       $this->buildForm();
                }
 
+               $pager = new NewFilesPager( $this->getContext(), $opts );
+
                $out->addHTML( $pager->getBody() );
                if ( !$this->including() ) {
                        $out->addHTML( $pager->getNavigationBar() );
                }
        }
 
+       protected function buildForm() {
+               $formDescriptor = [
+                       'like' => [
+                               'type' => 'text',
+                               'label-message' => 'newimages-label',
+                               'name' => 'like',
+                       ],
+
+                       'showbots' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-showbots',
+                               'name' => 'showbots',
+                       ],
+
+                       'hidepatrolled' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-hidepatrolled',
+                               'name' => 'hidepatrolled',
+                       ],
+
+                       'limit' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'limit' ),
+                               'name' => 'limit',
+                       ],
+
+                       'offset' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'offset' ),
+                               'name' => 'offset',
+                       ],
+               ];
+
+               if ( $this->getConfig()->get( 'MiserMode' ) ) {
+                       unset( $formDescriptor['like'] );
+               }
+
+               if ( !$this->getUser()->useFilePatrol() ) {
+                       unset( $formDescriptor['hidepatrolled'] );
+               }
+
+               $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+                       ->setWrapperLegendMsg( 'newimages-legend' )
+                       ->setSubmitTextMsg( 'ilsubmit' )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
        protected function getGroupName() {
                return 'changes';
        }
index 718a6dc..d2513ed 100644 (file)
@@ -349,6 +349,7 @@ class SpecialNewpages extends IncludableSpecialPage {
 
                if ( $this->patrollable( $result ) ) {
                        $classes[] = 'not-patrolled';
+                       $this->getOutput()->addModuleStyles( 'mediawiki.page.patrol' );
                }
 
                # Add a class for zero byte pages
index 54b471e..342509c 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\Linker\LinkRenderer;
+
 /**
  * A special page that lists protected pages
  *
@@ -59,7 +61,8 @@ class SpecialProtectedpages extends SpecialPage {
                        $size,
                        $indefOnly,
                        $cascadeOnly,
-                       $noRedirect
+                       $noRedirect,
+                       $this->getLinkRenderer()
                );
 
                $this->getOutput()->addHTML( $this->showOptions(
@@ -279,8 +282,27 @@ class ProtectedPagesPager extends TablePager {
        public $mForm, $mConds;
        private $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect;
 
+       /**
+        * @var LinkRenderer
+        */
+       private $linkRenderer;
+
+       /**
+        * @param SpecialProtectedpages $form
+        * @param array $conds
+        * @param $type
+        * @param $level
+        * @param $namespace
+        * @param string $sizetype
+        * @param int $size
+        * @param bool $indefonly
+        * @param bool $cascadeonly
+        * @param bool $noredirect
+        * @param LinkRenderer $linkRenderer
+        */
        function __construct( $form, $conds = [], $type, $level, $namespace,
-               $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false, $noredirect = false
+               $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false, $noredirect = false,
+               LinkRenderer $linkRenderer
        ) {
                $this->mForm = $form;
                $this->mConds = $conds;
@@ -292,6 +314,7 @@ class ProtectedPagesPager extends TablePager {
                $this->indefonly = (bool)$indefonly;
                $this->cascadeonly = (bool)$cascadeonly;
                $this->noredirect = (bool)$noredirect;
+               $this->linkRenderer = $linkRenderer;
                parent::__construct( $form->getContext() );
        }
 
@@ -354,8 +377,6 @@ class ProtectedPagesPager extends TablePager {
                /** @var $row object */
                $row = $this->mCurrentRow;
 
-               $formatted = '';
-
                switch ( $field ) {
                        case 'log_timestamp':
                                // when timestamp is null, this is a old protection row
@@ -384,7 +405,7 @@ class ProtectedPagesPager extends TablePager {
                                                )
                                        );
                                } else {
-                                       $formatted = Linker::link( $title );
+                                       $formatted = $this->linkRenderer->makeLink( $title );
                                }
                                if ( !is_null( $row->page_len ) ) {
                                        $formatted .= $this->getLanguage()->getDirMark() .
@@ -401,9 +422,9 @@ class ProtectedPagesPager extends TablePager {
                                        $value, /* User preference timezone */true ) );
                                $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
                                if ( $this->getUser()->isAllowed( 'protect' ) && $title ) {
-                                       $changeProtection = Linker::linkKnown(
+                                       $changeProtection = $this->linkRenderer->makeKnownLink(
                                                $title,
-                                               $this->msg( 'protect_change' )->escaped(),
+                                               $this->msg( 'protect_change' )->text(),
                                                [],
                                                [ 'action' => 'unprotect' ]
                                        );
index a475f05..3e89686 100644 (file)
@@ -25,7 +25,7 @@
  * Let users reset tokens like the watchlist token.
  *
  * @ingroup SpecialPage
- * @deprecated 1.26
+ * @deprecated since 1.26
  */
 class SpecialResetTokens extends FormSpecialPage {
        private $tokensList;
index 20f2fc8..a76b511 100644 (file)
@@ -104,19 +104,20 @@ class ShortPagesPage extends QueryPage {
                                Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
                }
 
-               $hlink = Linker::linkKnown(
+               $linkRenderer = $this->getLinkRenderer();
+               $hlink = $linkRenderer->makeKnownLink(
                        $title,
-                       $this->msg( 'hist' )->escaped(),
+                       $this->msg( 'hist' )->text(),
                        [],
                        [ 'action' => 'history' ]
                );
                $hlinkInParentheses = $this->msg( 'parentheses' )->rawParams( $hlink )->escaped();
 
                if ( $this->isCached() ) {
-                       $plink = Linker::link( $title );
+                       $plink = $linkRenderer->makeLink( $title );
                        $exists = $title->exists();
                } else {
-                       $plink = Linker::linkKnown( $title );
+                       $plink = $linkRenderer->makeKnownLink( $title );
                        $exists = true;
                }
 
index 2139949..e957b3c 100644 (file)
@@ -128,8 +128,7 @@ class SpecialTags extends SpecialPage {
                        ChangeTags::listExtensionDefinedTags(), true );
 
                // List all defined tags, even if they were never applied
-               $definedTags = array_keys( array_merge(
-                       $this->explicitlyDefinedTags, $this->extensionDefinedTags ) );
+               $definedTags = array_keys( $this->explicitlyDefinedTags + $this->extensionDefinedTags );
 
                // Show header only if there exists atleast one tag
                if ( !$tagStats && !$definedTags ) {
@@ -176,12 +175,13 @@ class SpecialTags extends SpecialPage {
                $newRow = '';
                $newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) );
 
+               $linkRenderer = $this->getLinkRenderer();
                $disp = ChangeTags::tagDescription( $tag );
                if ( $showEditLinks ) {
                        $disp .= ' ';
-                       $editLink = Linker::link(
+                       $editLink = $linkRenderer->makeLink(
                                $this->msg( "tag-$tag" )->inContentLanguage()->getTitle(),
-                               $this->msg( 'tags-edit' )->escaped()
+                               $this->msg( 'tags-edit' )->text()
                        );
                        $disp .= $this->msg( 'parentheses' )->rawParams( $editLink )->escaped();
                }
@@ -191,9 +191,9 @@ class SpecialTags extends SpecialPage {
                $desc = !$msg->exists() ? '' : $msg->parse();
                if ( $showEditLinks ) {
                        $desc .= ' ';
-                       $editDescLink = Linker::link(
+                       $editDescLink = $linkRenderer->makeLink(
                                $this->msg( "tag-$tag-description" )->inContentLanguage()->getTitle(),
-                               $this->msg( 'tags-edit' )->escaped()
+                               $this->msg( 'tags-edit' )->text()
                        );
                        $desc .= $this->msg( 'parentheses' )->rawParams( $editDescLink )->escaped();
                }
@@ -217,14 +217,16 @@ class SpecialTags extends SpecialPage {
                $activeMsg = ( $isActive ? 'tags-active-yes' : 'tags-active-no' );
                $newRow .= Xml::tags( 'td', null, $this->msg( $activeMsg )->escaped() );
 
-               $hitcountLabel = $this->msg( 'tags-hitcount' )->numParams( $hitcount )->escaped();
+               $hitcountLabelMsg = $this->msg( 'tags-hitcount' )->numParams( $hitcount );
                if ( $this->getConfig()->get( 'UseTagFilter' ) ) {
-                       $hitcountLabel = Linker::link(
+                       $hitcountLabel = $linkRenderer->makeLink(
                                SpecialPage::getTitleFor( 'Recentchanges' ),
-                               $hitcountLabel,
+                               $hitcountLabelMsg->text(),
                                [],
                                [ 'tagfilter' => $tag ]
                        );
+               } else {
+                       $hitcountLabel = $hitcountLabelMsg->escaped();
                }
 
                // add raw $hitcount for sorting, because tags-hitcount contains numbers and letters
@@ -235,8 +237,9 @@ class SpecialTags extends SpecialPage {
 
                // delete
                if ( $showDeleteActions && ChangeTags::canDeleteTag( $tag )->isOK() ) {
-                       $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ),
-                               $this->msg( 'tags-delete' )->escaped(),
+                       $actionLinks[] = $linkRenderer->makeKnownLink(
+                               $this->getPageTitle( 'delete' ),
+                               $this->msg( 'tags-delete' )->text(),
                                [],
                                [ 'tag' => $tag ] );
                }
@@ -245,16 +248,18 @@ class SpecialTags extends SpecialPage {
 
                        // activate
                        if ( ChangeTags::canActivateTag( $tag )->isOK() ) {
-                               $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'activate' ),
-                                       $this->msg( 'tags-activate' )->escaped(),
+                               $actionLinks[] = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( 'activate' ),
+                                       $this->msg( 'tags-activate' )->text(),
                                        [],
                                        [ 'tag' => $tag ] );
                        }
 
                        // deactivate
                        if ( ChangeTags::canDeactivateTag( $tag )->isOK() ) {
-                               $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'deactivate' ),
-                                       $this->msg( 'tags-deactivate' )->escaped(),
+                               $actionLinks[] = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( 'deactivate' ),
+                                       $this->msg( 'tags-deactivate' )->text(),
                                        [],
                                        [ 'tag' => $tag ] );
                        }
index 0ef6af1..bfb52e8 100644 (file)
@@ -22,6 +22,9 @@
  * @ingroup Upload
  */
 
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
+
 /**
  * Form for handling uploads and special page.
  *
@@ -261,7 +264,7 @@ class SpecialUpload extends SpecialPage {
                        'texttop' => $this->uploadFormTextTop,
                        'textaftersummary' => $this->uploadFormTextAfterSummary,
                        'destfile' => $this->mDesiredDestName,
-               ], $context );
+               ], $context, $this->getLinkRenderer() );
 
                # Check the token, but only if necessary
                if (
@@ -313,9 +316,9 @@ class SpecialUpload extends SpecialPage {
                if ( $title instanceof Title ) {
                        $count = $title->isDeleted();
                        if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) {
-                               $restorelink = Linker::linkKnown(
+                               $restorelink = $this->getLinkRenderer()->makeKnownLink(
                                        SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
-                                       $this->msg( 'restorelink' )->numParams( $count )->escaped()
+                                       $this->msg( 'restorelink' )->numParams( $count )->text()
                                );
                                $link = $this->msg( $user->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted' )
                                        ->rawParams( $restorelink )->parseAsBlock();
@@ -336,7 +339,7 @@ class SpecialUpload extends SpecialPage {
         * @param string $message HTML message to be passed to mainUploadForm
         */
        protected function showRecoverableUploadError( $message ) {
-               $sessionKey = $this->mUpload->stashSession();
+               $sessionKey = $this->mUpload->stashFile()->getFileKey();
                $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . "</h2>\n" .
                        '<div class="error">' . $message . "</div>\n";
 
@@ -365,11 +368,12 @@ class SpecialUpload extends SpecialPage {
                        return false;
                }
 
-               $sessionKey = $this->mUpload->stashSession();
+               $sessionKey = $this->mUpload->stashFile()->getFileKey();
 
                // Add styles for the warning, reused from the live preview
                $this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
 
+               $linkRenderer = $this->getLinkRenderer();
                $warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
                        . '<div class="mw-destfile-warning"><ul>';
                foreach ( $warnings as $warning => $args ) {
@@ -381,9 +385,9 @@ class SpecialUpload extends SpecialPage {
                        } elseif ( $warning == 'was-deleted' ) {
                                # If the file existed before and was deleted, warn the user of this
                                $ltitle = SpecialPage::getTitleFor( 'Log' );
-                               $llink = Linker::linkKnown(
+                               $llink = $linkRenderer->makeKnownLink(
                                        $ltitle,
-                                       wfMessage( 'deletionlog' )->escaped(),
+                                       wfMessage( 'deletionlog' )->text(),
                                        [],
                                        [
                                                'type' => 'delete',
@@ -833,11 +837,17 @@ class UploadForm extends HTMLForm {
 
        protected $mMaxUploadSize = [];
 
-       public function __construct( array $options = [], IContextSource $context = null ) {
+       public function __construct( array $options = [], IContextSource $context = null,
+               LinkRenderer $linkRenderer = null
+       ) {
                if ( $context instanceof IContextSource ) {
                        $this->setContext( $context );
                }
 
+               if ( !$linkRenderer ) {
+                       $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               }
+
                $this->mWatch = !empty( $options['watch'] );
                $this->mForReUpload = !empty( $options['forreupload'] );
                $this->mSessionKey = isset( $options['sessionkey'] ) ? $options['sessionkey'] : '';
@@ -862,12 +872,12 @@ class UploadForm extends HTMLForm {
                Hooks::run( 'UploadFormInitDescriptor', [ &$descriptor ] );
                parent::__construct( $descriptor, $context, 'upload' );
 
-               # Add a link to edit MediaWik:Licenses
+               # Add a link to edit MediaWiki:Licenses
                if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
-                       $this->getOutput()->addModuleStyles( 'mediawiki.special' );
-                       $licensesLink = Linker::linkKnown(
+                       $this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
+                       $licensesLink = $linkRenderer->makeKnownLink(
                                $this->msg( 'licenses' )->inContentLanguage()->getTitle(),
-                               $this->msg( 'licenses-edit' )->escaped(),
+                               $this->msg( 'licenses-edit' )->text(),
                                [],
                                [ 'action' => 'edit' ]
                        );
index 555fe5c..1412324 100644 (file)
@@ -391,17 +391,21 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                if ( $files && count( $files ) ) {
                        sort( $files );
                        $fileListItemsHtml = '';
+                       $linkRenderer = $this->getLinkRenderer();
                        foreach ( $files as $file ) {
-                               $itemHtml = Linker::linkKnown( $this->getPageTitle( "file/$file" ), htmlspecialchars( $file ) );
+                               $itemHtml = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( "file/$file" ),
+                                       $file
+                               );
                                try {
                                        $fileObj = $this->stash->getFile( $file );
                                        $thumb = $fileObj->generateThumbName( $file, [ 'width' => 220 ] );
                                        $itemHtml .=
                                                $this->msg( 'word-separator' )->escaped() .
                                                $this->msg( 'parentheses' )->rawParams(
-                                                       Linker::linkKnown(
+                                                       $linkRenderer->makeKnownLink(
                                                                $this->getPageTitle( "thumb/$file/$thumb" ),
-                                                               $this->msg( 'uploadstash-thumbnail' )->escaped()
+                                                               $this->msg( 'uploadstash-thumbnail' )->text()
                                                        )
                                                )->escaped();
                                } catch ( Exception $e ) {
index 58cde7e..17d77ba 100644 (file)
@@ -429,7 +429,10 @@ class SpecialWatchlist extends ChangesListSpecialPage {
 
                $out->addSubtitle(
                        $this->msg( 'watchlistfor2', $user->getName() )
-                               ->rawParams( SpecialEditWatchlist::buildTools( null ) )
+                               ->rawParams( SpecialEditWatchlist::buildTools(
+                                       $this->getLanguage(),
+                                       $this->getLinkRenderer()
+                               ) )
                );
 
                $this->setTopText( $opts );
index 40706fa..5e10269 100644 (file)
@@ -429,8 +429,11 @@ class ImageListPager extends TablePager {
                                // If statement for paranoia
                                if ( $file ) {
                                        $thumb = $file->transform( [ 'width' => 180, 'height' => 360 ] );
-
-                                       return $thumb->toHtml( [ 'desc-link' => true ] );
+                                       if ( $thumb ) {
+                                               return $thumb->toHtml( [ 'desc-link' => true ] );
+                                       } else {
+                                               return wfMessage( 'thumbnail_error', '' )->escaped();
+                                       }
                                } else {
                                        return htmlspecialchars( $value );
                                }
index ae57736..d1f9f40 100644 (file)
@@ -30,33 +30,30 @@ class NewFilesPager extends ReverseChronologicalPager {
        protected $gallery;
 
        /**
-        * @var bool
+        * @var FormOptions
         */
-       protected $showBots;
+       protected $opts;
 
        /**
-        * @var bool
+        * @param IContextSource $context
+        * @param FormOptions $opts
         */
-       protected $hidePatrolled;
-
-       function __construct( IContextSource $context, $par = null ) {
-               $this->like = $context->getRequest()->getText( 'like' );
-               $this->showBots = $context->getRequest()->getBool( 'showbots', 0 );
-               $this->hidePatrolled = $context->getRequest()->getBool( 'hidepatrolled', 0 );
-               if ( is_numeric( $par ) ) {
-                       $this->setLimit( $par );
-               }
+       function __construct( IContextSource $context, FormOptions $opts ) {
+               $this->opts = $opts;
+
+               $this->setLimit( $opts->getValue( 'limit' ) );
 
                parent::__construct( $context );
        }
 
        function getQueryInfo() {
+               $opts = $this->opts;
                $conds = $jconds = [];
                $tables = [ 'image' ];
                $fields = [ 'img_name', 'img_user', 'img_timestamp' ];
                $options = [];
 
-               if ( !$this->showBots ) {
+               if ( !$opts->getValue( 'showbots' ) ) {
                        $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
 
                        if ( count( $groupsWithBotPermission ) ) {
@@ -72,7 +69,7 @@ class NewFilesPager extends ReverseChronologicalPager {
                        }
                }
 
-               if ( $this->hidePatrolled ) {
+               if ( $opts->getValue( 'hidepatrolled' ) ) {
                        $tables[] = 'recentchanges';
                        $conds['rc_type'] = RC_LOG;
                        $conds['rc_log_type'] = 'upload';
@@ -92,9 +89,10 @@ class NewFilesPager extends ReverseChronologicalPager {
                        $options[] = 'STRAIGHT_JOIN';
                }
 
-               if ( !$this->getConfig()->get( 'MiserMode' ) && $this->like !== null ) {
+               $likeVal = $opts->getValue( 'like' );
+               if ( !$this->getConfig()->get( 'MiserMode' ) && $likeVal !== '' ) {
                        $dbr = wfGetDB( DB_SLAVE );
-                       $likeObj = Title::newFromText( $this->like );
+                       $likeObj = Title::newFromText( $likeVal );
                        if ( $likeObj instanceof Title ) {
                                $like = $dbr->buildLike(
                                        $dbr->anyString(),
@@ -154,54 +152,4 @@ class NewFilesPager extends ReverseChronologicalPager {
                        . "</i><br />\n"
                );
        }
-
-       function getForm() {
-               $fields = [
-                       'like' => [
-                               'type' => 'text',
-                               'label-message' => 'newimages-label',
-                               'name' => 'like',
-                       ],
-                       'showbots' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-showbots',
-                               'name' => 'showbots',
-                       ],
-                       'hidepatrolled' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-hidepatrolled',
-                               'name' => 'hidepatrolled',
-                       ],
-                       'limit' => [
-                               'type' => 'hidden',
-                               'default' => $this->mLimit,
-                               'name' => 'limit',
-                       ],
-                       'offset' => [
-                               'type' => 'hidden',
-                               'default' => $this->getRequest()->getText( 'offset' ),
-                               'name' => 'offset',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'MiserMode' ) ) {
-                       unset( $fields['like'] );
-               }
-
-               if ( !$this->getUser()->useFilePatrol() ) {
-                       unset( $fields['hidepatrolled'] );
-               }
-
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setTitle( $this->getTitle() ); // Remove subpage
-               $form = new HTMLForm( $fields, $context );
-
-               $form->setSubmitTextMsg( 'ilsubmit' );
-               $form->setSubmitProgressive();
-
-               $form->setMethod( 'get' );
-               $form->setWrapperLegendMsg( 'newimages-legend' );
-
-               return $form;
-       }
 }
diff --git a/includes/specials/pre-authmanager/README b/includes/specials/pre-authmanager/README
deleted file mode 100644 (file)
index 1cfdd5f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This directory temporarily hosts pre-AuthManager code as a way of feature-flagging.
-Class names are postfixed with 'PreAuthManager' and SpecialPageFactory adds/removes
-that postfix based on the feature flag.
-
-This is a horrible hack that will only be in place for a few weeks, to allow instant
-rollback while AuthManager is tested in WMF production and major problems are ironed
-out. In the past such issues have been handled via deployment branches, but that
-meant blocking the work of all WMF developers from being deployed. This is hoped
-to be a less disruptive method.
-
diff --git a/includes/specials/pre-authmanager/SpecialChangeEmail.php b/includes/specials/pre-authmanager/SpecialChangeEmail.php
deleted file mode 100644 (file)
index 7861562..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-/**
- * Implements Special:ChangeEmail
- *
- * 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
- * @ingroup SpecialPage
- */
-
-/**
- * Let users change their email address.
- *
- * @ingroup SpecialPage
- */
-class SpecialChangeEmailPreAuthManager extends FormSpecialPage {
-       /**
-        * @var Status
-        */
-       private $status;
-
-       public function __construct() {
-               parent::__construct( 'ChangeEmail', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * @return bool
-        */
-       public function isListed() {
-               global $wgAuth;
-
-               return $wgAuth->allowPropChange( 'emailaddress' );
-       }
-
-       /**
-        * Main execution point
-        * @param string $par
-        */
-       function execute( $par ) {
-               $out = $this->getOutput();
-               $out->disallowUserJs();
-
-               parent::execute( $par );
-       }
-
-       protected function checkExecutePermissions( User $user ) {
-               global $wgAuth;
-
-               if ( !$wgAuth->allowPropChange( 'emailaddress' ) ) {
-                       throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
-               }
-
-               $this->requireLogin( 'changeemail-no-info' );
-
-               // This could also let someone check the current email address, so
-               // require both permissions.
-               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
-                       throw new PermissionsError( 'viewmyprivateinfo' );
-               }
-
-               parent::checkExecutePermissions( $user );
-       }
-
-       protected function getFormFields() {
-               $user = $this->getUser();
-
-               $fields = [
-                       'Name' => [
-                               'type' => 'info',
-                               'label-message' => 'username',
-                               'default' => $user->getName(),
-                       ],
-                       'OldEmail' => [
-                               'type' => 'info',
-                               'label-message' => 'changeemail-oldemail',
-                               'default' => $user->getEmail() ?: $this->msg( 'changeemail-none' )->text(),
-                       ],
-                       'NewEmail' => [
-                               'type' => 'email',
-                               'label-message' => 'changeemail-newemail',
-                               'autofocus' => true,
-                               'help-message' => 'changeemail-newemail-help',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
-                       $fields['Password'] = [
-                               'type' => 'password',
-                               'label-message' => 'changeemail-password'
-                       ];
-               }
-
-               return $fields;
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-
-       protected function alterForm( HTMLForm $form ) {
-               $form->setId( 'mw-changeemail-form' );
-               $form->setTableId( 'mw-changeemail-table' );
-               $form->setSubmitTextMsg( 'changeemail-submit' );
-               $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
-                       $form->addHeaderText( $this->msg( 'changeemail-passwordrequired' )->parseAsBlock() );
-               }
-       }
-
-       public function onSubmit( array $data ) {
-               $password = isset( $data['Password'] ) ? $data['Password'] : null;
-               $status = $this->attemptChange( $this->getUser(), $password, $data['NewEmail'] );
-
-               $this->status = $status;
-
-               return $status;
-       }
-
-       public function onSuccess() {
-               $request = $this->getRequest();
-
-               $returnto = $request->getVal( 'returnto' );
-               $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
-               if ( !$titleObj instanceof Title ) {
-                       $titleObj = Title::newMainPage();
-               }
-               $query = $request->getVal( 'returntoquery' );
-
-               if ( $this->status->value === true ) {
-                       $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
-               } elseif ( $this->status->value === 'eauth' ) {
-                       # Notify user that a confirmation email has been sent...
-                       $this->getOutput()->wrapWikiMsg( "<div class='error' style='clear: both;'>\n$1\n</div>",
-                               'eauthentsent', $this->getUser()->getName() );
-                       // just show the link to go back
-                       $this->getOutput()->addReturnTo( $titleObj, wfCgiToArray( $query ) );
-               }
-       }
-
-       /**
-        * @param User $user
-        * @param string $pass
-        * @param string $newaddr
-        * @return Status
-        */
-       private function attemptChange( User $user, $pass, $newaddr ) {
-               global $wgAuth;
-
-               if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) {
-                       return Status::newFatal( 'invalidemailaddress' );
-               }
-
-               if ( $newaddr === $user->getEmail() ) {
-                       return Status::newFatal( 'changeemail-nochange' );
-               }
-
-               $throttleInfo = LoginForm::incrementLoginThrottle( $user->getName() );
-               if ( $throttleInfo ) {
-                       $lang = $this->getLanguage();
-                       return Status::newFatal(
-                               'changeemail-throttled',
-                               $lang->formatDuration( $throttleInfo['wait'] )
-                       );
-               }
-
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' )
-                       && !$user->checkTemporaryPassword( $pass )
-                       && !$user->checkPassword( $pass )
-               ) {
-                       return Status::newFatal( 'wrongpassword' );
-               }
-
-               LoginForm::clearLoginThrottle( $user->getName() );
-
-               $oldaddr = $user->getEmail();
-               $status = $user->setEmailWithConfirmation( $newaddr );
-               if ( !$status->isGood() ) {
-                       return $status;
-               }
-
-               Hooks::run( 'PrefsEmailAudit', [ $user, $oldaddr, $newaddr ] );
-
-               $user->saveSettings();
-
-               $wgAuth->updateExternalDB( $user );
-
-               return $status;
-       }
-
-       public function requiresUnblock() {
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialChangePassword.php b/includes/specials/pre-authmanager/SpecialChangePassword.php
deleted file mode 100644 (file)
index 3955fee..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-<?php
-/**
- * Implements Special:ChangePassword
- *
- * 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
- * @ingroup SpecialPage
- */
-
-/**
- * Let users recover their password.
- *
- * @ingroup SpecialPage
- */
-class SpecialChangePasswordPreAuthManager extends FormSpecialPage {
-       protected $mUserName;
-       protected $mDomain;
-
-       // Optional Wikitext Message to show above the password change form
-       protected $mPreTextMessage = null;
-
-       // label for old password input
-       protected $mOldPassMsg = null;
-
-       public function __construct() {
-               parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
-               $this->listed( false );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Main execution point
-        * @param string|null $par
-        */
-       function execute( $par ) {
-               $this->getOutput()->disallowUserJs();
-
-               parent::execute( $par );
-       }
-
-       protected function checkExecutePermissions( User $user ) {
-               parent::checkExecutePermissions( $user );
-
-               if ( !$this->getRequest()->wasPosted() ) {
-                       $this->requireLogin( 'resetpass-no-info' );
-               }
-       }
-
-       /**
-        * Set a message at the top of the Change Password form
-        * @since 1.23
-        * @param Message $msg Message to parse and add to the form header
-        */
-       public function setChangeMessage( Message $msg ) {
-               $this->mPreTextMessage = $msg;
-       }
-
-       /**
-        * Set a message at the top of the Change Password form
-        * @since 1.23
-        * @param string $msg Message label for old/temp password field
-        */
-       public function setOldPasswordMessage( $msg ) {
-               $this->mOldPassMsg = $msg;
-       }
-
-       protected function getFormFields() {
-               $user = $this->getUser();
-               $request = $this->getRequest();
-
-               $oldpassMsg = $this->mOldPassMsg;
-               if ( $oldpassMsg === null ) {
-                       $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
-               }
-
-               $fields = [
-                       'Name' => [
-                               'type' => 'info',
-                               'label-message' => 'username',
-                               'default' => $request->getVal( 'wpName', $user->getName() ),
-                       ],
-                       'Password' => [
-                               'type' => 'password',
-                               'label-message' => $oldpassMsg,
-                       ],
-                       'NewPassword' => [
-                               'type' => 'password',
-                               'label-message' => 'newpassword',
-                       ],
-                       'Retype' => [
-                               'type' => 'password',
-                               'label-message' => 'retypenew',
-                       ],
-               ];
-
-               if ( !$this->getUser()->isLoggedIn() ) {
-                       $fields['LoginOnChangeToken'] = [
-                               'type' => 'hidden',
-                               'label' => 'Change Password Token',
-                               'default' => LoginForm::getLoginToken()->toString(),
-                       ];
-               }
-
-               $extraFields = [];
-               Hooks::run( 'ChangePasswordForm', [ &$extraFields ] );
-               foreach ( $extraFields as $extra ) {
-                       list( $name, $label, $type, $default ) = $extra;
-                       $fields[$name] = [
-                               'type' => $type,
-                               'name' => $name,
-                               'label-message' => $label,
-                               'default' => $default,
-                       ];
-               }
-
-               if ( !$user->isLoggedIn() ) {
-                       $fields['Remember'] = [
-                               'type' => 'check',
-                               'label' => $this->msg( 'remembermypassword' )
-                                               ->numParams(
-                                                       ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
-                                               )->text(),
-                               'default' => $request->getVal( 'wpRemember' ),
-                       ];
-               }
-
-               return $fields;
-       }
-
-       protected function alterForm( HTMLForm $form ) {
-               $form->setId( 'mw-resetpass-form' );
-               $form->setTableId( 'mw-resetpass-table' );
-               $form->setWrapperLegendMsg( 'resetpass_header' );
-               $form->setSubmitTextMsg(
-                       $this->getUser()->isLoggedIn()
-                               ? 'resetpass-submit-loggedin'
-                               : 'resetpass_submit'
-               );
-               $form->addButton( [
-                       'name' => 'wpCancel',
-                       'value' => $this->msg( 'resetpass-submit-cancel' )->text()
-               ] );
-               $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
-               if ( $this->mPreTextMessage instanceof Message ) {
-                       $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
-               }
-               $form->addHiddenFields(
-                       $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
-       }
-
-       public function onSubmit( array $data ) {
-               global $wgAuth;
-
-               $request = $this->getRequest();
-
-               if ( $request->getCheck( 'wpLoginToken' ) ) {
-                       // This comes from Special:Userlogin when logging in with a temporary password
-                       return false;
-               }
-
-               if ( !$this->getUser()->isLoggedIn()
-                       && !LoginForm::getLoginToken()->match( $request->getVal( 'wpLoginOnChangeToken' ) )
-               ) {
-                       // Potential CSRF (bug 62497)
-                       return false;
-               }
-
-               if ( $request->getCheck( 'wpCancel' ) ) {
-                       $returnto = $request->getVal( 'returnto' );
-                       $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
-                       if ( !$titleObj instanceof Title ) {
-                               $titleObj = Title::newMainPage();
-                       }
-                       $query = $request->getVal( 'returntoquery' );
-                       $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
-
-                       return true;
-               }
-
-               $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
-               $this->mDomain = $wgAuth->getDomain();
-
-               if ( !$wgAuth->allowPasswordChange() ) {
-                       throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
-               }
-
-               $status = $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
-
-               return $status;
-       }
-
-       public function onSuccess() {
-               if ( $this->getUser()->isLoggedIn() ) {
-                       $this->getOutput()->wrapWikiMsg(
-                               "<div class=\"successbox\">\n$1\n</div>",
-                               'changepassword-success'
-                       );
-                       $this->getOutput()->returnToMain();
-               } else {
-                       $request = $this->getRequest();
-                       LoginForm::clearLoginToken();
-                       $token = LoginForm::getLoginToken()->toString();
-                       $data = [
-                               'action' => 'submitlogin',
-                               'wpName' => $this->mUserName,
-                               'wpDomain' => $this->mDomain,
-                               'wpLoginToken' => $token,
-                               'wpPassword' => $request->getVal( 'wpNewPassword' ),
-                       ] + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
-                       $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
-                       $login->setContext( $this->getContext() );
-                       $login->execute( null );
-               }
-       }
-
-       /**
-        * Checks the new password if it meets the requirements for passwords and set
-        * it as a current password, otherwise set the passed Status object to fatal
-        * and doesn't change anything
-        *
-        * @param string $oldpass The current (temporary) password.
-        * @param string $newpass The password to set.
-        * @param string $retype The string of the retype password field to check with newpass
-        * @return Status
-        */
-       protected function attemptReset( $oldpass, $newpass, $retype ) {
-               $isSelf = ( $this->mUserName === $this->getUser()->getName() );
-               if ( $isSelf ) {
-                       $user = $this->getUser();
-               } else {
-                       $user = User::newFromName( $this->mUserName );
-               }
-
-               if ( !$user || $user->isAnon() ) {
-                       return Status::newFatal( $this->msg( 'nosuchusershort', $this->mUserName ) );
-               }
-
-               if ( $newpass !== $retype ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'badretype' ] );
-                       return Status::newFatal( $this->msg( 'badretype' ) );
-               }
-
-               $throttleInfo = LoginForm::incrementLoginThrottle( $this->mUserName );
-               if ( $throttleInfo ) {
-                       return Status::newFatal( $this->msg( 'changepassword-throttled' )
-                               ->durationParams( $throttleInfo['wait'] )
-                       );
-               }
-
-               // @todo Make these separate messages, since the message is written for both cases
-               if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'wrongpassword' ] );
-                       return Status::newFatal( $this->msg( 'resetpass-wrong-oldpass' ) );
-               }
-
-               // User is resetting their password to their old password
-               if ( $oldpass === $newpass ) {
-                       return Status::newFatal( $this->msg( 'resetpass-recycled' ) );
-               }
-
-               // Do AbortChangePassword after checking mOldpass, so we don't leak information
-               // by possibly aborting a new password before verifying the old password.
-               $abortMsg = 'resetpass-abort-generic';
-               if ( !Hooks::run( 'AbortChangePassword', [ $user, $oldpass, $newpass, &$abortMsg ] ) ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'abortreset' ] );
-                       return Status::newFatal( $this->msg( $abortMsg ) );
-               }
-
-               // Please reset throttle for successful logins, thanks!
-               LoginForm::clearLoginThrottle( $this->mUserName );
-
-               try {
-                       $user->setPassword( $newpass );
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'success' ] );
-               } catch ( PasswordError $e ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'error' ] );
-                       return Status::newFatal( new RawMessage( $e->getMessage() ) );
-               }
-
-               if ( $isSelf ) {
-                       // This is needed to keep the user connected since
-                       // changing the password also modifies the user's token.
-                       $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
-                       $user->setCookies( null, null, $remember );
-               }
-               $user->saveSettings();
-               $this->resetPasswordExpiration( $user );
-               return Status::newGood();
-       }
-
-       public function requiresUnblock() {
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-
-       /**
-        * For resetting user password expiration, until AuthManager comes along
-        * @param User $user
-        */
-       private function resetPasswordExpiration( User $user ) {
-               global $wgPasswordExpirationDays;
-               $newExpire = null;
-               if ( $wgPasswordExpirationDays ) {
-                       $newExpire = wfTimestamp(
-                               TS_MW,
-                               time() + ( $wgPasswordExpirationDays * 24 * 3600 )
-                       );
-               }
-               // Give extensions a chance to force an expiration
-               Hooks::run( 'ResetPasswordExpiration', [ $this, &$newExpire ] );
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update(
-                       'user',
-                       [ 'user_password_expires' => $dbw->timestampOrNull( $newExpire ) ],
-                       [ 'user_id' => $user->getId() ],
-                       __METHOD__
-               );
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialCreateAccount.php b/includes/specials/pre-authmanager/SpecialCreateAccount.php
deleted file mode 100644 (file)
index 14f70b5..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
- *
- * 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
- * @ingroup SpecialPage
- */
-
-/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
- * @todo FIXME: This (and the rest of the login frontend) needs to die a horrible painful death
- *
- * @ingroup SpecialPage
- */
-class SpecialCreateAccountPreAuthManager extends SpecialRedirectToSpecial {
-       function __construct() {
-               parent::__construct(
-                       'CreateAccount',
-                       'Userlogin',
-                       'signup',
-                       [ 'returnto', 'returntoquery', 'uselang' ]
-               );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       // No reason to hide this link on Special:Specialpages
-       public function isListed() {
-               return true;
-       }
-
-       public function isRestricted() {
-               return !User::groupHasPermission( '*', 'createaccount' );
-       }
-
-       public function userCanExecute( User $user ) {
-               return $user->isAllowed( 'createaccount' );
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialPasswordReset.php b/includes/specials/pre-authmanager/SpecialPasswordReset.php
deleted file mode 100644 (file)
index e8719a7..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-<?php
-/**
- * Implements Special:PasswordReset
- *
- * 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
- * @ingroup SpecialPage
- */
-
-/**
- * Special page for requesting a password reset email
- *
- * @ingroup SpecialPage
- */
-class SpecialPasswordResetPreAuthManager extends FormSpecialPage {
-       /**
-        * @var Message
-        */
-       private $email;
-
-       /**
-        * @var User
-        */
-       private $firstUser;
-
-       /**
-        * @var Status
-        */
-       private $result;
-
-       /**
-        * @var string $method Identifies which password reset field was specified by the user.
-        */
-       private $method;
-
-       public function __construct() {
-               parent::__construct( 'PasswordReset', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       public function userCanExecute( User $user ) {
-               return $this->canChangePassword( $user ) === true && parent::userCanExecute( $user );
-       }
-
-       public function checkExecutePermissions( User $user ) {
-               $error = $this->canChangePassword( $user );
-               if ( is_string( $error ) ) {
-                       throw new ErrorPageError( 'internalerror', $error );
-               } elseif ( !$error ) {
-                       throw new ErrorPageError( 'internalerror', 'resetpass_forbidden' );
-               }
-
-               parent::checkExecutePermissions( $user );
-       }
-
-       protected function getFormFields() {
-               global $wgAuth;
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-               $a = [];
-               if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
-                       $a['Username'] = [
-                               'type' => 'text',
-                               'label-message' => 'passwordreset-username',
-                       ];
-
-                       if ( $this->getUser()->isLoggedIn() ) {
-                               $a['Username']['default'] = $this->getUser()->getName();
-                       }
-               }
-
-               if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
-                       $a['Email'] = [
-                               'type' => 'email',
-                               'label-message' => 'passwordreset-email',
-                       ];
-               }
-
-               if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
-                       $domains = $wgAuth->domainList();
-                       $a['Domain'] = [
-                               'type' => 'select',
-                               'options' => $domains,
-                               'label-message' => 'passwordreset-domain',
-                       ];
-               }
-
-               if ( $this->getUser()->isAllowed( 'passwordreset' ) ) {
-                       $a['Capture'] = [
-                               'type' => 'check',
-                               'label-message' => 'passwordreset-capture',
-                               'help-message' => 'passwordreset-capture-help',
-                       ];
-               }
-
-               return $a;
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-
-       public function alterForm( HTMLForm $form ) {
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-
-               $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $i = 0;
-               if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
-                       $i++;
-               }
-               if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
-                       $i++;
-               }
-               if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
-                       $i++;
-               }
-
-               $message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one';
-
-               $form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() );
-               $form->setSubmitTextMsg( 'mailmypassword' );
-       }
-
-       /**
-        * Process the form.  At this point we know that the user passes all the criteria in
-        * userCanExecute(), and if the data array contains 'Username', etc, then Username
-        * resets are allowed.
-        * @param array $data
-        * @throws MWException
-        * @throws ThrottledError|PermissionsError
-        * @return bool|array
-        */
-       public function onSubmit( array $data ) {
-               global $wgAuth, $wgMinimalPasswordLength;
-
-               if ( isset( $data['Domain'] ) ) {
-                       if ( $wgAuth->validDomain( $data['Domain'] ) ) {
-                               $wgAuth->setDomain( $data['Domain'] );
-                       } else {
-                               $wgAuth->setDomain( 'invaliddomain' );
-                       }
-               }
-
-               if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) {
-                       // The user knows they don't have the passwordreset permission,
-                       // but they tried to spoof the form. That's naughty
-                       throw new PermissionsError( 'passwordreset' );
-               }
-
-               /**
-                * @var $firstUser User
-                * @var $users User[]
-                */
-
-               if ( isset( $data['Username'] ) && $data['Username'] !== '' ) {
-                       $method = 'username';
-                       $users = [ User::newFromName( $data['Username'] ) ];
-               } elseif ( isset( $data['Email'] )
-                       && $data['Email'] !== ''
-                       && Sanitizer::validateEmail( $data['Email'] )
-               ) {
-                       $method = 'email';
-                       $res = wfGetDB( DB_SLAVE )->select(
-                               'user',
-                               User::selectFields(),
-                               [ 'user_email' => $data['Email'] ],
-                               __METHOD__
-                       );
-
-                       if ( $res ) {
-                               $users = [];
-
-                               foreach ( $res as $row ) {
-                                       $users[] = User::newFromRow( $row );
-                               }
-                       } else {
-                               // Some sort of database error, probably unreachable
-                               throw new MWException( 'Unknown database error in ' . __METHOD__ );
-                       }
-               } else {
-                       // The user didn't supply any data
-                       return false;
-               }
-
-               // Check for hooks (captcha etc), and allow them to modify the users list
-               $error = [];
-               if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) {
-                       return [ $error ];
-               }
-
-               $this->method = $method;
-
-               if ( count( $users ) == 0 ) {
-                       if ( $method == 'email' ) {
-                               // Don't reveal whether or not an email address is in use
-                               return true;
-                       } else {
-                               return [ 'noname' ];
-                       }
-               }
-
-               $firstUser = $users[0];
-
-               if ( !$firstUser instanceof User || !$firstUser->getId() ) {
-                       // Don't parse username as wikitext (bug 65501)
-                       return [ [ 'nosuchuser', wfEscapeWikiText( $data['Username'] ) ] ];
-               }
-
-               // Check against the rate limiter
-               if ( $this->getUser()->pingLimiter( 'mailpassword' ) ) {
-                       throw new ThrottledError;
-               }
-
-               // Check against password throttle
-               foreach ( $users as $user ) {
-                       if ( $user->isPasswordReminderThrottled() ) {
-
-                               # Round the time in hours to 3 d.p., in case someone is specifying
-                               # minutes or seconds.
-                               return [ [
-                                       'throttled-mailpassword',
-                                       round( $this->getConfig()->get( 'PasswordReminderResendTime' ), 3 )
-                               ] ];
-                       }
-               }
-
-               // All the users will have the same email address
-               if ( $firstUser->getEmail() == '' ) {
-                       // This won't be reachable from the email route, so safe to expose the username
-                       return [ [ 'noemail', wfEscapeWikiText( $firstUser->getName() ) ] ];
-               }
-
-               // We need to have a valid IP address for the hook, but per bug 18347, we should
-               // send the user's name if they're logged in.
-               $ip = $this->getRequest()->getIP();
-               if ( !$ip ) {
-                       return [ 'badipaddress' ];
-               }
-               $caller = $this->getUser();
-               Hooks::run( 'User::mailPasswordInternal', [ &$caller, &$ip, &$firstUser ] );
-               $username = $caller->getName();
-               $msg = IP::isValid( $username )
-                       ? 'passwordreset-emailtext-ip'
-                       : 'passwordreset-emailtext-user';
-
-               // Send in the user's language; which should hopefully be the same
-               $userLanguage = $firstUser->getOption( 'language' );
-
-               $passwords = [];
-               foreach ( $users as $user ) {
-                       $password = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-                       $user->setNewpassword( $password );
-                       $user->saveSettings();
-                       $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password )
-                               ->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later
-               }
-               $passwordBlock = implode( "\n\n", $passwords );
-
-               $this->email = $this->msg( $msg )->inLanguage( $userLanguage );
-               $this->email->params(
-                       $username,
-                       $passwordBlock,
-                       count( $passwords ),
-                       '<' . Title::newMainPage()->getCanonicalURL() . '>',
-                       round( $this->getConfig()->get( 'NewPasswordExpiry' ) / 86400 )
-               );
-
-               $title = $this->msg( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
-
-               $this->result = $firstUser->sendMail( $title->text(), $this->email->text() );
-
-               if ( isset( $data['Capture'] ) && $data['Capture'] ) {
-                       // Save the user, will be used if an error occurs when sending the email
-                       $this->firstUser = $firstUser;
-               } else {
-                       // Blank the email if the user is not supposed to see it
-                       $this->email = null;
-               }
-
-               if ( $this->result->isGood() ) {
-                       return true;
-               } elseif ( isset( $data['Capture'] ) && $data['Capture'] ) {
-                       // The email didn't send, but maybe they knew that and that's why they captured it
-                       return true;
-               } else {
-                       // @todo FIXME: The email wasn't sent, but we have already set
-                       // the password throttle timestamp, so they won't be able to try
-                       // again until it expires...  :(
-                       return [ [ 'mailerror', $this->result->getMessage() ] ];
-               }
-       }
-
-       public function onSuccess() {
-               if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) {
-                       // @todo Logging
-
-                       if ( $this->result->isGood() ) {
-                               $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture' );
-                       } else {
-                               $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture',
-                                       $this->result->getMessage(), $this->firstUser->getName() );
-                       }
-
-                       $this->getOutput()->addHTML( Html::rawElement( 'pre', [], $this->email->escaped() ) );
-               }
-
-               if ( $this->method === 'email' ) {
-                       $this->getOutput()->addWikiMsg( 'passwordreset-emailsentemail' );
-               } else {
-                       $this->getOutput()->addWikiMsg( 'passwordreset-emailsentusername' );
-               }
-
-               $this->getOutput()->returnToMain();
-       }
-
-       protected function canChangePassword( User $user ) {
-               global $wgAuth;
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-
-               // Maybe password resets are disabled, or there are no allowable routes
-               if ( !is_array( $resetRoutes ) ||
-                       !in_array( true, array_values( $resetRoutes ) )
-               ) {
-                       return 'passwordreset-disabled';
-               }
-
-               // Maybe the external auth plugin won't allow local password changes
-               if ( !$wgAuth->allowPasswordChange() ) {
-                       return 'resetpass_forbidden';
-               }
-
-               // Maybe email features have been disabled
-               if ( !$this->getConfig()->get( 'EnableEmail' ) ) {
-                       return 'passwordreset-emaildisabled';
-               }
-
-               // Maybe the user is blocked (check this here rather than relying on the parent
-               // method as we have a more specific error message to use here
-               if ( $user->isBlocked() ) {
-                       return 'blocked-mailpassword';
-               }
-
-               return true;
-       }
-
-       /**
-        * Hide the password reset page if resets are disabled.
-        * @return bool
-        */
-       function isListed() {
-               if ( $this->canChangePassword( $this->getUser() ) === true ) {
-                       return parent::isListed();
-               }
-
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialUserlogin.php b/includes/specials/pre-authmanager/SpecialUserlogin.php
deleted file mode 100644 (file)
index 09132f2..0000000
+++ /dev/null
@@ -1,1847 +0,0 @@
-<?php
-/**
- * Implements Special:UserLogin
- *
- * 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
- * @ingroup SpecialPage
- */
-use MediaWiki\Logger\LoggerFactory;
-use Psr\Log\LogLevel;
-use MediaWiki\Session\SessionManager;
-
-/**
- * Implements Special:UserLogin
- *
- * @ingroup SpecialPage
- */
-class LoginFormPreAuthManager extends SpecialPage {
-       const SUCCESS = 0;
-       const NO_NAME = 1;
-       const ILLEGAL = 2;
-       const WRONG_PLUGIN_PASS = 3;
-       const NOT_EXISTS = 4;
-       const WRONG_PASS = 5;
-       const EMPTY_PASS = 6;
-       const RESET_PASS = 7;
-       const ABORTED = 8;
-       const CREATE_BLOCKED = 9;
-       const THROTTLED = 10;
-       const USER_BLOCKED = 11;
-       const NEED_TOKEN = 12;
-       const WRONG_TOKEN = 13;
-       const USER_MIGRATED = 14;
-
-       public static $statusCodes = [
-               self::SUCCESS => 'success',
-               self::NO_NAME => 'no_name',
-               self::ILLEGAL => 'illegal',
-               self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
-               self::NOT_EXISTS => 'not_exists',
-               self::WRONG_PASS => 'wrong_pass',
-               self::EMPTY_PASS => 'empty_pass',
-               self::RESET_PASS => 'reset_pass',
-               self::ABORTED => 'aborted',
-               self::CREATE_BLOCKED => 'create_blocked',
-               self::THROTTLED => 'throttled',
-               self::USER_BLOCKED => 'user_blocked',
-               self::NEED_TOKEN => 'need_token',
-               self::WRONG_TOKEN => 'wrong_token',
-               self::USER_MIGRATED => 'user_migrated',
-       ];
-
-       /**
-        * Valid error and warning messages
-        *
-        * Special:Userlogin can show an error or warning message on the form when
-        * coming from another page. This is done via the ?error= or ?warning= GET
-        * parameters.
-        *
-        * This array is the list of valid message keys. All other values will be
-        * ignored.
-        *
-        * @since 1.24
-        * @var string[]
-        */
-       public static $validErrorMessages = [
-               'exception-nologin-text',
-               'watchlistanontext',
-               'changeemail-no-info',
-               'resetpass-no-info',
-               'confirmemail_needlogin',
-               'prefsnologintext2',
-       ];
-
-       public $mAbortLoginErrorMsg = null;
-       /**
-        * @var int How many seconds user is throttled for
-        * @since 1.27
-        */
-       public $mThrottleWait = '?';
-
-       protected $mUsername;
-       protected $mPassword;
-       protected $mRetype;
-       protected $mReturnTo;
-       protected $mCookieCheck;
-       protected $mPosted;
-       protected $mAction;
-       protected $mCreateaccount;
-       protected $mCreateaccountMail;
-       protected $mLoginattempt;
-       protected $mRemember;
-       protected $mEmail;
-       protected $mDomain;
-       protected $mLanguage;
-       protected $mSkipCookieCheck;
-       protected $mReturnToQuery;
-       protected $mToken;
-       protected $mStickHTTPS;
-       protected $mType;
-       protected $mReason;
-       protected $mRealName;
-       protected $mEntryError = '';
-       protected $mEntryErrorType = 'error';
-
-       private $mTempPasswordUsed;
-       private $mLoaded = false;
-       private $mSecureLoginUrl;
-
-       /** @var WebRequest */
-       private $mOverrideRequest = null;
-
-       /** @var WebRequest Effective request; set at the beginning of load */
-       private $mRequest = null;
-
-       /**
-        * @param WebRequest $request
-        */
-       public function __construct( $request = null ) {
-               global $wgUseMediaWikiUIEverywhere;
-               parent::__construct( 'Userlogin' );
-
-               $this->mOverrideRequest = $request;
-               // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
-               $wgUseMediaWikiUIEverywhere = true;
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Returns an array of all valid error messages.
-        *
-        * @return array
-        */
-       public static function getValidErrorMessages() {
-               static $messages = null;
-               if ( !$messages ) {
-                       $messages = self::$validErrorMessages;
-                       Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
-               }
-
-               return $messages;
-       }
-
-       /**
-        * Loader
-        */
-       function load() {
-               global $wgAuth, $wgHiddenPrefs, $wgEnableEmail;
-
-               if ( $this->mLoaded ) {
-                       return;
-               }
-               $this->mLoaded = true;
-
-               if ( $this->mOverrideRequest === null ) {
-                       $request = $this->getRequest();
-               } else {
-                       $request = $this->mOverrideRequest;
-               }
-               $this->mRequest = $request;
-
-               $this->mType = $request->getText( 'type' );
-               $this->mUsername = $request->getText( 'wpName' );
-               $this->mPassword = $request->getText( 'wpPassword' );
-               $this->mRetype = $request->getText( 'wpRetype' );
-               $this->mDomain = $request->getText( 'wpDomain' );
-               $this->mReason = $request->getText( 'wpReason' );
-               $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
-               $this->mPosted = $request->wasPosted();
-               $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
-                       && $wgEnableEmail;
-               $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
-               $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
-               $this->mAction = $request->getVal( 'action' );
-               $this->mRemember = $request->getCheck( 'wpRemember' );
-               $this->mFromHTTP = $request->getBool( 'fromhttp', false )
-                       || $request->getBool( 'wpFromhttp', false );
-               $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
-                       || $request->getBool( 'wpForceHttps', false );
-               $this->mLanguage = $request->getText( 'uselang' );
-               $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
-               $this->mToken = $this->mType == 'signup'
-                       ? $request->getVal( 'wpCreateaccountToken' )
-                       : $request->getVal( 'wpLoginToken' );
-               $this->mReturnTo = $request->getVal( 'returnto', '' );
-               $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
-
-               // Show an error or warning passed on from a previous page
-               $entryError = $this->msg( $request->getVal( 'error', '' ) );
-               $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
-               // bc: provide login link as a parameter for messages where the translation
-               // was not updated
-               $loginreqlink = Linker::linkKnown(
-                       $this->getPageTitle(),
-                       $this->msg( 'loginreqlink' )->escaped(),
-                       [],
-                       [
-                               'returnto' => $this->mReturnTo,
-                               'returntoquery' => $this->mReturnToQuery,
-                               'uselang' => $this->mLanguage,
-                               'fromhttp' => $this->mFromHTTP ? '1' : '0',
-                       ]
-               );
-
-               // Only show valid error or warning messages.
-               if ( $entryError->exists()
-                       && in_array( $entryError->getKey(), self::getValidErrorMessages() )
-               ) {
-                       $this->mEntryErrorType = 'error';
-                       $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
-
-               } elseif ( $entryWarning->exists()
-                       && in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
-               ) {
-                       $this->mEntryErrorType = 'warning';
-                       $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
-               }
-
-               if ( $wgEnableEmail ) {
-                       $this->mEmail = $request->getText( 'wpEmail' );
-               } else {
-                       $this->mEmail = '';
-               }
-               if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
-                       $this->mRealName = $request->getText( 'wpRealName' );
-               } else {
-                       $this->mRealName = '';
-               }
-
-               if ( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mDomain = $wgAuth->getDomain();
-               }
-               $wgAuth->setDomain( $this->mDomain );
-
-               # 1. When switching accounts, it sucks to get automatically logged out
-               # 2. Do not return to PasswordReset after a successful password change
-               #    but goto Wiki start page (Main_Page) instead ( bug 33997 )
-               $returnToTitle = Title::newFromText( $this->mReturnTo );
-               if ( is_object( $returnToTitle )
-                       && ( $returnToTitle->isSpecial( 'Userlogout' )
-                               || $returnToTitle->isSpecial( 'PasswordReset' ) )
-               ) {
-                       $this->mReturnTo = '';
-                       $this->mReturnToQuery = '';
-               }
-       }
-
-       function getDescription() {
-               if ( $this->mType === 'signup' ) {
-                       return $this->msg( 'createaccount' )->text();
-               } else {
-                       return $this->msg( 'login' )->text();
-               }
-       }
-
-       /**
-        * @param string|null $subPage
-        */
-       public function execute( $subPage ) {
-               // Make sure session is persisted
-               $session = SessionManager::getGlobalSession();
-               $session->persist();
-
-               $this->load();
-
-               // Check for [[Special:Userlogin/signup]]. This affects form display and
-               // page title.
-               if ( $subPage == 'signup' ) {
-                       $this->mType = 'signup';
-               }
-               $this->setHeaders();
-
-               // Make sure it's possible to log in
-               if ( $this->mType !== 'signup' && !$session->canSetUser() ) {
-                       throw new ErrorPageError(
-                               'cannotloginnow-title',
-                               'cannotloginnow-text',
-                               [
-                                       $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
-                               ]
-                       );
-               }
-
-               /**
-                * In the case where the user is already logged in, and was redirected to
-                * the login form from a page that requires login, do not show the login
-                * page. The use case scenario for this is when a user opens a large number
-                * of tabs, is redirected to the login page on all of them, and then logs
-                * in on one, expecting all the others to work properly.
-                *
-                * However, do show the form if it was visited intentionally (no 'returnto'
-                * is present). People who often switch between several accounts have grown
-                * accustomed to this behavior.
-                */
-               if (
-                       $this->mType !== 'signup' &&
-                       !$this->mPosted &&
-                       $this->getUser()->isLoggedIn() &&
-                       ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' )
-               ) {
-                       $this->successfulLogin();
-               }
-
-               // If logging in and not on HTTPS, either redirect to it or offer a link.
-               global $wgSecureLogin;
-               if ( $this->mRequest->getProtocol() !== 'https' ) {
-                       $title = $this->getFullTitle();
-                       $query = [
-                               'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null,
-                               'returntoquery' => $this->mReturnToQuery !== '' ?
-                                       $this->mReturnToQuery : null,
-                               'title' => null,
-                               ( $this->mEntryErrorType === 'error' ? 'error' : 'warning' ) => $this->mEntryError,
-                       ] + $this->mRequest->getQueryValues();
-                       $url = $title->getFullURL( $query, false, PROTO_HTTPS );
-                       if ( $wgSecureLogin
-                               && wfCanIPUseHTTPS( $this->getRequest()->getIP() )
-                               && !$this->mFromHTTP ) // Avoid infinite redirect
-                       {
-                               $url = wfAppendQuery( $url, 'fromhttp=1' );
-                               $this->getOutput()->redirect( $url );
-                               // Since we only do this redir to change proto, always vary
-                               $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
-
-                               return;
-                       } else {
-                               // A wiki without HTTPS login support should set $wgServer to
-                               // http://somehost, in which case the secure URL generated
-                               // above won't actually start with https://
-                               if ( substr( $url, 0, 8 ) === 'https://' ) {
-                                       $this->mSecureLoginUrl = $url;
-                               }
-                       }
-               }
-
-               if ( !is_null( $this->mCookieCheck ) ) {
-                       $this->onCookieRedirectCheck( $this->mCookieCheck );
-
-                       return;
-               } elseif ( $this->mPosted ) {
-                       if ( $this->mCreateaccount ) {
-                               $this->addNewAccount();
-
-                               return;
-                       } elseif ( $this->mCreateaccountMail ) {
-                               $this->addNewAccountMailPassword();
-
-                               return;
-                       } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
-                               $this->processLogin();
-
-                               return;
-                       }
-               }
-               $this->mainLoginForm( $this->mEntryError, $this->mEntryErrorType );
-       }
-
-       /**
-        * @private
-        */
-       function addNewAccountMailPassword() {
-               if ( $this->mEmail == '' ) {
-                       $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() );
-
-                       return;
-               }
-
-               $status = $this->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info(
-                       'Account creation attempt with mailed password',
-                       [ 'event' => 'accountcreation', 'status' => $status ]
-               );
-               if ( !$status->isGood() ) {
-                       $error = $status->getMessage();
-                       $this->mainLoginForm( $error->toString() );
-
-                       return;
-               }
-
-               /** @var User $u */
-               $u = $status->getValue();
-
-               // Wipe the initial password and mail a temporary one
-               $u->setPassword( null );
-               $u->saveSettings();
-               $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
-
-               Hooks::run( 'AddNewAccount', [ $u, true ] );
-               $u->addNewUserLogEntry( 'byemail', $this->mReason );
-
-               $out = $this->getOutput();
-               $out->setPageTitle( $this->msg( 'accmailtitle' ) );
-
-               if ( !$result->isGood() ) {
-                       $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() );
-               } else {
-                       $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
-                       $this->executeReturnTo( 'success' );
-               }
-       }
-
-       /**
-        * @private
-        * @return bool
-        */
-       function addNewAccount() {
-               global $wgContLang, $wgUser, $wgEmailAuthentication, $wgLoginLanguageSelector;
-
-               # Create the account and abort if there's a problem doing so
-               $status = $this->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', [
-                       'event' => 'accountcreation',
-                       'status' => $status,
-               ] );
-
-               if ( !$status->isGood() ) {
-                       $error = $status->getMessage();
-                       $this->mainLoginForm( $error->toString() );
-
-                       return false;
-               }
-
-               $u = $status->getValue();
-
-               # Only save preferences if the user is not creating an account for someone else.
-               if ( $this->getUser()->isAnon() ) {
-                       # If we showed up language selection links, and one was in use, be
-                       # smart (and sensible) and save that language as the user's preference
-                       if ( $wgLoginLanguageSelector && $this->mLanguage ) {
-                               $u->setOption( 'language', $this->mLanguage );
-                       } else {
-
-                               # Otherwise the user's language preference defaults to $wgContLang,
-                               # but it may be better to set it to their preferred $wgContLang variant,
-                               # based on browser preferences or URL parameters.
-                               $u->setOption( 'language', $wgContLang->getPreferredVariant() );
-                       }
-                       if ( $wgContLang->hasVariants() ) {
-                               $u->setOption( 'variant', $wgContLang->getPreferredVariant() );
-                       }
-               }
-
-               $out = $this->getOutput();
-
-               # Send out an email authentication message if needed
-               if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
-                       $status = $u->sendConfirmationMail();
-                       if ( $status->isGood() ) {
-                               $out->addWikiMsg( 'confirmemail_oncreate' );
-                       } else {
-                               $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
-                       }
-               }
-
-               # Save settings (including confirmation token)
-               $u->saveSettings();
-
-               # If not logged in, assume the new account as the current one and set
-               # session cookies then show a "welcome" message or a "need cookies"
-               # message as needed
-               if ( $this->getUser()->isAnon() ) {
-                       $u->setCookies();
-                       $wgUser = $u;
-                       // This should set it for OutputPage and the Skin
-                       // which is needed or the personal links will be
-                       // wrong.
-                       $this->getContext()->setUser( $u );
-                       Hooks::run( 'AddNewAccount', [ $u, false ] );
-                       $u->addNewUserLogEntry( 'create' );
-                       if ( $this->hasSessionCookie() ) {
-                               $this->successfulCreation();
-                       } else {
-                               $this->cookieRedirectCheck( 'new' );
-                       }
-               } else {
-                       # Confirm that the account was created
-                       $out->setPageTitle( $this->msg( 'accountcreated' ) );
-                       $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
-                       $out->addReturnTo( $this->getPageTitle() );
-                       Hooks::run( 'AddNewAccount', [ $u, false ] );
-                       $u->addNewUserLogEntry( 'create2', $this->mReason );
-               }
-
-               return true;
-       }
-
-       /**
-        * Make a new user account using the loaded data.
-        * @private
-        * @throws PermissionsError|ReadOnlyError
-        * @return Status
-        */
-       public function addNewAccountInternal() {
-               global $wgAuth, $wgAccountCreationThrottle, $wgEmailConfirmToEdit;
-
-               // If the user passes an invalid domain, something is fishy
-               if ( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       return Status::newFatal( 'wrongpassword' );
-               }
-
-               // If we are not allowing users to login locally, we should be checking
-               // to see if the user is actually able to authenticate to the authenti-
-               // cation server before they create an account (otherwise, they can
-               // create a local account and login as any domain user). We only need
-               // to check this for domains that aren't local.
-               if ( 'local' != $this->mDomain && $this->mDomain != '' ) {
-                       if (
-                               !$wgAuth->canCreateAccounts() &&
-                               (
-                                       !$wgAuth->userExists( $this->mUsername ) ||
-                                       !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
-                               )
-                       ) {
-                               return Status::newFatal( 'wrongpassword' );
-                       }
-               }
-
-               if ( wfReadOnly() ) {
-                       throw new ReadOnlyError;
-               }
-
-               # Request forgery checks.
-               $token = self::getCreateaccountToken();
-               if ( $token->wasNew() ) {
-                       return Status::newFatal( 'nocookiesfornew' );
-               }
-
-               # The user didn't pass a createaccount token
-               if ( !$this->mToken ) {
-                       return Status::newFatal( 'sessionfailure' );
-               }
-
-               # Validate the createaccount token
-               if ( !$token->match( $this->mToken ) ) {
-                       return Status::newFatal( 'sessionfailure' );
-               }
-
-               # Check permissions
-               $currentUser = $this->getUser();
-               $creationBlock = $currentUser->isBlockedFromCreateAccount();
-               if ( !$currentUser->isAllowed( 'createaccount' ) ) {
-                       throw new PermissionsError( 'createaccount' );
-               } elseif ( $creationBlock instanceof Block ) {
-                       // Throws an ErrorPageError.
-                       $this->userBlockedMessage( $creationBlock );
-
-                       // This should never be reached.
-                       return false;
-               }
-
-               # Include checks that will include GlobalBlocking (Bug 38333)
-               $permErrors = $this->getPageTitle()->getUserPermissionsErrors(
-                       'createaccount',
-                       $currentUser,
-                       true
-               );
-
-               if ( count( $permErrors ) ) {
-                       throw new PermissionsError( 'createaccount', $permErrors );
-               }
-
-               $ip = $this->getRequest()->getIP();
-               if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
-                       return Status::newFatal( 'sorbs_create_account_reason' );
-               }
-
-               # Now create a dummy user ($u) and check if it is valid
-               $u = User::newFromName( $this->mUsername, 'creatable' );
-               if ( !$u ) {
-                       return Status::newFatal( 'noname' );
-               }
-
-               $cache = ObjectCache::getLocalClusterInstance();
-               # Make sure the user does not exist already
-               $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) );
-               if ( !$lock ) {
-                       return Status::newFatal( 'usernameinprogress' );
-               } elseif ( $u->idForName( User::READ_LOCKING ) ) {
-                       return Status::newFatal( 'userexists' );
-               }
-
-               if ( $this->mCreateaccountMail ) {
-                       # do not force a password for account creation by email
-                       # set invalid password, it will be replaced later by a random generated password
-                       $this->mPassword = null;
-               } else {
-                       if ( $this->mPassword !== $this->mRetype ) {
-                               return Status::newFatal( 'badretype' );
-                       }
-
-                       # check for password validity, return a fatal Status if invalid
-                       $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
-                       if ( !$validity->isGood() ) {
-                               $validity->ok = false; // make sure this Status is fatal
-                               return $validity;
-                       }
-               }
-
-               # if you need a confirmed email address to edit, then obviously you
-               # need an email address.
-               if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) {
-                       return Status::newFatal( 'noemailtitle' );
-               }
-
-               if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) {
-                       return Status::newFatal( 'invalidemailaddress' );
-               }
-
-               # Set some additional data so the AbortNewAccount hook can be used for
-               # more than just username validation
-               $u->setEmail( $this->mEmail );
-               $u->setRealName( $this->mRealName );
-
-               $abortError = '';
-               $abortStatus = null;
-               if ( !Hooks::run( 'AbortNewAccount', [ $u, &$abortError, &$abortStatus ] ) ) {
-                       // Hook point to add extra creation throttles and blocks
-                       wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
-                       if ( $abortStatus === null ) {
-                               // Report back the old string as a raw message status.
-                               // This will report the error back as 'createaccount-hook-aborted'
-                               // with the given string as the message.
-                               // To return a different error code, return a Status object.
-                               $abortError = new Message( 'createaccount-hook-aborted', [ $abortError ] );
-                               $abortError->text();
-
-                               return Status::newFatal( $abortError );
-                       } else {
-                               // For MediaWiki 1.23+ and updated hooks, return the Status object
-                               // returned from the hook.
-                               return $abortStatus;
-                       }
-               }
-
-               // Hook point to check for exempt from account creation throttle
-               if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
-                       wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
-                               "allowed account creation w/o throttle\n" );
-               } else {
-                       if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) {
-                               $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip );
-                               $value = $cache->get( $key );
-                               if ( !$value ) {
-                                       $cache->set( $key, 0, $cache::TTL_DAY );
-                               }
-                               if ( $value >= $wgAccountCreationThrottle ) {
-                                       return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle );
-                               }
-                               $cache->incr( $key );
-                       }
-               }
-
-               if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
-                       return Status::newFatal( 'externaldberror' );
-               }
-
-               self::clearCreateaccountToken();
-
-               return $this->initUser( $u, false );
-       }
-
-       /**
-        * Actually add a user to the database.
-        * Give it a User object that has been initialised with a name.
-        *
-        * @param User $u
-        * @param bool $autocreate True if this is an autocreation via auth plugin
-        * @return Status Status object, with the User object in the value member on success
-        * @private
-        */
-       function initUser( $u, $autocreate ) {
-               global $wgAuth;
-
-               $status = $u->addToDatabase();
-               if ( !$status->isOK() ) {
-                       return $status;
-               }
-
-               if ( $wgAuth->allowPasswordChange() ) {
-                       $u->setPassword( $this->mPassword );
-               }
-
-               $u->setEmail( $this->mEmail );
-               $u->setRealName( $this->mRealName );
-               $u->setToken();
-
-               Hooks::run( 'LocalUserCreated', [ $u, $autocreate ] );
-               $oldUser = $u;
-               $wgAuth->initUser( $u, $autocreate );
-               if ( $oldUser !== $u ) {
-                       wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
-               }
-
-               $u->saveSettings();
-
-               // Update user count
-               DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
-               // Watch user's userpage and talk page
-               $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
-
-               return Status::newGood( $u );
-       }
-
-       /**
-        * Internally authenticate the login request.
-        *
-        * This may create a local account as a side effect if the
-        * authentication plugin allows transparent local account
-        * creation.
-        * @return int
-        */
-       public function authenticateUserData() {
-               global $wgUser, $wgAuth;
-
-               $this->load();
-
-               if ( $this->mUsername == '' ) {
-                       return self::NO_NAME;
-               }
-
-               // We require a login token to prevent login CSRF
-               // Handle part of this before incrementing the throttle so
-               // token-less login attempts don't count towards the throttle
-               // but wrong-token attempts do.
-
-               // If the user doesn't have a login token yet, set one.
-               $token = self::getLoginToken();
-               if ( $token->wasNew() ) {
-                       return self::NEED_TOKEN;
-               }
-               // If the user didn't pass a login token, tell them we need one
-               if ( !$this->mToken ) {
-                       return self::NEED_TOKEN;
-               }
-
-               $throttleCount = self::incrementLoginThrottle( $this->mUsername );
-               if ( $throttleCount ) {
-                       $this->mThrottleWait = $throttleCount['wait'];
-                       return self::THROTTLED;
-               }
-
-               // Validate the login token
-               if ( !$token->match( $this->mToken ) ) {
-                       return self::WRONG_TOKEN;
-               }
-
-               // Load the current user now, and check to see if we're logging in as
-               // the same name. This is necessary because loading the current user
-               // (say by calling getName()) calls the UserLoadFromSession hook, which
-               // potentially creates the user in the database. Until we load $wgUser,
-               // checking for user existence using User::newFromName($name)->getId() below
-               // will effectively be using stale data.
-               if ( $this->getUser()->getName() === $this->mUsername ) {
-                       wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
-
-                       return self::SUCCESS;
-               }
-
-               $u = User::newFromName( $this->mUsername );
-               if ( $u === false ) {
-                       return self::ILLEGAL;
-               }
-
-               $msg = null;
-               // Give extensions a way to indicate the username has been updated,
-               // rather than telling the user the account doesn't exist.
-               if ( !Hooks::run( 'LoginUserMigrated', [ $u, &$msg ] ) ) {
-                       $this->mAbortLoginErrorMsg = $msg;
-                       return self::USER_MIGRATED;
-               }
-
-               if ( !User::isUsableName( $u->getName() ) ) {
-                       return self::ILLEGAL;
-               }
-
-               $isAutoCreated = false;
-               if ( $u->getId() == 0 ) {
-                       $status = $this->attemptAutoCreate( $u );
-                       if ( $status !== self::SUCCESS ) {
-                               return $status;
-                       } else {
-                               $isAutoCreated = true;
-                       }
-               } else {
-                       $u->load();
-               }
-
-               // Give general extensions, such as a captcha, a chance to abort logins
-               $abort = self::ABORTED;
-               if ( !Hooks::run( 'AbortLogin', [ $u, $this->mPassword, &$abort, &$msg ] ) ) {
-                       if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) {
-                               throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort );
-                       }
-                       $this->mAbortLoginErrorMsg = $msg;
-                       return $abort;
-               }
-
-               global $wgBlockDisablesLogin;
-               if ( !$u->checkPassword( $this->mPassword ) ) {
-                       if ( $u->checkTemporaryPassword( $this->mPassword ) ) {
-                               /**
-                                * The e-mailed temporary password should not be used for actu-
-                                * al logins; that's a very sloppy habit, and insecure if an
-                                * attacker has a few seconds to click "search" on someone's
-                                * open mail reader.
-                                *
-                                * Allow it to be used only to reset the password a single time
-                                * to a new value, which won't be in the user's e-mail ar-
-                                * chives.
-                                *
-                                * For backwards compatibility, we'll still recognize it at the
-                                * login form to minimize surprises for people who have been
-                                * logging in with a temporary password for some time.
-                                *
-                                * As a side-effect, we can authenticate the user's e-mail ad-
-                                * dress if it's not already done, since the temporary password
-                                * was sent via e-mail.
-                                */
-                               if ( !$u->isEmailConfirmed() && !wfReadOnly() ) {
-                                       $u->confirmEmail();
-                                       $u->saveSettings();
-                               }
-
-                               // At this point we just return an appropriate code/ indicating
-                               // that the UI should show a password reset form; bot inter-
-                               // faces etc will probably just fail cleanly here.
-                               $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed';
-                               $this->mTempPasswordUsed = true;
-                               $retval = self::RESET_PASS;
-                       } else {
-                               $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
-                       }
-               } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
-                       // If we've enabled it, make it so that a blocked user cannot login
-                       $retval = self::USER_BLOCKED;
-               } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) {
-                       // Force reset now, without logging in
-                       $retval = self::RESET_PASS;
-                       $this->mAbortLoginErrorMsg = 'resetpass-expired';
-               } else {
-                       Hooks::run( 'UserLoggedIn', [ $u ] );
-                       $oldUser = $u;
-                       $wgAuth->updateUser( $u );
-                       if ( $oldUser !== $u ) {
-                               wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
-                       }
-                       $wgUser = $u;
-                       // This should set it for OutputPage and the Skin
-                       // which is needed or the personal links will be
-                       // wrong.
-                       $this->getContext()->setUser( $u );
-
-                       // Please reset throttle for successful logins, thanks!
-                       self::clearLoginThrottle( $this->mUsername );
-
-                       if ( $isAutoCreated ) {
-                               // Must be run after $wgUser is set, for correct new user log
-                               Hooks::run( 'AuthPluginAutoCreate', [ $u ] );
-                       }
-
-                       $retval = self::SUCCESS;
-               }
-               Hooks::run( 'LoginAuthenticateAudit', [ $u, $this->mPassword, $retval ] );
-
-               return $retval;
-       }
-
-       /**
-        * Increment the login attempt throttle hit count for the (username,current IP)
-        * tuple unless the throttle was already reached.
-        *
-        * @since 1.27 Return value changed.
-        * @param string $username The user name
-        * @return bool|array false if below limit or an array if above limit
-        *   Array contains keys wait, count, and throttleIndex
-        */
-       public static function incrementLoginThrottle( $username ) {
-               global $wgPasswordAttemptThrottle, $wgRequest;
-               $canUsername = User::getCanonicalName( $username, 'usable' );
-               $username = $canUsername !== false ? $canUsername : $username;
-
-               $throttleCount = 0;
-               if ( is_array( $wgPasswordAttemptThrottle ) ) {
-                       $throttleConfig = $wgPasswordAttemptThrottle;
-                       if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
-                               // old style. Convert for backwards compat.
-                               $throttleConfig = [ $wgPasswordAttemptThrottle ];
-                       }
-                       foreach ( $throttleConfig as $index => $specificThrottle ) {
-                               if ( isset( $specificThrottle['allIPs'] ) ) {
-                                       $ip = 'All';
-                               } else {
-                                       $ip = $wgRequest->getIP();
-                               }
-                               $throttleKey = wfGlobalCacheKey( 'password-throttle',
-                                       $index, $ip, md5( $username )
-                               );
-                               $count = $specificThrottle['count'];
-                               $period = $specificThrottle['seconds'];
-
-                               $cache = ObjectCache::getLocalClusterInstance();
-                               $throttleCount = $cache->get( $throttleKey );
-                               if ( !$throttleCount ) {
-                                       $cache->add( $throttleKey, 1, $period ); // start counter
-                               } elseif ( $throttleCount < $count ) {
-                                       $cache->incr( $throttleKey );
-                               } elseif ( $throttleCount >= $count ) {
-                                       $logMsg = 'Login attempt rejected because logins to '
-                                               . '{acct} from IP {ip} have been throttled for '
-                                               . '{period} seconds due to {count} failed attempts';
-                                       // If we are hitting a throttle for >= 50 attempts,
-                                       // it is much more likely to be an attack than someone
-                                       // simply forgetting their password, so log it at a
-                                       // higher level.
-                                       $level = $count >= 50 ? LogLevel::WARNING : LogLevel::INFO;
-                                       // It should be noted that once the throttle is hit,
-                                       // every attempt to login will generate the log message
-                                       // until the throttle expires, not just the attempt that
-                                       // puts the throttle over the top.
-                                       LoggerFactory::getInstance( 'password-throttle' )->log(
-                                               $level,
-                                               $logMsg,
-                                               [
-                                                       'ip' => $ip,
-                                                       'period' => $period,
-                                                       'acct' => $username,
-                                                       'count' => $count,
-                                                       'throttleIdentifier' => $index,
-                                                       'method' => __METHOD__
-                                               ]
-                                       );
-
-                                       return [
-                                               'throttleIndex' => $index,
-                                               'wait' => $period,
-                                               'count' => $count
-                                       ];
-                               }
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Increment the login attempt throttle hit count for the (username,current IP)
-        * tuple unless the throttle was already reached.
-        *
-        * @deprecated Use LoginForm::incrementLoginThrottle instead
-        * @param string $username The user name
-        * @return bool|int true if above throttle, or 0 (prior to 1.27, returned current count)
-        */
-       public static function incLoginThrottle( $username ) {
-               wfDeprecated( __METHOD__, "1.27" );
-               $res = self::incrementLoginThrottle( $username );
-               return is_array( $res ) ? true : 0;
-       }
-
-       /**
-        * Clear the login attempt throttle hit count for the (username,current IP) tuple.
-        * @param string $username The user name
-        * @return void
-        */
-       public static function clearLoginThrottle( $username ) {
-               global $wgRequest, $wgPasswordAttemptThrottle;
-               $canUsername = User::getCanonicalName( $username, 'usable' );
-               $username = $canUsername !== false ? $canUsername : $username;
-
-               if ( is_array( $wgPasswordAttemptThrottle ) ) {
-                       $throttleConfig = $wgPasswordAttemptThrottle;
-                       if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
-                               // old style. Convert for backwards compat.
-                               $throttleConfig = [ $wgPasswordAttemptThrottle ];
-                       }
-                       foreach ( $throttleConfig as $index => $specificThrottle ) {
-                               if ( isset( $specificThrottle['allIPs'] ) ) {
-                                       $ip = 'All';
-                               } else {
-                                       $ip = $wgRequest->getIP();
-                               }
-                               $throttleKey = wfGlobalCacheKey( 'password-throttle', $index,
-                                       $ip, md5( $username )
-                               );
-                               ObjectCache::getLocalClusterInstance()->delete( $throttleKey );
-                       }
-               }
-       }
-
-       /**
-        * Attempt to automatically create a user on login. Only succeeds if there
-        * is an external authentication method which allows it.
-        *
-        * @param User $user
-        *
-        * @return int Status code
-        */
-       function attemptAutoCreate( $user ) {
-               global $wgAuth;
-
-               if ( $this->getUser()->isBlockedFromCreateAccount() ) {
-                       wfDebug( __METHOD__ . ": user is blocked from account creation\n" );
-
-                       return self::CREATE_BLOCKED;
-               }
-
-               if ( !$wgAuth->autoCreate() ) {
-                       return self::NOT_EXISTS;
-               }
-
-               if ( !$wgAuth->userExists( $user->getName() ) ) {
-                       wfDebug( __METHOD__ . ": user does not exist\n" );
-
-                       return self::NOT_EXISTS;
-               }
-
-               if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
-                       wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" );
-
-                       return self::WRONG_PLUGIN_PASS;
-               }
-
-               $abortError = '';
-               if ( !Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
-                       // Hook point to add extra creation throttles and blocks
-                       wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
-                       $this->mAbortLoginErrorMsg = $abortError;
-
-                       return self::ABORTED;
-               }
-
-               wfDebug( __METHOD__ . ": creating account\n" );
-               $status = $this->initUser( $user, true );
-
-               if ( !$status->isOK() ) {
-                       $errors = $status->getErrorsByType( 'error' );
-                       $this->mAbortLoginErrorMsg = $errors[0]['message'];
-
-                       return self::ABORTED;
-               }
-
-               return self::SUCCESS;
-       }
-
-       function processLogin() {
-               global $wgLang, $wgSecureLogin, $wgInvalidPasswordReset;
-
-               $authRes = $this->authenticateUserData();
-               switch ( $authRes ) {
-                       case self::SUCCESS:
-                               # We've verified now, update the real record
-                               $user = $this->getUser();
-                               $user->touch();
-
-                               if ( $user->requiresHTTPS() ) {
-                                       $this->mStickHTTPS = true;
-                               }
-
-                               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                                       $user->setCookies( $this->mRequest, false, $this->mRemember );
-                               } else {
-                                       $user->setCookies( $this->mRequest, null, $this->mRemember );
-                               }
-                               self::clearLoginToken();
-
-                               // Reset the throttle
-                               self::clearLoginThrottle( $this->mUsername );
-
-                               $request = $this->getRequest();
-                               if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
-                                       /* Replace the language object to provide user interface in
-                                        * correct language immediately on this first page load.
-                                        */
-                                       $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
-                                       $userLang = Language::factory( $code );
-                                       $wgLang = $userLang;
-                                       RequestContext::getMain()->setLanguage( $userLang );
-                                       $this->getContext()->setLanguage( $userLang );
-                                       // Reset SessionID on Successful login (bug 40995)
-                                       $this->renewSessionId();
-                                       if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) {
-                                               $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) );
-                                       } elseif ( $wgInvalidPasswordReset
-                                               && !$user->isValidPassword( $this->mPassword )
-                                       ) {
-                                               $status = $user->checkPasswordValidity(
-                                                       $this->mPassword,
-                                                       'login'
-                                               );
-                                               $this->resetLoginForm(
-                                                       $status->getMessage( 'resetpass-validity-soft' )
-                                               );
-                                       } else {
-                                               $this->successfulLogin();
-                                       }
-                               } else {
-                                       $this->cookieRedirectCheck( 'login' );
-                               }
-                               break;
-
-                       case self::NEED_TOKEN:
-                               $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin';
-                               $this->mainLoginForm( $this->msg( $error )->parse() );
-                               break;
-                       case self::WRONG_TOKEN:
-                               $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::NO_NAME:
-                       case self::ILLEGAL:
-                               $error = $this->mAbortLoginErrorMsg ?: 'noname';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::NOT_EXISTS:
-                               if ( $this->getUser()->isAllowed( 'createaccount' ) ) {
-                                       $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser';
-                                       $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->parse() );
-                               } else {
-                                       $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort';
-                                       $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->text() );
-                               }
-                               break;
-                       case self::WRONG_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::EMPTY_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::RESET_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce';
-                               $this->resetLoginForm( $this->msg( $error ) );
-                               break;
-                       case self::CREATE_BLOCKED:
-                               $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() );
-                               break;
-                       case self::THROTTLED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-throttled';
-                               $this->mainLoginForm( $this->msg( $error )
-                                       ->durationParams( $this->mThrottleWait )->text()
-                               );
-                               break;
-                       case self::USER_BLOCKED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked';
-                               $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() );
-                               break;
-                       case self::ABORTED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic';
-                               $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->text() );
-                               break;
-                       case self::USER_MIGRATED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-migrated-generic';
-                               $params = [];
-                               if ( is_array( $error ) ) {
-                                       $error = array_shift( $this->mAbortLoginErrorMsg );
-                                       $params = $this->mAbortLoginErrorMsg;
-                               }
-                               $this->mainLoginForm( $this->msg( $error, $params )->text() );
-                               break;
-                       default:
-                               throw new MWException( 'Unhandled case value' );
-               }
-
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
-                       'event' => 'login',
-                       'successful' => $authRes === self::SUCCESS,
-                       'status' => LoginForm::$statusCodes[$authRes],
-               ] );
-       }
-
-       /**
-        * Show the Special:ChangePassword form, with custom message
-        * @param Message $msg
-        */
-       protected function resetLoginForm( Message $msg ) {
-               // Allow hooks to explain this password reset in more detail
-               Hooks::run( 'LoginPasswordResetMessage', [ &$msg, $this->mUsername ] );
-               $reset = new SpecialChangePasswordPreAuthManager();
-               $derivative = new DerivativeContext( $this->getContext() );
-               $derivative->setTitle( $reset->getPageTitle() );
-               $reset->setContext( $derivative );
-               if ( !$this->mTempPasswordUsed ) {
-                       $reset->setOldPasswordMessage( 'oldpassword' );
-               }
-               $reset->setChangeMessage( $msg );
-               $reset->execute( null );
-       }
-
-       /**
-        * @param User $u
-        * @param bool $throttle
-        * @param string $emailTitle Message name of email title
-        * @param string $emailText Message name of email text
-        * @return Status
-        */
-       function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle',
-               $emailText = 'passwordremindertext'
-       ) {
-               global $wgNewPasswordExpiry, $wgMinimalPasswordLength;
-
-               if ( $u->getEmail() == '' ) {
-                       return Status::newFatal( 'noemail', $u->getName() );
-               }
-               $ip = $this->getRequest()->getIP();
-               if ( !$ip ) {
-                       return Status::newFatal( 'badipaddress' );
-               }
-
-               $currentUser = $this->getUser();
-               Hooks::run( 'User::mailPasswordInternal', [ &$currentUser, &$ip, &$u ] );
-
-               $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-               $u->setNewpassword( $np, $throttle );
-               $u->saveSettings();
-               $userLanguage = $u->getOption( 'language' );
-
-               $mainPage = Title::newMainPage();
-               $mainPageUrl = $mainPage->getCanonicalURL();
-
-               $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>',
-                       round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text();
-               $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m );
-
-               return $result;
-       }
-
-       /**
-        * Run any hooks registered for logins, then HTTP redirect to
-        * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
-        * nice message here, but that's really not as useful as just being sent to
-        * wherever you logged in from.  It should be clear that the action was
-        * successful, given the lack of error messages plus the appearance of your
-        * name in the upper right.
-        *
-        * @private
-        */
-       function successfulLogin() {
-               # Run any hooks; display injected HTML if any, else redirect
-               $currentUser = $this->getUser();
-               $injected_html = '';
-               $direct = RequestContext::getMain()->getRequest()->wasPosted();
-               Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
-
-               if ( $injected_html !== '' ) {
-                       $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
-                               'loginsuccess', $injected_html );
-               } else {
-                       $this->executeReturnTo( 'successredirect' );
-               }
-       }
-
-       /**
-        * Run any hooks registered for logins, then display a message welcoming
-        * the user.
-        *
-        * @private
-        */
-       function successfulCreation() {
-               # Run any hooks; display injected HTML
-               $currentUser = $this->getUser();
-               $injected_html = '';
-               $welcome_creation_msg = 'welcomecreation-msg';
-               $direct = RequestContext::getMain()->getRequest()->wasPosted();
-
-               Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
-
-               /**
-                * Let any extensions change what message is shown.
-                * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
-                * @since 1.18
-                */
-               Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
-
-               $this->displaySuccessfulAction(
-                       'signup',
-                       $this->msg( 'welcomeuser', $this->getUser()->getName() ),
-                       $welcome_creation_msg, $injected_html
-               );
-       }
-
-       /**
-        * Display a "successful action" page.
-        *
-        * @param string $type Condition of return to; see `executeReturnTo`
-        * @param string|Message $title Page's title
-        * @param string $msgname
-        * @param string $injected_html
-        */
-       private function displaySuccessfulAction( $type, $title, $msgname, $injected_html ) {
-               $out = $this->getOutput();
-               $out->setPageTitle( $title );
-               if ( $msgname ) {
-                       $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
-               }
-
-               $out->addHTML( $injected_html );
-
-               $this->executeReturnTo( $type );
-       }
-
-       /**
-        * Output a message that informs the user that they cannot create an account because
-        * there is a block on them or their IP which prevents account creation.  Note that
-        * User::isBlockedFromCreateAccount(), which gets this block, ignores the 'hardblock'
-        * setting on blocks (bug 13611).
-        * @param Block $block The block causing this error
-        * @throws ErrorPageError
-        */
-       function userBlockedMessage( Block $block ) {
-               # Let's be nice about this, it's likely that this feature will be used
-               # for blocking large numbers of innocent people, e.g. range blocks on
-               # schools. Don't blame it on the user. There's a small chance that it
-               # really is the user's fault, i.e. the username is blocked and they
-               # haven't bothered to log out before trying to create an account to
-               # evade it, but we'll leave that to their guilty conscience to figure
-               # out.
-               $errorParams = [
-                       $block->getTarget(),
-                       $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(),
-                       $block->getByName()
-               ];
-
-               if ( $block->getType() === Block::TYPE_RANGE ) {
-                       $errorMessage = 'cantcreateaccount-range-text';
-                       $errorParams[] = $this->getRequest()->getIP();
-               } else {
-                       $errorMessage = 'cantcreateaccount-text';
-               }
-
-               throw new ErrorPageError(
-                       'cantcreateaccounttitle',
-                       $errorMessage,
-                       $errorParams
-               );
-       }
-
-       /**
-        * Add a "return to" link or redirect to it.
-        * Extensions can use this to reuse the "return to" logic after
-        * inject steps (such as redirection) into the login process.
-        *
-        * @param string $type One of the following:
-        *    - error: display a return to link ignoring $wgRedirectOnLogin
-        *    - signup: display a return to link using $wgRedirectOnLogin if needed
-        *    - success: display a return to link using $wgRedirectOnLogin if needed
-        *    - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
-        * @param string $returnTo
-        * @param array|string $returnToQuery
-        * @param bool $stickHTTPs Keep redirect link on HTTPs
-        * @since 1.22
-        */
-       public function showReturnToPage(
-               $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false
-       ) {
-               $this->mReturnTo = $returnTo;
-               $this->mReturnToQuery = $returnToQuery;
-               $this->mStickHTTPS = $stickHTTPs;
-               $this->executeReturnTo( $type );
-       }
-
-       /**
-        * Add a "return to" link or redirect to it.
-        *
-        * @param string $type One of the following:
-        *    - error: display a return to link ignoring $wgRedirectOnLogin
-        *    - signup: display a return to link using $wgRedirectOnLogin if needed
-        *    - success: display a return to link using $wgRedirectOnLogin if needed
-        *    - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
-        */
-       private function executeReturnTo( $type ) {
-               global $wgRedirectOnLogin, $wgSecureLogin;
-
-               if ( $type != 'error' && $wgRedirectOnLogin !== null ) {
-                       $returnTo = $wgRedirectOnLogin;
-                       $returnToQuery = [];
-               } else {
-                       $returnTo = $this->mReturnTo;
-                       $returnToQuery = wfCgiToArray( $this->mReturnToQuery );
-               }
-
-               // Allow modification of redirect behavior
-               Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
-
-               $returnToTitle = Title::newFromText( $returnTo );
-               if ( !$returnToTitle ) {
-                       $returnToTitle = Title::newMainPage();
-               }
-
-               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                       $options = [ 'http' ];
-                       $proto = PROTO_HTTP;
-               } elseif ( $wgSecureLogin ) {
-                       $options = [ 'https' ];
-                       $proto = PROTO_HTTPS;
-               } else {
-                       $options = [];
-                       $proto = PROTO_RELATIVE;
-               }
-
-               if ( $type == 'successredirect' ) {
-                       $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
-                       $this->getOutput()->redirect( $redirectUrl );
-               } else {
-                       $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
-               }
-       }
-
-       /**
-        * @param string $msg
-        * @param string $msgtype
-        * @throws ErrorPageError
-        * @throws Exception
-        * @throws FatalError
-        * @throws MWException
-        * @throws PermissionsError
-        * @throws ReadOnlyError
-        * @private
-        */
-       function mainLoginForm( $msg, $msgtype = 'error' ) {
-               global $wgEnableEmail, $wgEnableUserEmail;
-               global $wgHiddenPrefs, $wgLoginLanguageSelector;
-               global $wgAuth, $wgEmailConfirmToEdit;
-               global $wgSecureLogin, $wgPasswordResetRoutes;
-               global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
-
-               $titleObj = $this->getPageTitle();
-               $user = $this->getUser();
-               $out = $this->getOutput();
-
-               if ( $this->mType == 'signup' ) {
-                       // Block signup here if in readonly. Keeps user from
-                       // going through the process (filling out data, etc)
-                       // and being informed later.
-                       $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true );
-                       if ( count( $permErrors ) ) {
-                               throw new PermissionsError( 'createaccount', $permErrors );
-                       } elseif ( $user->isBlockedFromCreateAccount() ) {
-                               $this->userBlockedMessage( $user->isBlockedFromCreateAccount() );
-
-                               return;
-                       } elseif ( wfReadOnly() ) {
-                               throw new ReadOnlyError;
-                       }
-               }
-
-               // Pre-fill username (if not creating an account, bug 44775).
-               if ( $this->mUsername == '' && $this->mType != 'signup' ) {
-                       if ( $user->isLoggedIn() ) {
-                               $this->mUsername = $user->getName();
-                       } else {
-                               $this->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
-                       }
-               }
-
-               // Generic styles and scripts for both login and signup form
-               $out->addModuleStyles( [
-                       'mediawiki.ui',
-                       'mediawiki.ui.button',
-                       'mediawiki.ui.checkbox',
-                       'mediawiki.ui.input',
-                       'mediawiki.special.userlogin.common.styles'
-               ] );
-
-               if ( $this->mType == 'signup' ) {
-                       // Additional styles and scripts for signup form
-                       $out->addModules( [
-                               'mediawiki.special.userlogin.signup.js'
-                       ] );
-                       $out->addModuleStyles( [
-                               'mediawiki.special.userlogin.signup.styles'
-                       ] );
-
-                       $template = new UsercreateTemplate( $this->getConfig() );
-
-                       // Must match number of benefits defined in messages
-                       $template->set( 'benefitCount', 3 );
-
-                       $q = 'action=submitlogin&type=signup';
-                       $linkq = 'type=login';
-               } else {
-                       // Additional styles for login form
-                       $out->addModuleStyles( [
-                               'mediawiki.special.userlogin.login.styles'
-                       ] );
-
-                       $template = new UserloginTemplate( $this->getConfig() );
-
-                       $q = 'action=submitlogin&type=login';
-                       $linkq = 'type=signup';
-               }
-
-               if ( $this->mReturnTo !== '' ) {
-                       $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
-                       if ( $this->mReturnToQuery !== '' ) {
-                               $returnto .= '&returntoquery=' .
-                                       wfUrlencode( $this->mReturnToQuery );
-                       }
-                       $q .= $returnto;
-                       $linkq .= $returnto;
-               }
-
-               # Don't show a "create account" link if the user can't.
-               if ( $this->showCreateOrLoginLink( $user ) ) {
-                       # Pass any language selection on to the mode switch link
-                       if ( $wgLoginLanguageSelector && $this->mLanguage ) {
-                               $linkq .= '&uselang=' . $this->mLanguage;
-                       }
-                       // Supply URL, login template creates the button.
-                       $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
-               } else {
-                       $template->set( 'link', '' );
-               }
-
-               $resetLink = $this->mType == 'signup'
-                       ? null
-                       : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
-
-               $template->set( 'header', '' );
-               $template->set( 'formheader', '' );
-               $template->set( 'skin', $this->getSkin() );
-               $template->set( 'name', $this->mUsername );
-               $template->set( 'password', $this->mPassword );
-               $template->set( 'retype', $this->mRetype );
-               $template->set( 'createemailset', $this->mCreateaccountMail );
-               $template->set( 'email', $this->mEmail );
-               $template->set( 'realname', $this->mRealName );
-               $template->set( 'domain', $this->mDomain );
-               $template->set( 'reason', $this->mReason );
-
-               $template->set( 'action', $titleObj->getLocalURL( $q ) );
-               $template->set( 'message', $msg );
-               $template->set( 'messagetype', $msgtype );
-               $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
-               $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
-               $template->set( 'useemail', $wgEnableEmail );
-               $template->set( 'emailrequired', $wgEmailConfirmToEdit );
-               $template->set( 'emailothers', $wgEnableUserEmail );
-               $template->set( 'canreset', $wgAuth->allowPasswordChange() );
-               $template->set( 'resetlink', $resetLink );
-               $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
-                       ( $wgCookieExpiration > 0 ) :
-                       ( $wgExtendedLoginCookieExpiration > 0 ) );
-               $template->set( 'usereason', $user->isLoggedIn() );
-               $template->set( 'remember', $this->mRemember );
-               $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
-               $template->set( 'stickhttps', (int)$this->mStickHTTPS );
-               $template->set( 'loggedin', $user->isLoggedIn() );
-               $template->set( 'loggedinuser', $user->getName() );
-
-               if ( $this->mType == 'signup' ) {
-                       $template->set( 'token', self::getCreateaccountToken()->toString() );
-               } else {
-                       $template->set( 'token', self::getLoginToken()->toString() );
-               }
-
-               # Prepare language selection links as needed
-               if ( $wgLoginLanguageSelector ) {
-                       $template->set( 'languages', $this->makeLanguageSelector() );
-                       if ( $this->mLanguage ) {
-                               $template->set( 'uselang', $this->mLanguage );
-                       }
-               }
-
-               $template->set( 'secureLoginUrl', $this->mSecureLoginUrl );
-               // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
-               $usingHTTPS = $this->mRequest->getProtocol() == 'https';
-               $signupendHTTPS = $this->msg( 'signupend-https' );
-               if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
-                       $template->set( 'signupend', $signupendHTTPS->parse() );
-               } else {
-                       $template->set( 'signupend', $this->msg( 'signupend' )->parse() );
-               }
-
-               // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
-               if ( $usingHTTPS ) {
-                       $template->set( 'fromhttp', $this->mFromHTTP );
-               }
-
-               // Give authentication and captcha plugins a chance to modify the form
-               $wgAuth->modifyUITemplate( $template, $this->mType );
-               if ( $this->mType == 'signup' ) {
-                       Hooks::run( 'UserCreateForm', [ &$template ] );
-               } else {
-                       Hooks::run( 'UserLoginForm', [ &$template ] );
-               }
-
-               $out->disallowUserJs(); // just in case...
-               $out->addTemplate( $template );
-       }
-
-       /**
-        * Whether the login/create account form should display a link to the
-        * other form (in addition to whatever the skin provides).
-        *
-        * @param User $user
-        * @return bool
-        */
-       private function showCreateOrLoginLink( &$user ) {
-               if ( $this->mType == 'signup' ) {
-                       return true;
-               } elseif ( $user->isAllowed( 'createaccount' ) ) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Check if a session cookie is present.
-        *
-        * This will not pick up a cookie set during _this_ request, but is meant
-        * to ensure that the client is returning the cookie which was set on a
-        * previous pass through the system.
-        *
-        * @private
-        * @return bool
-        */
-       function hasSessionCookie() {
-               global $wgDisableCookieCheck, $wgInitialSessionId;
-
-               return $wgDisableCookieCheck || (
-                       $wgInitialSessionId &&
-                       $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
-               );
-       }
-
-       /**
-        * Get the login token from the current session
-        * @since 1.27 returns a MediaWiki\Session\Token instead of a string
-        * @return MediaWiki\Session\Token
-        */
-       public static function getLoginToken() {
-               global $wgRequest;
-               return $wgRequest->getSession()->getToken( '', 'login' );
-       }
-
-       /**
-        * Formerly randomly generated a login token that would be returned by
-        * $this->getLoginToken().
-        *
-        * Since 1.27, this is a no-op. The token is generated as necessary by
-        * $this->getLoginToken().
-        *
-        * @deprecated since 1.27
-        */
-       public static function setLoginToken() {
-               wfDeprecated( __METHOD__, '1.27' );
-       }
-
-       /**
-        * Remove any login token attached to the current session
-        */
-       public static function clearLoginToken() {
-               global $wgRequest;
-               $wgRequest->getSession()->resetToken( 'login' );
-       }
-
-       /**
-        * Get the createaccount token from the current session
-        * @since 1.27 returns a MediaWiki\Session\Token instead of a string
-        * @return MediaWiki\Session\Token
-        */
-       public static function getCreateaccountToken() {
-               global $wgRequest;
-               return $wgRequest->getSession()->getToken( '', 'createaccount' );
-       }
-
-       /**
-        * Formerly randomly generated a createaccount token that would be returned
-        * by $this->getCreateaccountToken().
-        *
-        * Since 1.27, this is a no-op. The token is generated as necessary by
-        * $this->getCreateaccountToken().
-        *
-        * @deprecated since 1.27
-        */
-       public static function setCreateaccountToken() {
-               wfDeprecated( __METHOD__, '1.27' );
-       }
-
-       /**
-        * Remove any createaccount token attached to the current session
-        */
-       public static function clearCreateaccountToken() {
-               global $wgRequest;
-               $wgRequest->getSession()->resetToken( 'createaccount' );
-       }
-
-       /**
-        * Renew the user's session id, using strong entropy
-        */
-       private function renewSessionId() {
-               global $wgSecureLogin, $wgCookieSecure;
-               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                       $wgCookieSecure = false;
-               }
-
-               SessionManager::getGlobalSession()->resetId();
-               SessionManager::getGlobalSession()->resetAllTokens();
-       }
-
-       /**
-        * @param string $type
-        * @private
-        */
-       function cookieRedirectCheck( $type ) {
-               $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
-               $query = [ 'wpCookieCheck' => $type ];
-               if ( $this->mReturnTo !== '' ) {
-                       $query['returnto'] = $this->mReturnTo;
-                       $query['returntoquery'] = $this->mReturnToQuery;
-               }
-               $check = $titleObj->getFullURL( $query );
-
-               $this->getOutput()->redirect( $check );
-       }
-
-       /**
-        * @param string $type
-        * @private
-        */
-       function onCookieRedirectCheck( $type ) {
-               if ( !$this->hasSessionCookie() ) {
-                       if ( $type == 'new' ) {
-                               $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() );
-                       } elseif ( $type == 'login' ) {
-                               $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() );
-                       } else {
-                               # shouldn't happen
-                               $this->mainLoginForm( $this->msg( 'error' )->text() );
-                       }
-               } else {
-                       $this->successfulLogin();
-               }
-       }
-
-       /**
-        * Produce a bar of links which allow the user to select another language
-        * during login/registration but retain "returnto"
-        *
-        * @return string
-        */
-       function makeLanguageSelector() {
-               $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
-               if ( $msg->isBlank() ) {
-                       return '';
-               }
-               $langs = explode( "\n", $msg->text() );
-               $links = [];
-               foreach ( $langs as $lang ) {
-                       $lang = trim( $lang, '* ' );
-                       $parts = explode( '|', $lang );
-                       if ( count( $parts ) >= 2 ) {
-                               $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
-                       }
-               }
-
-               return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
-                       $this->getLanguage()->pipeList( $links ) )->escaped() : '';
-       }
-
-       /**
-        * Create a language selector link for a particular language
-        * Links back to this page preserving type and returnto
-        *
-        * @param string $text Link text
-        * @param string $lang Language code
-        * @return string
-        */
-       function makeLanguageSelectorLink( $text, $lang ) {
-               if ( $this->getLanguage()->getCode() == $lang ) {
-                       // no link for currently used language
-                       return htmlspecialchars( $text );
-               }
-               $query = [ 'uselang' => $lang ];
-               if ( $this->mType == 'signup' ) {
-                       $query['type'] = 'signup';
-               }
-               if ( $this->mReturnTo !== '' ) {
-                       $query['returnto'] = $this->mReturnTo;
-                       $query['returntoquery'] = $this->mReturnToQuery;
-               }
-
-               $attr = [];
-               $targetLanguage = Language::factory( $lang );
-               $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
-
-               return Linker::linkKnown(
-                       $this->getPageTitle(),
-                       htmlspecialchars( $text ),
-                       $attr,
-                       $query
-               );
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-
-       /**
-        * Private function to check password expiration, until AuthManager comes
-        * along to handle that.
-        * @param User $user
-        * @return string|bool
-        */
-       private function checkUserPasswordExpired( User $user ) {
-               global $wgPasswordExpireGrace;
-               $dbr = wfGetDB( DB_SLAVE );
-               $ts = $dbr->selectField( 'user', 'user_password_expires', [ 'user_id' => $user->getId() ] );
-
-               $expired = false;
-               $now = wfTimestamp();
-               $expUnix = wfTimestamp( TS_UNIX, $ts );
-               if ( $ts !== null && $expUnix < $now ) {
-                       $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
-               }
-               return $expired;
-       }
-
-       protected function getSubpagesForPrefixSearch() {
-               return [ 'signup' ];
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialUserlogout.php b/includes/specials/pre-authmanager/SpecialUserlogout.php
deleted file mode 100644 (file)
index 6d6a714..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * Implements Special:Userlogout
- *
- * 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
- * @ingroup SpecialPage
- */
-
-/**
- * Implements Special:Userlogout
- *
- * @ingroup SpecialPage
- */
-class SpecialUserlogoutPreAuthManager extends UnlistedSpecialPage {
-       function __construct() {
-               parent::__construct( 'Userlogout' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       function execute( $par ) {
-               /**
-                * Some satellite ISPs use broken precaching schemes that log people out straight after
-                * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
-                */
-               if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&amp;' ) !== false ) {
-                       wfDebug( "Special:Userlogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" );
-                       throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) );
-               }
-
-               $this->setHeaders();
-               $this->outputHeader();
-
-               // Make sure it's possible to log out
-               $session = MediaWiki\Session\SessionManager::getGlobalSession();
-               if ( !$session->canSetUser() ) {
-                       throw new ErrorPageError(
-                               'cannotlogoutnow-title',
-                               'cannotlogoutnow-text',
-                               [
-                                       $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
-                               ]
-                       );
-               }
-
-               $user = $this->getUser();
-               $oldName = $user->getName();
-               $user->logout();
-
-               $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL(
-                       $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $out = $this->getOutput();
-               $out->addWikiMsg( 'logouttext', $loginURL );
-
-               // Hook.
-               $injected_html = '';
-               Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
-               $out->addHTML( $injected_html );
-
-               $out->returnToMain();
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-}
diff --git a/includes/templates/Usercreate.php b/includes/templates/Usercreate.php
deleted file mode 100644 (file)
index 0a5aa61..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-<?php
-// @codingStandardsIgnoreFile
-/**
- * Html form for account creation (since 1.22 with VForm appearance).
- *
- * 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
- * @ingroup Templates
- * @deprecated Will be removed when AuthManager lands.
- *   The signup form will be generated via HTMLForm.
- */
-
-class UsercreateTemplate extends BaseTemplate {
-       /**
-        * Extensions (AntiSpoof and TitleBlacklist) call this in response to
-        * UserCreateForm hook to add checkboxes to the create account form.
-        */
-       function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
-               $this->data['extraInput'][] = [
-                       'name' => $name,
-                       'value' => $value,
-                       'type' => $type,
-                       'msg' => $msg,
-                       'helptext' => $helptext,
-               ];
-       }
-
-       function execute() {
-?>
-<div class="mw-ui-container">
-       <?php if ( $this->haveData( 'languages' ) ) { ?>
-               <div id="languagelinks">
-                       <p><?php $this->html( 'languages' ); ?></p>
-               </div>
-       <?php }
-             if ( !wfMessage( 'signupstart' )->isDisabled() ) { ?>
-               <div id="signupstart"><?php $this->msgWiki( 'signupstart' ); ?></div>
-       <?php } ?>
-       <div id="userloginForm">
-               <form name="userlogin2" id="userlogin2" class="mw-ui-vform" method="post" action="<?php $this->text( 'action' ); ?>">
-                       <section class="mw-form-header">
-                               <?php $this->html( 'header' ); ?>
-                       </section>
-                       <!-- This element is used by the mediawiki.special.userlogin.signup.js module. -->
-                       <div
-                               id="mw-createacct-status-area"
-                               <?php if ( $this->data['message'] ) { ?>
-                                       class="<?php echo $this->data['messagetype']; ?>box"
-                               <?php } else { ?>
-                                       style="display: none;"
-                               <?php } ?>
-                       >
-                       <?php if ( $this->data['message'] ) { ?>
-                                       <?php if ( $this->data['messagetype'] == 'error' ) { ?>
-                                               <strong><?php $this->msg( 'createacct-error' ); ?></strong>
-                                               <br />
-                                       <?php } ?>
-                                       <?php $this->html( 'message' ); ?>
-                       <?php } ?>
-                       </div>
-
-                       <?php if ( $this->data['formheader'] ) { ?>
-                               <div class="mw-form-formheader">
-                                       <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add html here */ ?>
-                               </div>
-                       <?php } ?>
-
-                       <div class="mw-ui-vform-field">
-                               <label for='wpName2'>
-                                       <?php $this->msg( 'userlogin-yourname' ); ?>
-
-                                       <span class="mw-ui-flush-right"><?php echo $this->getMsg( 'createacct-helpusername' )->parse(); ?></span>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpName', $this->data['name'], 'text', [
-                                       'class' => 'mw-ui-input loginText',
-                                       'id' => 'wpName2',
-                                       'tabindex' => '1',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( $this->data['loggedin'] ?
-                                               'createacct-another-username-ph' : 'userlogin-yourname-ph' )->text(),
-                               ] );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['createemail'] ) { ?>
-                                       <div class="mw-ui-checkbox">
-                                               <input name="wpCreateaccountMail" type="checkbox" value="1" id="wpCreateaccountMail" tabindex="2"
-                                                       <?php if ( $this->data['createemailset'] ) {
-                                                               echo 'checked="checked"';
-                                                       } ?>
-                                               ><label for="wpCreateaccountMail">
-                                                       <?php $this->msg( 'createaccountmail' ); ?>
-                                               </label>
-                                       </div>
-                               <?php } ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field mw-row-password">
-                               <label for='wpPassword2'><?php $this->msg( 'userlogin-yourpassword' ); ?></label>
-                               <?php
-                               echo Html::input( 'wpPassword', null, 'password', [
-                                       'class' => 'mw-ui-input loginPassword',
-                                       'id' => 'wpPassword2',
-                                       'tabindex' => '3',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( 'createacct-yourpassword-ph' )->text()
-                               ] + User::passwordChangeInputAttribs() );
-                               ?>
-                       </div>
-
-                       <?php
-                       if ( $this->data['usedomain'] ) {
-                               $select = new XmlSelect( 'wpDomain', false, $this->data['domain'] );
-                               $select->setAttribute( 'tabindex', 4 );
-                               foreach ( $this->data['domainnames'] as $dom ) {
-                                       $select->addOption( $dom );
-                               }
-                       ?>
-                               <div class="mw-ui-vform-field" id="mw-user-domain-section">
-                                       <label for="wpDomain"><?php $this->msg( 'yourdomainname' ); ?></label>
-                                       <div>
-                                               <?php echo $select->getHTML(); ?>
-                                       </div>
-                               </div>
-                       <?php } ?>
-
-                       <div class="mw-ui-vform-field mw-row-password">
-                               <label for='wpRetype'><?php $this->msg( 'createacct-yourpasswordagain' ); ?></label>
-                               <?php
-                               echo Html::input( 'wpRetype', null, 'password', [
-                                       'class' => 'mw-ui-input loginPassword',
-                                       'id' => 'wpRetype',
-                                       'tabindex' => '5',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( 'createacct-yourpasswordagain-ph' )->text()
-                               ] + User::passwordChangeInputAttribs() );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['useemail'] ) { ?>
-                                       <label for='wpEmail'>
-                                               <?php
-                                                       $this->msg( $this->data['emailrequired'] ?
-                                                               'createacct-emailrequired' :
-                                                               'createacct-emailoptional'
-                                                       );
-                                               ?>
-                                       </label>
-                                       <?php
-                                               echo Html::input( 'wpEmail', $this->data['email'], 'email', [
-                                                       'class' => 'mw-ui-input loginText',
-                                                       'id' => 'wpEmail',
-                                                       'tabindex' => '6',
-                                                       'size' => '20',
-                                                       'required' => $this->data['emailrequired'],
-                                                       'placeholder' => $this->getMsg( $this->data['loggedin'] ?
-                                                               'createacct-another-email-ph' : 'createacct-email-ph' )->text()
-                                               ] );
-                                       ?>
-                               <?php } ?>
-                       </div>
-
-                       <?php if ( $this->data['userealname'] ) { ?>
-                               <div class="mw-ui-vform-field">
-                                       <label for='wpRealName'><?php $this->msg( 'createacct-realname' ); ?></label>
-                                       <input type='text' class='mw-ui-input loginText' name="wpRealName" id="wpRealName"
-                                               tabindex="7"
-                                               value="<?php $this->text( 'realname' ); ?>" size='20' />
-                                       <div class="prefsectiontip">
-                                               <?php $this->msgWiki( $this->data['loggedin'] ? 'createacct-another-realname-tip' : 'prefs-help-realname' ); ?>
-                                       </div>
-                               </div>
-                       <?php } ?>
-
-                       <?php if ( $this->data['usereason'] ) { ?>
-                               <div class="mw-ui-vform-field">
-                                       <label for='wpReason'><?php $this->msg( 'createacct-reason' ); ?></label>
-                                       <?php echo Html::input( 'wpReason', $this->data['reason'], 'text', [
-                                               'class' => 'mw-ui-input loginText',
-                                               'id' => 'wpReason',
-                                               'tabindex' => '8',
-                                               'size' => '20',
-                                               'placeholder' => $this->getMsg( 'createacct-reason-ph' )->text()
-                                       ] ); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php
-                       $tabIndex = 9;
-                       if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
-                               foreach ( $this->data['extraInput'] as $inputItem ) { ?>
-                                       <div class="mw-ui-vform-field">
-                                               <?php
-                                               // If it's a checkbox, output the whole thing (assume it has a msg).
-                                               if ( $inputItem['type'] == 'checkbox' ) {
-                                               ?>
-                                                       <div class="mw-ui-checkbox">
-                                                               <input
-                                                                       name="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                                       id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                                       type="checkbox" value="1"
-                                                                       tabindex="<?php echo $tabIndex++; ?>"
-                                                                       <?php if ( !empty( $inputItem['value'] ) ) {
-                                                                               echo 'checked="checked"';
-                                                                       } ?>
-                                                               ><label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>">
-                                                                       <?php $this->msg( $inputItem['msg'] ); ?>
-                                                               </label>
-                                                       </div>
-                                               <?php
-                                               } else {
-                                                       // Not a checkbox.
-                                                       // TODO (bug 31909) support other input types, e.g. select boxes.
-                                               ?>
-                                                       <?php if ( !empty( $inputItem['msg'] ) ) { ?>
-                                                               <label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>">
-                                                                       <?php $this->msgWiki( $inputItem['msg'] ); ?>
-                                                               </label>
-                                                       <?php } ?>
-                                                       <input
-                                                               type="<?php echo htmlspecialchars( $inputItem['type'] ); ?>"
-                                                               class="mw-ui-input"
-                                                               name="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                               tabindex="<?php echo $tabIndex++; ?>"
-                                                               value="<?php echo htmlspecialchars( $inputItem['value'] ); ?>"
-                                                               id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                       />
-                                               <?php } ?>
-                                               <?php if ( $inputItem['helptext'] !== false ) { ?>
-                                                       <div class="prefsectiontip">
-                                                               <?php $this->msgWiki( $inputItem['helptext'] ); ?>
-                                                       </div>
-                                               <?php } ?>
-                                       </div>
-                               <?php
-                               }
-                       }
-
-                       // A separate placeholder for any inserting any extrafields, e.g used by ConfirmEdit extension
-                       if ( $this->haveData( 'extrafields' ) ) {
-                               echo $this->data['extrafields'];
-                       }
-                       // skip one index.
-                       $tabIndex++;
-                       ?>
-                       <div class="mw-ui-vform-field mw-submit">
-                               <?php
-                               echo Html::submitButton(
-                                       $this->getMsg( $this->data['loggedin'] ? 'createacct-another-submit' : 'createacct-submit' ),
-                                       [
-                                               'id' => 'wpCreateaccount',
-                                               'name' => 'wpCreateaccount',
-                                               'tabindex' => $tabIndex++
-                                       ],
-                                       [
-                                               'mw-ui-block',
-                                               'mw-ui-constructive',
-                                       ]
-                               );
-                               ?>
-                       </div>
-                       <?php if ( $this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
-                       <?php if ( $this->haveData( 'token' ) ) { ?><input type="hidden" name="wpCreateaccountToken" value="<?php $this->text( 'token' ); ?>" /><?php } ?>
-               </form>
-               <?php if ( !wfMessage( 'signupend' )->isDisabled() ) { ?>
-                       <div id="signupend"><?php $this->html( 'signupend' ); ?></div>
-               <?php } ?>
-       </div>
-       <div class="mw-createacct-benefits-container">
-               <h2><?php $this->msg( 'createacct-benefit-heading' ); ?></h2>
-               <div class="mw-createacct-benefits-list">
-                       <?php
-                       for ( $benefitIdx = 1; $benefitIdx <= $this->data['benefitCount']; $benefitIdx++ ) {
-                               // Pass each benefit's head text (by default a number) as a parameter to the body's message for PLURAL handling.
-                               $headUnescaped = $this->getMsg( "createacct-benefit-head$benefitIdx" )->text();
-                       ?>
-                               <div class="mw-number-text <?php $this->msg( "createacct-benefit-icon$benefitIdx" ); ?>">
-                                       <h3><?php $this->msg( "createacct-benefit-head$benefitIdx" ); ?></h3>
-                                       <p><?php echo $this->getMsg( "createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped(); ?></p>
-                               </div>
-                       <?php } ?>
-               </div>
-       </div>
-</div>
-<?php
-
-       }
-}
diff --git a/includes/templates/Userlogin.php b/includes/templates/Userlogin.php
deleted file mode 100644 (file)
index e816b62..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-// @codingStandardsIgnoreFile
-/**
- * HTML form for user login (since 1.22 with VForm appearance).
- *
- * 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
- * @ingroup Templates
- * @deprecated Will be removed when AuthManager lands.
- *   The login form will be generated via HTMLForm.
- */
-
-class UserloginTemplate extends BaseTemplate {
-
-       function execute() {
-               global $wgCookieExpiration;
-               $expirationDays = ceil( $wgCookieExpiration / ( 3600 * 24 ) );
-?>
-<div class="mw-ui-container">
-       <div id="userloginprompt"><?php $this->msgWiki('loginprompt') ?></div>
-       <?php if ( $this->haveData( 'languages' ) ) { ?>
-               <div id="languagelinks">
-                       <p><?php $this->html( 'languages' ); ?></p>
-               </div>
-       <?php } ?>
-       <div id="userloginForm">
-               <form name="userlogin" class="mw-ui-vform" method="post" action="<?php $this->text( 'action' ); ?>">
-                       <?php if ( $this->data['loggedin'] ) { ?>
-                               <div class="warningbox">
-                                       <?php echo $this->getMsg( 'userlogin-loggedin' )->params( $this->data['loggedinuser'] )->parse(); ?>
-                               </div>
-                       <?php } ?>
-                       <section class="mw-form-header">
-                               <?php $this->html( 'header' ); /* extensions such as ConfirmEdit add form HTML here */ ?>
-                       </section>
-
-                       <?php if ( $this->data['message'] ) { ?>
-                               <div class="<?php $this->text( 'messagetype' ); ?>box">
-                                       <?php if ( $this->data['messagetype'] == 'error' ) { ?>
-                                               <strong><?php $this->msg( 'loginerror' ); ?></strong>
-                                               <br />
-                                       <?php } ?>
-                                       <?php $this->html( 'message' ); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php if ( $this->data['formheader'] ) { ?>
-                               <div class="mw-form-formheader">
-                                       <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add HTML here */ ?>
-                               </div>
-                       <?php } ?>
-                       <div class="mw-ui-vform-field">
-                               <label for="wpName1">
-                                       <?php
-                                       $this->msg( 'userlogin-yourname' );
-
-                                       if ( $this->data['secureLoginUrl'] ) {
-                                               echo Html::element( 'a', [
-                                                       'href' => $this->data['secureLoginUrl'],
-                                                       'class' => 'mw-ui-flush-right mw-secure',
-                                               ], $this->getMsg( 'userlogin-signwithsecure' )->text() );
-                                       }
-                                       ?>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpName', $this->data['name'], 'text', [
-                                       'class' => 'loginText mw-ui-input',
-                                       'id' => 'wpName1',
-                                       'tabindex' => '1',
-                                       // 'required' is blacklisted for now in Html.php due to browser issues.
-                                       // Keeping here in case that changes.
-                                       'required' => true,
-                                       // Set focus to this field if it's blank.
-                                       'autofocus' => !$this->data['name'],
-                                       'placeholder' => $this->getMsg( 'userlogin-yourname-ph' )->text()
-                               ] );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <label for="wpPassword1">
-                                       <?php
-                                       $this->msg( 'userlogin-yourpassword' );
-                                       ?>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpPassword', null, 'password', [
-                                       'class' => 'loginPassword mw-ui-input',
-                                       'id' => 'wpPassword1',
-                                       'tabindex' => '2',
-                                       // Set focus to this field if username is filled in.
-                                       'autofocus' => (bool)$this->data['name'],
-                                       'placeholder' => $this->getMsg( 'userlogin-yourpassword-ph' )->text()
-                               ] );
-                               ?>
-                       </div>
-
-                       <?php
-                       if ( isset( $this->data['usedomain'] ) && $this->data['usedomain'] ) {
-                               $select = new XmlSelect( 'wpDomain', false, $this->data['domain'] );
-                               $select->setAttribute( 'tabindex', 3 );
-                               foreach ( $this->data['domainnames'] as $dom ) {
-                                       $select->addOption( $dom );
-                               }
-                       ?>
-                               <div class="mw-ui-vform-field" id="mw-user-domain-section">
-                                       <label for="wpDomain"><?php $this->msg( 'yourdomainname' ); ?></label>
-                                       <?php echo $select->getHTML(); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php
-                       if ( $this->haveData( 'extrafields' ) ) {
-                               echo $this->data['extrafields'];
-                       }
-                       ?>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['canremember'] ) { ?>
-                                       <div class="mw-ui-checkbox">
-                                               <input name="wpRemember" type="checkbox" value="1" id="wpRemember" tabindex="4"
-                                                       <?php if ( $this->data['remember'] ) {
-                                                               echo 'checked="checked"';
-                                                       } ?>
-                                               ><label for="wpRemember">
-                                                       <?php echo $this->getMsg( 'userlogin-remembermypassword' )->numParams( $expirationDays )->escaped(); ?></label>
-                                       </div>
-                               <?php } ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php
-                               $attrs = [
-                                       'id' => 'wpLoginAttempt',
-                                       'name' => 'wpLoginAttempt',
-                                       'tabindex' => '6',
-                               ];
-                               $modifiers = [
-                                       'mw-ui-progressive',
-                               ];
-                               echo Html::submitButton( $this->getMsg( 'pt-login-button' )->text(), $attrs, $modifiers );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field mw-form-related-link-container" id="mw-userlogin-help">
-                               <?php
-                               echo Html::element(
-                                       'a',
-                                       [
-                                               'href' => Skin::makeInternalOrExternalUrl(
-                                                       wfMessage( 'helplogin-url' )->inContentLanguage()->text()
-                                               ),
-                                       ],
-                                       $this->getMsg( 'userlogin-helplink2' )->text()
-                               );
-                               ?>
-                       </div>
-                       <?php
-
-                       if ( $this->data['useemail'] && $this->data['canreset'] && $this->data['resetlink'] === true ) {
-                               echo Html::rawElement(
-                                       'div',
-                                       [
-                                               'class' => 'mw-ui-vform-field mw-form-related-link-container',
-                                       ],
-                                       Linker::link(
-                                               SpecialPage::getTitleFor( 'PasswordReset' ),
-                                               $this->getMsg( 'userlogin-resetpassword-link' )->escaped()
-                                       )
-                               );
-                       }
-
-                       if ( $this->haveData( 'createOrLoginHref' ) ) {
-                               if ( $this->data['loggedin'] ) { ?>
-                                       <div class="mw-form-related-link-container mw-ui-vform-field">
-                                               <a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7"><?php $this->msg( 'userlogin-createanother' ); ?></a>
-                                       </div>
-                               <?php } else { ?>
-                                       <div id="mw-createaccount-cta" class="mw-ui-vform-field">
-                                               <?php $this->msg( 'userlogin-noaccount' ); ?><a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7" class="mw-ui-button"><?php $this->msg( 'userlogin-joinproject' ); ?></a>
-                                       </div>
-                               <?php
-                               }
-                       }
-
-                       // Hidden fields
-                       $fields = '';
-                       if ( $this->haveData( 'uselang' ) ) {
-                               $fields .= Html::hidden( 'uselang', $this->data['uselang'] );
-                       }
-                       if ( $this->haveData( 'token' ) ) {
-                               $fields .= Html::hidden( 'wpLoginToken', $this->data['token'] );
-                       }
-                       if ( $this->data['cansecurelogin'] ) {
-                               $fields .= Html::hidden( 'wpForceHttps', $this->data['stickhttps'] );
-                       }
-                       if ( $this->data['cansecurelogin'] && $this->haveData( 'fromhttp' ) ) {
-                               $fields .= Html::hidden( 'wpFromhttp', $this->data['fromhttp'] );
-                       }
-                       echo $fields;
-
-                       ?>
-               </form>
-       </div>
-</div>
-<?php
-
-       }
-}
index b2d6ba1..666f3f9 100644 (file)
@@ -32,31 +32,31 @@ use \IteratorAggregate;
 use \ReverseArrayIterator;
 use \Sanitizer;
 
-# A note for future librarization[1] -- this file is a good candidate
-# for splitting into an independent library, except that it is currently
-# highly optimized for MediaWiki use.  It only implements the portions
-# of the HTML5 tree builder used by tags supported by MediaWiki, and
-# does not contain a true tokenizer pass, instead relying on
-# comment stripping, attribute normalization, and escaping done by
-# the MediaWiki Sanitizer.  It also deliberately avoids building
-# a true DOM in memory, instead serializing elements to an output string
-# as soon as possible (usually as soon as the tag is closed) to reduce
-# its memory footprint.
-
-# We've been gradually lifting some of these restrictions to handle
-# non-sanitized output generated by extensions, but we shortcut the tokenizer
-# for speed (primarily by splitting on `<`) and so rely on syntactic
-# well-formedness.
-
-# On the other hand, I've been pretty careful to note with comments in the
-# code the places where this implementation omits features of the spec or
-# depends on the MediaWiki Sanitizer.  Perhaps in the future we'll want to
-# implement the missing pieces and make this a standalone PHP HTML5 parser.
-# In order to do so, some sort of MediaWiki-specific API will need
-# to be added to (a) allow the Balancer to bypass the tokenizer,
-# and (b) support on-the-fly flattening instead of DOM node creation.
-
-# [1]: https://www.mediawiki.org/wiki/Library_infrastructure_for_MediaWiki
+// A note for future librarization[1] -- this file is a good candidate
+// for splitting into an independent library, except that it is currently
+// highly optimized for MediaWiki use.  It only implements the portions
+// of the HTML5 tree builder used by tags supported by MediaWiki, and
+// does not contain a true tokenizer pass, instead relying on
+// comment stripping, attribute normalization, and escaping done by
+// the MediaWiki Sanitizer.  It also deliberately avoids building
+// a true DOM in memory, instead serializing elements to an output string
+// as soon as possible (usually as soon as the tag is closed) to reduce
+// its memory footprint.
+
+// We've been gradually lifting some of these restrictions to handle
+// non-sanitized output generated by extensions, but we shortcut the tokenizer
+// for speed (primarily by splitting on `<`) and so rely on syntactic
+// well-formedness.
+
+// On the other hand, I've been pretty careful to note with comments in the
+// code the places where this implementation omits features of the spec or
+// depends on the MediaWiki Sanitizer.  Perhaps in the future we'll want to
+// implement the missing pieces and make this a standalone PHP HTML5 parser.
+// In order to do so, some sort of MediaWiki-specific API will need
+// to be added to (a) allow the Balancer to bypass the tokenizer,
+// and (b) support on-the-fly flattening instead of DOM node creation.
+
+// [1]: https://www.mediawiki.org/wiki/Library_infrastructure_for_MediaWiki
 
 /**
  * Utility constants and sets for the HTML5 tree building algorithm.
@@ -464,20 +464,23 @@ class BalanceElement {
         * by the HTML serialization specification, and replace this node
         * in its parent by that string.
         *
+        * @param array $config Balancer configuration; see Balancer::__construct().
+        *
         * @see __toString()
         */
-       public function flatten( $tidyCompat = false ) {
+       public function flatten( array $config ) {
                Assert::parameter( $this->parent !== null, '$this', 'must be a child' );
                Assert::parameter( $this->parent !== 'flat', '$this', 'already flat' );
                $idx = array_search( $this, $this->parent->children, true );
                Assert::parameter(
                        $idx !== false, '$this', 'must be a child of its parent'
                );
+               $tidyCompat = $config['tidyCompat'];
                if ( $tidyCompat ) {
                        $blank = true;
                        foreach ( $this->children as $elt ) {
                                if ( !is_string( $elt ) ) {
-                                       $elt = $elt->flatten( $tidyCompat );
+                                       $elt = $elt->flatten( $config );
                                }
                                if ( $blank && preg_match( '/[^\t\n\f\r ]/', $elt ) ) {
                                        $blank = false;
@@ -500,7 +503,7 @@ class BalanceElement {
                        $flat = "{$this}";
                }
                $this->parent->children[$idx] = $flat;
-               $this->parent = 'flat'; # for assertion checking
+               $this->parent = 'flat'; // for assertion checking
                return $flat;
        }
 
@@ -544,7 +547,7 @@ class BalanceElement {
                return $out;
        }
 
-       # Utility functions on BalanceElements.
+       // Utility functions on BalanceElements.
 
        /**
         * Determine if $this represents a specific HTML tag, is a member of
@@ -561,7 +564,7 @@ class BalanceElement {
                        return isset( $set[$this->namespaceURI] ) &&
                                isset( $set[$this->namespaceURI][$this->localName] );
                } else {
-                       # assume this is an HTML element name.
+                       // assume this is an HTML element name.
                        return $this->isHtml() && $this->localName === $set;
                }
        }
@@ -661,9 +664,11 @@ class BalanceStack implements IteratorAggregate {
         */
        public $fosterParentMode = false;
        /**
-        * Tidy compatibility mode, determines behavior of body/blockquote
+        * Configuration options governing flattening.
+        * @var array $config
+        * @see Balancer::__construct()
         */
-       public $tidyCompat = false;
+       private $config;
        /**
         * Reference to the current element
         */
@@ -672,14 +677,16 @@ class BalanceStack implements IteratorAggregate {
        /**
         * Create a new BalanceStack with a single BalanceElement on it,
         * representing the root &lt;html&gt; node.
+        * @param array $config Balancer configuration; see Balancer::_construct().
         */
-       public function __construct() {
-               # always a root <html> element on the stack
+       public function __construct( array $config ) {
+               // always a root <html> element on the stack
                array_push(
                        $this->elements,
                        new BalanceElement( BalanceSets::HTML_NAMESPACE, 'html', [] )
                );
                $this->currentNode = $this->elements[0];
+               $this->config = $config;
        }
 
        /**
@@ -692,7 +699,7 @@ class BalanceStack implements IteratorAggregate {
                $out = '';
                foreach ( $this->elements[0]->children as $elt ) {
                        $out .= is_string( $elt ) ? $elt :
-                               $elt->flatten( $this->tidyCompat );
+                               $elt->flatten( $this->config );
                }
                return $out;
        }
@@ -719,7 +726,7 @@ class BalanceStack implements IteratorAggregate {
                ) {
                        $this->fosterParent( $value );
                } elseif (
-                       $this->tidyCompat && !$isComment &&
+                       $this->config['tidyCompat'] && !$isComment &&
                        $this->currentNode->isA( BalanceSets::$tidyPWrapSet )
                ) {
                        $this->insertHTMLELement( 'mw:p-wrap', [] );
@@ -970,7 +977,7 @@ class BalanceStack implements IteratorAggregate {
                        $this->currentNode = null;
                }
                if ( !$elt->isHtmlNamed( 'mw:p-wrap' ) ) {
-                       $elt->flatten( $this->tidyCompat );
+                       $elt->flatten( $this->config );
                }
        }
 
@@ -980,7 +987,6 @@ class BalanceStack implements IteratorAggregate {
         * @param int $idx
         */
        public function popTo( $idx ) {
-               $length = count( $this->elements );
                for ( $length = count( $this->elements ); $length > $idx; $length-- ) {
                        $this->pop();
                }
@@ -1045,7 +1051,7 @@ class BalanceStack implements IteratorAggregate {
                        // otherwise, it will eventually serialize when the parent
                        // is serialized, we just hold onto the memory for its
                        // tree of objects a little longer.
-                       $elt->flatten( $this->tidyCompat );
+                       $elt->flatten( $this->config );
                }
                Assert::postcondition(
                        array_search( $elt, $this->elements, true ) === false,
@@ -1069,7 +1075,7 @@ class BalanceStack implements IteratorAggregate {
                }
        }
 
-       # Fostering and adoption.
+       // Fostering and adoption.
 
        /**
         * Foster parent the given $elt in the stack of open elements.
@@ -1086,7 +1092,7 @@ class BalanceStack implements IteratorAggregate {
                        $parent = $this->elements[$lastTemplate];
                } elseif ( $lastTable >= 0 ) {
                        $parent = $this->elements[$lastTable]->parent;
-                       # Assume all tables have parents, since we're not running scripts!
+                       // Assume all tables have parents, since we're not running scripts!
                        Assert::invariant(
                                $parent !== null, "All tables should have parents"
                        );
@@ -1095,7 +1101,7 @@ class BalanceStack implements IteratorAggregate {
                        $parent = $this->elements[0]; // the `html` element.
                }
 
-               if ( $this->tidyCompat ) {
+               if ( $this->config['tidyCompat'] ) {
                        if ( is_string( $elt ) ) {
                                // We're fostering text: do we need a p-wrapper?
                                if ( $parent->isA( BalanceSets::$tidyPWrapSet ) ) {
@@ -1151,34 +1157,28 @@ class BalanceStack implements IteratorAggregate {
                        return true; // no more handling required
                }
 
-               // Let outer loop counter be zero.
-               $outer = 0;
-
                // Outer loop: If outer loop counter is greater than or
                // equal to eight, then abort these steps.
-               while ( $outer < 8 ) {
-                       // Increment outer loop counter by one.
-                       $outer++;
-
+               for ( $outer = 0; $outer < 8; $outer++ ) {
                        // Let the formatting element be the last element in the list
                        // of active formatting elements that: is between the end of
                        // the list and the last scope marker in the list, if any, or
                        // the start of the list otherwise, and has the same tag name
                        // as the token.
-                       $fmtelt = $afe->findElementByTag( $tag );
+                       $fmtElt = $afe->findElementByTag( $tag );
 
                        // If there is no such node, then abort these steps and instead
                        // act as described in the "any other end tag" entry below.
-                       if ( !$fmtelt ) {
+                       if ( !$fmtElt ) {
                                return false; // false means handle by the default case
                        }
 
                        // Otherwise, if there is such a node, but that node is not in
                        // the stack of open elements, then this is a parse error;
                        // remove the element from the list, and abort these steps.
-                       $index = $this->indexOf( $fmtelt );
+                       $index = $this->indexOf( $fmtElt );
                        if ( $index < 0 ) {
-                               $afe->remove( $fmtelt );
+                               $afe->remove( $fmtElt );
                                return true;   // true means no more handling required
                        }
 
@@ -1186,7 +1186,7 @@ class BalanceStack implements IteratorAggregate {
                        // the stack of open elements, but the element is not in scope,
                        // then this is a parse error; ignore the token, and abort
                        // these steps.
-                       if ( !$this->inScope( $fmtelt ) ) {
+                       if ( !$this->inScope( $fmtElt ) ) {
                                return true;
                        }
 
@@ -1194,13 +1194,13 @@ class BalanceStack implements IteratorAggregate {
                        // open elements that is lower in the stack than the formatting
                        // element, and is an element in the special category. There
                        // might not be one.
-                       $furthestblock = null;
-                       $furthestblockindex = -1;
-                       $stacklen = $this->length();
-                       for ( $i = $index+1; $i < $stacklen; $i++ ) {
+                       $furthestBlock = null;
+                       $furthestBlockIndex = -1;
+                       $stackLength = $this->length();
+                       for ( $i = $index+1; $i < $stackLength; $i++ ) {
                                if ( $this->node( $i )->isA( BalanceSets::$specialSet ) ) {
-                                       $furthestblock = $this->node( $i );
-                                       $furthestblockindex = $i;
+                                       $furthestBlock = $this->node( $i );
+                                       $furthestBlockIndex = $i;
                                        break;
                                }
                        }
@@ -1211,140 +1211,134 @@ class BalanceStack implements IteratorAggregate {
                        // up to and including the formatting element, and remove the
                        // formatting element from the list of active formatting
                        // elements.
-                       if ( !$furthestblock ) {
-                               $this->popTag( $fmtelt );
-                               $afe->remove( $fmtelt );
-                               return true;
-                       } else {
-                               // Let the common ancestor be the element immediately above
-                               // the formatting element in the stack of open elements.
-                               $ancestor = $this->node( $index-1 );
-
-                               // Let a bookmark note the position of the formatting
-                               // element in the list of active formatting elements
-                               // relative to the elements on either side of it in the
-                               // list.
-                               $BOOKMARK = new BalanceElement( '[bookmark]', '[bookmark]', [] );
-                               $afe->insertAfter( $fmtelt, $BOOKMARK );
-
-                               // Let node and last node be the furthest block.
-                               $node = $furthestblock;
-                               $lastnode = $furthestblock;
-                               $nodeindex = $furthestblockindex;
-                               $isAFE = false;
-
-                               // Let inner loop counter be zero.
-                               $inner = 0;
-
-                               while ( true ) {
-
-                                       // Increment inner loop counter by one.
-                                       $inner++;
-
-                                       // Let node be the element immediately above node in
-                                       // the stack of open elements, or if node is no longer
-                                       // in the stack of open elements (e.g. because it got
-                                       // removed by this algorithm), the element that was
-                                       // immediately above node in the stack of open elements
-                                       // before node was removed.
-                                       $node = $this->node( --$nodeindex );
-
-                                       // If node is the formatting element, then go
-                                       // to the next step in the overall algorithm.
-                                       if ( $node === $fmtelt ) break;
-
-                                       // If the inner loop counter is greater than three and node
-                                       // is in the list of active formatting elements, then remove
-                                       // node from the list of active formatting elements.
-                                       $isAFE = $afe->isInList( $node );
-                                       if ( $inner > 3 && $isAFE ) {
-                                               $afe->remove( $node );
-                                               $isAFE = false;
-                                       }
-
-                                       // If node is not in the list of active formatting
-                                       // elements, then remove node from the stack of open
-                                       // elements and then go back to the step labeled inner
-                                       // loop.
-                                       if ( !$isAFE ) {
-                                               // Don't flatten here, since we're about to relocate
-                                               // parts of this $node.
-                                               $this->removeElement( $node, false );
-                                               continue;
-                                       }
-
-                                       // Create an element for the token for which the
-                                       // element node was created with common ancestor as
-                                       // the intended parent, replace the entry for node
-                                       // in the list of active formatting elements with an
-                                       // entry for the new element, replace the entry for
-                                       // node in the stack of open elements with an entry for
-                                       // the new element, and let node be the new element.
-                                       $newelt = new BalanceElement(
-                                               $node->namespaceURI, $node->localName, $node->attribs );
-                                       $afe->replace( $node, $newelt );
-                                       $this->replaceAt( $nodeindex, $newelt );
-                                       $node = $newelt;
-
-                                       // If last node is the furthest block, then move the
-                                       // aforementioned bookmark to be immediately after the
-                                       // new node in the list of active formatting elements.
-                                       if ( $lastnode === $furthestblock ) {
-                                               $afe->remove( $BOOKMARK );
-                                               $afe->insertAfter( $newelt, $BOOKMARK );
-                                       }
-
-                                       // Insert last node into node, first removing it from
-                                       // its previous parent node if any.
-                                       $node->appendChild( $lastnode );
-
-                                       // Let last node be node.
-                                       $lastnode = $node;
-                               }
-
-                               // If the common ancestor node is a table, tbody, tfoot,
-                               // thead, or tr element, then, foster parent whatever last
-                               // node ended up being in the previous step, first removing
-                               // it from its previous parent node if any.
-                               if (
-                                       $this->fosterParentMode &&
-                                       $ancestor->isA( BalanceSets::$tableSectionRowSet )
-                               ) {
-                                       $this->fosterParent( $lastnode );
-                               } else {
-                                       // Otherwise, append whatever last node ended up being in
-                                       // the previous step to the common ancestor node, first
-                                       // removing it from its previous parent node if any.
-                                       $ancestor->appendChild( $lastnode );
+                       if ( !$furthestBlock ) {
+                               $this->popTag( $fmtElt );
+                               $afe->remove( $fmtElt );
+                               return true;
+                       }
+
+                       // Let the common ancestor be the element immediately above
+                       // the formatting element in the stack of open elements.
+                       $ancestor = $this->node( $index-1 );
+
+                       // Let a bookmark note the position of the formatting
+                       // element in the list of active formatting elements
+                       // relative to the elements on either side of it in the
+                       // list.
+                       $BOOKMARK = new BalanceElement( '[bookmark]', '[bookmark]', [] );
+                       $afe->insertAfter( $fmtElt, $BOOKMARK );
+
+                       // Let node and last node be the furthest block.
+                       $node = $furthestBlock;
+                       $lastNode = $furthestBlock;
+                       $nodeIndex = $furthestBlockIndex;
+                       $isAFE = false;
+
+                       // Inner loop
+                       for ( $inner = 1; true; $inner++ ) {
+                               // Let node be the element immediately above node in
+                               // the stack of open elements, or if node is no longer
+                               // in the stack of open elements (e.g. because it got
+                               // removed by this algorithm), the element that was
+                               // immediately above node in the stack of open elements
+                               // before node was removed.
+                               $node = $this->node( --$nodeIndex );
+
+                               // If node is the formatting element, then go
+                               // to the next step in the overall algorithm.
+                               if ( $node === $fmtElt ) break;
+
+                               // If the inner loop counter is greater than three and node
+                               // is in the list of active formatting elements, then remove
+                               // node from the list of active formatting elements.
+                               $isAFE = $afe->isInList( $node );
+                               if ( $inner > 3 && $isAFE ) {
+                                       $afe->remove( $node );
+                                       $isAFE = false;
+                               }
+
+                               // If node is not in the list of active formatting
+                               // elements, then remove node from the stack of open
+                               // elements and then go back to the step labeled inner
+                               // loop.
+                               if ( !$isAFE ) {
+                                       // Don't flatten here, since we're about to relocate
+                                       // parts of this $node.
+                                       $this->removeElement( $node, false );
+                                       continue;
                                }
 
                                // Create an element for the token for which the
-                               // formatting element was created, with furthest block
-                               // as the intended parent.
-                               $newelt2 = new BalanceElement(
-                                       $fmtelt->namespaceURI, $fmtelt->localName, $fmtelt->attribs );
+                               // element node was created with common ancestor as
+                               // the intended parent, replace the entry for node
+                               // in the list of active formatting elements with an
+                               // entry for the new element, replace the entry for
+                               // node in the stack of open elements with an entry for
+                               // the new element, and let node be the new element.
+                               $newElt = new BalanceElement(
+                                       $node->namespaceURI, $node->localName, $node->attribs );
+                               $afe->replace( $node, $newElt );
+                               $this->replaceAt( $nodeIndex, $newElt );
+                               $node = $newElt;
+
+                               // If last node is the furthest block, then move the
+                               // aforementioned bookmark to be immediately after the
+                               // new node in the list of active formatting elements.
+                               if ( $lastNode === $furthestBlock ) {
+                                       $afe->remove( $BOOKMARK );
+                                       $afe->insertAfter( $newElt, $BOOKMARK );
+                               }
+
+                               // Insert last node into node, first removing it from
+                               // its previous parent node if any.
+                               $node->appendChild( $lastNode );
+
+                               // Let last node be node.
+                               $lastNode = $node;
+                       }
+
+                       // If the common ancestor node is a table, tbody, tfoot,
+                       // thead, or tr element, then, foster parent whatever last
+                       // node ended up being in the previous step, first removing
+                       // it from its previous parent node if any.
+                       if (
+                               $this->fosterParentMode &&
+                               $ancestor->isA( BalanceSets::$tableSectionRowSet )
+                       ) {
+                               $this->fosterParent( $lastNode );
+                       } else {
+                               // Otherwise, append whatever last node ended up being in
+                               // the previous step to the common ancestor node, first
+                               // removing it from its previous parent node if any.
+                               $ancestor->appendChild( $lastNode );
+                       }
 
-                               // Take all of the child nodes of the furthest block and
-                               // append them to the element created in the last step.
-                               $newelt2->adoptChildren( $furthestblock );
+                       // Create an element for the token for which the
+                       // formatting element was created, with furthest block
+                       // as the intended parent.
+                       $newElt2 = new BalanceElement(
+                               $fmtElt->namespaceURI, $fmtElt->localName, $fmtElt->attribs );
 
-                               // Append that new element to the furthest block.
-                               $furthestblock->appendChild( $newelt2 );
+                       // Take all of the child nodes of the furthest block and
+                       // append them to the element created in the last step.
+                       $newElt2->adoptChildren( $furthestBlock );
 
-                               // Remove the formatting element from the list of active
-                               // formatting elements, and insert the new element into the
-                               // list of active formatting elements at the position of
-                               // the aforementioned bookmark.
-                               $afe->remove( $fmtelt );
-                               $afe->replace( $BOOKMARK, $newelt2 );
+                       // Append that new element to the furthest block.
+                       $furthestBlock->appendChild( $newElt2 );
 
-                               // Remove the formatting element from the stack of open
-                               // elements, and insert the new element into the stack of
-                               // open elements immediately below the position of the
-                               // furthest block in that stack.
-                               $this->removeElement( $fmtelt );
-                               $this->insertAfter( $furthestblock, $newelt2 );
-                       }
+                       // Remove the formatting element from the list of active
+                       // formatting elements, and insert the new element into the
+                       // list of active formatting elements at the position of
+                       // the aforementioned bookmark.
+                       $afe->remove( $fmtElt );
+                       $afe->replace( $BOOKMARK, $newElt2 );
+
+                       // Remove the formatting element from the stack of open
+                       // elements, and insert the new element into the stack of
+                       // open elements immediately below the position of the
+                       // furthest block in that stack.
+                       $this->removeElement( $fmtElt );
+                       $this->insertAfter( $furthestBlock, $newElt2 );
                }
 
                return true;
@@ -1677,11 +1671,11 @@ class BalanceActiveFormattingElements {
 
                // Loop backward through the list until we find a marker or an
                // open element
-               $foundit = false;
+               $foundIt = false;
                while ( $entry->prevAFE ) {
                        $entry = $entry->prevAFE;
                        if ( $entry instanceof BalanceMarker || $stack->indexOf( $entry ) >= 0 ) {
-                               $foundit = true;
+                               $foundIt = true;
                                break;
                        }
                }
@@ -1690,7 +1684,7 @@ class BalanceActiveFormattingElements {
                // the first element if we didn't find a marker or open element),
                // recreating formatting elements and pushing them back onto the list
                // of open elements.
-               if ( $foundit ) {
+               if ( $foundIt ) {
                        $entry = $entry->nextAFE;
                }
                do {
@@ -1771,7 +1765,7 @@ class BalanceActiveFormattingElements {
  *     <style>/<noframes> want RAWTEXT modes which we only loosely emulate.)
  *
  *   We generally mark places where we omit cases from the spec due to
- *   disallowed elements with a comment: `# OMITTED: <element-name>`.
+ *   disallowed elements with a comment: `// OMITTED: <element-name>`.
  *
  *   The HTML spec keeps a flag during the parsing process to track
  *   whether or not a "parse error" has been encountered.  We don't
@@ -1789,8 +1783,8 @@ class Balancer {
        private $afe;
        private $stack;
        private $strict;
-       private $tidyCompat;
        private $allowComments;
+       private $config;
 
        private $textIntegrationMode;
        private $pendingTableText;
@@ -1857,7 +1851,7 @@ class Balancer {
         *         false to get a bit more performance.
         */
        public function __construct( array $config = [] ) {
-               $config = $config + [
+               $this->config = $config = $config + [
                        'strict' => false,
                        'allowedHtmlElements' => null,
                        'tidyCompat' => false,
@@ -1865,10 +1859,9 @@ class Balancer {
                ];
                $this->allowedHtmlElements = $config['allowedHtmlElements'];
                $this->strict = $config['strict'];
-               $this->tidyCompat = $config['tidyCompat'];
                $this->allowComments = $config['allowComments'];
                if ( $this->allowedHtmlElements !== null ) {
-                       # Sanity check!
+                       // Sanity check!
                        $bad = array_uintersect_assoc(
                                $this->allowedHtmlElements,
                                BalanceSets::$unsupportedSet[BalanceSets::HTML_NAMESPACE],
@@ -1905,8 +1898,7 @@ class Balancer {
                $this->parseMode = 'inBodyMode';
                $this->bitsIterator = new ExplodeIterator( '<', $text );
                $this->afe = new BalanceActiveFormattingElements();
-               $this->stack = new BalanceStack();
-               $this->stack->tidyCompat = $this->tidyCompat;
+               $this->stack = new BalanceStack( $this->config );
                $this->processingCallback = $processingCallback;
                $this->processingArgs = $processingArgs;
 
@@ -1915,8 +1907,8 @@ class Balancer {
                        $this->inRCDATA =
                        $this->inRAWTEXT = false;
 
-               # The stack is constructed with an <html> element already on it.
-               # Set this up as a fragment parsed with <body> as the context.
+               // The stack is constructed with an <html> element already on it.
+               // Set this up as a fragment parsed with <body> as the context.
                $this->fragmentContext =
                        new BalanceElement( BalanceSets::HTML_NAMESPACE, 'body', [] );
                $this->resetInsertionMode();
@@ -1951,12 +1943,12 @@ class Balancer {
         * Pass a token to the tree builder.  The $token will be one of the
         * strings "tag", "endtag", or "text".
         */
-       private function insertToken( $token, $value, $attribs = null, $selfclose = false ) {
+       private function insertToken( $token, $value, $attribs = null, $selfClose = false ) {
                // validate tags against $unsupportedSet
                if ( $token === 'tag' || $token === 'endtag' ) {
                        if ( isset( BalanceSets::$unsupportedSet[BalanceSets::HTML_NAMESPACE][$value] ) ) {
-                               # As described in "simplifications" above, these tags are
-                               # not supported in the balancer.
+                               // As described in "simplifications" above, these tags are
+                               // not supported in the balancer.
                                Assert::invariant(
                                        !$this->strict,
                                        "Unsupported $token <$value> found."
@@ -1964,7 +1956,7 @@ class Balancer {
                                return false;
                        }
                } elseif ( $token === 'text' && $value === '' ) {
-                       # Don't actually inject the empty string as a text token.
+                       // Don't actually inject the empty string as a text token.
                        return true;
                }
                // Support pre/listing/textarea by suppressing initial linefeed
@@ -1973,7 +1965,7 @@ class Balancer {
                        if ( $token === 'text' ) {
                                if ( $value[0] === "\n" ) {
                                        if ( $value === "\n" ) {
-                                               # Nothing would be left, don't inject the empty string.
+                                               // Nothing would be left, don't inject the empty string.
                                                return true;
                                        }
                                        $value = substr( $value, 1 );
@@ -2012,14 +2004,14 @@ class Balancer {
                        $isForeign = false;
                }
                if ( $isForeign ) {
-                       return $this->insertForeignToken( $token, $value, $attribs, $selfclose );
+                       return $this->insertForeignToken( $token, $value, $attribs, $selfClose );
                } else {
                        $func = $this->parseMode;
-                       return $this->$func( $token, $value, $attribs, $selfclose );
+                       return $this->$func( $token, $value, $attribs, $selfClose );
                }
        }
 
-       private function insertForeignToken( $token, $value, $attribs = null, $selfclose = false ) {
+       private function insertForeignToken( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
@@ -2032,7 +2024,7 @@ class Balancer {
                                ) {
                                        break;
                                }
-                               /* otherwise, fall through */
+                               // otherwise, fall through
                        case 'b':
                        case 'big':
                        case 'blockquote':
@@ -2091,7 +2083,7 @@ class Balancer {
                                                break;
                                        }
                                }
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        }
                        // "Any other start tag"
                        $adjusted = ( $this->fragmentContext && $this->stack->length()===1 ) ?
@@ -2099,7 +2091,7 @@ class Balancer {
                        $this->stack->insertForeignElement(
                                $adjusted->namespaceURI, $value, $attribs
                        );
-                       if ( $selfclose ) {
+                       if ( $selfClose ) {
                                $this->stack->pop();
                        }
                        return true;
@@ -2109,7 +2101,7 @@ class Balancer {
                                if ( $node->isHtml() && !$first ) {
                                        // process the end tag as HTML
                                        $func = $this->parseMode;
-                                       return $this->$func( $token, $value, $attribs, $selfclose );
+                                       return $this->$func( $token, $value, $attribs, $selfClose );
                                } elseif ( $i === 0 ) {
                                        return true;
                                } elseif ( $node->localName === $value ) {
@@ -2129,13 +2121,13 @@ class Balancer {
                $x = $this->bitsIterator->current();
                $this->bitsIterator->next();
                $regs = [];
-               # Handle comments.  These won't be generated by mediawiki (they
-               # are stripped in the Sanitizer) but may be generated by extensions.
+               // Handle comments.  These won't be generated by mediawiki (they
+               // are stripped in the Sanitizer) but may be generated by extensions.
                if (
                        $this->allowComments &&
                        !( $this->inRCDATA || $this->inRAWTEXT ) &&
                        preg_match( Balancer::VALID_COMMENT_REGEX, $x, $regs, PREG_OFFSET_CAPTURE ) &&
-                       /* verify EOF condition where necessary */
+                       // verify EOF condition where necessary
                        ( $regs[4][1] < 0 || !$this->bitsIterator->valid() )
                ) {
                        $contents = $regs[2][0];
@@ -2144,16 +2136,16 @@ class Balancer {
                        $this->insertToken( 'text', str_replace( '>', '&gt;', $rest ) );
                        return;
                }
-               # $slash: Does the current element start with a '/'?
-               # $t: Current element name
-               # $attribStr: String between element name and >
-               # $brace: Ending '>' or '/>'
-               # $rest: Everything until the next element from the $bitsIterator
+               // $slash: Does the current element start with a '/'?
+               // $t: Current element name
+               // $attribStr: String between element name and >
+               // $brace: Ending '>' or '/>'
+               // $rest: Everything until the next element from the $bitsIterator
                if ( preg_match( Sanitizer::ELEMENT_BITS_REGEX, $x, $regs ) ) {
                        list( /* $qbar */, $slash, $t, $attribStr, $brace, $rest ) = $regs;
                        $t = strtolower( $t );
                        if ( $this->strict ) {
-                               /* Verify that attributes are all properly double-quoted */
+                               // Verify that attributes are all properly double-quoted
                                Assert::invariant(
                                        preg_match(
                                                '/^( [:_A-Z0-9][-.:_A-Z0-9]*="[^"]*")*[ ]*$/i', $attribStr
@@ -2167,13 +2159,13 @@ class Balancer {
                        );
                        $slash = $t = $attribStr = $brace = $rest = null;
                }
-               $goodtag = $t;
+               $goodTag = $t;
                if ( $this->inRCDATA ) {
                        if ( $slash && $t === $this->inRCDATA ) {
                                $this->inRCDATA = false;
                        } else {
                                // No tags allowed; this emulates the "rcdata" tokenizer mode.
-                               $goodtag = false;
+                               $goodTag = false;
                        }
                }
                if ( $this->inRAWTEXT ) {
@@ -2181,39 +2173,39 @@ class Balancer {
                                $this->inRAWTEXT = false;
                        } else {
                                // No tags allowed, no entity-escaping done.
-                               $goodtag = false;
+                               $goodTag = false;
                        }
                }
                $sanitize = $this->allowedHtmlElements !== null;
                if ( $sanitize ) {
-                       $goodtag = $t && isset( $this->allowedHtmlElements[$t] );
+                       $goodTag = $t && isset( $this->allowedHtmlElements[$t] );
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        if ( is_callable( $this->processingCallback ) ) {
                                call_user_func_array( $this->processingCallback, [ &$attribStr, $this->processingArgs ] );
                        }
                        if ( $sanitize ) {
-                               $goodtag = Sanitizer::validateTag( $attribStr, $t );
+                               $goodTag = Sanitizer::validateTag( $attribStr, $t );
                        }
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        if ( $sanitize ) {
                                $attribs = Sanitizer::decodeTagAttributes( $attribStr );
                                $attribs = Sanitizer::validateTagAttributes( $attribs, $t );
                        } else {
                                $attribs = Sanitizer::decodeTagAttributes( $attribStr );
                        }
-                       $goodtag = $this->insertToken(
+                       $goodTag = $this->insertToken(
                                $slash ? 'endtag' : 'tag', $t, $attribs, $brace === '/>'
                        );
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        $rest = str_replace( '>', '&gt;', $rest );
                        $this->insertToken( 'text', str_replace( '>', '&gt;', $rest ) );
                } elseif ( $this->inRAWTEXT ) {
                        $this->insertToken( 'text', "<$x" );
                } else {
-                       # bad tag; serialize entire thing as text.
+                       // bad tag; serialize entire thing as text.
                        $this->insertToken( 'text', '&lt;' . str_replace( '>', '&gt;', $x ) );
                }
        }
@@ -2227,9 +2219,9 @@ class Balancer {
                return $oldMode;
        }
 
-       private function switchModeAndReprocess( $mode, $token, $value, $attribs, $selfclose ) {
+       private function switchModeAndReprocess( $mode, $token, $value, $attribs, $selfClose ) {
                $this->switchMode( $mode );
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
        private function resetInsertionMode() {
@@ -2244,9 +2236,9 @@ class Balancer {
                        if ( $node->isHtml() ) {
                                switch ( $node->localName ) {
                                case 'select':
-                                       $stacklen = $this->stack->length();
-                                       for ( $j = $i + 1; $j < $stacklen-1; $j++ ) {
-                                               $ancestor = $this->stack->node( $stacklen-$j-1 );
+                                       $stackLength = $this->stack->length();
+                                       for ( $j = $i + 1; $j < $stackLength-1; $j++ ) {
+                                               $ancestor = $this->stack->node( $stackLength-$j-1 );
                                                if ( $ancestor->isHtmlNamed( 'template' ) ) {
                                                        break;
                                                }
@@ -2282,12 +2274,12 @@ class Balancer {
                                case 'body':
                                        $this->switchMode( 'inBodyMode' );
                                        return;
-                               # OMITTED: <frameset>
-                               # OMITTED: <html>
-                               # OMITTED: <head>
+                               // OMITTED: <frameset>
+                               // OMITTED: <html>
+                               // OMITTED: <head>
                                default:
                                        if ( !$last ) {
-                                               # OMITTED: <head>
+                                               // OMITTED: <head>
                                                if ( $node->isA( BalanceSets::$tableCellSet ) ) {
                                                        $this->switchMode( 'inCellMode' );
                                                        return;
@@ -2303,14 +2295,14 @@ class Balancer {
        }
 
        private function stopParsing() {
-               # Most of the spec methods are inapplicable, other than step 2:
-               # "pop all the nodes off the stack of open elements".
-               # We're going to keep the top-most <html> element on the stack, though.
-
-               # Clear the AFE list first, otherwise the element objects will stay live
-               # during serialization, potentially using O(N^2) memory. Note that
-               # popping the stack will never result in reconstructing the active
-               # formatting elements.
+               // Most of the spec methods are inapplicable, other than step 2:
+               // "pop all the nodes off the stack of open elements".
+               // We're going to keep the top-most <html> element on the stack, though.
+
+               // Clear the AFE list first, otherwise the element objects will stay live
+               // during serialization, potentially using O(N^2) memory. Note that
+               // popping the stack will never result in reconstructing the active
+               // formatting elements.
                $this->afe = null;
                $this->stack->popTo( 1 );
        }
@@ -2322,14 +2314,14 @@ class Balancer {
                return true;
        }
 
-       private function inTextMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTextMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
                        $this->stack->pop();
                        return $this->switchModeAndReprocess(
-                               $this->originalInsertionMode, $token, $value, $attribs, $selfclose
+                               $this->originalInsertionMode, $token, $value, $attribs, $selfClose
                        );
                } elseif ( $token === 'endtag' ) {
                        $this->stack->pop();
@@ -2339,7 +2331,7 @@ class Balancer {
                return true;
        }
 
-       private function inHeadMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inHeadMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( preg_match( '/^[\x09\x0A\x0C\x0D\x20]+/', $value, $matches ) ) {
                                $this->stack->insertText( $matches[0] );
@@ -2352,9 +2344,9 @@ class Balancer {
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'meta':
-                               # OMITTED: in a full HTML parser, this might change the encoding.
-                               /* falls through */
-                       # OMITTED: <html>
+                               // OMITTED: in a full HTML parser, this might change the encoding.
+                               // falls through
+                       // OMITTED: <html>
                        case 'base':
                        case 'basefont':
                        case 'bgsound':
@@ -2362,26 +2354,26 @@ class Balancer {
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
                                return true;
-                       # OMITTED: <title>
-                       # OMITTED: <noscript>
+                       // OMITTED: <title>
+                       // OMITTED: <noscript>
                        case 'noframes':
                        case 'style':
                                return $this->parseRawText( $value, $attribs );
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'template':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->afe->insertMarker();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                $this->switchMode( 'inTemplateMode' );
                                $this->templateInsertionModes[] = $this->parseMode;
                                return true;
-                       # OMITTED: <head>
+                       // OMITTED: <head>
                        }
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
-                       # OMITTED: <head>
-                       # OMITTED: <body>
-                       # OMITTED: <html>
+                       // OMITTED: <head>
+                       // OMITTED: <body>
+                       // OMITTED: <html>
                        case 'br':
                                break; // handle at the bottom of the function
                        case 'template':
@@ -2406,36 +2398,36 @@ class Balancer {
                // If not handled above
                $this->inHeadMode( 'endtag', 'head' ); // synthetic </head>
                // Then redo this one
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
-       private function inBodyMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inBodyMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->afe->reconstruct( $this->stack );
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
                        if ( !empty( $this->templateInsertionModes ) ) {
-                               return $this->inTemplateMode( $token, $value, $attribs, $selfclose );
+                               return $this->inTemplateMode( $token, $value, $attribs, $selfClose );
                        }
                        $this->stopParsing();
                        return true;
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'base':
                        case 'basefont':
                        case 'bgsound':
                        case 'link':
                        case 'meta':
                        case 'noframes':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'style':
                        case 'template':
-                       # OMITTED: <title>
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
-                       # OMITTED: <body>
-                       # OMITTED: <frameset>
+                       // OMITTED: <title>
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
+                       // OMITTED: <body>
+                       // OMITTED: <frameset>
 
                        case 'address':
                        case 'article':
@@ -2489,7 +2481,7 @@ class Balancer {
                                }
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->ignoreLinefeed = true;
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'form':
@@ -2509,7 +2501,7 @@ class Balancer {
                                return true;
 
                        case 'li':
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                foreach ( $this->stack as $node ) {
                                        if ( $node->isHtmlNamed( 'li' ) ) {
                                                $this->inBodyMode( 'endtag', 'li' );
@@ -2530,7 +2522,7 @@ class Balancer {
 
                        case 'dd':
                        case 'dt':
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                foreach ( $this->stack as $node ) {
                                        if ( $node->isHtmlNamed( 'dd' ) ) {
                                                $this->inBodyMode( 'endtag', 'dd' );
@@ -2553,12 +2545,12 @@ class Balancer {
                                $this->stack->insertHTMLElement( $value, $attribs );
                                return true;
 
-                       # OMITTED: <plaintext>
+                       // OMITTED: <plaintext>
 
                        case 'button':
                                if ( $this->stack->inScope( 'button' ) ) {
                                        $this->inBodyMode( 'endtag', 'button' );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
@@ -2576,7 +2568,7 @@ class Balancer {
                                                $this->stack->removeElement( $activeElement, false );
                                        }
                                }
-                               /* Falls through */
+                               // Falls through
                        case 'b':
                        case 'big':
                        case 'code':
@@ -2608,17 +2600,17 @@ class Balancer {
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->afe->insertMarker();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'table':
-                               # The document is never in "quirks mode"; see simplifications
-                               # above.
+                               // The document is never in "quirks mode"; see simplifications
+                               // above.
                                if ( $this->stack->inButtonScope( 'p' ) ) {
                                        $this->inBodyMode( 'endtag', 'p' );
                                }
                                $this->stack->insertHTMLElement( $value, $attribs );
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                $this->switchMode( 'inTableMode' );
                                return true;
 
@@ -2631,15 +2623,15 @@ class Balancer {
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'input':
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
-                               # OMITTED: frameset_ok
-                               # (hence we don't need to examine the tag's "type" attribute)
+                               // OMITTED: frameset_ok
+                               // (hence we don't need to examine the tag's "type" attribute)
                                return true;
 
                        case 'menuitem':
@@ -2659,22 +2651,22 @@ class Balancer {
                                return true;
 
                        case 'image':
-                               # warts!
-                               return $this->inBodyMode( $token, 'img', $attribs, $selfclose );
+                               // warts!
+                               return $this->inBodyMode( $token, 'img', $attribs, $selfClose );
 
-                       # OMITTED: <isindex>
+                       // OMITTED: <isindex>
 
                        case 'textarea':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->ignoreLinefeed = true;
                                $this->inRCDATA = $value; // emulate rcdata tokenizer mode
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
-                       # OMITTED: <xmp>
-                       # OMITTED: <iframe>
-                       # OMITTED: <noembed>
-                       # OMITTED: <noscript>
+                       // OMITTED: <xmp>
+                       // OMITTED: <iframe>
+                       // OMITTED: <noembed>
+                       // OMITTED: <noscript>
 
                        case 'select':
                                $this->afe->reconstruct( $this->stack );
@@ -2719,30 +2711,30 @@ class Balancer {
 
                        case 'math':
                                $this->afe->reconstruct( $this->stack );
-                               # We skip the spec's "adjust MathML attributes" and
-                               # "adjust foreign attributes" steps, since the browser will
-                               # do this later when it parses the output and it doesn't affect
-                               # balancing.
+                               // We skip the spec's "adjust MathML attributes" and
+                               // "adjust foreign attributes" steps, since the browser will
+                               // do this later when it parses the output and it doesn't affect
+                               // balancing.
                                $this->stack->insertForeignElement(
                                        BalanceSets::MATHML_NAMESPACE, $value, $attribs
                                );
-                               if ( $selfclose ) {
-                                       # emit explicit </math> tag.
+                               if ( $selfClose ) {
+                                       // emit explicit </math> tag.
                                        $this->stack->pop();
                                }
                                return true;
 
                        case 'svg':
                                $this->afe->reconstruct( $this->stack );
-                               # We skip the spec's "adjust SVG attributes" and
-                               # "adjust foreign attributes" steps, since the browser will
-                               # do this later when it parses the output and it doesn't affect
-                               # balancing.
+                               // We skip the spec's "adjust SVG attributes" and
+                               // "adjust foreign attributes" steps, since the browser will
+                               // do this later when it parses the output and it doesn't affect
+                               // balancing.
                                $this->stack->insertForeignElement(
                                        BalanceSets::SVG_NAMESPACE, $value, $attribs
                                );
-                               if ( $selfclose ) {
-                                       # emit explicit </svg> tag.
+                               if ( $selfClose ) {
+                                       // emit explicit </svg> tag.
                                        $this->stack->pop();
                                }
                                return true;
@@ -2750,7 +2742,7 @@ class Balancer {
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <frame>
+                       // OMITTED: <frame>
                        case 'head':
                        case 'tbody':
                        case 'td':
@@ -2768,10 +2760,10 @@ class Balancer {
                        return true;
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
-                       # </body>,</html> are unsupported.
+                       // </body>,</html> are unsupported.
 
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'address':
                        case 'article':
@@ -2831,7 +2823,7 @@ class Balancer {
                        case 'p':
                                if ( !$this->stack->inButtonScope( 'p' ) ) {
                                        $this->inBodyMode( 'tag', 'p', [] );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2839,7 +2831,7 @@ class Balancer {
 
                        case 'li':
                                if ( !$this->stack->inListItemScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2848,7 +2840,7 @@ class Balancer {
                        case 'dd':
                        case 'dt':
                                if ( !$this->stack->inScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2861,14 +2853,14 @@ class Balancer {
                        case 'h5':
                        case 'h6':
                                if ( !$this->stack->inScope( BalanceSets::$headingSet ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags();
                                $this->stack->popTag( BalanceSets::$headingSet );
                                return true;
 
                        case 'sarcasm':
-                               # Take a deep breath, then:
+                               // Take a deep breath, then:
                                break;
 
                        case 'a':
@@ -2886,15 +2878,15 @@ class Balancer {
                        case 'tt':
                        case 'u':
                                if ( $this->stack->adoptionAgency( $value, $this->afe ) ) {
-                                       return true; # If we did something, we're done.
+                                       return true; // If we did something, we're done.
                                }
-                               break; # Go to the "any other end tag" case.
+                               break; // Go to the "any other end tag" case.
 
                        case 'applet':
                        case 'marquee':
                        case 'object':
                                if ( !$this->stack->inScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags();
                                $this->stack->popTag( $value );
@@ -2902,7 +2894,7 @@ class Balancer {
                                return true;
 
                        case 'br':
-                               # Turn </br> into <br>
+                               // Turn </br> into <br>
                                return $this->inBodyMode( 'tag', $value, [] );
                        }
 
@@ -2910,7 +2902,7 @@ class Balancer {
                        foreach ( $this->stack as $i => $node ) {
                                if ( $node->isHtmlNamed( $value ) ) {
                                        $this->stack->generateImpliedEndTags( $value );
-                                       $this->stack->popTo( $i ); # including $i
+                                       $this->stack->popTo( $i ); // including $i
                                        break;
                                } elseif ( $node->isA( BalanceSets::$specialSet ) ) {
                                        return true; // ignore this close token.
@@ -2925,14 +2917,15 @@ class Balancer {
                }
        }
 
-       private function inTableMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( $this->textIntegrationMode ) {
-                               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                        } elseif ( $this->stack->currentNode->isA( BalanceSets::$tableSectionRowSet ) ) {
                                $this->pendingTableText = '';
                                $this->originalInsertionMode = $this->parseMode;
-                               return $this->switchModeAndReprocess( 'inTableTextMode', $token, $value, $attribs, $selfclose );
+                               return $this->switchModeAndReprocess( 'inTableTextMode',
+                                       $token, $value, $attribs, $selfClose );
                        }
                        // fall through to default case.
                } elseif ( $token === 'eof' ) {
@@ -2952,7 +2945,7 @@ class Balancer {
                                return true;
                        case 'col':
                                $this->inTableMode( 'tag', 'colgroup', [] );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'tbody':
                        case 'tfoot':
                        case 'thead':
@@ -2964,18 +2957,18 @@ class Balancer {
                        case 'th':
                        case 'tr':
                                $this->inTableMode( 'tag', 'tbody', [] );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'table':
                                if ( !$this->stack->inTableScope( $value ) ) {
                                        return true; // Ignore this tag.
                                }
                                $this->inTableMode( 'endtag', $value );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
 
                        case 'style':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'input':
                                if ( !isset( $attribs['type'] ) || strcasecmp( $attribs['type'], 'hidden' ) !== 0 ) {
@@ -3007,11 +3000,11 @@ class Balancer {
                                $this->stack->popTag( $value );
                                $this->resetInsertionMode();
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'tbody':
                        case 'td':
                        case 'tfoot':
@@ -3020,7 +3013,7 @@ class Balancer {
                        case 'tr':
                                return true; // Ignore the token.
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else" clause.
                } elseif ( $token === 'comment' ) {
@@ -3029,12 +3022,12 @@ class Balancer {
                }
                // This is the "anything else" case:
                $this->stack->fosterParentMode = true;
-               $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               $this->inBodyMode( $token, $value, $attribs, $selfClose );
                $this->stack->fosterParentMode = false;
                return true;
        }
 
-       private function inTableTextMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableTextMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->pendingTableText .= $value;
                        return true;
@@ -3052,7 +3045,7 @@ class Balancer {
                        $this->stack->insertText( $text );
                }
                return $this->switchModeAndReprocess(
-                       $this->originalInsertionMode, $token, $value, $attribs, $selfclose
+                       $this->originalInsertionMode, $token, $value, $attribs, $selfClose
                );
        }
 
@@ -3068,7 +3061,7 @@ class Balancer {
                return true;
        }
 
-       private function inCaptionMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inCaptionMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'caption':
@@ -3081,7 +3074,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endCaption() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3093,13 +3086,13 @@ class Balancer {
                                return true;
                        case 'table':
                                if ( $this->endCaption() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'body':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'tbody':
                        case 'td':
                        case 'tfoot':
@@ -3112,10 +3105,10 @@ class Balancer {
                        // Fall through to "anything else" case.
                }
                // The Anything Else case
-               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inColumnGroupMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inColumnGroupMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( preg_match( '/^[\x09\x0A\x0C\x0D\x20]+/', $value, $matches ) ) {
                                $this->stack->insertText( $matches[0] );
@@ -3127,13 +3120,13 @@ class Balancer {
                        // Fall through to handle non-whitespace below.
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'col':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
                                return true;
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else".
                } elseif ( $token === 'endtag' ) {
@@ -3148,11 +3141,11 @@ class Balancer {
                        case 'col':
                                return true; // Ignore the token.
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else".
                } elseif ( $token === 'eof' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'comment' ) {
                        $this->stack->insertComment( $value );
                        return true;
@@ -3163,7 +3156,7 @@ class Balancer {
                        return true; // Ignore the token.
                }
                $this->inColumnGroupMode( 'endtag', 'colgroup' );
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
        // Helper function for inTableBodyMode
@@ -3180,7 +3173,7 @@ class Balancer {
                $this->switchMode( 'inTableMode' );
                return true;
        }
-       private function inTableBodyMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableBodyMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'tr':
@@ -3191,7 +3184,7 @@ class Balancer {
                        case 'th':
                        case 'td':
                                $this->inTableBodyMode( 'tag', 'tr', [] );
-                               $this->insertToken( $token, $value, $attribs, $selfclose );
+                               $this->insertToken( $token, $value, $attribs, $selfClose );
                                return true;
                        case 'caption':
                        case 'col':
@@ -3200,7 +3193,7 @@ class Balancer {
                        case 'tfoot':
                        case 'thead':
                                if ( $this->endSection() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3208,7 +3201,7 @@ class Balancer {
                        switch ( $value ) {
                        case 'table':
                                if ( $this->endSection() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'tbody':
@@ -3218,11 +3211,11 @@ class Balancer {
                                        $this->endSection();
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'td':
                        case 'th':
                        case 'tr':
@@ -3230,7 +3223,7 @@ class Balancer {
                        }
                }
                // Anything else:
-               return $this->inTableMode( $token, $value, $attribs, $selfclose );
+               return $this->inTableMode( $token, $value, $attribs, $selfClose );
        }
 
        // Helper function for inRowMode
@@ -3243,7 +3236,7 @@ class Balancer {
                $this->switchMode( 'inTableBodyMode' );
                return true;
        }
-       private function inRowMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inRowMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'th':
@@ -3261,7 +3254,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endRow() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3272,7 +3265,7 @@ class Balancer {
                                return true;
                        case 'table':
                                if ( $this->endRow() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'tbody':
@@ -3282,21 +3275,21 @@ class Balancer {
                                        $this->stack->inTableScope( $value ) &&
                                        $this->endRow()
                                ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'td':
                        case 'th':
                                return true; // Ignore the token.
                        }
                }
                // Anything else:
-               return $this->inTableMode( $token, $value, $attribs, $selfclose );
+               return $this->inTableMode( $token, $value, $attribs, $selfClose );
        }
 
        // Helper for inCellMode
@@ -3311,7 +3304,7 @@ class Balancer {
                        return false;
                }
        }
-       private function inCellMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inCellMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'caption':
@@ -3324,7 +3317,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endCell() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3339,11 +3332,11 @@ class Balancer {
                                        $this->switchMode( 'inRowMode' );
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                                return true;
 
                        case 'table':
@@ -3356,24 +3349,24 @@ class Balancer {
                                        $this->stack->popTag( BalanceSets::$tableCellSet );
                                        $this->afe->clearToMarker();
                                        $this->switchMode( 'inRowMode' );
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
                }
                // Anything else:
-               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inSelectMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inSelectMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'option':
                                if ( $this->stack->currentNode->isHtmlNamed( 'option' ) ) {
                                        $this->stack->pop();
@@ -3399,10 +3392,10 @@ class Balancer {
                                        return true; // ignore token (fragment case)
                                }
                                $this->inSelectMode( 'endtag', 'select' );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'script':
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
@@ -3431,7 +3424,7 @@ class Balancer {
                                $this->resetInsertionMode();
                                return true;
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                } elseif ( $token === 'comment' ) {
                        $this->stack->insertComment( $value );
@@ -3441,7 +3434,7 @@ class Balancer {
                return true;
        }
 
-       private function inSelectInTableMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inSelectInTableMode( $token, $value, $attribs = null, $selfClose = false ) {
                switch ( $value ) {
                case 'caption':
                case 'table':
@@ -3453,22 +3446,22 @@ class Balancer {
                case 'th':
                        if ( $token === 'tag' ) {
                                $this->inSelectInTableMode( 'endtag', 'select' );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        } elseif ( $token === 'endtag' ) {
                                if ( $this->stack->inTableScope( $value ) ) {
                                        $this->inSelectInTableMode( 'endtag', 'select' );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
                }
                // anything else
-               return $this->inSelectMode( $token, $value, $attribs, $selfclose );
+               return $this->inSelectMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inTemplateMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTemplateMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' || $token === 'comment' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'eof' ) {
                        if ( $this->stack->indexOf( 'template' ) < 0 ) {
                                $this->stopParsing();
@@ -3477,7 +3470,7 @@ class Balancer {
                                $this->afe->clearToMarker();
                                array_pop( $this->templateInsertionModes );
                                $this->resetInsertionMode();
-                               $this->insertToken( $token, $value, $attribs, $selfclose );
+                               $this->insertToken( $token, $value, $attribs, $selfClose );
                        }
                        return true;
                } elseif ( $token === 'tag' ) {
@@ -3488,11 +3481,11 @@ class Balancer {
                        case 'link':
                        case 'meta':
                        case 'noframes':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'style':
                        case 'template':
-                       # OMITTED: <title>
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                       // OMITTED: <title>
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'caption':
                        case 'colgroup':
@@ -3500,32 +3493,32 @@ class Balancer {
                        case 'tfoot':
                        case 'thead':
                                return $this->switchModeAndReprocess(
-                                       'inTableMode', $token, $value, $attribs, $selfclose
+                                       'inTableMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'col':
                                return $this->switchModeAndReprocess(
-                                       'inColumnGroupMode', $token, $value, $attribs, $selfclose
+                                       'inColumnGroupMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'tr':
                                return $this->switchModeAndReprocess(
-                                       'inTableBodyMode', $token, $value, $attribs, $selfclose
+                                       'inTableBodyMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'td':
                        case 'th':
                                return $this->switchModeAndReprocess(
-                                       'inRowMode', $token, $value, $attribs, $selfclose
+                                       'inRowMode', $token, $value, $attribs, $selfClose
                                );
                        }
                        return $this->switchModeAndReprocess(
-                               'inBodyMode', $token, $value, $attribs, $selfclose
+                               'inBodyMode', $token, $value, $attribs, $selfClose
                        );
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        return true;
                } else {
index 71d032f..b620132 100644 (file)
@@ -53,7 +53,16 @@ abstract class UploadBase {
                'ISO-8859-1',
                'ISO-8859-2',
                'UTF-16',
-               'UTF-32'
+               'UTF-32',
+               'WINDOWS-1250',
+               'WINDOWS-1251',
+               'WINDOWS-1252',
+               'WINDOWS-1253',
+               'WINDOWS-1254',
+               'WINDOWS-1255',
+               'WINDOWS-1256',
+               'WINDOWS-1257',
+               'WINDOWS-1258',
        ];
 
        const SUCCESS = 0;
@@ -949,10 +958,11 @@ abstract class UploadBase {
         *
         * @param User $user
         * @return UploadStashFile Stashed file
+        * @throws UploadStashBadPathException
+        * @throws UploadStashFileException
+        * @throws UploadStashNotLoggedInException
         */
        public function stashFile( User $user = null ) {
-               // was stashSessionFile
-
                $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $user );
                $file = $stash->stashFile( $this->mTempPath, $this->getSourceType() );
                $this->mLocalFile = $file;
@@ -964,19 +974,23 @@ abstract class UploadBase {
         * Stash a file in a temporary directory, returning a key which can be used
         * to find the file again. See stashFile().
         *
+        * @deprecated since 1.28
         * @return string File key
         */
        public function stashFileGetKey() {
+               wfDeprecated( __METHOD__, '1.28' );
                return $this->stashFile()->getFileKey();
        }
 
        /**
         * alias for stashFileGetKey, for backwards compatibility
         *
+        * @deprecated since 1.28
         * @return string File key
         */
        public function stashSession() {
-               return $this->stashFileGetKey();
+               wfDeprecated( __METHOD__, '1.28' );
+               return $this->stashFile()->getFileKey();
        }
 
        /**
index 1276842..908c8aa 100644 (file)
@@ -161,14 +161,6 @@ class UploadFromStash extends UploadBase {
                return $this->mLocalFile;
        }
 
-       /**
-        * This should return the key instead of the UploadStashFile instance, for backward compatibility.
-        * @return string
-        */
-       public function stashSession() {
-               return $this->stashFile()->getFileKey();
-       }
-
        /**
         * Remove a temporarily kept file stashed by saveTempUploadedFile().
         * @return bool Success
index 39507af..36526d7 100644 (file)
@@ -648,8 +648,6 @@ class User implements IDBAccessObject {
         * @since 1.27
         */
        public static function newSystemUser( $name, $options = [] ) {
-               global $wgDisableAuthManager;
-
                $options += [
                        'validate' => 'valid',
                        'create' => true,
@@ -662,9 +660,6 @@ class User implements IDBAccessObject {
                }
 
                $fields = self::selectFields();
-               if ( $wgDisableAuthManager ) {
-                       $fields = array_merge( $fields, [ 'user_password', 'user_newpassword' ] );
-               }
 
                $dbw = wfGetDB( DB_MASTER );
                $row = $dbw->selectRow(
@@ -681,49 +676,15 @@ class User implements IDBAccessObject {
 
                // A user is considered to exist as a non-system user if it can
                // authenticate, or has an email set, or has a non-invalid token.
-               if ( !$user->mEmail && $user->mToken === self::INVALID_TOKEN ) {
-                       if ( $wgDisableAuthManager ) {
-                               $passwordFactory = new PasswordFactory();
-                               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                               try {
-                                       $password = $passwordFactory->newFromCiphertext( $row->user_password );
-                               } catch ( PasswordError $e ) {
-                                       wfDebug( 'Invalid password hash found in database.' );
-                                       $password = PasswordFactory::newInvalidPassword();
-                               }
-                               try {
-                                       $newpassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-                               } catch ( PasswordError $e ) {
-                                       wfDebug( 'Invalid password hash found in database.' );
-                                       $newpassword = PasswordFactory::newInvalidPassword();
-                               }
-                               $canAuthenticate = !$password instanceof InvalidPassword ||
-                                       !$newpassword instanceof InvalidPassword;
-                       } else {
-                               $canAuthenticate = AuthManager::singleton()->userCanAuthenticate( $name );
-                       }
-               }
-               if ( $user->mEmail || $user->mToken !== self::INVALID_TOKEN || $canAuthenticate ) {
+               if ( $user->mEmail || $user->mToken !== self::INVALID_TOKEN ||
+                       AuthManager::singleton()->userCanAuthenticate( $name )
+               ) {
                        // User exists. Steal it?
                        if ( !$options['steal'] ) {
                                return null;
                        }
 
-                       if ( $wgDisableAuthManager ) {
-                               $nopass = PasswordFactory::newInvalidPassword()->toString();
-                               $dbw->update(
-                                       'user',
-                                       [
-                                               'user_password' => $nopass,
-                                               'user_newpassword' => $nopass,
-                                               'user_newpass_time' => null,
-                                       ],
-                                       [ 'user_id' => $user->getId() ],
-                                       __METHOD__
-                               );
-                       } else {
-                               AuthManager::singleton()->revokeAccessForUser( $name );
-                       }
+                       AuthManager::singleton()->revokeAccessForUser( $name );
 
                        $user->invalidateEmail();
                        $user->mToken = self::INVALID_TOKEN;
@@ -1387,8 +1348,6 @@ class User implements IDBAccessObject {
         */
        protected function loadFromUserObject( $user ) {
                $user->load();
-               $user->loadGroups();
-               $user->loadOptions();
                foreach ( self::$mCacheVars as $var ) {
                        $this->$var = $user->$var;
                }
@@ -2510,31 +2469,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function setPassword( $str ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       return $this->setPasswordInternal( $str );
-               }
-
-               if ( $str !== null ) {
-                       if ( !$wgAuth->allowPasswordChange() ) {
-                               throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
-                       }
-
-                       $status = $this->checkPasswordValidity( $str );
-                       if ( !$status->isGood() ) {
-                               throw new PasswordError( $status->getMessage()->text() );
-                       }
-               }
-
-               if ( !$wgAuth->setPassword( $this, $str ) ) {
-                       throw new PasswordError( wfMessage( 'externaldberror' )->text() );
-               }
-
-               $this->setOption( 'watchlisttoken', false );
-               $this->setPasswordInternal( $str );
-
-               return true;
+               return $this->setPasswordInternal( $str );
        }
 
        /**
@@ -2546,16 +2481,7 @@ class User implements IDBAccessObject {
         *  through the web interface.
         */
        public function setInternalPassword( $str ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       $this->setPasswordInternal( $str );
-               }
-
-               if ( $wgAuth->allowSetLocalPassword() ) {
-                       $this->setOption( 'watchlisttoken', false );
-                       $this->setPasswordInternal( $str );
-               }
+               $this->setPasswordInternal( $str );
        }
 
        /**
@@ -2567,55 +2493,26 @@ class User implements IDBAccessObject {
         * @return bool Success
         */
        private function setPasswordInternal( $str ) {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $id = self::idFromName( $this->getName(), self::READ_LATEST );
-                       if ( $id == 0 ) {
-                               throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
-                       }
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $dbw = wfGetDB( DB_MASTER );
-                       $dbw->update(
-                               'user',
-                               [
-                                       'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
-                                       'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
-                                       'user_newpass_time' => $dbw->timestampOrNull( null ),
-                               ],
-                               [
-                                       'user_id' => $id,
-                               ],
-                               __METHOD__
-                       );
-
-                       // When the main password is changed, invalidate all bot passwords too
-                       BotPassword::invalidateAllPasswordsForUser( $this->getName() );
-               } else {
-                       $manager = AuthManager::singleton();
-
-                       // If the user doesn't exist yet, fail
-                       if ( !$manager->userExists( $this->getName() ) ) {
-                               throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
-                       }
+               $manager = AuthManager::singleton();
 
-                       $status = $this->changeAuthenticationData( [
-                               'username' => $this->getName(),
-                               'password' => $str,
-                               'retype' => $str,
-                       ] );
-                       if ( !$status->isGood() ) {
-                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                       ->info( __METHOD__ . ': Password change rejected: '
-                                               . $status->getWikiText( null, null, 'en' ) );
-                               return false;
-                       }
+               // If the user doesn't exist yet, fail
+               if ( !$manager->userExists( $this->getName() ) ) {
+                       throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
+               }
 
-                       $this->setOption( 'watchlisttoken', false );
+               $status = $this->changeAuthenticationData( [
+                       'username' => $this->getName(),
+                       'password' => $str,
+                       'retype' => $str,
+               ] );
+               if ( !$status->isGood() ) {
+                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                               ->info( __METHOD__ . ': Password change rejected: '
+                                       . $status->getWikiText( null, null, 'en' ) );
+                       return false;
                }
 
+               $this->setOption( 'watchlisttoken', false );
                SessionManager::singleton()->invalidateSessionsForUser( $this );
 
                return true;
@@ -2634,12 +2531,6 @@ class User implements IDBAccessObject {
         * @since 1.27
         */
        public function changeAuthenticationData( array $data ) {
-               global $wgDisableAuthManager;
-               if ( $wgDisableAuthManager ) {
-                       throw new LogicException( __METHOD__ . ' cannot be called when $wgDisableAuthManager '
-                               . 'is true' );
-               }
-
                $manager = AuthManager::singleton();
                $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
                $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
@@ -2725,32 +2616,7 @@ class User implements IDBAccessObject {
         * @param bool $throttle If true, reset the throttle timestamp to the present
         */
        public function setNewpassword( $str, $throttle = true ) {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $id = $this->getId();
-                       if ( $id == 0 ) {
-                               throw new LogicException( 'Cannot set new password for a user that is not in the database.' );
-                       }
-
-                       $dbw = wfGetDB( DB_MASTER );
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $update = [
-                               'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
-                       ];
-
-                       if ( $str === null ) {
-                               $update['user_newpass_time'] = null;
-                       } elseif ( $throttle ) {
-                               $update['user_newpass_time'] = $dbw->timestamp();
-                       }
-
-                       $dbw->update( 'user', $update, [ 'user_id' => $id ], __METHOD__ );
-               } else {
-                       throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-               }
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
        }
 
        /**
@@ -2760,33 +2626,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function isPasswordReminderThrottled() {
-               global $wgPasswordReminderResendTime, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       if ( !$wgPasswordReminderResendTime ) {
-                               return false;
-                       }
-
-                       $this->load();
-
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-                       $newpassTime = $db->selectField(
-                               'user',
-                               'user_newpass_time',
-                               [ 'user_id' => $this->getId() ],
-                               __METHOD__
-                       );
-
-                       if ( $newpassTime === null ) {
-                               return false;
-                       }
-                       $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
-                       return time() < $expiry;
-               } else {
-                       throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-               }
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
        }
 
        /**
@@ -3018,7 +2858,7 @@ class User implements IDBAccessObject {
         * @return string|bool User's current value for the option, or false if this option is disabled.
         * @see resetTokenFromOption()
         * @see getOption()
-        * @deprecated 1.26 Applications should use the OAuth extension
+        * @deprecated since 1.26 Applications should use the OAuth extension
         */
        public function getTokenFromOption( $oname ) {
                global $wgHiddenPrefs;
@@ -4282,87 +4122,27 @@ class User implements IDBAccessObject {
         * @return bool True if the given password is correct, otherwise False
         */
        public function checkPassword( $password ) {
-               global $wgAuth, $wgLegacyEncoding, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $this->load();
-
-                       // Some passwords will give a fatal Status, which means there is
-                       // some sort of technical or security reason for this password to
-                       // be completely invalid and should never be checked (e.g., T64685)
-                       if ( !$this->checkPasswordValidity( $password )->isOK() ) {
-                               return false;
-                       }
-
-                       // Certain authentication plugins do NOT want to save
-                       // domain passwords in a mysql database, so we should
-                       // check this (in case $wgAuth->strict() is false).
-                       if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
+               $manager = AuthManager::singleton();
+               $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+                       $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
+                       [
+                               'username' => $this->getName(),
+                               'password' => $password,
+                       ]
+               );
+               $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+               switch ( $res->status ) {
+                       case AuthenticationResponse::PASS:
                                return true;
-                       } elseif ( $wgAuth->strict() ) {
-                               // Auth plugin doesn't allow local authentication
-                               return false;
-                       } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
-                               // Auth plugin doesn't allow local authentication for this user name
+                       case AuthenticationResponse::FAIL:
+                               // Hope it's not a PreAuthenticationProvider that failed...
+                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                       ->info( __METHOD__ . ': Authentication failed: ' . $res->message->plain() );
                                return false;
-                       }
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-
-                       try {
-                               $mPassword = $passwordFactory->newFromCiphertext( $db->selectField(
-                                       'user', 'user_password', [ 'user_id' => $this->getId() ], __METHOD__
-                               ) );
-                       } catch ( PasswordError $e ) {
-                               wfDebug( 'Invalid password hash found in database.' );
-                               $mPassword = PasswordFactory::newInvalidPassword();
-                       }
-
-                       if ( !$mPassword->equals( $password ) ) {
-                               if ( $wgLegacyEncoding ) {
-                                       // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
-                                       // Check for this with iconv
-                                       $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
-                                       if ( $cp1252Password === $password || !$mPassword->equals( $cp1252Password ) ) {
-                                               return false;
-                                       }
-                               } else {
-                                       return false;
-                               }
-                       }
-
-                       if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
-                               $this->setPasswordInternal( $password );
-                       }
-
-                       return true;
-               } else {
-                       $manager = AuthManager::singleton();
-                       $reqs = AuthenticationRequest::loadRequestsFromSubmission(
-                               $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
-                               [
-                                       'username' => $this->getName(),
-                                       'password' => $password,
-                               ]
-                       );
-                       $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
-                       switch ( $res->status ) {
-                               case AuthenticationResponse::PASS:
-                                       return true;
-                               case AuthenticationResponse::FAIL:
-                                       // Hope it's not a PreAuthenticationProvider that failed...
-                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                               ->info( __METHOD__ . ': Authentication failed: ' . $res->message->plain() );
-                                       return false;
-                               default:
-                                       throw new BadMethodCallException(
-                                               'AuthManager returned a response unsupported by ' . __METHOD__
-                                       );
-                       }
+                       default:
+                               throw new BadMethodCallException(
+                                       'AuthManager returned a response unsupported by ' . __METHOD__
+                               );
                }
        }
 
@@ -4375,43 +4155,8 @@ class User implements IDBAccessObject {
         * @return bool True if matches, false otherwise
         */
        public function checkTemporaryPassword( $plaintext ) {
-               global $wgNewPasswordExpiry, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $this->load();
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-
-                       $row = $db->selectRow(
-                               'user',
-                               [ 'user_newpassword', 'user_newpass_time' ],
-                               [ 'user_id' => $this->getId() ],
-                               __METHOD__
-                       );
-                       try {
-                               $newPassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-                       } catch ( PasswordError $e ) {
-                               wfDebug( 'Invalid password hash found in database.' );
-                               $newPassword = PasswordFactory::newInvalidPassword();
-                       }
-
-                       if ( $newPassword->equals( $plaintext ) ) {
-                               if ( is_null( $row->user_newpass_time ) ) {
-                                       return true;
-                               }
-                               $expiry = wfTimestamp( TS_UNIX, $row->user_newpass_time ) + $wgNewPasswordExpiry;
-                               return ( time() < $expiry );
-                       } else {
-                               return false;
-                       }
-               } else {
-                       // Can't check the temporary password individually.
-                       return $this->checkPassword( $plaintext );
-               }
+               // Can't check the temporary password individually.
+               return $this->checkPassword( $plaintext );
        }
 
        /**
@@ -5161,12 +4906,20 @@ class User implements IDBAccessObject {
                                // If we actually have a slave server, the count is
                                // at least one behind because the current transaction
                                // has not been committed and replicated.
-                               $this->initEditCount( 1 );
+                               $this->mEditCount = $this->initEditCount( 1 );
                        } else {
                                // But if DB_SLAVE is selecting the master, then the
                                // count we just read includes the revision that was
                                // just added in the working transaction.
-                               $this->initEditCount();
+                               $this->mEditCount = $this->initEditCount();
+                       }
+               } else {
+                       if ( $this->mEditCount === null ) {
+                               $this->getEditCount();
+                               $dbr = wfGetDB( DB_SLAVE );
+                               $this->mEditCount += ( $dbr !== $dbw ) ? 1 : 0;
+                       } else {
+                               $this->mEditCount++;
                        }
                }
                // Edit count in user cache too
@@ -5280,45 +5033,10 @@ class User implements IDBAccessObject {
         *     - false will be converted to 'create' if this object is the same as
         *       $wgUser and to 'create2' otherwise
         * @param string $reason User supplied reason
-        * @return int|bool True if not $wgNewUserLog or not $wgDisableAuthManager;
-        *   otherwise ID of log item or 0 on failure
+        * @return bool true
         */
        public function addNewUserLogEntry( $action = false, $reason = '' ) {
-               global $wgUser, $wgNewUserLog, $wgDisableAuthManager;
-               if ( !$wgDisableAuthManager || empty( $wgNewUserLog ) ) {
-                       return true; // disabled
-               }
-
-               if ( $action === true ) {
-                       $action = 'byemail';
-               } elseif ( $action === false ) {
-                       if ( $this->equals( $wgUser ) ) {
-                               $action = 'create';
-                       } else {
-                               $action = 'create2';
-                       }
-               }
-
-               if ( $action === 'create' || $action === 'autocreate' ) {
-                       $performer = $this;
-               } else {
-                       $performer = $wgUser;
-               }
-
-               $logEntry = new ManualLogEntry( 'newusers', $action );
-               $logEntry->setPerformer( $performer );
-               $logEntry->setTarget( $this->getUserPage() );
-               $logEntry->setComment( $reason );
-               $logEntry->setParameters( [
-                       '4::userid' => $this->getId(),
-               ] );
-               $logid = $logEntry->insert();
-
-               if ( $action !== 'autocreate' ) {
-                       $logEntry->publish( $logid );
-               }
-
-               return (int)$logid;
+               return true; // disabled
        }
 
        /**
index 916e2f8..2ebc9ed 100644 (file)
@@ -14,6 +14,9 @@
  *     $gen->generateAutoload();
  */
 class AutoloadGenerator {
+       const FILETYPE_JSON = 'json';
+       const FILETYPE_PHP = 'php';
+
        /**
         * @var string Root path of the project being scanned for classes
         */
@@ -122,11 +125,11 @@ class AutoloadGenerator {
         * Updates the AutoloadClasses field at the given
         * filename.
         *
-        * @param {string} $filename Filename of JSON
+        * @param string $filename Filename of JSON
         *  extension/skin registration file
+        * @return string Updated Json of the file given as the $filename parameter
         */
        protected function generateJsonAutoload( $filename ) {
-               require_once __DIR__ . '/../../includes/json/FormatJson.php';
                $key = 'AutoloadClasses';
                $json = FormatJson::decode( file_get_contents( $filename ), true );
                unset( $json[$key] );
@@ -148,10 +151,8 @@ class AutoloadGenerator {
                // Sorting the list of autoload classes.
                ksort( $json[$key] );
 
-               // Update file, using constants for the required
-               // formatting.
-               file_put_contents( $filename,
-                       FormatJson::encode( $json, true ) . "\n" );
+               // Return the whole JSON file
+               return FormatJson::encode( $json, true ) . "\n";
        }
 
        /**
@@ -198,8 +199,7 @@ class AutoloadGenerator {
                }
 
                $output = implode( "\n\t", $content );
-               file_put_contents(
-                       $filename,
+               return
                        <<<EOD
 <?php
 // This file is generated by $commandName, do not adjust manually
@@ -210,36 +210,60 @@ global \${$this->variableName};
        {$output}
 ];
 
-EOD
-               );
+EOD;
 
        }
 
        /**
-        * Write out all known classes to autoload.php, extension.json, or skin.json in
-        * the provided basedir
+        * Returns all known classes as a string, which can be used to put into a target
+        * file (e.g. extension.json, skin.json or autoload.php)
         *
         * @param string $commandName Value used in file comment to direct
         *  developers towards the appropriate way to update the autoload.
+        * @return string
         */
-       public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+       public function getAutoload( $commandName = 'AutoloadGenerator' ) {
 
                // We need to check whether an extenson.json or skin.json exists or not, and
                // incase it doesn't, update the autoload.php file.
 
-               $jsonFilename = null;
-               if ( file_exists( $this->basepath . "/extension.json" ) ) {
-                       $jsonFilename = $this->basepath . "/extension.json";
-               } elseif ( file_exists( $this->basepath . "/skin.json" ) ) {
-                       $jsonFilename = $this->basepath . "/skin.json";
-               }
+               $fileinfo = $this->getTargetFileinfo();
 
-               if ( $jsonFilename !== null ) {
-                       $this->generateJsonAutoload( $jsonFilename );
+               if ( $fileinfo['type'] === self::FILETYPE_JSON ) {
+                       return $this->generateJsonAutoload( $fileinfo['filename'] );
                } else {
-                       $this->generatePHPAutoload( $commandName, $this->basepath . '/autoload.php' );
+                       return $this->generatePHPAutoload( $commandName, $fileinfo['filename'] );
+               }
+       }
+
+       /**
+        * Returns the filename of the extension.json of skin.json, if there's any, or
+        * otherwise the path to the autoload.php file in an array as the "filename"
+        * key and with the type (AutoloadGenerator::FILETYPE_JSON or AutoloadGenerator::FILETYPE_PHP)
+        * of the file as the "type" key.
+        *
+        * @return array
+        */
+       public function getTargetFileinfo() {
+               $fileinfo = [
+                       'filename' => $this->basepath . '/autoload.php',
+                       'type' => self::FILETYPE_PHP
+               ];
+               if ( file_exists( $this->basepath . '/extension.json' ) ) {
+                       $fileinfo = [
+                               'filename' => $this->basepath . '/extension.json',
+                               'type' => self::FILETYPE_JSON
+                       ];
+               } elseif ( file_exists( $this->basepath . '/skin.json' ) ) {
+                       $fileinfo = [
+                               'filename' => $this->basepath . '/skin.json',
+                               'type' => self::FILETYPE_JSON
+                       ];
                }
+
+               return $fileinfo;
        }
+
        /**
         * Ensure that Unix-style path separators ("/") are used in the path.
         *
@@ -249,6 +273,24 @@ EOD
        protected static function normalizePathSeparator( $path ) {
                return str_replace( '\\', '/', $path );
        }
+
+       /**
+        * Initialize the source files and directories which are used for the MediaWiki default
+        * autoloader in {mw-base-dir}/autoload.php including:
+        *  * includes/
+        *  * languages/
+        *  * maintenance/
+        *  * mw-config/
+        *  * /*.php
+        */
+       public function initMediaWikiDefault() {
+               foreach ( [ 'includes', 'languages', 'maintenance', 'mw-config' ] as $dir ) {
+                       $this->readDir( $this->basepath . '/' . $dir );
+               }
+               foreach ( glob( $this->basepath . '/*.php' ) as $file ) {
+                       $this->readFile( $file );
+               }
+       }
 }
 
 /**
index c7bd395..9fc2431 100644 (file)
@@ -217,7 +217,7 @@ class BatchRowIterator implements RecursiveIterator {
         * `=` conditions while the final key uses a `>` condition
         *
         * Example output:
-        *        array( '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' )
+        *        [ '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' ]
         *
         * @return array The SQL conditions necessary to select the next set
         *  of rows in the batched query
index f3d72e8..dd3ea1b 100644 (file)
@@ -324,7 +324,7 @@ class MWCryptRand {
                                ": Falling back to using a pseudo random state to generate randomness.\n" );
                }
                while ( strlen( $buffer ) < $bytes ) {
-                       $buffer .= MWCryptHash::hmac( $this->randomState(), mt_rand() );
+                       $buffer .= MWCryptHash::hmac( $this->randomState(), strval( mt_rand() ) );
                        // This code is never really cryptographically strong, if we use it
                        // at all, then set strong to false.
                        $this->strong = false;
index f76e97e..62946bb 100644 (file)
@@ -63,7 +63,8 @@
                        "Jdforrester",
                        "Alaa",
                        "Izoozo",
-                       "علاء"
+                       "علاء",
+                       "Hhaboh162002"
                ]
        },
        "tog-underline": "سطر تحت الوصلات:",
        "tagline": "من {{SITENAME}}",
        "help": "مساعدة",
        "search": "بحث",
+       "search-ignored-headings": "# <!-- أترك هذا السطر كما هو --> <pre>\n# سيتم تجاهل الترويسات خلال عملية البحث\n#ا لتغييرات ستأخذ مجراها ما أن يتم فهرسة الصفحة التي تحتوي على ترويسات\n# يمكنك فرض عملية فهرسة الصفحة من خلال تعديل فارغ\n# الصيغة هي كالأتي:\n# * كل ما يكتب بعد \"#\" إلى آخر السطر يعتبر تعليق\n# * كل سطر غير فارغ سيكون العنوان الذي سيتم تجاهله (سيأخذ العنوان كما هو بالضبط بالتشكيل وخلافه)\nالمراجع\nالوصلات الخارجية\nأنظر أيضا\n#</pre><!--أترك هذا السطر كما هو -->",
        "searchbutton": "ابحث",
        "go": "اذهب",
        "searcharticle": "اذهب",
        "createacct-email-ph": "أدخل عنوان بريدك الإلكتروني",
        "createacct-another-email-ph": "أدخل عنوان البريد الإلكتروني",
        "createaccountmail": "استخدم كلمة سر عشوائية مؤقتة وارسلها إلى عنوان البريد الإلكتروني المحدد أدناه",
+       "createaccountmail-help": "يمكن استخدامه لإنشاء حساب لشخص آخر من دون معرفة كلمة المرور.",
        "createacct-realname": "الاسم الحقيقي (اختياري)",
        "createaccountreason": "السبب:",
        "createacct-reason": "السبب",
        "createacct-reason-ph": "لماذا تقوم بإنشاء حساب آخر",
+       "createacct-reason-help": "رسالة تظهر في سجل إنشاء الحسابات",
        "createacct-submit": "افتح الحساب",
        "createacct-another-submit": "أنشئ حسابا",
        "createacct-continue-submit": "مواصلة إنشاء الحساب",
        "savearticle": "احفظ الصفحة",
        "savechanges": "احفظ التغييرات",
        "publishpage": "نشر الصفحة",
-       "publishchanges": "انشر التغييرات",
+       "publishchanges": "نشر التغييرات",
        "preview": "عرض مسبق",
        "showpreview": "أظهر معاينة",
        "showdiff": "عرض التغييرات",
        "blankarticle": "<strong>تنبيه:</strong> الصفحة التي تريد إنشاءها فارغة. إذا نقرت \"{{int:savearticle}}\" ثانية فستنشأ الصفحة بدون محتوى.",
-       "anoneditwarning": "'''تحذير:''' لم تقم بالدخول.\nسيسجل عنوان الآيبي خاصتك في تاريخ هذه الصفحة.",
+       "anoneditwarning": "<strong>تحذير:</strong> أنت غير مسجل الدخول. عنوان الأيبي الخاص بك سيكون معروضا بشكل علني لو قمت بأي تعديلات. لو أنك <strong>[$1 سجلت الدخول]</strong> أو <strong>[$2 أنشأت حسابا]</strong>، فتعديلاتك ستنسب لاسم المستخدم الخاص بك، بالإضافة إلى فوائد أخرى.",
        "anonpreviewwarning": "''أنت غير مسجل الدخول. الحفظ سيسجل عنوان الأيبي الخاص بك في تاريخ هذه الصفحة.''",
        "missingsummary": "'''تنبيه:''' لم تقم بكتابة ملخص للتعديل.\nإذا قمت بضغط حفظ الصفحة مرة أخرى، فيتم حفظ تعديلك بدون ملخص.",
        "selfredirect": "<strong>تحذير:</strong> أنت تقوم بتحويل الصفحة إلى نفسها.\nربما حددت الهدف الخطأ للتحويلة أو أنك تقوم بتحرير الصفحة الخطأ.\n\nإذا نقرت على «{{int:savearticle}}» مرة أخرى، سيتم إنشاء التحويلة رغم الخطأ.",
        "content-model-css": "CSS",
        "content-json-empty-object": "غرض فارغ",
        "content-json-empty-array": "مصفوفة فارغة",
+       "deprecated-self-close-category": "صفحات تستخدم وسوم أتش تي أم أل غير صالحة",
        "duplicate-args-warning": "<strong>تنبيه:</strong> المدخل \"$3\" ل[[:$1]] المستعمل في [[:$2]] مكرر. آخر قيمة مكرر منه هي المعتمدة.",
        "duplicate-args-category": "صفحات تستعمل قالبا ببيانات مكررة",
        "duplicate-args-category-desc": "تحوي هذه الصفحة استدعاءات قالب تستخدم متغيرات مزدوجة مثل <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> أو <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "preferences": "تفضيلات",
        "mypreferences": "تفضيلات",
        "prefs-edits": "عدد التعديلات:",
-       "prefsnologintext2": "الرجاء $1 لضبط تفضيلات المستخدم.",
+       "prefsnologintext2": "الرجاء تسجيل الدخول لضبط تفضيلات المستخدم.",
        "prefs-skin": "واجهة",
        "skin-preview": "عرض مسبق",
        "datedefault": "لا تفضيل",
        "recentchangesdays-max": "الحد الأقصى {{PLURAL:$1|أقل من يوم|يوم واحد|يومان|$1 أيام|$1 يوما|$1 يوم}}",
        "recentchangescount": "عدد التعديلات الظاهرة مبدئيا:",
        "prefs-help-recentchangescount": "بما في ذلك أحدث التغييرات وتاريخ الصفحات والسجلات.",
-       "prefs-help-watchlist-token2": "Ù\87ذا Ù\87Ù\88 Ø§Ù\84Ù\85Ù\81تاح Ø§Ù\84سرÙ\8a Ù\84تغذÙ\8aØ© Ø§Ù\84Ù\88Ù\90ب لقائمة مراقبتك.\nيمكن لأي شخص يعرفه أن يقرأ قائمة مراقبتك، ولذا لا تتشاركه مع أحد. [[Special:ResetTokens|انقر هنا إذا أردت إعادة ضبطه]].",
+       "prefs-help-watchlist-token2": "Ù\87ذا Ù\87Ù\88 Ø§Ù\84Ù\85Ù\81تاح Ø§Ù\84سرÙ\8a Ù\84تغذÙ\8aØ© Ø§Ù\84Ù\88Ù\8aب لقائمة مراقبتك.\nيمكن لأي شخص يعرفه أن يقرأ قائمة مراقبتك، ولذا لا تتشاركه مع أحد. [[Special:ResetTokens|انقر هنا إذا أردت إعادة ضبطه]].",
        "savedprefs": "تم حفظ تفضيلاتك.",
        "savedrights": "حُفظت الصلاحيات الجديدة {{GENDER:$1|للمستخدم|للمستخدمة}} $1.",
        "timezonelegend": "المنطقة الزمنية:",
        "recentchanges-legend-heading": "<strong>شرح:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (راجع أيضا [[Special:NewPages|قائمة الصفحات الجديدة]])",
        "recentchanges-submit": "أظهر",
-       "rcnotefrom": "بالأسفل التغييرات منذ <strong>$2</strong> (إلى <strong>$1</strong> معروضة).",
+       "rcnotefrom": "بالأسفل {{PLURAL:$5|التغيير|التغييرات}} منذ <strong>$2</strong> (إلى <strong>$1</strong> معروضة).",
        "rclistfrom": "أظهر التغييرات بدء من $3 $2",
        "rcshowhideminor": "$1 التعديلات الطفيفة",
        "rcshowhideminor-show": "أظهر",
        "ignorewarnings": "تجاهل أية تحذيرات",
        "minlength1": "أسماء الملفات يجب أن تتكون من حرف واحد على الأقل.",
        "illegalfilename": "اسم الملف \"$1\" يحتوي على حروف غير مسموح بها في عناوين الصفحات.\nمن فضلك أعد تسمية الملف وحاول رفعه مرة أخرى.",
-       "filename-toolong": "Ø·Ù\88Ù\84 Ø£Ø³Ù\85اء Ø§Ù\84Ù\85Ù\84Ù\81ات Ù\8aجب Ø£Ù\86 Ù\84ا Ù\8aتجاÙ\88ز 240 Ø­Ø±Ù\81 (باÙ\8aت)",
+       "filename-toolong": "Ø·Ù\88Ù\84 Ø£Ø³Ù\85اء Ø§Ù\84Ù\85Ù\84Ù\81ات Ù\8aجب Ø£Ù\86 Ù\84ا Ù\8aتجاÙ\88ز 240 Ø¨Ø§Ù\8aت",
        "badfilename": "تم تغيير اسم الملف إلى \"$1\".",
        "filetype-mime-mismatch": "امتداد الملف \".$1\" لا يطابق نوع MIME للملف ($2).",
        "filetype-badmime": "من غير المسموح به رفع ملفات من النوع \"$1\".",
        "img-auth-nopathinfo": "PATH_INFO مفقود.\nخادومك ليس مضبوطاً لتمرير هذه المعلومة.\nقد يكون مبنياً على نظام CGI ولا يمكنه دعم img_auth.\nراجع https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "المسار المطلوب غير موجود في مجلد الرفع المضبوط.",
        "img-auth-badtitle": "تعذر تشكيل عنوان صالح من \"$1\".",
-       "img-auth-nologinnWL": "لست والجاً و\"$1\" ليست في القائمة البيضاء.",
+       "img-auth-nologinnWL": "لست والجا و\"$1\" ليست في القائمة البيضاء.",
        "img-auth-nofile": "الملف \"$1\" غير موجود.",
        "img-auth-isdir": "أنت تحاول الوصول إلى الدليل \"$1\".\nيسمح بوصول الملفات فقط.",
        "img-auth-streaming": "عرض \"$1\".",
        "listusers-noresult": "لم يتم إيجاد مستخدم.",
        "listusers-blocked": "(ممنوع)",
        "activeusers": "قائمة المستخدمين النشطين",
-       "activeusers-intro": "هذه قائمة بالمستخدمين الذين مارسوا نوعاً من النشاط خلال {{PLURAL:$1||اليوم الماضي|اليومين الماضيين|ال$1 أيام الماضية|ال$1 يوماً ماضياً|ال$1 يوم ماضي}}.",
-       "activeusers-count": "{{PLURAL:$1|لا أفعال|فعل واحد|فعلان اثنان|$1 أفعال|$1 فعلاً|$1 فعل}} منذ {{PLURAL:$3||يوم|يومين|$3 أيام|$3 يوماً|$1 يوم}}",
+       "activeusers-intro": "هذه قائمة بالمستخدمين الذين مارسوا نوعا من النشاط خلال {{PLURAL:$1||اليوم الماضي|اليومين الماضيين|ال$1 أيام الماضية|ال$1 يوما ماضيا|ال$1 يوم ماضي}}.",
+       "activeusers-count": "{{PLURAL:$1|لا أفعال|فعل واحد|فعلان اثنان|$1 أفعال|$1 فعلا|$1 فعل}} منذ {{PLURAL:$3||يوم|يومين|$3 أيام|$3 يوما|$1 يوم}}",
        "activeusers-from": "اعرض المستخدمين ابتداء من:",
        "activeusers-hidebots": "أخف البوتات",
        "activeusers-hidesysops": "أخف الإداريين",
        "mywatchlist": "قائمة مراقبتي",
        "watchlistfor2": "ل$1 $2",
        "nowatchlist": "لا توجد مدخلات في قائمة مراقبتك.",
-       "watchlistanontext": "الرجاء $1 لعرض أو تعديل الصفحات في قائمة مراقبتك.",
+       "watchlistanontext": "الرجاء تسجيل الدخول لعرض أو تعديل الصفحات في قائمة مراقبتك.",
        "watchnologin": "غير مسجل الدخول",
        "addwatch": "إضافة إلى قائمة المراقبة",
        "addedwatchtext": "\"[[:$1]]\" وصفحة نقاشها أضيفتا إلى [[Special:Watchlist|قائمة مراقبتك]].",
        "alreadyrolled": "لم يمكن استرجاع آخر تعديل ل[[$1]] بواسطة [[User:$2|$2]] ([[User talk:$2|نقاش]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]])؛\nشخص آخر عدل أو استرجع الصفحة بالفعل.\n\nآخر تعديل كان بواسطة [[User:$3|$3]] ([[User talk:$3|نقاش]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "ملخص التعديل كان:<em>$1</em>.",
        "revertpage": "استرجع تعديلات [[Special:Contributions/$2|$2]] ([[User talk:$2|نقاش]]) حتى آخر مراجعة ل[[User:$1|$1]]",
-       "revertpage-nouser": "استرجع تعديلات مستخدم مخفيّ حتى آخر مراجعة ل{{GENDER:$1|[[User:$1|$1]]}}",
+       "revertpage-nouser": "استرجع تعديلات مستخدم مخفي حتى آخر مراجعة ل{{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "استرجع تعديلات $1؛\nاسترجع حتى آخر نسخة بواسطة $2.",
        "sessionfailure-title": "فشل في الجلسة",
        "sessionfailure": "يبدو أنه هناك مشكلة في جلسة الدخول الخاصة بك؛\nلذلك فقد ألغيت هذه العملية كإجراء احترازي ضد الاختراق.\nمن فضلك اضغط على مفتاح \"رجوع\" لتحميل الصفحة التي جئت منها، ثم حاول مرة أخرى.",
        "whatlinkshere-prev": "{{PLURAL:$1|السابق|ال$1 السابقة}}",
        "whatlinkshere-next": "{{PLURAL:$1|التالية|ال$1 التالية}}",
        "whatlinkshere-links": "وصلات",
-       "whatlinkshere-hideredirs": "$1 Ø§Ù\84تحÙ\88Ù\8aÙ\84ات",
-       "whatlinkshere-hidetrans": "$1 Ø§Ù\84تضÙ\85Ù\8aÙ\86ات",
-       "whatlinkshere-hidelinks": "$1 الوصلات",
+       "whatlinkshere-hideredirs": "$1 تحويلات",
+       "whatlinkshere-hidetrans": "$1 تضمينات",
+       "whatlinkshere-hidelinks": "$1 وصلات",
        "whatlinkshere-hideimages": "$1 وصلات الملفات",
        "whatlinkshere-filters": "مرشحات",
        "whatlinkshere-submit": "اذهب",
        "autoblockid": "منع تلقائي #$1",
        "block": "امنع المستخدم",
        "unblock": "إلغاء منع مستخدم",
-       "blockip": "منع المستخدم",
+       "blockip": "منع {{GENDER:$1|المستخدم|المستخدمة}}",
        "blockip-legend": "منع المستخدم",
        "blockiptext": "استخدم النموذج التالي لمنع مستخدم، أو عنوان آيبي، معين من التعديل أو إنشاء حسابات جديدة. تُستخدم هذه العملية لمنع التخريب فقط، ويجب أن تتماشى مع [[{{MediaWiki:Policy-url}}|سياسة المنع]]. أدخل تعليلاً واضحًا لسبب المنع في الخانة المخصصة لذلك (مثلاً: ذكر صفحات محددة تمّ تخريبها من قبل المستخدم).",
        "ipaddressorusername": "عنوان الأيبي أو اسم المستخدم:",
        "ipb-unblock": "رفع المنع عن مستخدم أو عنوان أيبي",
        "ipb-blocklist": "عرض حالات المنع الحالية",
        "ipb-blocklist-contribs": "مساهمات $1",
+       "ipb-blocklist-duration-left": "يتبقى $1",
        "unblockip": "رفع المنع عن المستخدم",
        "unblockiptext": "استخدم الاستمارة أدناه لاسترجاع صلاحية الكتابة الخاصة بعنوان أيبي أو مستخدم تم سحبها منه مسبقا.",
        "ipusubmit": "ارفع هذا المنع",
        "lockdbsuccesstext": "لقد أغلقت قاعدة البيانات.<br />\nتذكر أن [[Special:UnlockDB|تزيل الغلق]] بعد اكتمال أعمال الصيانة.",
        "unlockdbsuccesstext": "تم إعادة فتح قاعدة البيانات",
        "lockfilenotwritable": "ملف غلق قاعدة البيانات لا يمكن الكتابة عليه.\nلغلق قاعدة البيانات أو إزالة الغلق يجب أن يكون هذا الملف قابلاً للكتابة من قبل خادوم الويب.",
+       "databaselocked": "قاعدة البيانات مقفلة بالفعل.",
        "databasenotlocked": "قاعدة البيانات ليست مغلقة.",
        "lockedbyandtime": "(من $1 على $2 في $3 )",
        "move-page": "نقل $1",
        "confirm-watch-top": "إضافة هذه الصفحة إلى قائمة مراقبتك؟",
        "confirm-unwatch-button": "موافق",
        "confirm-unwatch-top": "إزالة هذه الصفحة من قائمة مراقبتك؟",
+       "confirm-rollback-button": "موافق",
        "semicolon-separator": "؛&#32;",
        "comma-separator": "،&#32;",
        "quotation-marks": "«$1»",
        "api-error-missingparam": "خطأ داخلي : متغيرات مفقودة ضمن الطلب.",
        "api-error-missingresult": "خطأ داخلي : لا يمكن التحديد ما إذا كان النسخ ناجحاً.",
        "api-error-mustbeloggedin": "يجب أن تكون مسجلا في لتحميل الملفات.",
-       "api-error-mustbeposted": "خطأ داخلي: يتطلب طلب HTTP POST.",
+       "api-error-mustbeposted": "خطأ داخلي: الطلب يتطلب HTTP POST.",
        "api-error-noimageinfo": "نجح التحميل، ولكن الخادم لم يقدم لنا أي معلومات حول الملف.",
        "api-error-nomodule": "خطأ داخلي: لم يتم تعيين تحميل الوحدة النمطية.",
        "api-error-ok-but-empty": "خطأ داخلي : لم يكن هناك استجابة من الملقم.",
        "log-action-filter-block-reblock": "منع التعديل",
        "log-action-filter-block-unblock": "رفع المنع",
        "log-action-filter-delete-delete": "حذف الصفحات",
+       "log-action-filter-delete-restore": "استرجاع الصفحات",
        "log-action-filter-delete-event": "حذف السجلات",
        "log-action-filter-delete-revision": "حذف المراجعات",
        "log-action-filter-import-interwiki": "استيراد عابر للويكي",
        "log-action-filter-upload-overwrite": "إعادة الرفع",
        "authmanager-create-disabled": "إنشاء الحسابات معطل.",
        "authmanager-create-from-login": "لإنشاء حساب، برجاء ملء الحقول أدناه.",
+       "authmanager-retype-help": "كلمة المرور مرة أخرى للتأكيد.",
        "authmanager-email-label": "البريد الإلكتروني",
        "authmanager-email-help": "عنوان البريد الإلكتروني",
        "authmanager-realname-label": "الاسم الحقيقي",
        "authprovider-resetpass-skip-label": "تخطى",
        "authprovider-resetpass-skip-help": "تخطي إعادة تعيين كلمة المرور",
        "cannotauth-not-allowed-title": "الإذن مرفوض",
+       "changecredentials": "تغيير الاعتماد",
+       "changecredentials-submit": "تغيير الاعتماد",
+       "removecredentials": "إزالة الاعتماد",
+       "removecredentials-submit": "إزالة الاعتماد",
        "credentialsform-account": "اسم الحساب:",
        "cannotlink-no-provider-title": "لا توجد حسابات قابلة للربط",
        "cannotlink-no-provider": "لا توجد حسابات قابلة للربط",
index 38bba71..8f881e0 100644 (file)
        "recentchanges-label-unpatrolled": "التعديل ده مإتراجعش لسه",
        "recentchanges-legend-heading": "<strong>شرح</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (بص كمان على [[Special:NewPages|قايمه الصفحات الجديده]])",
-       "rcnotefrom": "دى التعديلات من '''$2''' (ل '''$1''' معروضه).",
+       "rcnotefrom": "{{PLURAL:$5|ده التعديل|دى التعديلات}} من اول <strong>$3, $4</strong> (لغايه<strong>$1</strong> معروضه).",
        "rclistfrom": "اظهر التعديلات بدايه من $3 $2",
        "rcshowhideminor": "$1 تعديلات صغيره",
        "rcshowhideminor-show": "اعرض",
        "upload_directory_read_only": "مجلد التحميل ($1) مش ممكن الكتابة عليه بواسطة سيرڨر الويب.",
        "uploaderror": "غلطه فى التحميل",
        "uploadtext": "استخدم الاستمارة علشان تحميل الملفات.\nلعرض أو البحث ف الملفات المتحملة سابقا، راجع عمليات المسح [[Special:Log/delete|deletion log]] [[Special:FileList|لستة الملفات المتحملة]]، عمليات التحميل  موجودة فى [[Special:Log/upload|سجل التحميل]].\n\nعلشان تحط صورة فى صفحة، استخدم الوصلات فى الصيغ التالية:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' علشان استخدام النسخة الكاملة لملف\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|نص بديل]]</nowiki></code>''' لاستخدام صورة عرضها 200 بكسل فى صندوق فى الجانب الأيسر مع 'نص بديل' كوصف\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' للوصل للملف مباشرة بدون عرض الملف.",
-       "upload-permitted": "أنواع الملفات المسموحة: $1.",
-       "upload-preferred": "أنواع الملفات المفضلة: $1.",
-       "upload-prohibited": "أنواع الملفات الممنوعة: $1.",
+       "upload-permitted": "{{PLURAL:$2|نوع|انواع}} الملفات اللى مسموح بيها: $1.",
+       "upload-preferred": "{{PLURAL:$2|نوع|انواع}} الملفات المفضله: $1.",
+       "upload-prohibited": "{{PLURAL:$2|نوع|انواع}} الملفات الممنوعه: $1.",
        "uploadlogpage": "سجل التحميل",
        "uploadlogpagetext": "تحت فية لستة بأحدث عمليات تحميل الملفات.\nانظر [[Special:NewFiles|معرض الملفات الجديدة]] لعرض بصرى أكتر",
        "filename": "اسم الملف",
        "mywatchlist": "لستة  الصفح اللى باراقبها",
        "watchlistfor2": "لليوزر $1 ($2)",
        "nowatchlist": "مافيش حاجة فى لستة مراقبتك.",
-       "watchlistanontext": "لو سمحت $1 لعرض أو تعديل الصفحات فى لستة مراقبتك.",
+       "watchlistanontext": "لو سمحت اعمل لوجين لعرض أو تعديل الصفحات فى لستة مراقبتك.",
        "watchnologin": "مش متسجل",
        "addedwatchtext": "تمت إضافة الصفحه  \"$1\"  [[Special:Watchlist|للستة الصفحات اللى بتراقبها]].\nالتعديلات اللى بعد كده ها تتحط على الصفحه دى، وصفحة المناقش الخاصه بها ها تتحط هناك. واسم الصفحة هايظهر  بخط <b>عريض</b> فى صفحة [[Special:RecentChanges|أحدث التعديلات]] لتسهيل تحديدها واكتشافها.",
        "removedwatchtext": "الصفحه دى اتشالت \"[[:$1]]\" من [[Special:Watchlist|لستة الصفحات اللى بتراقبها]].",
        "whatlinkshere-hidelinks": "$1 لينكات",
        "whatlinkshere-hideimages": "$1 وصلة صورة",
        "whatlinkshere-filters": "فلاتر",
-       "blockip": "منع يوزر",
+       "blockip": "بلوك {{GENDER:$1|اليوزر|اليوزره}}",
        "blockip-legend": "منع اليوزر",
        "blockiptext": "استخدم الاستمارة اللى تحت لمنع عنوان أيبى أو يوزر معين من الكتابة.\nدا لازم يحصل بس علشان تمنع التخريب ،و على حسب\n[[{{MediaWiki:Policy-url}}|السياسة]].\nاكتب سبب محدد تحت (يعنى مثلا، اكتب الصفحات المعينة اللى اتخربت بسببه).",
        "ipaddressorusername": "عنوان الأيبى أو اسم اليوزر:",
index 5760e81..7325d39 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ayuda",
        "search": "Buscar",
+       "search-ignored-headings": " #<!-- dexar esta llinia exactamente como ta --> <pre>\n# Testeres que nun se tendrán en cuenta na gueta.\n# Los cambios fechos equí son efeutivos nel momentu que s'indexa la páxina cola testera.\n# Pue forzar el reindexáu d'una páxina faciendo una edición nula.\n# La sintaxis ye la siguiente:\n#   * Tolo qu'hai dende un caráuter \"#\" al fin de llinia ye un comentariu\n#   * Cada llinia nun-balera ye'l títulu exactu a descartar, incluyendo mayúscules y demás\nReferencies\nEnllaces esternos\nVer tamién\n #</pre> <!-- dexar esta llinia exactamente como ta -->",
        "searchbutton": "Guetar",
        "go": "Dir",
        "searcharticle": "Dir",
index 16bf5bc..8554e0b 100644 (file)
        "minoredit": "Kiçik redaktə",
        "watchthis": "Bu səhifəni izlə",
        "savearticle": "Səhifəni qeyd et",
+       "publishpage": "Səhifəni yayımla",
+       "publishchanges": "Dəyişiklikləri yayımla",
        "preview": "Sınaq görüntüsü",
        "showpreview": "Sınaq göstərişi",
        "showdiff": "Dəyişiklikləri göstər",
index 89dbf65..84abebd 100644 (file)
        "tagline": "{{SITENAME}} проектынан",
        "help": "Белешмә",
        "search": "Эҙләү",
+       "search-ignored-headings": " #<!-- был юлды нисек бар шулай ҡалдырығыҙ --> <pre>\n# Эҙләүҙәр инҡар иткән атамалар.\n# Атамаһы булған бит индексланғас та үҙгәртмәләр үҙ көсөнә инәсәк.\n# Буш төҙәтеү менән һеҙ битте яңынан индекслата алаһығыҙ\n# Синтаксис шулай күренә:\n#   * Ошо символға «#» башланған юлдың аҙағына тиклем комментарий була\n#   * Һәр буш булмаған юл - инҡар ителгәндең атамаһы, быға регистр ҙа инә\nИҫкәрмәләр\nҺылтанмалар\nҠарағыҙ шулай уҡ\n#</pre> <!-- был юлды шул көйө ҡалдырығыҙ -->",
        "searchbutton": "Эҙләү",
        "go": "Күсеү",
        "searcharticle": "Күсеү",
        "wlshowtime": "Күрһәтеү өсөн ваҡыт арауығы",
        "wlshowhideminor": "Әҙ генә үҙгәрештәр",
        "wlshowhidebots": "Бот",
-       "wlshowhideliu": "Ñ\82анÑ\8bлÒ\93ан Ò¡Ñ\83лланÑ\8bÑ\83Ñ\81Ñ\8bлаÑ\80",
+       "wlshowhideliu": "Ñ\82еÑ\80кÓ\99лгÓ\99н Ò¡Ð°Ñ\82наÑ\88Ñ\8bÑ\83Ñ\81Ñ\8b",
        "wlshowhideanons": "Аноним ҡулланыусылар",
        "wlshowhidepatr": "Тикшерелгән төҙәтеүҙәр",
        "wlshowhidemine": "Минең үҙгәртеүҙәр",
        "logentry-delete-delete": "$1 $3 битен {{GENDER:$2|юйҙы}}",
        "logentry-delete-restore": "$1 $3 битен {{GENDER:$2|тергеҙҙе}}",
        "logentry-delete-event": "$1 журналдағы {{PLURAL:$5|яҙманы}} $3: $4 {{GENDER:$2|үҙгәртте}}",
-       "logentry-delete-revision": "$1 {{PLURAL:$5|$5 версияның}} күренеүсәнлеген   $3: $4 битендә {{GENDER:$2|үҙгәртте}}",
+       "logentry-delete-revision": "Ҡатнашыусы $1 $3: $4 битенең {{PLURAL:$5|$5 версиялары|$5 версияларының|1=версиялар}} күренешен {{GENDER:$2|үҙгәртте|үҙгәртте}}.",
        "logentry-delete-event-legacy": "$1  $3 журналы яҙмаларының күренеүсәнлеген {{GENDER:$2|үҙгәртте}}",
        "logentry-delete-revision-legacy": "$1  $3 битендә версияларҙың күренеүсәнлеген {{GENDER:$2|үҙгәртте}}",
        "logentry-suppress-delete": "$1 $3 битен {{GENDER:$2|баҫырылдырҙы}}",
index 2eba576..2396035 100644 (file)
@@ -16,7 +16,8 @@
                        "아라",
                        "Matthias Klostermayr",
                        "Macofe",
-                       "George Animal"
+                       "George Animal",
+                       "Lokal Profil"
                ]
        },
        "tog-underline": "Links unterstreichen:",
        "accountcreated": "Benytzerkonto is erstöid worn",
        "accountcreatedtext": "'s Benytzerkonto $1 is aigrichtt worn.",
        "loginlanguagelabel": "Sproch: $1",
+       "pt-login": "Eilogga",
        "changepassword": "Posswort ändern",
        "oldpassword": "Oids Posswort:",
        "newpassword": "Neichs Posswort:",
index 839d286..b3d7e8c 100644 (file)
        "tagline": "Gikan sa {{SITENAME}}",
        "help": "Katabangan",
        "search": "Maghanap",
+       "search-ignored-headings": " #<!-- walaton ining linya eksaktong siring sana kaini --> <pre> \n# Mga Kapamayuhanan na pinagpapabayaan sa paghahanap. \n# Mga Kaliwatan kaini magkaka-epekto matapos na an pahina na igwang kapamayuhanan maipaghukdo. \n# Ika makakapagpuwersa sa pahina na maihuhukdo otro sa paagi nin paghimo nin sarong blangko na pagliwat. # An Sintaks iyo ining minasunod: \n# * An gabos magpoon sa sarong karakter na \"#\" sagkod sa tapos kan linya iyo an sarong komento \n# * An lambang linya na bakong blangko iyo an eksaktong titulo na pababayaan, kaso asin gabos na bagay \nMga Panultulan\nPanluwas na mga sugpon\nHilingon man \n#</pre> <!-- walaton ining linya eksaktong siring sana kaini -->",
        "searchbutton": "Maghanap",
        "go": "Dumani",
        "searcharticle": "Lakaw",
        "expand_templates_generate_xml": "Ipahiling an panlunhay na kahoy nin XML",
        "expand_templates_preview": "Patânaw",
        "mw-widgets-dateinput-placeholder-day": "TTTT-BB-AA",
-       "mw-widgets-dateinput-placeholder-month": "TTTT-BB",
-       "api-error-blacklisted": "Pakipili tabi nin sarong nalalaen, deskriptibong titulo."
+       "mw-widgets-dateinput-placeholder-month": "TTTT-BB"
 }
index e8bcee2..fd87b0f 100644 (file)
        "tagline": "Зьвесткі з {{GRAMMAR:родны|{{SITENAME}}}}",
        "help": "Дапамога",
        "search": "Пошук",
+       "search-ignored-headings": " #<!-- не зьмяняйце гэты радок --> <pre>\n# Загалоўкі, якія мусіць ігнараваць пошукавы рухавік.\n# Зьмены будуць ужытыя па наступным індэксаваньні старонкі.\n# Вы можаце змусіць пераіндэксаваць старонку пустым рэдагаваньнем.\n# Сынтакс наступны:\n#   * Усё, што пачынаецца з \"#\" — камэнтар\n#   * Усякі непусты радок — загаловак, які трэба ігнараваць\nКрыніцы\nВонкавыя спасылкі\nГлядзіце таксама\n #</pre> <!-- не зьмяняйце гэты радок -->",
        "searchbutton": "Пошук",
        "go": "Старонка",
        "searcharticle": "Старонка",
        "passwordreset": "Ачыстка паролю",
        "passwordreset-text-one": "Запоўніце гэтую форму, каб атрымаць часовы пароль электроннай поштай.",
        "passwordreset-text-many": "{{PLURAL:$1|Запоўніце адно з палёў, каб атрымаць часовы пароль праз электронную пошту.}}",
-       "passwordreset-disabled": "Ð\9cагÑ\87Ñ\8bмаÑ\81Ñ\8cÑ\86Ñ\8c Ð°Ñ\87Ñ\8bÑ\81Ñ\82кÑ\96 Ð¿Ð°Ñ\80олÑ\8e Ð±Ñ\8bла Ð·Ð°Ð±Ð°Ñ\80оненаÑ\8f Ñ\9e {{GRAMMAR:меÑ\81нÑ\8b|{{SITENAME}}}}.",
-       "passwordreset-emaildisabled": "Функцыі e-mail у гэтай вікі былі адключаныя.",
+       "passwordreset-disabled": "Ð\9cагÑ\87Ñ\8bмаÑ\81Ñ\8cÑ\86Ñ\8c Ð°Ñ\87Ñ\8bÑ\81Ñ\82кÑ\96 Ð¿Ð°Ñ\80олÑ\8e Ð±Ñ\8bла Ð°Ð´ÐºÐ»Ñ\8eÑ\87анаÑ\8f Ñ\9e Ð³Ñ\8dÑ\82ай Ð²Ñ\96кÑ\96.",
+       "passwordreset-emaildisabled": "Функцыі электроннай пошты ў гэтай вікі былі адключаныя.",
        "passwordreset-username": "Імя ўдзельніка:",
        "passwordreset-domain": "Дамэн:",
        "passwordreset-capture": "Паказаць канчатковы электронны ліст?",
        "action-applychangetags": "дадаваньне метак пры рэдагаваньні",
        "action-changetags": "дадаваньне і выдаленьне адвольных метак да асобных вэрсіяў і запісаў у журнале падзеяў",
        "action-deletechangetags": "выдаленьне метак з базы зьвестак",
+       "action-purge": "ачыстку кэшу гэтай старонкі",
        "nchanges": "$1 {{PLURAL:$1|зьмена|зьмены|зьменаў}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|з апошняга візыту}}",
        "enhancedrc-history": "гісторыя",
        "pagelang-language": "Мова",
        "pagelang-use-default": "Ужываць мову па змоўчаньні",
        "pagelang-select-lang": "Абярыце мову",
+       "pagelang-submit": "Адправіць",
        "right-pagelang": "Зьмяніць мову старонкі",
        "action-pagelang": "зьмену мовы старонкі",
        "log-name-pagelang": "Журнал зьменаў мовы",
        "special-characters-group-ipa": "МФА (IPA)",
        "special-characters-group-symbols": "Сымбалі",
        "special-characters-group-greek": "Грэцкія",
+       "special-characters-group-greekextended": "Пашыраная грэцкая",
        "special-characters-group-cyrillic": "Кірылічныя",
        "special-characters-group-arabic": "Арабскія",
        "special-characters-group-arabicextended": "Арабскія пашыраныя",
        "mw-widgets-titleinput-description-new-page": "старонка яшчэ не існуе",
        "mw-widgets-titleinput-description-redirect": "перанакіраваньне на $1",
        "randomrootpage": "Выпадковая карэнная старонка",
+       "log-action-filter-block": "Тып блякаваньня:",
+       "log-action-filter-delete": "Тып выдаленьня:",
+       "log-action-filter-import": "Тып імпарту:",
+       "log-action-filter-move": "Тып пераносу:",
+       "log-action-filter-all": "Усе",
        "changecredentials": "Зьмена ўліковых зьвестак",
        "removecredentials": "Выдаленьне ўліковых зьвестак",
        "removecredentials-submit": "Выдаліць уліковыя зьвесткі",
index 14c32f3..a5c5a14 100644 (file)
        "action-managechangetags": "ট্যাগ তৈরি ও সক্রিয়/নিষ্ক্রিয়",
        "action-applychangetags": "আপনার পরিবর্তনগুলোর সাথে ট্যাগ সংযোজন করুন",
        "action-changetags": "নির্দিষ্ট সংস্করণ এবং দীর্ঘ সম্পাদনাগুলোতে ট্যাগ সংযোজন ও অপসারণ করুন",
+       "action-purge": "এই পাতা হালনাগাদ করুন",
        "nchanges": "$1টি {{PLURAL:$1|পরিবর্তন}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|সর্বশেষ প্রদর্শনের পর}} $1টি",
        "enhancedrc-history": "ইতিহাস",
        "watchnologin": "আপনি প্রবেশ করেননি",
        "addwatch": "নজরতালিকায় যোগ করো",
        "addedwatchtext": "\"[[:$1]]\" ও এর আলোচনা পাতাটি আপনার [[Special:Watchlist|নজরতালিকাতে]] যোগ করা হয়েছে।",
+       "addedwatchtext-talk": "\"[[:$1]]\" ও এর সাথে জড়িত পাতা আপনার [[Special:Watchlist|নজরতালিকাতে]] যোগ করা হয়েছে।",
        "addedwatchtext-short": "\"$1\" পাতাটি আপনার নজরতালিকায় যোগ করা হয়েছে।",
        "removewatch": "নজরতালিকা থেকে অপসারণ",
        "removedwatchtext": "\"[[:$1]]\" ও এর আলোচনা পাতাটি আপনার [[Special:Watchlist|নজরতালিকা]] থেকে সরানো হয়েছে।",
+       "removedwatchtext-talk": "\"[[:$1]]\" ও এর সাথে জড়িত পাতা আপনার [[Special:Watchlist|নজরতালিকা]] থেকে সরানো হয়েছে।",
        "removedwatchtext-short": "\"$1\" পাতাটি আপনার নজরতালিকা থেকে সরিয়ে নেয়া হয়েছে।",
        "watch": "নজর রাখুন",
        "watchthispage": "নজরে রাখুন",
index 482c3ba..5553398 100644 (file)
        "tagline": "ཡོང་ཁུངས་{{SITENAME}}",
        "help": "ཕན་གྲོགས།",
        "search": "འཚོལ་བ།",
+       "search-ignored-headings": " #<!-- སྟར་པ་འདི་སྔར་གྱི་ཇི་མ་ཇི་འཞིན་དུ་འཇོག་རོགས། --> <pre>\n# འགོ་བརྗོད་དེ་འཚོལ་ཞིབ་ནང་སྣང་མེད་དུ་བསྐྱུར་རོགས།\n# ཤོག་ངོས་འདིའི་འགོ་བརྗོད་ལ་ཐོ་འགོད་རེའུ་མིག་དུ་འགོད་ཚར་མ་ཐག་འགྱུར་བ་རྣམས་མངོན་ཐུབ།\n# ཁྱེད་ཀྱི་རྩོམ་སྒྲིག་སྟོང་པ་དྱས་མ་ཐག་ཤོག་ངོས་འདི་དབང་ཤུགས་ཀྱི་ཐོ་འགོད་རེའུ་མིག་དུ་འགོད་ཐུབ།\n# ཚིག་སྦྱོར་རྣམས་གཤམ་གསལ་ལྟར་དཀོད་རོགས།\n#   * ཡིག་འབྲུ་\"#\" ནས་སྟར་པའི་འཇུག་བར་ཚང་མ་མཆན་འགྲེལ་ཡིན།\n#   * སྟོང་ཆ་མེད་པའི་སྟར་པ་འདི་སྣང་མེད་དུ་བསྐྱུར་དགོས་པའི་འགོ་བརྗོད་ཡིན། \nཟུར་མཆན།\nཕྱི་ཕྱོགས་སྦྲེལ་མཐུད།\nའདིར་ཡང་གཟིགས་རོགས།\n #</pre> <!-- སྟར་པ་འདི་སྔར་གྱི་ཇི་མ་ཇི་འཞིན་དུ་འཇོག་རོགས། -->",
        "searchbutton": "འཚོལ།",
        "go": "སོང་།",
        "searcharticle": "འཚོལ།",
index cdf6cb1..82c9d61 100644 (file)
@@ -65,7 +65,7 @@
        "tog-ccmeonemails": "Pošalji mi kopije e-pošte koju pošaljem drugim korisnicima",
        "tog-diffonly": "Ne prikazuj sadržaj stranice ispod razlika",
        "tog-showhiddencats": "Prikaži skrivene kategorije",
-       "tog-norollbackdiff": "Izostavi razliku nakon vraćanja",
+       "tog-norollbackdiff": "Ne prikazuj razliku nakon izvršenog vraćanja",
        "tog-useeditwarning": "Upozori me kad napuštam stranicu za izmjene bez sačuvanih promjena",
        "tog-prefershttps": "Uvijek koristi sigurnu konekciju kada sam prijavljen.",
        "underline-always": "Uvijek",
        "minoredit": "Ovo je manja izmjena",
        "watchthis": "Prati ovu stranicu",
        "savearticle": "Sačuvaj stranicu",
+       "publishpage": "Objavi stranicu",
+       "publishchanges": "Objavi izmjene",
        "preview": "Pregled stranice",
        "showpreview": "Prikaži izgled",
        "showdiff": "Prikaži izmjene",
        "revdelete-unsuppress": "Ukloni ograničenja na vraćenim revizijama",
        "revdelete-log": "Razlog:",
        "revdelete-submit": "Primijeni na odabrane {{PLURAL:$1|reviziju|revizije}}",
-       "revdelete-success": "'''Vidljivost revizije uspješno ažurirana.'''",
+       "revdelete-success": "'''Vidljivost izmjene je ažurirana.'''",
        "revdelete-failure": "'''Vidljivost revizije nije mogla biti ažurirana:'''\n$1",
        "logdelete-success": "'''Vidljivost evidencije uspješno postavljena.'''",
        "logdelete-failure": "'''Zapisnik vidljivosti nije mogao biti postavljen:'''\n$1",
        "rightslogtext": "Ovo je zapisnik promjena korisničkih prava.",
        "action-read": "čitate ovu stranicu",
        "action-edit": "uređujete ovu stranicu",
-       "action-createpage": "napravite stranicu",
-       "action-createtalk": "kreirate stranice za razgovor",
+       "action-createpage": "napravite ovu stranicu",
+       "action-createtalk": "pravite stranice za razgovor",
        "action-createaccount": "napravite ovaj korisnički račun",
        "action-history": "gledate historiju ove stranice",
        "action-minoredit": "da označite ovu izmjenu kao malu",
        "action-viewmyprivateinfo": "pogledajte svoje privatne informacije",
        "action-editmyprivateinfo": "uredite svoje privatne podatke",
        "action-editcontentmodel": "uredi model sadržaja stranice",
-       "action-managechangetags": "napravite i uklonite oznake iz baze podataka",
+       "action-managechangetags": "pravite i (de)aktivirate oznake",
        "action-applychangetags": "dodate oznake uz vaše izmjene",
        "action-changetags": "dodate ili uklonite razne oznake na pojedinačnim verzijama i unosima u zapisnicima",
        "nchanges": "$1 {{PLURAL:$1|promjena|promjene|promjena}}",
index 85468aa..965b9b3 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ajuda",
        "search": "Cerca",
+       "search-ignored-headings": " #<!-- deixeu aquesta línia tal com està --> <pre>\n# Títols que seran ignorats pel cercador.\n# Els canvis fets aquí tindran efecte tant aviat com la pàgina amb el títol sigui indexada.\n# Podeu forçar que una pàgina s'indexi de nou fent una edició nul·la.\n# La sintaxi és la següent:\n#   * Tot el que hi hagi des d'un caràcter \"#\" fins el final de línia és un comentari\n#   * Tota línia no buida és el títol exacte a ignorar, amb les majúscules i complet\nReferències\nEnllaços externs\nVegeu també\n #</pre> <!-- deixeu aquesta línia tal com està -->",
        "searchbutton": "Cerca",
        "go": "Vés-hi",
        "searcharticle": "Vés-hi",
        "grant-editprotected": "Modifica pàgines protegides",
        "grant-highvolume": "Edició d'alt volum",
        "grant-oversight": "Amaga usuaris i suprimeix revisions",
+       "grant-patrol": "Patrulla els canvis de les pàgines",
        "grant-protect": "Protecció i desprotecció de pàgines",
        "grant-rollback": "Reversió de canvis en pàgines",
        "grant-sendemail": "Enviament de correus a altres usuaris",
        "sp-contributions-username": "Adreça IP o nom d'usuari:",
        "sp-contributions-toponly": "Mostra només les darreres revisions",
        "sp-contributions-newonly": "Mostra només modificacions que són creacions de pàgina",
+       "sp-contributions-hideminor": "Amaga les edicions menors",
        "sp-contributions-submit": "Cerca",
        "whatlinkshere": "Què hi enllaça",
        "whatlinkshere-title": "Pàgines que enllacen amb «$1»",
        "tooltip-ca-nstab-category": "Vegeu la pàgina de la categoria",
        "tooltip-minoredit": "Marca-ho com una modificació menor",
        "tooltip-save": "Deseu els canvis",
+       "tooltip-publish": "Publica els canvis",
        "tooltip-preview": "Reviseu els vostres canvis, feu-ho abans de desar res!",
        "tooltip-diff": "Mostra quins canvis heu fet al text",
        "tooltip-compareselectedversions": "Vegeu les diferències entre les dues versions seleccionades d'aquesta pàgina.",
        "pageinfo-category-files": "Nombre d'arxius",
        "markaspatrolleddiff": "Marca com a supervisat",
        "markaspatrolledtext": "Marca la pàgina com a supervisada",
+       "markaspatrolledtext-file": "Marc la versió del fitxer com patrullada",
        "markedaspatrolled": "Marca com a supervisat",
        "markedaspatrolledtext": "S'ha marcat com a patrullada la revisió seleccionada de [[:$1]].",
        "rcpatroldisabled": "S'ha inhabilitat la supervisió dels canvis recents",
        "log-action-filter-delete-restore": "Restauració de pàgines",
        "log-action-filter-delete-event": "Registre de supressió",
        "log-action-filter-delete-revision": "Supressió de revisions",
+       "log-action-filter-managetags-create": "Creació de l'etiqueta",
+       "log-action-filter-managetags-delete": "Supressió de l'etiqueta",
+       "log-action-filter-managetags-activate": "Activació de l'etiqueta",
+       "log-action-filter-newusers-autocreate": "Creació automàtica",
        "log-action-filter-patrol-patrol": "Patrullatge manual",
        "log-action-filter-patrol-autopatrol": "Patrullatge automàtic",
        "log-action-filter-protect-protect": "Protecció",
index eca5136..2773c85 100644 (file)
        "activeusers-hidebots": "Къайлабаха боташ",
        "activeusers-hidesysops": "Къайлабаха куьйгалхой",
        "activeusers-noresult": "Декъашхой цакарий.",
+       "activeusers-submit": "Гайта жигара декъашхой",
        "listgrouprights": "Декъашхойн тобанийн бакъонаш",
        "listgrouprights-summary": "Лахахьа гойту декъашхошна яла йиш йолу бакъонаш. [[{{MediaWiki:Listgrouprights-helppage}}|хьажа кхин хааме]].",
        "listgrouprights-key": "Легенда:\n* <span class=\"listgrouprights-granted\">Ела бакъонаш</span>\n* <span class=\"listgrouprights-revoked\">ДӀаяьхна бакъонаш</span>",
index 5214d3f..86a7951 100644 (file)
@@ -32,7 +32,8 @@
                        "LordMsz",
                        "Matma Rex",
                        "Dvorapa",
-                       "Walter Klosse"
+                       "Walter Klosse",
+                       "Martin Urbanec"
                ]
        },
        "tog-underline": "Podtrhávat odkazy:",
        "tagline": "Z {{grammar:2sg|{{SITENAME}}}}",
        "help": "Nápověda",
        "search": "Hledat",
+       "search-ignored-headings": " #<!-- tento řádek ponechte beze změny --> <pre>\n# Zde uvedené nadpisy budou ignorovány vyhledáváním.\n# Změny této stránky se projeví ve chvíli, kdy je stránka používající příslušný nadpis indexována.\n# Přeindexování stránky můžete vynutit prázdnou editací.\n# Syntaxe je taková:\n#   * Cokoli od znaku „#“ do konce řádky je komentář.\n#   * Každá neprázdná řádka je přesný nadpis, který se má ignorovat, včetně velikosti písmen a tak.\nReference\nExterní odkazy\nSouvisející články\nSouvisející stránky\n #</pre> <!-- tento řádek ponechte beze změny -->",
        "searchbutton": "Hledat",
        "go": "Jít na",
        "searcharticle": "Jít na",
        "content-model-css": "CSS",
        "content-json-empty-object": "Prázdný objekt",
        "content-json-empty-array": "Prázdné pole",
-       "deprecated-self-close-category": "Stránky s neplatnými sebeuzavírajícími se HTML značkami",
-       "deprecated-self-close-category-desc": "Stránka obsahuje neplatné sebeuzavírající se HTML značky, například <code>&lt;b/></code> nebo <code>&lt;span/></code>. Jejich chování se v zájmu konzistence se specifikací HTML5 brzy změní, proto je jejich použití ve wikitextu zastaralé.",
+       "deprecated-self-close-category": "Stránky s neplatnými sebeuzavírajícími HTML značkami",
+       "deprecated-self-close-category-desc": "Stránka obsahuje neplatné sebeuzavírající HTML značky, například <code>&lt;b/></code> nebo <code>&lt;span/></code>. Jejich chování se v zájmu konzistence se specifikací HTML5 brzy změní, proto je jejich použití ve wikitextu zastaralé.",
        "duplicate-args-warning": "<strong>Upozornění:</strong> Stránka [[:$1]] volá [[:$2]] s více než jednou hodnotou parametru „$3“. Použije se jen poslední uvedená hodnota.",
        "duplicate-args-category": "Stránky s duplicitními argumenty ve voláních šablon",
        "duplicate-args-category-desc": "Stránka obsahuje volání šablony, které používá duplicitní argumenty, např. <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> nebo <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "action-applychangetags": "přidávat značky k vlastním změnám",
        "action-changetags": "přidávat libovolné značky na jednotlivé revize a protokolovací záznamy a odebírat je",
        "action-deletechangetags": "mazat značky z databáze",
+       "action-purge": "vyčistit vyrovnávací paměť této stránky",
        "nchanges": "$1 {{PLURAL:$1|změna|změny|změn}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od poslední návštěvy}}",
        "enhancedrc-history": "historie",
        "querypage-disabled": "Tato speciální stránka je z výkonnostních důvodů vypnuta.",
        "apihelp": "Nápověda k API",
        "apihelp-no-such-module": "Modul „$1“ nebyl nalezen.",
-       "apisandbox": "API pískoviště",
-       "apisandbox-jsonly": "Pro použití API pískoviště je nutný JavaScript.",
+       "apisandbox": "Pískoviště API",
+       "apisandbox-jsonly": "Pro použití pískoviště API je nutný JavaScript.",
        "apisandbox-api-disabled": "API je na tomto webu vypnuto.",
        "apisandbox-intro": "Pomocí této stránky můžete experimentovat s <strong>webovými službami MediaWiki API</strong>.\nPodrobnosti využití API najdete v [[mw:API:Main page|jeho dokumentaci]]. Příklad: [https://www.mediawiki.org/wiki/API#A_simple_example získání obsahu Hlavní stránky]. Další příklady uvidíte vybráním parametru action.\n\nUvědomte si, že přestože jste na pískovišti, mohou akce provedené na této stránce wiki změnit.",
        "apisandbox-fullscreen": "Rozbalit panel",
        "listgrouprights-namespaceprotection-header": "Omezení jmenných prostorů",
        "listgrouprights-namespaceprotection-namespace": "Jmenný prostor",
        "listgrouprights-namespaceprotection-restrictedto": "Oprávnění umožňující uživateli editovat",
-       "listgrants": "Svolení",
-       "listgrants-summary": "Následující seznam obsahuje svolení a jim odpovídající přístup k uživatelským právům. Uživatelé mohou aplikace autorizovat k využití jejich účtu, ale s omezenými právy na základě svolení, která uživatel aplikaci poskytl. Aplikace konající jménem uživatele ale nemůže využít oprávnění, která uživatel nemá.\nK jednotlivým oprávněním mohou existovat [[{{MediaWiki:Listgrouprights-helppage}}|doplňující informace]].",
-       "listgrants-grant": "Svolení",
+       "listgrants": "Skupiny oprávnění",
+       "listgrants-summary": "Následující seznam obsahuje skupiny oprávnění a jim odpovídající přístup k uživatelským právům. Uživatelé mohou aplikace autorizovat k využití jejich účtu, ale s omezenými právy na základě skupin oprávnění, která uživatel aplikaci dovolil použít. Aplikace konající jménem uživatele ale nemůže využít oprávnění, která uživatel nemá.\nK jednotlivým oprávněním mohou existovat [[{{MediaWiki:Listgrouprights-helppage}}|doplňující informace]].",
+       "listgrants-grant": "Skupina oprávnění",
        "listgrants-rights": "Oprávnění",
        "trackingcategories": "Sledovací kategorie",
        "trackingcategories-summary": "Tato stránka obsahuje seznam sledovacích kategorií, které automaticky přidává software MediaWiki. Jejich jména lze změnit úpravou příslušných systémových hlášení ve jmenném prostoru {{ns:8}}.",
        "watchnologin": "Nejste přihlášen(a)",
        "addwatch": "Přidat do sledovaných stránek",
        "addedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly přidány mezi [[Special:Watchlist|stránky, které sledujete]].",
+       "addedwatchtext-talk": "„[[:$1]]“ a související stránka byly přidány mezi [[Special:Watchlist|stránky, které sledujete]].",
        "addedwatchtext-short": "Stránka „$1“ byla přidána mezi stránky, které sledujete.",
        "removewatch": "Vyřadit ze sledovaných stránek",
-       "removedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly vyřazeny z vašeho [[Special:Watchlist|seznamu sledovaných stránek]].",
+       "removedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly vyřazeny ze [[Special:Watchlist|stránek, které sledujete]]",
+       "removedwatchtext-talk": "„[[:$1]]“ a související stránka byly vyřazeny ze [[Special:Watchlist|stránek, které sledujete]].",
        "removedwatchtext-short": "Stránka „$1“ byla vyřazena z vašeho seznamu sledovaných stránek.",
        "watch": "Sledovat",
        "watchthispage": "Sledovat tuto stránku",
index c643580..a1a9953 100644 (file)
@@ -17,7 +17,8 @@
                        "Matma Rex",
                        "Diafol",
                        "Nemo bis",
-                       "Dafyddt"
+                       "Dafyddt",
+                       "Jdforrester"
                ]
        },
        "tog-underline": "Tanlinellu cysylltiadau:",
        "minoredit": "Golygiad bychan yw hwn",
        "watchthis": "Gwylier y dudalen hon",
        "savearticle": "Cadw'r dudalen",
+       "publishpage": "Cyhoeddi tudalen",
+       "publishchanges": "Cyhoeddi newidiadau",
        "preview": "Rhagolwg",
        "showpreview": "Dangos rhagolwg",
        "showdiff": "Dangos newidiadau",
        "special-characters-title-emdash": "heiffen em",
        "special-characters-title-minus": "arwydd minws",
        "mw-widgets-dateinput-placeholder-day": "BBBB-MM-DD",
-       "mw-widgets-dateinput-placeholder-month": "BBBB-MM",
-       "api-error-blacklisted": "Dewiswch deitl gwahanol sy'n disgrifio'r gwaith, os gwelwch yn dda."
+       "mw-widgets-dateinput-placeholder-month": "BBBB-MM"
 }
index aa6b2f0..9833f1a 100644 (file)
        "tagline": "Fra {{SITENAME}}",
        "help": "Hjælp",
        "search": "Søg",
+       "search-ignored-headings": " #<!-- lad denne linje være præcis som den er --> <pre>\n# Overskrifter, der vil blive ignoreret af søgning.\n# Ændringer til dette træder i kraft så snart siden med overskriften er indekseret.\n# Du kan tvinge siden til genindeksering ved at lave en nul redigering.\n# syntaksen er som følger:\n#   * Alt fra en tegnet \"#\" til slutningen af linjen er en kommentar\n#   * Hver ikke-tomme linje er den nøjagtige titel der skal ignoreres, der skelnes også mellem store og små bogstaver\nReferencer\nEksterne henvisninger\nSe også\nKilder og henvisninger\nEksterne kilder/henvisninger\nKilder\n #</pre> <!-- lad denne linje være præcis som den er -->",
        "searchbutton": "Søg",
        "go": "Gå til",
        "searcharticle": "Gå til",
        "mw-widgets-dateinput-placeholder-month": "ÅÅÅÅ-MM",
        "mw-widgets-titleinput-description-new-page": "side eksisterer ikke endnu",
        "mw-widgets-titleinput-description-redirect": "omdiriger til $1",
-       "api-error-blacklisted": "Vælg venligst en anden, beskrivende titel.",
        "randomrootpage": "Tilfældig stamside",
        "log-action-filter-block": "Blokeringstype:",
        "log-action-filter-move": "Flyttetype:",
index cecccf6..60e8456 100644 (file)
        "tagline": "Aus {{SITENAME}}",
        "help": "Hilfe",
        "search": "Suche",
+       "search-ignored-headings": " #<!-- diese Zeile nicht verändern --> <pre>\n# Überschriften, die von der Suche ignoriert werden.\n# Diese Änderungen werden wirksam, sobald die Seite mit der Überschrift indexiert wurde.\n# Du kannst die Seitenindexierung erzwingen, indem du einen Nulledit durchführst.\n# Syntax:\n#   * Alles, was einer Raute („#“) bis zum Zeilenende folgt, ist ein Kommentar.\n#   * Jede nicht-leere Zeile ist der exakte zu ignorierende Titel.\nEinzelnachweise\nWeblinks\nSiehe auch\n #</pre> <!-- diese Zeile nicht verändern -->",
        "searchbutton": "Suchen",
        "go": "Ausführen",
        "searcharticle": "Seite",
        "action-applychangetags": "Markierungen zusammen mit deinen Änderungen anzuwenden",
        "action-changetags": "beliebige Markierungen zu einzelnen Versionen und Logbucheinträgen hinzuzufügen und zu entfernen",
        "action-deletechangetags": "Markierungen aus der Datenbank zu löschen",
+       "action-purge": "den Cache dieser Seite zu leeren",
        "nchanges": "$1 {{PLURAL:$1|Änderung|Änderungen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|seit dem letzten Besuch}}",
        "enhancedrc-history": "Versionsgeschichte",
        "watchnologin": "Du bist nicht angemeldet",
        "addwatch": "Zur Beobachtungsliste hinzufügen",
        "addedwatchtext": "„[[:$1]]“ und die Diskussionsseite wurden zu deiner [[Special:Watchlist|Beobachtungsliste]] hinzugefügt.",
+       "addedwatchtext-talk": "„[[:$1]]“ und ihre dazugehörige Seite wurden zu deiner [[Special:Watchlist|Beobachtungsliste]] hinzugefügt.",
        "addedwatchtext-short": "Die Seite „$1“ wurde zu deiner Beobachtungsliste hinzugefügt.",
        "removewatch": "Von der Beobachtungsliste entfernen",
        "removedwatchtext": "„[[:$1]]“ und die Diskussionsseite wurden von deiner [[Special:Watchlist|Beobachtungsliste]] entfernt.",
+       "removedwatchtext-talk": "„[[:$1]]“ und ihre dazugehörige Seite wurden von deiner [[Special:Watchlist|Beobachtungsliste]] entfernt.",
        "removedwatchtext-short": "Die Seite „$1“ wurde von deiner Beobachtungsliste entfernt.",
        "watch": "Beobachten",
        "watchthispage": "Seite beobachten",
index 579985d..11b289a 100644 (file)
@@ -23,7 +23,8 @@
                        "Calak",
                        "Macofe",
                        "Matma Rex",
-                       "Kumkumuk"
+                       "Kumkumuk",
+                       "Gırd"
                ]
        },
        "tog-underline": "Bınê gırey de xete bance:",
        "april-date": "Nisane $1",
        "may-date": "Gulane $1",
        "june-date": "{{PLURAL:$1|1=1ᵉ|$1}} Heziran",
-       "july-date": "Temuze $1",
+       "july-date": "Temuz $1",
        "august-date": "Tebaxe $1",
        "september-date": "Keşkelun $1",
-       "october-date": "Tışrino Verên $1",
-       "november-date": "Tışrino Peyên $1",
+       "october-date": "$1 Cetan",
+       "november-date": "$1 Kelverdan",
        "december-date": "Kanun $1",
        "period-am": "AM",
        "period-pm": "PM",
        "about": "Heqa cı de",
        "article": "Pela zerreki",
        "newwindow": "(pençereyê newey de beno a)",
-       "cancel": "Peyd ke",
+       "cancel": "Bıtexelne",
        "moredotdotdot": "Vêşi...",
        "morenotlisted": "Vêşi lista nêbi...",
        "mypage": "Pele",
        "faq": "PZP",
        "faqpage": "Project: PZP",
        "actions": "Hereketi",
-       "namespaces": "Heruna naman",
+       "namespaces": "Heruna nameyan",
        "variants": "Varyanti",
        "navigation-heading": "Menuyê navigasyoni",
        "errorpagetitle": "Xeta",
        "search": "Cı geyre",
        "searchbutton": "Cı geyre",
        "go": "Şo",
-       "searcharticle": "So",
+       "searcharticle": "Şo",
        "history": "Tarixê pele",
        "history_short": "Tarix",
        "updatedmarker": "cıkewtena mına peyêne ra dıme biyo rocane",
-       "printableversion": "Versiyonê nusterin",
-       "permalink": "Gıreyo jûqere",
+       "printableversion": "Asayışê çapkerdışi",
+       "permalink": "Gıreyo daimi",
        "print": "Çap ke",
        "view": "Bıvêne",
-       "view-foreign": "$1'i bıvin",
+       "view-foreign": "$1 de bıvêne",
        "edit": "Bıvurne",
        "edit-local": "Şınasnayışê lokali bıvurne",
-       "create": "Vıraze",
+       "create": "Bıvıraz",
        "create-local": "Şınasnayışê lokali cı ke",
        "editthispage": "Ena pele bıvurne",
        "create-this-page": "Na pele bınuse",
        "redirectedfrom": "($1 ra kırışı yê)",
        "redirectpagesub": "Pela berdışi",
        "redirectto": "Beno hetê:",
-       "lastmodifiedat": "Ena pele tewr peyên roca $2, $1 de biya rocaniye.",
+       "lastmodifiedat": "Ena pele tewr peyên roca $1, seate $2 de biya rocaniye.{{MediaWiki bın}}",
        "viewcount": "Ena pele {{PLURAL:$1|rae|$1 rey}} vêniya.",
        "protectedpage": "Pela pawıtiye",
        "jumpto": "Şo be:",
        "copyright": "Zerrekacı $1 bındı not biya.",
        "copyrightpage": "{{ns:project}}:Heqa telifi",
        "currentevents": "Hediseyê rocaneyi",
-       "currentevents-url": "Project:Rocani hadisey",
+       "currentevents-url": "Project:Hediseyê rocaneyi",
        "disclaimers": "Redê mesuliyeti",
        "disclaimerpage": "Project:Reddê mesuliyetê bıngey",
        "edithelp": "Peştdariya vurnayışi",
        "policy-url": "Project:Terzê hereketi",
        "portal": "Portalê cemaeti",
        "portal-url": "Project:Portalê cemaeti",
-       "privacy": "Politikay Nımnayışi",
-       "privacypage": "Project:Xısusiyetê nımtışi",
+       "privacy": "Politikaya nımıteyiye",
+       "privacypage": "Project:Xısusiyetê nımıtışi",
        "badaccess": "Xeta mısadey",
        "badaccess-group0": "Heqa şıma çıniya, karo ke şıma waşt, bıkerê.",
        "badaccess-groups": "No fealiyeto ke şıma waşt, tenya karberanê {{PLURAL:$2|grubi|gruban ra yewi}} rê akerdeyo: $1.",
        "cannotdelete-title": "Şıma nêşenê pela \"$1\" besterê",
        "delete-hook-aborted": "Esterıtışi terefê çengeli ra ibtal bi.\nQet tesrih beyan nêbi.",
        "no-null-revision": "Qandé \"$1\" zew rewizyono newe névıraziya.",
-       "badtitle": "Sernameo xırabın",
+       "badtitle": "Sernameyo xırabın",
        "badtitletext": "Sernameyê pela ke şıma waşt, nêvêrd, vengo ya zi zıwano miyanêno ğelet gırêdaye ya zi sernameyê wiki.\nBeno ke, tede yew ya zi zêdê işareti estê ke sernameyan de nêxebetiyenê.",
        "perfcached": "Datay cı ver hazır biye. No semedê ra nıkayin niyo! tewr zaf {{PLURAL:$1|netice|$1 netice}} debêno de",
        "perfcachedts": "Cêr de malumatê nımıteyi esti, demdê newe kerdışo peyın: $1. Tewr zaf {{PLURAL:$4|netice|$4 neticey cı}} debyayo de",
        "actionthrottled": "Kerden peysnaya",
        "actionthrottledtext": "Riyê tedbirê anti-spami ra,  wextê do kılmek de şıma nê fealiyeti nêşkenê zaf zêde bıkerê, şıma ki no hedi viyarna ra.\nÇend deqey ra tepeya reyna bıcerrebnên.",
        "protectedpagetext": "Na per qey nêvuriyayiş ho pawyeno ya zi kerdışe bini.",
-       "viewsourcetext": "To şikinay çımey na pele bıvêne u kopya kerê:",
+       "viewsourcetext": "To şikinay çımey na pele bıvêne u kopya kerê:{{MediaWiki Wesiqe malumat}}",
        "viewyourtext": "Na pela '''Vurnayışê ke kerdê''' re şıma şenê kopya kerê:",
        "protectedinterface": "Na pela qandê nusnerin destegê verri dana u kes xırabin nêqero deye kerda kılit.",
        "editinginterface": "'''İqaz:''' Şıma hayo yew pela ke seba nuşteyê meqalanê cayanê bırnayeyan dana, vurnenê.\nVurnayışê na pele karberanê binan rê serpela karberi kena ke bımocno.\nSeba çarnayışi, yardımê [https://translatewiki.net/wiki/Main_Page?setlang=diq translatewiki.net]i ra procêdoşkerdışi rê diqet kerên.",
        "remembermypassword": "Parola mı nê cıgeyrayoği de biya xo viri (seba tewr zêde $1 {{PLURAL:$1|roce|rocan}})",
        "userlogin-remembermypassword": "Mı biya xo viri",
        "userlogin-signwithsecure": "Ebe teqdimkerê asayişın cıkewe",
+       "cannotloginnow-title": "Enewke ronıştışo nêabeno",
+       "cannotloginnow-text": "$1 karkerdışa ronıştış akerdış mıkum niyo.",
        "yourdomainname": "Nameyê şıma yo meydani",
        "password-change-forbidden": "Şıma na wiki de nêşenê parola bıvurnê.",
        "externaldberror": "Ya database de xeta esta ya zi heqê şıma çino şıma no hesab bıvurni.",
        "login": "Cı kewe",
+       "login-security": "Kamiya xo araşt kerê",
        "nav-login-createaccount": "Dekew de / hesab vıraze",
        "userlogin": "Cıkewtış / hesab vıraze",
-       "userloginnocreate": "Cı kewe",
+       "userloginnocreate": "Dekewtış",
        "logout": "Bıveciye",
        "userlogout": "Bıveciye",
        "notloggedin": "Şıma cıkewtış nêvıraşto",
        "nologinlink": "Yew hesab ake",
        "createaccount": "Hesab vıraze",
        "gotaccount": "Hesabê şıma esto? '''$1'''.",
-       "gotaccountlink": "Cı kewe",
+       "gotaccountlink": "Ronıştış ak",
        "userlogin-resetlink": "Melumatê cıkewtışi xo vira kerdê?",
        "userlogin-resetpassword-link": "Parola xo kerda xo vira?",
        "userlogin-helplink2": "Heqa qeydbiyayışi de peşti bıgêrên",
        "userlogin-loggedin": "Tı xora namey {{GENDER:$1|$1}} ra kewtê/kewtay cı.\nFormê cêrêni bıgureyne ke namey karberio bin ra cı kewê.",
+       "userlogin-reauth": "Eger ke {{GENDER:$1|$1}} şımayê se xo araşt kerdışirê fına ronıştış akerê.",
        "userlogin-createanother": "Zewbi hesab vıraz",
        "createacct-emailrequired": "Adresa e-postey",
        "createacct-emailoptional": "Adresa e-postey (mecburi niya)",
        "loginlanguagelabel": "Zıwan: $1",
        "suspicious-userlogout": "Waştişê tu ya veciyayişi kebul nibiya cunki ihtimal o ke waştiş yew browser ya zi proksiyê heripiyaye ra ameya.",
        "createacct-another-realname-tip": "Nameyo raştıkên keyfiyo.\nŞıma nameyo xoyo raştıkên ke bımocnê, seba iştırakanê karberi be ney ra istıfade beno.",
-       "pt-login": "Cı kewe",
-       "pt-login-button": "Cı kewe",
+       "pt-login": "Cıkewtış",
+       "pt-login-button": "Cıkewtış",
        "pt-login-continue-button": "Cıkewten rê dewam ke",
        "pt-createaccount": "Hesab vıraze",
        "pt-userlogout": "Veciyayış",
        "botpasswords-label-appid": "Nameyê boti:",
        "botpasswords-label-create": "Vıraze",
        "botpasswords-label-update": "Rocane ke",
-       "botpasswords-label-cancel": "Bıtexelne",
+       "botpasswords-label-cancel": "Bıterkın",
        "botpasswords-label-delete": "Bestere",
        "botpasswords-label-resetpassword": "Parola raçarne",
        "botpasswords-label-grants-column": "Dayen",
        "resetpass_forbidden": "parolayi nêvuryayi",
        "resetpass-no-info": "şıma gani hesab akere u hona bıeşke bırese cı",
        "resetpass-submit-loggedin": "Parola bıvurne",
-       "resetpass-submit-cancel": "Bıtexelne",
+       "resetpass-submit-cancel": "Bıterkın",
        "resetpass-wrong-oldpass": "parolayo parola maqbul niyo.\nşıma ya parolaye xo vurnayo ya zi parolayo muwaqqat waşto.",
        "resetpass-recycled": "Parolaya şımaya newiye wa paroloya şımaya verêne ra ferqıne bo.",
        "resetpass-temp-emailed": "E postaya rışyayê yubkoda şıma ronıştış akerdo.  Ronıştışi xo temammkerdışi rê yu parolaya newi lazım a",
        "publishpage": "Perer bıhesırne",
        "publishchanges": "Vurnayışa vıla ke",
        "preview": "Verqayt",
-       "showpreview": "Verqayti bıasne",
-       "showdiff": "Vurriyayışan bıasne",
+       "showpreview": "Verqayti bımocne",
+       "showdiff": "Vurriyayışan bımocne",
        "anoneditwarning": "<strong>İqaz:</strong> Şıma be hesabê xo nêkewtê cı. \nAdresê şımayê IP tarixê vırnayışê na pele de do qeyd bo. Eke şıma <strong>[$1 cıkewê]</strong> ya zi <strong>[$2 hesab vırazê]</strong>, vurnayışê şıma be zewbina kare ra nameyê şıma rê bar beno.",
        "anonpreviewwarning": "\"Şıma be hesabê xo nêkewtê cı. Eke qeyd kerê, adresê şımaê IP tarixê vırnayışê na pele de do qeyd bo.\"",
        "missingsummary": "'''DİQET:''' Şıma jû xulasa nênuşte.\nEke şıma \"{{int:savearticle}}\" reyna bıtıknê, vırnayışê şıma bê xulasa qeyd beno.",
        "newarticle": "(Newe)",
        "newarticletext": "To yew gıre tıkna be ra yew pela ke hewna çıniya.\nSeba afernayışê pele ra, qutiya metnê cêrêni bıgurene (seba melumati qaytê [$1 pela peşti] ke).\nEke be ğeletine ameya tiya, wa gocega <strong>peyser</strong>i programê xo de bıtıkne.",
        "anontalkpagetext": "----''No pel, pel o karbero hesab a nêkerdeyan o, ya zi karbero hesab akerdeyan o labele pê hesabê xo nêkewto de. No sebeb ra ma IP adres şuxulneni û ney IP adresan herkes eşkeno bıvino. Eke şıma qayil niye ina bo xo ri [[Special:CreateAccount|yew hesab bıvıraze]] veyaxut [[Special:UserLogin|hesab akere]].''",
-       "noarticletext": "Ena pele de hewna theba çıni yo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê  sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.",
+       "noarticletext": "Ena pele de hewna theba çıniyo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê  sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.{{MediaWiki mesaca pera newi}}",
        "noarticletext-nopermission": "Ena pele de hewna theba çıniyo.\nTı şenay zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|seba sernameyê na pele cı geyre]], ya zi <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre]</span>, ema destur çıniyo ke na pele vırazê.",
        "missing-revision": "Rewizyonê name dê pela da #$1 \"{{FULLPAGENAME}}\" dı çıniyo.\n\nNo normal de tarix dê pelanê besterneyan dı ena xırabin asena.\nDetayê besternayışi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} tiya dı] aseno.",
        "userpage-userdoesnotexist": "Hesabê karberi \"<nowiki>$1</nowiki>\" qeyd nêbiyo.\nKerem ke, tı ke wazenay na pele bafernê/bıvurnê, qontrol ke.",
        "mergehistory-empty": "Revizyonî yew nibenê.",
        "mergehistory-done": "$1 ra $3 {{PLURAL:$3|revizyon|revizyoni}} [[:$2]] de {{PLURAL:$3|biyo|biyê}} têmiyan.",
        "mergehistory-fail": "Tarixê pele yew nibeno, ma rica kenê ke pel u wext control bike.",
+       "mergehistory-fail-bad-timestamp": "Mora zemani ravêrdi niya",
+       "mergehistory-fail-invalid-source": "Çime per ravêrdi niya",
+       "mergehistory-fail-invalid-dest": "Hedef per ravêrdi niya",
+       "mergehistory-fail-permission": "Verori yewkerdışi rê mısade çıni yo.",
+       "mergehistory-fail-self-merge": "Çıne u hedef pera zey pê yê",
        "mergehistory-no-source": "Pela çımeyê $1 çıniya.",
        "mergehistory-no-destination": "Pela destinasyoni $1 çini yo.",
        "mergehistory-invalid-source": "Pela çime gani yew seroğê raşt biy.",
        "mergelog": "Qeydé zew kerdışi",
        "revertmerge": "Abırnê",
        "mergelogpagetext": "Cêr de yew liste esta ke mocnena ra, raya tewr peyêne kamci pela tarixi be a bine ra şanawa pê.",
-       "history-title": "Revizyona pela \"$1\"",
+       "history-title": "Tarixê çımraviyarnayışê \"$1\"",
        "difference-title": "Pela \"$1\" ferqê çım ra viyarnayışan",
        "difference-title-multipage": "Ferkê pelan dê \"$1\" u \"$2\"",
        "difference-multipage": "(Ferqê pelan)",
-       "lineno": "Xeta $1i:",
+       "lineno": "Xeta $1:",
        "compareselectedversions": "Rewizyonanê weçineyan pêver ke",
        "showhideselectedversions": "Revizyonanê weçinıtan bımocne/bınımne",
        "editundo": "peyser bıgê",
        "searchprofile-images": "Multimedya",
        "searchprofile-everything": "Heme çi",
        "searchprofile-advanced": "Raverşiyaye",
-       "searchprofile-articles-tooltip": "$1 de cı geyré",
-       "searchprofile-images-tooltip": "Dosya cı geyr",
+       "searchprofile-articles-tooltip": "$1 de cı geyre",
+       "searchprofile-images-tooltip": "Dosya cı geyre",
        "searchprofile-everything-tooltip": "Tedeesteyan hemine cı geyre (pelanê mınaqeşeyi zi tey)",
-       "searchprofile-advanced-tooltip": "qe cayê nimeyî bigêre",
+       "searchprofile-advanced-tooltip": "Cayê nameyanê xısusiyan de cı geyre",
        "search-result-size": "$1 ({{PLURAL:$2|1 çeku|$2 çekuy}})",
        "search-result-category-size": "{{PLURAL:$1|1 eza|$1 ezayan}} ({{PLURAL:$2|1 kategoriyê bini|$2 kategirayanê binan}}, {{PLURAL:$3|1 dosya|$3 dosyayan}})",
        "search-redirect": "($1 ra ardış)",
        "showingresults": "#<strong>$2</strong> netican ra {{PLURAL:$1|<strong>1</strong> netice cêr dero|<strong>$1</strong> neticey cêr derê}}.",
        "showingresultsinrange": "{{PLURAL:$1|<strong>1</strong> netice|<strong>$1</strong> neticey}} be mabeynê #<strong>$2</strong> ra be #<strong>$3</strong> cêr asenê.",
        "search-showingresults": "{{PLURAL:$4|Netice <strong>$1</strong> be <strong>$3</strong>|Neticeyi <strong>$1 - $2</strong> be <strong>$3</strong>}}",
-       "search-nonefound": "Zey perskerdışê şıma netice nêvêniya.",
+       "search-nonefound": "Zey perskerdışê şıma peyniye çıniya.",
        "search-nonefound-thiswiki": "Ena sita dı zey waşten da şıma theba nêvineya",
        "powersearch-legend": "Cıgeyrayışo hera",
        "powersearch-ns": "Cayanê nameyan de cıgeyrayış:",
        "right-passwordreset": "E-postayanê parola reset kerdışa vineno",
        "right-managechangetags": "[[Special:Tags|Etiketi]] vıraz u aktiv (me)ke",
        "right-applychangetags": "[[Special:Tags|Etiketa]]  vurnayışana piya dezge fi.",
+       "grant-group-page-interaction": "Peran na tesiri",
+       "grant-group-file-interaction": "Medya na tesiri",
+       "grant-group-watchlist-interaction": "Lista da xoya tesir",
        "grant-group-email": "e-poste bırışe",
+       "grant-group-high-volume": "Performansa aktiviteya vengê berzi",
        "grant-group-customization": "Şexsi kerdış u tercihi",
+       "grant-group-administration": "Performans hereketa idarey",
        "grant-group-other": "Enwayi babet aktivitey",
        "grant-blockusers": "Karberi men ke u meni wedarne",
        "grant-createaccount": "Hesab vıraze",
        "grant-createeditmovepage": "Perer vırazê, bıvurnê u berê",
+       "grant-delete": "Besternayış, revizyon  u qeydé peran",
+       "grant-editinterface": "Canameyê MediaWiki u CSS/javScripta karberi bıvurnê",
+       "grant-editmycssjs": "CSS/JavaScripta karberiya xo bıvurnê",
        "grant-editmyoptions": "Tercihanê xo bıvurne",
        "grant-editmywatchlist": "Listeyseyran de xo bıvırne",
        "grant-editpage": "Peran bıvurnê",
        "grant-editprotected": "Srar bıyaye peran bıvurnê",
+       "grant-highvolume": "Vengê berzi dayış",
+       "grant-oversight": "Karberan u ploğyayê revizyona bınımn",
        "grant-patrol": "Perer de vurnayışa çımra ravyarn",
+       "grant-protect": "Şeveknayış u wedarıtışê şeveknayışê pelan",
+       "grant-sendemail": "Karberanê binan rê e-posta bırışê",
+       "grant-uploadeditmovefile": "Dosyaya bar ke, bıvurnê  yana berê",
+       "grant-uploadfile": "Dosyaya newi bar ke",
+       "grant-basic": "Heqê basiti",
+       "grant-viewdeleted": "Besteryaya peran u dosyaya bıasne",
+       "grant-viewmywatchlist": "Lista serykerdışê xo bıvêne",
        "newuserlogpage": "Cıkewtışê hesabvıraştışi",
        "newuserlogpagetext": "Ena log de viraştişê karberî esta.",
        "rightslog": "Qeydê heqanê karberi",
        "rightslogtext": "Ena listeyê loganê ke heqqa karbaranî mucneno.",
        "action-read": "ena pela wanayış",
        "action-edit": "ena pela bıvurnê",
-       "action-createpage": "pelan vıraze",
+       "action-createpage": "Ena perer bıvıraze",
        "action-createtalk": "pelanê werênayışi bıvıraze",
        "action-createaccount": "hesabê nê karberi bıvıraze",
+       "action-autocreateaccount": "nê hesabê karberiyê teberi otomatik vıraze",
+       "action-history": "tarixê na pele bıvêne",
        "action-minoredit": "nê vurnayışi be qıckek işaret ke",
        "action-move": "ena pele bere",
        "action-move-subpages": "ena pele, u pelanê daê bınênan bere",
        "action-move-rootuserpages": "pelanê karberiyê bıngeyan bere",
+       "action-move-categorypages": "Pera kategoriyer ber",
        "action-movefile": "ena dosya bere",
        "action-upload": "ena dosya bar ke",
        "action-reupload": "dosyayê ke database de esto ser ey binuse",
        "action-viewmywatchlist": "Listeyseyran de xo bıvin",
        "action-viewmyprivateinfo": "Xısusi tercihane xo bıvin",
        "action-editmyprivateinfo": "Xısusi malumate xo bıvurne",
+       "action-editcontentmodel": "Zerrekê modela yu perer timar ke",
+       "action-managechangetags": "Vıraz u etiketa aktiv (me) ke",
+       "action-applychangetags": "Vurnayışana piya etiket kerdışi zi dezge fi",
+       "action-purge": "Ane perer newe ke",
        "nchanges": "$1 {{PLURAL:$1|fın vurna|fıni vurna}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ra yok wazino}}",
        "enhancedrc-history": "tarix",
        "recentchanges-label-bot": "Eno vurnayış terefê yew boti ra vıraziyo",
        "recentchanges-label-unpatrolled": "Eno vurnayış hewna dewriya nêbiyo",
        "recentchanges-label-plusminus": "Ebadê pele de bazê bayti de vayeyê cı",
-       "recentchanges-legend-heading": "<strong>Kıtabek:</strong>",
+       "recentchanges-legend-heading": "<strong>Kıtabekê Vurriyayışê peyêni:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|Lista pelanê neweyan]] zi bıvêne)",
        "recentchanges-legend-plusminus": "''(±123)''",
        "recentchanges-submit": "Bıasne",
-       "rcnotefrom": "Cêr de <strong>$2</strong> ra nata vurnayışiyê asenê (tewr vêşi <strong>$1</strong> asenê).",
+       "rcnotefrom": "Cêr de <strong>$2</strong> ra nata {{PLURAL:$5|vurnayışiyê}} asenê (tewr vêşi <strong>$1</strong> asenê) <strong>$3, $4</strong>",
        "rclistfrom": "$3 $2 ra tepiya vurnayışanê neweyan bımocne",
-       "rcshowhideminor": "vurnayışê werdiyi $1",
-       "rcshowhideminor-show": "Bıasne",
+       "rcshowhideminor": "vurriyayışanê werdiyan $1",
+       "rcshowhideminor-show": "Bımocne",
        "rcshowhideminor-hide": "Bınımne",
        "rcshowhidebots": "botan $1",
-       "rcshowhidebots-show": "Bıasene",
+       "rcshowhidebots-show": "Bımocne",
        "rcshowhidebots-hide": "Bınımne",
        "rcshowhideliu": "karberê qeydbiyayeyi $1",
        "rcshowhideliu-show": "Bıasne",
        "rcshowhideliu-hide": "Bınımne",
        "rcshowhideanons": "karberê bênameyi $1",
-       "rcshowhideanons-show": "Bıasene",
+       "rcshowhideanons-show": "Bımocne",
        "rcshowhideanons-hide": "Bınımne",
        "rcshowhidepatr": "$1 vurnayışê ke dewriya geyrayê",
        "rcshowhidepatr-show": "Bıasne",
        "rcshowhidepatr-hide": "Bınımne",
        "rcshowhidemine": "vurnayışanê mı $1",
-       "rcshowhidemine-show": "Bıasne",
+       "rcshowhidemine-show": "Bımocne",
        "rcshowhidemine-hide": "Bınımne",
        "rcshowhidecategorization": "kategorizasyonê pele $1",
        "rcshowhidecategorization-show": "Bıasne",
        "rcshowhidecategorization-hide": "Bınımne",
-       "rclinks": "$2 rocan de $1 vurriyayışanê peyênan bıasne <br />$3",
+       "rclinks": "$2 rocan de $1 vurriyayışanê peyêna bıasne <br />$3",
        "diff": "ferq",
        "hist": "verên",
        "hide": "Bınımne",
-       "show": "Bıasne",
+       "show": "Bımocne",
        "minoreditletter": "q",
        "newpageletter": "N",
        "boteditletter": "b",
        "recentchangeslinked-to": "Heruna pela ke yena dayene, vurnayışanê pelanê ke daye ra gırêdayiyê inan bımocne",
        "recentchanges-page-added-to-category": "[[:$1]] kerd be kategoriye",
        "recentchanges-page-removed-from-category": "[[:$1]] kategoriye ra vet",
+       "autochange-username": "MediaWiki vurnayışo otomatik",
        "upload": "Dosya bar ke",
        "uploadbtn": "Dosya bar ke",
        "reuploaddesc": "Barkerdışi iptal ke u peyser şo formê barkerdışi",
        "upload-http-error": "Yew ğeletê HTTPî biyo: $1",
        "upload-copy-upload-invalid-domain": "Na domain ra kopyayê barkerdışanê nêbenê.",
        "upload-dialog-title": "Dosya bar ke",
-       "upload-dialog-button-cancel": "Bıtexelne",
+       "upload-dialog-button-cancel": "Bıterkın",
        "upload-dialog-button-done": "Temam",
        "upload-dialog-button-save": "Bışevekne",
        "upload-dialog-button-upload": "Bar ke",
        "backend-fail-read": "Na \"$1\" dosya nê wanêna",
        "backend-fail-create": "Dosyay $1 nê vırazıyê",
        "backend-fail-maxsize": "Dosyay $1 aya nênusneyêna feqet gırdeya cı {{PLURAL:$2|bayta|$2 bayto}}",
-       "backend-fail-readonly": "Depo kerdışê \"$1\" enewke salt wanêno.Sebebê cı zi:\"''$2''\"",
+       "backend-fail-readonly": "Depo kerdışê \"$1\" enewke salt wanêno.Sebebê cı zi:<em>$2</em>",
        "backend-fail-synced": "Dosyay \" $1 \" miyan de depo kerdışeyda cıdı pê nêtepıştey esta",
        "backend-fail-connect": "Depo kerdışê \"$1\" peyni de nêgrêdeya.",
        "backend-fail-internal": "Depo kerdışê \"$1\" peyni de ju xırabin vıcyê.",
        "uploadstash-badtoken": "Karkerdışê cı nêbı, muhtemelen desture şımayê timarkerdışi zeman do şıma ravêrdo. Fına bıcerbnê.",
        "uploadstash-errclear": "Besternayışê dosyayan nêbı",
        "uploadstash-refresh": "Listanê dosyayan aneweke",
+       "uploadstash-thumbnail": "asayışê qıckeki bıvêne",
        "invalid-chunk-offset": "Ofseto nêravyarde",
        "img-auth-accessdenied": "Cıresnayış vındarnayo.",
        "img-auth-nopathinfo": "PATH_INFO kemiyo.\nTeqdimkerê şıma seba ravurnayışê nê melumati eyar nêkerdo.\nBeno ke be CGI-bıngeyın bo u img_auth rê desteg nêbeno.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Selahiyetê resımi bıvêne.",
        "license": "Lisans:",
        "license-header": "Lisansdayış",
        "nolicense": "Theba nêweçineya",
+       "licenses-edit": "Weçenega lisansi bıvurnê",
        "license-nopreview": "(verqeydî çin o)",
-       "upload_source_url": "(yew URLê raştî, şar rê akerde yo)",
-       "upload_source_file": "(komputerê ti de yew dosya)",
+       "upload_source_url": "(to yew ravêrde dosya weçina,   şar rê akerde URL yo)",
+       "upload_source_file": "(komputer ra dos yu dosya weçina)",
+       "listfiles-delete": "bestere",
        "listfiles-summary": "Na pera bağsiya; heme resima bar biyayeyan mocnena.",
        "listfiles_search_for": "Qe nameyê medyayî bigêre:",
+       "listfiles-userdoesnotexist": "Hesabê karberi \"$1\" qeyd nêbiyo.",
        "imgfile": "dosya",
        "listfiles": "Lista Dosya",
        "listfiles_thumb": "Resmo qıckek",
        "listfiles-latestversion-yes": "Eya",
        "listfiles-latestversion-no": "Nê",
        "file-anchor-link": "Dosya",
-       "filehist": "Ravêrdê dosya",
+       "filehist": "Tarixê dosya",
        "filehist-help": "Seba diyayışê viyarteyê dosya tarixê ke qısımê tarix/zemani derê inan bıtıkne.",
        "filehist-deleteall": "pêro bestere",
        "filehist-deleteone": "bestere",
        "filerevert-legend": "Dosya raçarne",
        "filerevert-intro": "Ti ho ena dosyayê '''[[Media:$1|$1]]'''î  [$4 versiyonê $3, $2] rê reyna anî.",
        "filerevert-comment": "Sebeb:",
-       "filerevert-defaultcomment": "Versiyonê $2, $1 rê reyna ard",
+       "filerevert-defaultcomment": "Versiyonê $2, $1 rê reyna ard ($3)",
        "filerevert-submit": "Reyna biyere",
        "filerevert-success": "'''[[Media:$1|$1]]''' peyser çarna ra [versiyonanê $4, $3, $2].",
        "filerevert-badversion": "Vesiyonê lokalê verniyê eno dosya pê ena pulêwext de çin o.",
        "unwatchedpages": "Pelanê seyrnibiyeyî",
        "listredirects": "Listeya Hetenayışan",
        "listduplicatedfiles": "Lista dosyeyanê ke kopyaya cı vêniyena",
+       "listduplicatedfiles-entry": "[[$3|{{PLURAL:$2|kapyay|$2 kopyey}}]] dosya da [[:File:$1|$1]]'i est a",
        "unusedtemplates": "Şablonê ke nêguriyenê",
        "unusedtemplatestext": "no pel, {{ns:template}} pelê ke pelê binan de nêaseni, ninan keno.",
        "unusedtemplateswlh": "linkanê binî",
        "randomincategory-invalidcategory": "\"$1\" yew nameyê kategoriya vêrdiye niyo.",
        "randomincategory-nopages": "Kategori da [[:Category:$1|$1]] de qet  per çıniya.",
        "randomincategory-category": "Kategoriye:",
+       "randomincategory-legend": "Kategori ra raştamayi per",
        "randomincategory-submit": "Şo",
        "randomredirect": "Serçarnayışo rastameye",
        "randomredirect-nopages": "Cayê nameyê \"$1\" de serşıkıtışi çıniyê.",
        "protectedpages-unknown-performer": "Karbero nêzanaye",
        "protectedtitles": "Sernameyê pawıteyi",
        "protectedtitlesempty": "pê ney parametreyan sernuşteyê pawite çinê",
+       "protectedtitles-submit": "Sernaman bımocne",
        "listusers": "Listeyê Karberan",
        "listusers-editsonly": "Teyna karberan bimucne ke ey nuştê",
        "listusers-creationsort": "goreyê wextê vıraştışi rêz ker",
        "newpages-submit": "Bıasene",
        "newpages-username": "Nameyê karberi:",
        "ancientpages": "Pelê kehenêri",
-       "move": "Wegi",
-       "movethispage": "Ena peler wegi",
+       "move": "Bıkırış",
+       "movethispage": "Ena pele bıkırışe",
        "unusedimagestext": "Enê dosyey estê, feqet zerrey yew pele de wedardey niyê.\nXo vira mekerê ke, sıteyê webiê bini şenê direkt ebe URLi yew dosya ra gırê bê, u wına şenê verba gurênayışo feal de tiya hewna lista bê.",
        "unusedcategoriestext": "Kategoriyê ke cêr derê, nê bıbê zi, terefê qet madeyan ya zi kategoriyan ra nêgureniyenê.",
        "notargettitle": "Hedef çini yo",
        "apihelp-no-such-module": "Modulê \"$1\" çıniyo.",
        "apisandbox": "API qumdor",
        "apisandbox-fullscreen": "Panela hera kerdışi",
+       "apisandbox-unfullscreen": "Pele bımocne",
        "apisandbox-submit": "Bıwazê",
        "apisandbox-reset": "Bestere",
        "apisandbox-retry": "Fına",
        "checkbox-select": "Weçinaye: $1",
        "checkbox-all": "Pêro",
        "checkbox-none": "Temam",
-       "checkbox-invert": "Doç kerdış",
+       "checkbox-invert": "Rageyre",
        "allpages": "Peli pêro",
        "nextpage": "Pela badê cû ($1)",
        "prevpage": "Pela verêne ($1)",
        "allpagesfrom": "Pera liste kerdışi bıasne:",
        "allpagesto": "Pelanê ke be ena herfe qediyenê bımocne:",
-       "allarticles": "Wesiqey pêro",
+       "allarticles": "Peli pêro",
        "allinnamespace": "Peli pênro ( $1 cayênameyî)",
        "allpagessubmit": "Şo",
        "allpagesprefix": "herfê ke şıma tiya de nuşti, pê ney herfan pelê ke destpêkenê liste ker:",
        "categoriesfrom": "Kategoriyê ke be ninan dest pêkenê, bımocne:",
        "deletedcontributions": "İştırakê karberi esterdi",
        "deletedcontributions-title": "İştırakê karberi esterdi",
-       "sp-deletedcontributions-contribs": "iştıraqi",
+       "sp-deletedcontributions-contribs": "iştiraki",
        "linksearch": "Gıreyê teberi cı geyrê",
        "linksearch-pat": "bıgêr motif:",
        "linksearch-ns": "Heruna nameyi:",
        "addedwatchtext-short": "Pera $1`i çebyê listeya seyran de şıma",
        "removewatch": "Lista seyrkerdışi ra wedare",
        "removedwatchtext": "Ena pela \"[[:$1]]\" biya wedariya [[Special:Watchlist|listeyê seyr-kerdışi şıma]].",
+       "removedwatchtext-short": "Pera $1`i listeya seyran de şıma ra wedari yê",
        "watch": "Seyr ke",
        "watchthispage": "Ena pele seyr ke",
        "unwatch": "Teqib meke",
        "wlheader-enotif": "E-mail xeber dayiş abiyo.",
        "wlheader-showupdated": "ziyaretê şıma ye peyini de vuryayişê peli pê '''nuşteyo qalıni''' mocyayo.",
        "wlnote": "$3 saete $4 ra dıme {{PLURAL:$2|yew saete de|'''$2''' saetan de}} {{PLURAL:$1|vurnayışo peyên|vurnayışê '''$1''' peyêni}} cêrderê.",
-       "wlshowlast": "Peyni de vurnayışan ra  $1 seata u $2 roca  bımocnê",
+       "wlshowlast": "Peyni de  $1 seata u $2 roca  bıasne",
        "watchlist-hide": "Bınımne",
        "watchlist-submit": "Bıasene",
        "wlshowtime": "Periyoda zemani asenayışi:",
-       "wlshowhideminor": "vurnayışê werdiyi",
+       "wlshowhideminor": "vurriyayışê werdi",
        "wlshowhidebots": "boti",
        "wlshowhideliu": "karberê qeydıni",
        "wlshowhideanons": "karberê anonimi",
        "delete-edit-reasonlist": "Sebebê vurnayışan bıvurne",
        "delete-toobig": "no pel, pê $1 {{PLURAL:$1|tene vuriyayiş|tene vuriyayiş}}i wayirê yew tarixo kehen o.\nqey hewna nêşiyayişi wina pelani u {{SITENAME}}nêxerebnayişê keyepeli yew hed niyaya ro.",
        "delete-warning-toobig": "no pel wayirê tarixê vurnayiş ê derg o, $1 {{PLURAL:$1|revizyonê|revizyonê}} seri de.\nhewn a kerdışê ıney {{SITENAME}} şuxul bıne gırano;\nbı diqqet dewam kerê.",
+       "deleteprotected": "Şıma nêşenê ena perer esternê,  çıkı per starya ya.",
        "rollback": "vurnayişan tepiya bıger",
        "rollbacklink": "peyser biya",
        "rollbacklinkcount": "$1 {{PLURAL:$1|vurnayış|vurnayışi}} peyd gıroti",
        "maximum-size": "Ebatê maximumî",
        "pagesize": "(bitî)",
        "restriction-edit": "Bıvurne",
-       "restriction-move": "Berr",
-       "restriction-create": "Vıraze",
+       "restriction-move": "Bıkırış",
+       "restriction-create": "Bıvıraz",
        "restriction-upload": "Bar ke",
        "restriction-level-sysop": "tam pawiyayo",
        "restriction-level-autoconfirmed": "nêm pawiyayo",
        "blanknamespace": "(Ser)",
        "contributions": "İştiraqê {{GENDER:$1|karber}}i",
        "contributions-title": "Dekerdenê karber de $1",
-       "mycontris": "İştıraqi",
-       "anoncontribs": "İştıraqi",
+       "mycontris": "İştıraki",
+       "anoncontribs": "İştıraki",
        "contribsub2": "Qandê {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Hesabê karberi \"$1\" qeyd nêbiyo.",
        "nocontribs": "Ena kriteriya de vurnayîş çini yo.",
        "sp-contributions-username": "Adresa IPy ya zi nameyê karberi:",
        "sp-contributions-toponly": "Tenya rewizyonanê tewr peyniyan bimocne",
        "sp-contributions-submit": "Cı geyre",
-       "whatlinkshere": "Pele rê gıreyi",
+       "whatlinkshere": "Linkê tedeestey",
        "whatlinkshere-title": "Per da \"$1\" rê perê ke gre danê",
        "whatlinkshere-page": "Pele:",
        "linkshere": "Ena peleyan grey biya '''[[:$1]]''':",
        "whatlinkshere-links": "← gırey",
        "whatlinkshere-hideredirs": "Hetenayışê $1",
        "whatlinkshere-hidetrans": "Açarnayışê $1",
-       "whatlinkshere-hidelinks": "Greyê $1",
+       "whatlinkshere-hidelinks": "Gıreyê $1",
        "whatlinkshere-hideimages": "Gıreyê dosya $1",
-       "whatlinkshere-filters": "Avrêci",
+       "whatlinkshere-filters": "Parzûn",
        "whatlinkshere-submit": "Şo",
        "autoblockid": "Otomatik vındarnayış #$1",
        "block": "Karberi vındarne",
        "ipb-unblock-addr": "$1 a bik",
        "ipb-unblock": "Yew adresê IPî ya zi nameyê karberî blok bike",
        "ipb-blocklist": "Blokî ke hama estê ey bivîne",
-       "ipb-blocklist-contribs": "Qandê {{GENDER:$1|}} ra iştıraqi",
+       "ipb-blocklist-contribs": "İştirakê {{GENDER:$1|$1}}`i",
        "ipb-blocklist-duration-left": "$1 vet",
        "unblockip": "Hesabê karberî a bike",
        "unblockiptext": "Cıreştışê nuştışê IP ya zi karberio ke ver ra gêriyayo, seba peyser barkerdışi dey rê formê cêrêni bıgurenên.",
        "blocklink": "kılit ke",
        "unblocklink": "bloki wedare",
        "change-blocklink": "kılitkerdışi bıvurne",
-       "contribslink": "iştıraqi",
+       "contribslink": "iştıraki",
        "emaillink": "e-poste bırışe",
        "autoblocker": "Şıma otomatikmen kılit biy, çıke adresa şımaya ''IP''y terefê \"[[User:$1|$1]]\" gureniyena.\nSebebê kılitbiyayışê $1'i \"$2\"o",
        "blocklogpage": "Qeydê astengi",
        "blocklogtext": "No kuliyatê kılitkerdış u rakerdışê fealiyetê karberano.\nAdresê IP'ya ke otomatikmen kılit biyê lista de çıniya.\nSeba lista karberanê ke heta nıka kılit biyê [[Special:BlockList|lista kılitkerdışê IPy]] bıvinê.",
        "unblocklogentry": "$1 ake",
        "block-log-flags-anononly": "tenya karberê anonimi",
-       "block-log-flags-nocreate": "akerdışê hesabi racneyayo",
+       "block-log-flags-nocreate": "akerdışê hesabi kılit bi",
        "block-log-flags-noautoblock": "Oto-wedariye terkneyayo",
-       "block-log-flags-noemail": "e-posta biya bloqe",
-       "block-log-flags-nousertalk": "Pela verênayişi ke xo nêşeno bıvurno",
+       "block-log-flags-noemail": "e-poste kılit bi",
+       "block-log-flags-nousertalk": "pela werênayışê xo nêşeno ke bıvurno",
        "block-log-flags-angry-autoblock": "oto-wedariye amayen aktivo",
        "block-log-flags-hiddenname": "nameyê karberi nımteyo",
        "range_block_disabled": "Desturê administorî ke viraştişê blokê rangeyî kefiliyo.",
        "lockfilenotwritable": "dosyaya qefılnayişê databaseyi ser ra çiyek nênusyena.",
        "databasenotlocked": "Database a nibiya.",
        "lockedbyandtime": "({{GENDER:$1|$1}} ra $2 tepya $3 biyo)",
-       "move-page": "$1 Bere",
+       "move-page": "$1 Bıkırış",
        "move-page-legend": "Pele bere",
        "movepagetext": "Pe form ki ho bın de, tı eşkeno name yew pele bıvurni u tarixê pele hemi ya zi pyeran beri.\nMa nameyê kıhanyeri keno pele redireksiyoni ser nameyê newe.\nTı eşkeno pele redireksiyoni ki şıno nameyê originali bıvurni.\nEg tı nıwazeno, ma tı ra rica keni tı [[Special:DoubleRedirects|double]] ya zi [[Special:BrokenRedirects|broken redirects]] qontrol bıki.\nTı gani qontrol bıki eg gıreyan şıno peleyanê raşti.\n\nTeme eka ser yew name de yew nuşte esti, sistemê ma '''nıeşkeno''' nuşte tı beri. Eka ser ena name de yew pele vengi esti, sistemê ma eşkeno nuşte tı beri.\nTı nıeşkeni name yew pele reyna bıvurni.\n\n'''Teme!'''\nEna transfer ser peleyanê populari zaf muhumo;\nMa tu ra rica keni, tı en verni dı qontrol bıki u bışıravi.",
        "movepagetext-noredirectfixer": "Pe form ki ho bın de, tı eşkeno name yew pele bıvurni u tarixê pele hemi ya zi pyeran beri.\nMa nameyê kıhanyeri keno pele redireksiyoni ser nameyê newe.\nTı eşkeno pele redireksiyoni ki şıno nameyê originali bıvurni.\nEg tı nıwazeno, ma tı ra rica keni tı [[Special:DoubleRedirects|raçarnayışo dılet]] ya zi [[Special:BrokenRedirects|raçarnayışo xırab]]i qontrol bıke.\nTı gani qontrol bıki eg gıreyan şıno peleyanê raşti.\n\nTeme eka ser yew name de yew nuşte esti, sistemê ma '''nıeşkeno''' nuşte tı beri. Eka ser ena name de yew pele vengi esti, sistemê ma eşkeno nuşte tı beri.\nTı nıeşkeni name yew pele reyna bıvurni.\n\n'''İkaz!'''\nEna transfer ser peleyanê populari zaf muhumo;\nMa tu ra rica keni, tı en verni dı qontrol bıki u bışıravi.",
        "tooltip-ca-unprotect": "Starkerdışe ena peler bıvurne",
        "tooltip-ca-delete": "Ena pele bestere",
        "tooltip-ca-undelete": "peli biyarê halê ver hewnakerdışi",
-       "tooltip-ca-move": "Ena peler wegi",
+       "tooltip-ca-move": "Ena pele bıkırışe",
        "tooltip-ca-watch": "Ena pele lista xoya seyrkerdışi ke",
        "tooltip-ca-unwatch": "Ena pele lista xoya seyrkerdışi ra vece",
        "tooltip-search": "{{SITENAME}} de cı geyre",
        "tooltip-n-portal": "Heqa proceyi de, çı şenay bıkerê, çı koti vêniyeno",
        "tooltip-n-currentevents": "Vurnayışanê peyênan de melumatê pey bıvêne",
        "tooltip-n-recentchanges": "Wiki de lista vurnayışanê peyênan",
-       "tooltip-n-randompage": "Perake raşt amé",
+       "tooltip-n-randompage": "Pelê da raştameyiye bar ke",
        "tooltip-n-help": "Cayê peştigırewtışi",
        "tooltip-t-whatlinkshere": "Lista pelanê wikiya pêroina ke tiya gırê bena",
        "tooltip-t-recentchangeslinked": "Vurnayışê peyênê pelanê ke ena pela ra gırê biyê",
        "tooltip-ca-nstab-project": "Pela proceyi bıvêne",
        "tooltip-ca-nstab-image": "Pera dosyayer bıvin",
        "tooltip-ca-nstab-mediawiki": "Mesacê sistemi bıvêne",
-       "tooltip-ca-nstab-template": "Şabloni bıvin",
+       "tooltip-ca-nstab-template": "Şabloni bıvêne",
        "tooltip-ca-nstab-help": "Pela peşti bıvêne",
        "tooltip-ca-nstab-category": "Pela kategoriye bıvêne",
        "tooltip-minoredit": "Nay vırnayışa werdi nışan bıkeré",
        "anonymous": "{{PLURAL:$1|karberê|karberê}} anonimi yê keyepelê {{SITENAME}}i",
        "siteuser": "karberê {{SITENAME}}i $1",
        "anonuser": "karberê anonim o {{SITENAME}}i $1",
-       "lastmodifiedatby": "Ena pele tewr peyên roca $2, $1 by $3. de biya rocaniye",
+       "lastmodifiedatby": "Ena pele tewr peyên roca $2, $1 de tereftê $3 ra vuriya ya.",
        "othercontribs": "xebatê $1 ıney geriyayo diqqeti/geriyayo nezer.",
        "others": "bini",
        "siteusers": "{{SITENAME}} {{PLURAL:$2|karberê ey|karberanê ey}} $1",
        "svg-long-desc-animated": "SVG dosya, nominalin $1 × $2 piksela, ebatê dosya: $3",
        "svg-long-error": "Nêmeqbul dosyaya SVG'i: $1",
        "show-big-image": "Dosyaya oricinale",
-       "show-big-image-preview": "Verqayd dergiya: $1'i.",
+       "show-big-image-preview": "Verqaytê dergiya: $1.",
        "show-big-image-other": "Zewmi{{PLURAL:$2|Vılêşnayış|Vılêşnayışê}}: $1.",
        "show-big-image-size": "$1 × $2 piksel",
        "file-info-gif-looped": "viyariye biyo",
        "exif-planarconfiguration": "Rezeyê datayi",
        "exif-ycbcrsubsampling": "Subsampleyi ebatê Y heta C",
        "exif-ycbcrpositioning": "pozisyonê Y u C",
-       "exif-xresolution": "Rezulasyanê veriniye",
+       "exif-xresolution": "Qerarê verıniye",
        "exif-yresolution": "Rezulasyanê derganiye",
        "exif-stripoffsets": "Cayê melumatê resımi",
        "exif-rowsperstrip": "Yew reze de teneyê dizeyi",
        "exif-referenceblackwhite": "Çiftyê siya u sipe değerê referansi",
        "exif-datetime": "Zeman u tarixê vurnayişê dosyayi",
        "exif-imagedescription": "Serê resimi",
-       "exif-make": "Viraştoğê kamera",
-       "exif-model": "Modelê kamerayi",
+       "exif-make": "Vıraştoğê kamera",
+       "exif-model": "Modelê kamera",
        "exif-software": "Software ke hebitiyeno",
        "exif-artist": "Nuştoğ",
        "exif-copyright": "Wahirê copyrighti",
        "exif-urgency-low": "($1) Kemiyo",
        "exif-urgency-high": "( $1 ) Vêşiyo",
        "exif-urgency-other": "Sıftê  şınasiya karberi ($1)",
-       "namespacesall": "pêron",
+       "namespacesall": "pêro",
        "monthsall": "pêro",
        "confirmemail": "Adresê e-posta tesdiq ker",
        "confirmemail_noemail": "Yew emaîlê tu raştîyê çin o ke [[Special:Preferences|tercihê karberî]] ayar bike.",
        "deletedwhileediting": "'''Teme''': Ena pele  verniyê ti de eseteriyaya!",
        "confirmrecreate": "Karberê [[User:$1|$1]]î ([[User talk:$1|mesac]]), verniyê vurnayîşê ti ra ena pele wedarno, sebeb: ''$2''\nMa rica keno tesdiq bike ke ti raştî wazeno eno pel bivirazo.",
        "confirmrecreate-noreason": "karbero [[User:$1|$1]] ([[User talk:$1|mesac]]) , dest pêkerdışiena pela sero vurnayışiya tepya ena pela besternê. Şıma qayıli ke ena pela fına vırazê se ena pela tesdiq kerê.",
-       "recreate": "Reyna viraz",
+       "recreate": "Werzayne",
        "unit-pixel": "px",
        "confirm_purge_button": "Temam",
        "confirm-purge-top": "Vervirê na pele bestere?",
        "autosumm-replace": "Maqale pê '$1' vuriya",
        "autoredircomment": "heteneya [[$1]]",
        "autosumm-new": "Pela vıraziyê, '$1' bıvinê",
+       "autosumm-newblank": "Pera veng vıraziyê",
        "size-bytes": "$1 {{PLURAL:$1|bayt|bayti}}",
        "size-kilobytes": "$1 KB",
        "size-megabytes": "$1 MB",
        "watchlistedit-raw-done": "Listeyê tuyê seyrkerdişi rocaniye biyo",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 sername kerd|$1 sernamey kerdi}} cı:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 sername dard|$1 sernamey dardi}} we:",
+       "watchlistedit-clear-title": "Lista serykerdışê pak kerê",
+       "watchlistedit-clear-legend": "Lista serykerdışê pak kerê",
+       "watchlistedit-clear-explain": "Listeya serykerdış da şıma dı sernamey pêro besteryay",
        "watchlistedit-clear-titles": "Sernamey:",
        "watchlisttools-view": "Vurnayışanê elaqedaran bıvêne",
        "watchlisttools-edit": "Lista seyrkerdışi bıvêne û bıvurne",
        "version-software": "Softwareyê ronayi",
        "version-software-product": "Mal",
        "version-software-version": "Versiyon",
-       "version-entrypoints": "heruna dekewtış de GRE'i",
+       "version-entrypoints": "Heruna cıkewtışê URLi",
        "version-entrypoints-header-entrypoint": "Heruna dekewtışi",
        "version-entrypoints-header-url": "GRE",
        "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Article path]",
        "fileduplicatesearch-result-1": "Dosyayê ''$1î'' de hem-kopya çini yo.",
        "fileduplicatesearch-result-n": "Dosyayê ''$1î'' de {{PLURAL:$2|1 hem-kopya|$2 hem-kopyayî'}} esto.",
        "fileduplicatesearch-noresults": "Ebe namey \"$1\" ra dosya nêdiyayê.",
-       "specialpages": "Peleyê xısusiy",
+       "specialpages": "Pelê xısusiy",
        "specialpages-note-top": "Kıtabek",
        "specialpages-note": "* Pelê xasê normali.\n* <span class=\"mw-specialpagerestricted\">Pelê xasê nımıtey.</span>",
        "specialpages-group-maintenance": "Raporê pawıtışi",
        "specialpages-group-other": "Pelê xasiyê bini",
-       "specialpages-group-login": "Cı kewe / hesab vıraze",
+       "specialpages-group-login": "Dekew / hesab vıraz",
        "specialpages-group-changes": "Vurnayışê peyêni û qeydi",
        "specialpages-group-media": "Raporê medya û barkerdışi",
        "specialpages-group-users": "Karberi û heqi",
        "feedback-bugcheck": "Harika! Sadece [xırabina ke $1 ] çınyayışê cı kontrol keno.",
        "feedback-bugnew": "Mı qontrol ke. Xetaya newi xeber ke",
        "feedback-bugornote": "Jew mersela teferruato teknik esta şıma reca malumatê şıma hazıro se [ $1  jew xırab rapor] bıvinê.Zewbi zi, formê cerê xo rê şenê karfiyê. Vatışê xo pela da \"[ $3  $2 ]\", namey karber dê xoya piya u wasteriya karfiye.",
-       "feedback-cancel": "Peyd ke",
+       "feedback-cancel": "Bıterkın",
        "feedback-close": "Biya star",
        "feedback-error1": "Xeta: API ra neticey ne vıcyay",
        "feedback-error2": "Xeta: Timar kerdış nebı",
index 179bebb..6d1a32a 100644 (file)
        "tagline": "Z {{GRAMMAR:genitiw|{{SITENAME}}}}",
        "help": "Pomoc",
        "search": "Pytaś",
+       "search-ignored-headings": " #<!-- njezměń toś tu smužku --> <pre>\n# Nadpisma, kótarež pytanje ignorěrujo.\n# Toś te změny budu se wustatkowaś, za tym až bok jo se indicěrował.\n# Móžoš indicěrowanje bokow wunuźiś, z tym až pśewjedujoš proznu změnu.\n# Syntaksa:\n#   * Wšykno, což slědujo znamušku \"#\" až do kóńca smužki, jo komentar\n#   * Kuzda njeprozna smužka jo eksaktny titel, kótaryž ma se ignorěrowaś\nŽrědła\nEksterne wótkaze\nGlědaj teke\n #</pre> <!-- njezměń toś tu smužku -->",
        "searchbutton": "Pytaś",
        "go": "Nastawk",
        "searcharticle": "Nastawk",
index 30421d7..6ebcc19 100644 (file)
        "prefs-reset-intro": "तम ये पृष्ठलाई आफनो अभिरुचीहरू साइट पूर्वावस्थामी फर्काउनत फर्काउन प्रयोग गद्दु सकन्छौ । तै पाछा ये लाई रद्द गद्दु सकन्छौ ।",
        "prefs-emailconfirm-label": "इ-मेल एकिन प्रक्रिया:",
        "youremail": "ईमेल",
-       "username": "{{लिंग:$1|प्रयोगकर्ता नाम}}:",
-       "prefs-memberingroups": "निम्न {{बहुबचन:$1|समूह | समूहहरू}}को {{लिंग:$2|सदस्य}} :",
+       "username": "{{GENDER:$1|प्रयोगकर्ता नाम}}:",
+       "prefs-memberingroups": "निम्न {{PLURAL:$1|समूह|समूहहरू}}को {{GENDER:$2|सदस्य}} :",
        "prefs-registration": "दर्ता समय:",
        "yourrealname": "वास्तविक नाम:",
        "yourlanguage": "भाषा",
        "userrights": "प्रयोगकर्ता अधिकार व्यवस्थापन",
        "userrights-lookup-user": "प्रयोगकर्ता समूह व्यवस्थापन गर",
        "userrights-user-editname": "प्रयोगकर्ता नाम दिय:",
-       "editusergroup": "सम्पादन{{लिंग:$1}}समूहहरु",
+       "editusergroup": "{{GENDER:$1|प्रयोगकर्ता}}समूहहरू सम्पादन",
        "userrights-editusergroup": "प्रयोगकर्ता समूह सम्पादन गर",
-       "saveusergroups": "सुरक्षित{{लिंग:$1}}समूहहरु",
+       "saveusergroups": "सुरक्षित {{GENDER:$1|प्रयोगकर्ता}} समूहहरू",
        "userrights-groupsmember": "को सदस्य:",
        "userrights-groupsmember-auto": "अंतर्निहित सदस्य:",
        "userrights-reason": "कारण:",
        "group-bureaucrat": "प्रशासकहरू",
        "group-suppress": "लुकौन्या वाला",
        "group-all": "(सबै)",
-       "group-user-member": "{{लिङग:$1|प्रयोगकर्ता}}",
-       "group-autoconfirmed-member": "{{लिङग:$1|स्वनिर्धारित प्रयोगकर्ता}}",
-       "group-bot-member": "{{लिङग:$1|बोट}}",
-       "group-sysop-member": "{{लिङग:$1|प्रबन्धक}}",
-       "group-bureaucrat-member": "{{लिङग:$1|प्रशासक}}",
-       "group-suppress-member": "{{लिङग:$1|दबाउन्या}}",
+       "group-user-member": "{{GENDER:$1|प्रयोगकर्ता}}",
+       "group-autoconfirmed-member": "{{GENDER:$1|स्वनिर्धारित प्रयोगकर्ता}}",
+       "group-bot-member": "{{GENDER:$1|बोट}}",
+       "group-sysop-member": "{{GENDER:$1|प्रबन्धक}}",
+       "group-bureaucrat-member": "{{GENDER:$1|प्रशासक}}",
+       "group-suppress-member": "{{GENDER:$1|दबाउन्या}}",
        "grouppage-user": "{{एनयस:आयोजना}}:प्रयोगकर्ताहरू",
        "grouppage-autoconfirmed": "{{एनयस:आयोजना}}:स्वनिर्धारित प्रयोगकर्ताहरू",
        "grouppage-bot": "{{एनयस:आयोजना}}:बोटहरु",
        "tooltip-t-whatlinkshere": "यो सित जोडियाका सब्बै विकि पानानको सूची",
        "tooltip-t-recentchangeslinked": "यै पानामी जोडियाका पानामी अहिलको परिवर्तन",
        "tooltip-feed-atom": "यै पानाकी लेखा एक एटम फिड",
-       "tooltip-t-contributions": "यिन प्रयोगकर्ताका योगदानहरूको सूची हेरपुई",
+       "tooltip-t-contributions": "{{GENDER:$1|यिन प्रयोगकर्ता}}का योगदानहरूको सूची हेरपुई",
        "tooltip-t-upload": "चित्र अप्लोड अर",
        "tooltip-t-specialpages": "सब्बै खास खास पानानको शुचि ।",
        "tooltip-t-print": "यो पानाको छापिन्या संस्करण",
index 321a044..1a206aa 100644 (file)
@@ -95,5 +95,6 @@
        "protect_expiry_invalid": "Expiry time is invalid.",
        "protect_expiry_old": "Expiry time is in the past.",
        "protect-existing-expiry": "Existing expiry time: $3, $2",
-       "protect-existing-expiry-infinity": "Existing expiry time: infinite"
+       "protect-existing-expiry-infinity": "Existing expiry time: infinite",
+       "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# Headings that will be ignored by search.\n# Changes to this take effect as soon as the page with the heading is indexed.\n# You can force page reindexing by doing a null edit.\n# Syntax is as follows:\n#   * Everything from a \"#\" character to the end of the line is a comment.\n#   * Every non-blank line is the exact title to ignore, case and everything.\nReferences\nExternal links\nSee also\n #</pre> <!-- leave this line exactly as it is -->"
 }
index 7c755f7..839e081 100644 (file)
        "tagline": "From {{SITENAME}}",
        "help": "Help",
        "search": "Search",
+       "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# Headings that will be ignored by search.\n# Changes to this take effect as soon as the page with the heading is indexed.\n# You can force page reindexing by doing a null edit.\n# The syntax is as follows:\n#   * Everything from a \"#\" character to the end of the line is a comment.\n#   * Every non-blank line is the exact title to ignore, case and everything.\nReferences\nExternal links\nSee also\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Search",
        "go": "Go",
        "searcharticle": "Go",
        "passwordreset-emailelement": "Username:\n$1\n\nTemporary password:\n$2",
        "passwordreset-emailsentemail": "If this email address is associated with your account, then a password reset email will be sent.",
        "passwordreset-emailsentusername": "If there is an email address associated with this username, then a password reset email will be sent.",
-       "passwordreset-emailsent-capture": "A password reset email has been sent, which is shown below.",
-       "passwordreset-emailerror-capture": "A password reset email was generated, which is shown below, but sending it to the {{GENDER:$2|user}} failed: $1",
        "passwordreset-emailsent-capture2": "The password reset {{PLURAL:$1|email has|emails have}} been sent. The {{PLURAL:$1|username and password|list of usernames and passwords}} is shown below.",
        "passwordreset-emailerror-capture2": "Emailing the {{GENDER:$2|user}} failed: $1 The {{PLURAL:$3|username and password|list of usernames and passwords}} is shown below.",
        "passwordreset-nocaller": "A caller must be provided",
        "changeemail": "Change or remove email address",
        "changeemail-summary": "",
        "changeemail-header": "Complete this form to change your email address. If you would like to remove the association of any email address from your account, leave the new email address blank when submitting the form.",
-       "changeemail-passwordrequired": "You will need to enter your password to confirm this change.",
        "changeemail-no-info": "You must be logged in to access this page directly.",
        "changeemail-oldemail": "Current email address:",
        "changeemail-newemail": "New email address:",
        "undo-nochange": "The edit appears to have already been undone.",
        "undo-summary": "Undo revision $1 by [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]])",
        "undo-summary-username-hidden": "Undo revision $1 by a hidden user",
-       "cantcreateaccounttitle": "Cannot create account",
        "cantcreateaccount-text": "Account creation from this IP address (<strong>$1</strong>) has been blocked by [[User:$3|$3]].\n\nThe reason given by $3 is <em>$2</em>",
        "cantcreateaccount-range-text": "Account creation from IP addresses in the range <strong>$1</strong>, which includes your IP address (<strong>$4</strong>), has been blocked by [[User:$3|$3]].\n\nThe reason given by $3 is <em>$2</em>",
        "createaccount-hook-aborted": "$1",
        "action-applychangetags": "apply tags along with your changes",
        "action-changetags": "add and remove arbitrary tags on individual revisions and log entries",
        "action-deletechangetags": "delete tags from the database",
+       "action-purge": "purge this page",
        "nchanges": "$1 {{PLURAL:$1|change|changes}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|since last visit}}",
        "enhancedrc-history": "history",
        "watchnologin": "Not logged in",
        "addwatch": "Add to watchlist",
        "addedwatchtext": "\"[[:$1]]\" and its discussion page have been added to your [[Special:Watchlist|watchlist]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" and its associated page have been added to your [[Special:Watchlist|watchlist]].",
        "addedwatchtext-short": "The page \"$1\" has been added to your watchlist.",
        "removewatch": "Remove from watchlist",
        "removedwatchtext": "\"[[:$1]]\" and its discussion page have been removed from your [[Special:Watchlist|watchlist]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" and its associated page have been removed from your [[Special:Watchlist|watchlist]].",
        "removedwatchtext-short": "The page \"$1\" has been removed from your watchlist.",
        "watch": "Watch",
        "watchthispage": "Watch this page",
index 1a60284..e6a2368 100644 (file)
@@ -50,8 +50,8 @@
                        "Orikrin1998"
                ]
        },
-       "tog-underline": "Substreki ligilojn",
-       "tog-hideminor": "Kaŝi malgrandajn redaktetojn ĉe <i>Lastaj ŝanĝoj</i>",
+       "tog-underline": "Substrekado de ligiloj:",
+       "tog-hideminor": "Kaŝi etajn redaktojn de la lastaj ŝanĝoj",
        "tog-hidepatrolled": "Kaŝi patrolitajn redaktojn en lastaj ŝanĝoj",
        "tog-newpageshidepatrolled": "Kaŝi patrolitajn paĝojn de listo de novaj paĝoj",
        "tog-hidecategorization": "Kaŝi enkategoriigon de paĝoj",
@@ -65,7 +65,7 @@
        "tog-watchdefault": "Aldoni al mia atentaro paĝojn kaj dosierojn redaktitajn de mi",
        "tog-watchmoves": "Aldoni paĝojn kaj dosierojn, kiujn mi movas, al mia atentaro",
        "tog-watchdeletion": "Aldoni paĝojn kaj dosierojn, kiujn mi forigas, al mia atentaro",
-       "tog-watchuploads": "Aldonu novajn dosierojn, kiujn mi alŝutas, al mia atentaro",
+       "tog-watchuploads": "Aldoni novajn dosierojn, kiujn mi alŝutos, al mia atentaro",
        "tog-watchrollback": "Aldoni paĝojn, kie mi amasmalfaris, al mia atentaro.",
        "tog-minordefault": "Marki defaŭlte ĉiujn redaktojn kiel etajn",
        "tog-previewontop": "Montri antaŭrigardon antaŭ redaktilo",
@@ -86,7 +86,7 @@
        "tog-watchlistreloadautomatically": "Reŝargi la atentaron aŭtomate ĉiam, kiam filtrilo estas ŝanĝita (bezonas Ĝavoskripton)",
        "tog-watchlisthideanons": "Kaŝi redaktojn de anonimuloj de la atentaro",
        "tog-watchlisthidepatrolled": "Kaŝi patrolitajn redaktojn de la atentaro",
-       "tog-watchlisthidecategorization": "Kaŝu enkategoriigon de paĝoj",
+       "tog-watchlisthidecategorization": "Kaŝi enkategoriigon de paĝoj",
        "tog-ccmeonemails": "Sendi al mi kopiojn de retpoŝtaĵoj, kiujn mi sendis al aliaj uzantoj.",
        "tog-diffonly": "Ne montri paĝan enhavon sub la ŝanĝmontrilo",
        "tog-showhiddencats": "Montri kaŝitajn kategoriojn",
        "sun": "dim",
        "mon": "lun",
        "tue": "mar",
-       "wed": "Mer",
-       "thu": "Ä´aŭ",
-       "fri": "Ven",
+       "wed": "mer",
+       "thu": "ĵaŭ",
+       "fri": "ven",
        "sat": "sab",
        "january": "januaro",
        "february": "februaro",
        "period-am": "ATM",
        "period-pm": "PTM",
        "pagecategories": "{{PLURAL:$1|Kategorio|Kategorioj}}",
-       "category_header": "Artikoloj en kategorio \"$1\"",
+       "category_header": "Artikoloj en kategorio “$1”",
        "subcategories": "Subkategorioj",
        "category-media-header": "Dosieroj en kategorio “$1”",
        "category-empty": "<em>Tiu ĉi kategorio nuntempe enhavas neniun artikolon aŭ plurmedian dosieron.</em>",
        "listingcontinuesabbrev": "daŭrigo",
        "index-category": "Indeksitaj paĝoj",
        "noindex-category": "Neindeksitaj paĝoj",
-       "broken-file-category": "Paĝoj kun eraraj dosierligiloj",
+       "broken-file-category": "Paĝoj kun rompita ligilo al dosiero",
        "about": "Pri",
        "article": "Artikolo",
        "newwindow": "(en nova fenestro)",
        "badaccess-groups": "La ago, kiun vi petis, estas limigita al uzantoj en {{PLURAL:$2|la grupo|unu el la grupoj}}: $1.",
        "versionrequired": "Versio $1 de MediaWiki nepras",
        "versionrequiredtext": "La versio $1 de MediaWiki estas necesa por uzi ĉi tiun paĝon. Vidu [[Special:Version|paĝon pri versio]].",
-       "ok": "Ek!",
+       "ok": "Bone",
        "retrievedfrom": "Elŝutita el  \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|Vi havas}} $1 ($2).",
        "youhavenewmessagesfromusers": "Riceviĝis $1 de {{PLURAL:$3|alia uzanto|$3 uzantoj}} ($2).",
        "content-model-css": "CSS",
        "content-json-empty-object": "Malplena objeto",
        "content-json-empty-array": "Malplena tabelo",
+       "deprecated-self-close-category": "Paĝoj, kiuj enhavas nevalidan memferman HTML‑etikedon",
        "duplicate-args-warning": "'''Averto:''' [[:$1]] vokas al [[:$2]] kun pli ol unu valoro por la parametro \"$3\". Nur la lasta liverita valoro estos uzata.",
        "duplicate-args-category": "Paĝoj kun pluroblaj argumentoj en ŝablonvokoj",
        "duplicate-args-category-desc": "La paĝo enhavas uzon de ŝablono kun pluroble uzitaj argumentoj, kiel ekzemple <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> aŭ <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "badfilename": "Dosiernomo estis ŝanĝita al \"$1\".",
        "filetype-mime-mismatch": "Dosiera sufikso \".$1\" ne kongruas la MIME-tipon de la dosiero ($2).",
        "filetype-badmime": "Dosieroj de la MIME-tipo \"$1\" ne estas permesitaj por alŝutado.",
-       "filetype-bad-ie-mime": "Ne povas alŝuti ĉi tiun dosieron, ĉar Interreta Esplorilo detektus ĝin kiel \"$1\", kiu estas malpermesita kaj eble danĝera dosiertipo.",
+       "filetype-bad-ie-mime": "Ne povas alŝuti ĉi tiun dosieron, ĉar Internet Explorer detektus ĝin kiel dosieron “$1”, kiu estas malpermesita kaj eble danĝera dosiertipo.",
        "filetype-unwanted-type": "'''\".$1\"''' estas nevolata dosiero-tipo. {{PLURAL:$3|Preferata dosiero-tipo|Prefereataj dosiero-tipoj}} estas $2.",
        "filetype-banned-type": "'''\".$1\"''' ne estas {{PLURAL:$4|permesita dosiero-tipo|permesitaj dosiero-tipoj}}. {{PLURAL:$3|Permesita dosiero-tipo|Permesitaj dosiero-tipoj}} estas $2.",
        "filetype-missing": "Ĉi tiu dosiero ne inkluzivas finaĵon de dosiernomo (kiel \".jpg\").",
        "log-action-filter-newusers": "Tipo de konta kreado:",
        "log-action-filter-patrol": "Tipo de patrolado:",
        "log-action-filter-protect": "Tipo de protektad:",
-       "log-action-filter-rights": "Tipo de rajta ŝanĝo",
-       "log-action-filter-suppress": "Tipo de forigado",
+       "log-action-filter-rights": "Tipo de rajta ŝanĝo:",
+       "log-action-filter-suppress": "Tipo de subpremado:",
        "log-action-filter-upload": "Tipo de alŝutado:",
        "log-action-filter-all": "Ĉia",
        "log-action-filter-block-block": "Forbari",
        "authmanager-provider-password-domain": "Aŭtentikigo per pasvorto kaj domajno",
        "authmanager-provider-temporarypassword": "Provizora pasvorto:",
        "authprovider-confirmlink-message": "Laŭ viaj lastatempaj provoj de ensalutado, la sekvantaj kontoj povas esti ligita al via vikia konto. Ligi ilin ebligas ensalutadon per tiuj kontoj. Bonvolu elekti tiun, kiun ligendus.",
-       "authprovider-confirmlink-request-label": "Kontoj kiuj devus esti ligita",
+       "authprovider-confirmlink-request-label": "Kontoj, kiuj devas esti ligita",
        "authprovider-confirmlink-success-line": "$1: Ligita sukcese.",
        "authprovider-confirmlink-failed": "Ligado de konto ne plene sukcesis: $1",
        "authprovider-confirmlink-ok-help": "Kontinui post montrado de mesaĝoj pri malsukceso de ligado.",
index 4b76762..a9facb7 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ayuda",
        "search": "Buscar",
+       "search-ignored-headings": " #<!-- dejar esta línea exactamente como está --> <pre>\n# Títulos que serán ignorados por la búsqueda.\n# Los cambios estarán en vigor tan pronto como la página con el título esté indexada.\n# Puedes forzar la reindexación de una página haciendo una edición nula.\n# La sintaxis es la siguiente:\n#   * Todo lo que sigue a un carácter \"#\" hasta el final de la línea, es un comentario.\n#   * Todas las líneas que no están en blanco son los títulos exactos que se ignorarán (diferenciando mayúsculas de minúsculas).\nReferencias\nEnlaces externos\nVéase también\n #</pre> <!-- dejar esta línea exactamente como está -->",
        "searchbutton": "Buscar",
        "go": "Ir",
        "searcharticle": "Ir",
        "action-applychangetags": "aplicar etiquetas junto con los cambios",
        "action-changetags": "agregar y quitar etiquetas arbitrarias a revisiones individuales y entradas del registro",
        "action-deletechangetags": "eliminar etiquetas de la base de datos",
+       "action-purge": "purgar esta página",
        "nchanges": "$1 {{PLURAL:$1|cambio|cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde la última visita}}",
        "enhancedrc-history": "historial",
index 8517227..13085dd 100644 (file)
        "minoredit": "Aldaketa hau txikia da",
        "watchthis": "Orrialde hau jarraitu",
        "savearticle": "Gorde orria",
+       "savechanges": "Aldaketak gorde",
        "publishpage": "Orrialdea argitaratu",
        "publishchanges": "Aldaketak argitaratu",
        "preview": "Aurrebista erakutsi",
        "revdelete-unsuppress": "Berrezarritako aldaketen mugak kendu",
        "revdelete-log": "Arrazoia:",
        "revdelete-submit": "Hautatutako {{PLURAL:$1|berrikuspenari|berrikuspenei}} aplikatu",
-       "revdelete-success": "'''Berrikuspenen ikusgarritasuna eguneratu da.'''",
+       "revdelete-success": "Berrikuspenen ikusgarritasuna eguneratu da.",
        "revdelete-failure": "'''Ezin da berrikuspenaren ikuspena eguneratu:'''\n$1",
-       "logdelete-success": "'''Log ikusgarritasuna ondo ezarri da.'''",
+       "logdelete-success": "Log ikusgarritasuna ondo ezarri da.",
        "logdelete-failure": "'''Erregistroaren ikusgaitasuna ezin da honela ezarri:'''\n$1",
        "revdel-restore": "Aldatu ikusgaitasuna",
        "pagehist": "Orriaren historia",
        "mergehistory-go": "Aldaketa bateragarriak erakutsi",
        "mergehistory-submit": "Berrikuspenak bateratu",
        "mergehistory-empty": "Ezin da berrikuspenik bateratu",
-       "mergehistory-done": "$1(e)ko {{PLURAL:$3|berrikuspen|berrikuspen}} bateratu egin dira [[:$2]](e)n.",
+       "mergehistory-done": "$1(e)ko {{PLURAL:$3|berrikuspen}} bateratu egin {{PLURAL:$3|da|dira}} [[:$2]](e)n.",
        "mergehistory-fail": "Ezin izan da historia bateratu; egiaztatu orrialde eta denbora parametroak.",
        "mergehistory-no-source": "Ez da $1 jatorrizko orrialdea existitzen.",
        "mergehistory-no-destination": "Ez da $1 helburu orrialdea existitzen.",
        "editusergroup": "{{GENDER:$1|Erabiltzaile}} taldeak editatu",
        "editinguser": "'''[[User:$1|$1]]''' $2 lankidearen erabiltzaile-eskubideak aldatzen",
        "userrights-editusergroup": "Erabiltzaile taldeak editatu",
-       "saveusergroups": "Erabiltzaile taldeak gorde",
+       "saveusergroups": "Erabiltzaile {{GENDER:$1|taldeak}} gorde",
        "userrights-groupsmember": "Ondorengo talde honetako kide da:",
        "userrights-groupsmember-auto": "Honen kide inplizitua:",
        "userrights-groups-help": "Lankide hau zein taldetakoa den alda dezakezu:\n* Laukia hautatuta baldin badago, esan nahi du lankidea talde horretakoa dela.\n* Laukia hautatu gabe baldin badago, esan nahi du lankidea talde horretakoa ez dela.\n* Izartxoak (*) erakusten du ezin duzula talde horretatik kendu, taldera gehitu eta gero; edo alderantziz, ezin duzula talde horretara gehitu, taldetik kendu eta gero.",
        "userrights-changeable-col": "Alda ditzakezun taldeak",
        "userrights-unchangeable-col": "Aldatu ezin ditzakezun taldeak",
        "userrights-conflict": "Gatazka gertatu da erabiltzaile eskubideak aldatzean. Mesedez, berrikusi eta baieztatu zure aldaketak.",
-       "userrights-removed-self": "Arrakasta izan duzu zure eskumenak kentzen. Beraz jada ezin duzu orrialde hau gehiago ikusi.",
+       "userrights-removed-self": "Zure eskumenak kendu dituzu. Beraz jada ezin duzu orrialde hau gehiago ikusi.",
        "group": "Taldea:",
        "group-user": "Erabiltzaileak",
        "group-autoconfirmed": "Lankide autokonfirmatuak",
        "right-override-export-depth": "5eko sakonerararteko loturiko orrialdeak barne esportatu",
        "right-sendemail": "Beste erabiltzaileei e-posta bidali",
        "right-passwordreset": "Ikusi pasahitza berrezartze e-postak",
+       "grant-group-email": "E-posta bidali",
        "grant-createaccount": "Kontuak sortu",
        "grant-editmycssjs": "Zure CSS/JavaScript aldatu",
        "grant-editmyoptions": "Aldatu zure hobespenak",
        "rightslogtext": "Erabiltzaile eskubideetan izandako aldaketen erregistroa da hau.",
        "action-read": "orrialde hau irakurri",
        "action-edit": "orri hau aldatu",
-       "action-createpage": "orrialdeak sortu",
-       "action-createtalk": "eztabaida orrialdeak sortu",
+       "action-createpage": "Sortu orri hau",
+       "action-createtalk": "eztabaida orrialde hau sortu",
        "action-createaccount": "lankide hau sortu",
        "action-history": "orrialde honen historia ikusi",
        "action-minoredit": "markatu aldaketa hau txikitzat",
        "upload-form-label-infoform-title": "Xehetasunak",
        "upload-form-label-infoform-name": "Izena",
        "upload-form-label-infoform-description": "Deskribapena",
+       "upload-form-label-infoform-description-tooltip": "Azaldu laburki lanaren inguruko kontu aipagarri guztiak. Argazki batean, aipatu agertzen den gai nagusia, momentua, edo lekua.",
        "upload-form-label-usage-title": "Erabilera",
        "upload-form-label-usage-filename": "Fitxategiaren izena",
        "upload-form-label-own-work": "Hau neure lana da",
        "filerevert-legend": "Fitxategia leheneratu",
        "filerevert-intro": "'''[[Media:$1|$1]]''' berrezartzen ari zara [$4 $3(e)ko, $2(e)tako bertsiora].",
        "filerevert-comment": "Arrazoia:",
-       "filerevert-defaultcomment": "$2, $1 bertsiora leheneratu da",
+       "filerevert-defaultcomment": "$2, $1 ($3) bertsiora leheneratu da",
        "filerevert-submit": "Leheneratu",
        "filerevert-success": "'''[[Media:$1|$1]]''' [$4 $3(e)ko, $2(e)tako bertsiora] lehenratua izan da.",
        "filerevert-badversion": "Ez dago aurreragoko fitxategi honen bertsio lokalik emandako denbora tartean.",
        "listgrouprights-removegroup-self-all": "Talde guztiak norbere kontutik ezabatu",
        "listgrouprights-namespaceprotection-namespace": "Izen-tartea",
        "listgrants": "Diru-laguntzak",
+       "listgrants-grant": "Baimena eman",
        "listgrants-rights": "Eskubideak",
+       "trackingcategories": "Jarraipen kategoriak",
+       "trackingcategories-msg": "Jarraipen kategoria",
        "trackingcategories-name": "Mezuaren izena",
        "trackingcategories-nodesc": "Ez dago deskribapenik eskuragarri.",
        "trackingcategories-disabled": "Kategoria desgaitua dago",
        "emailccsubject": "Zure mezuaren kopia $1(r)i: $2",
        "emailsent": "Mezua bidali egin da",
        "emailsenttext": "Zure e-posta mezua bidali egin da.",
-       "emailuserfooter": "E-posta hau $1(e)k bidali dio $2(r)i {{SITENAME}}ko \"{{int:emailuser}}\" funtzioa erabiliz.",
+       "emailuserfooter": "E-posta hau $1(e)k {{GENDER:$1|bidali}} dio {{GENDER:$2|$2}}(r)i {{SITENAME}}ko \"{{int:emailuser}}\" funtzioa erabiliz.",
        "usermessage-summary": "Sistema mezua uzten.",
        "usermessage-editor": "Sistemako mezularia",
        "watchlist": "Jarraipen zerrenda",
        "wlshowhideanons": "erabiltzaile anonimoak",
        "wlshowhidepatr": "Patruilatutako aldaketak",
        "wlshowhidemine": "nire edizioak",
+       "wlshowhidecategorization": "orrialdearen kategorizazioa",
        "watchlist-options": "Jarraitze-zerrendaren aukerak",
        "watching": "Zerrendan gehitzen...",
        "unwatching": "Zerrendatik kentzen...",
        "sessionfailure": "Badirudi saioarekin arazoren bat dagoela; bandalismoak saihesteko ekintza hau ezeztatu egin da. Mesedez, nabigatzaileko \"atzera\" botoian klik egin, hona ekarri zaituen orrialde hori berriz kargatu, eta saiatu berriz.",
        "changecontentmodel-title-label": "Orriaren izenburua",
        "changecontentmodel-reason-label": "Arrazoia:",
+       "changecontentmodel-submit": "Aldatu",
        "logentry-contentmodel-change-revertlink": "desegin",
        "logentry-contentmodel-change-revert": "desegin",
        "protectlogpage": "Babes erregistroa",
        "ipb-unblock": "Erabiltzaile izen edo IP helbide bati blokeoa kendu",
        "ipb-blocklist": "Blokeaketak ikusi",
        "ipb-blocklist-contribs": "{{GENDER:$1|$1(r)en}} ekarpenak",
+       "ipb-blocklist-duration-left": "gainerako $1",
        "unblockip": "Erabiltzailea desblokeatu",
        "unblockiptext": "Erabili beheko formularioa lehenago blokeatutako IP helbide edo erabiltzaile baten idazketa baimenak leheneratzeko.",
        "ipusubmit": "Blokeoa ezabatu",
        "pageinfo-category-files": "Fitxategi kopurua",
        "markaspatrolleddiff": "Patruilatutzat markatu",
        "markaspatrolledtext": "Artikulu hau patruilatutzat markatu",
+       "markaspatrolledtext-file": "Fitxategi honen bertsioa patruilatutzat markatu",
        "markedaspatrolled": "Patruilatutzat markatu da",
        "markedaspatrolledtext": "[[:$1]]-(r)en bertsio hautatua patruilatutzat markatu da.",
        "rcpatroldisabled": "Aldaketa berrien patruilaketa ezgaituta dago",
        "confirm-watch-top": "Orrialde hau zure jarraipen-zerrendara gehitu?",
        "confirm-unwatch-button": "Ados",
        "confirm-unwatch-top": "Orrialde hau zure jarraipen-zerrendatik kendu?",
+       "confirm-rollback-button": "Ados",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "&larr; aurreko orrialdea",
        "imgmultipagenext": "hurrengo orrialdea &rarr;",
        "logentry-move-move_redir": "$1 {{GENDER:$2|wikilariak}} «$3» orria «$4» izenera aldatu du, birzuzenketaren gainetik",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:wikilariak}} «$3» orria «$4» izenera aldatu du, birbideratze bat gainidatzita, birbideratzerik utzi gabe",
        "logentry-patrol-patrol": "$1(e)k $3 orrialdearen $4 berrikuspena patruilatutzat {{GENDER:$2|markatu}} du",
-       "logentry-newusers-newusers": "$1 erabiltzaile kontua sortu da",
+       "logentry-newusers-newusers": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
        "logentry-newusers-create": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
        "logentry-newusers-create2": "$1 wikilariak $3 erabiltzaile kontua sortu du",
+       "logentry-newusers-byemail": "$1(e)k $3 erabiltzaile kontua {{GENDER:$2|sortu du}} eta pasahitza emailez bidali da",
        "logentry-upload-upload": "$1(e)k $3 {{GENDER:$2|igo du}}",
        "log-name-tag": "Etiketen erregistroa",
        "rightsnone": "(bat ere ez)",
        "expand_templates_generate_xml": "Erakutsi XML parse zuhaitza",
        "expand_templates_generate_rawhtml": "Erakutsi HTML gordina",
        "expand_templates_preview": "Aurreikusi",
-       "pagelanguage": "Orriaren hizkuntza aukeratu",
+       "pagelanguage": "Orriaren hizkuntza aldatu",
        "pagelang-name": "Orria",
        "pagelang-language": "Hizkuntza",
        "pagelang-use-default": "Hizkuntza lehenetsia erabili",
        "mw-widgets-dateinput-no-date": "Ez duzu datarik aukeratu",
        "mw-widgets-titleinput-description-new-page": "orri hori oraindik ez da existitzen",
        "mw-widgets-titleinput-description-redirect": "$1ra birzuzendu",
-       "sessionprovider-generic": "$1 sesio"
+       "sessionprovider-generic": "$1 sesio",
+       "log-action-filter-all": "Denak",
+       "log-action-filter-block-block": "Blokeatu",
+       "log-action-filter-block-reblock": "Blokeoa aldatu",
+       "log-action-filter-block-unblock": "blokeoa kendu",
+       "authmanager-userdoesnotexist": "\"$1\" erabiltzaile kontua ez dago erregistratua.",
+       "authmanager-email-label": "Emaila",
+       "authmanager-email-help": "Helbide elektronikoa",
+       "authmanager-realname-label": "Benetako izena",
+       "authmanager-realname-help": "Erabiltzailearen benetako izena",
+       "authprovider-resetpass-skip-label": "Utzi",
+       "authform-wrongtoken": "Token okerra"
 }
index 8c8cee9..28e2dd8 100644 (file)
        "tagline": "از {{SITENAME}}",
        "help": "راهنما",
        "search": "جستجو",
+       "search-ignored-headings": "#<!-- این صفحه را درست همانطور که هست رها کنید --> <pre>\n#سر‌فصل‌هایی که توسط تحقیق نادیده گرفته خواهندشد.‌\n#به محض اینکه صفحه با سرفصل، فهرست شده‌است،تغییرات متاثر می‌شود.\n#شما می‌توانید با انجام یک ویرایش پوچ صفحه را وادار به دوباره فهرست کردن کنید.\n#نحو به شرح زیر است:\n#  *همه چیز از یک خصیصهٔ \"#\" گرفته تا آخر خط، یک نظر است\n#  *هر خط بدون فاصله، عنوان دقیق برای نادیده گرفتن،موضوع و همه چیز منابع است\nاتصالات خارجی\nهمچنین مشاهده کنید\n#</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "جستجو",
        "go": "برو",
        "searcharticle": "برو",
        "watchthis": "پی‌گیری این صفحه",
        "savearticle": "صفحه ذخیره شود",
        "savechanges": "ذخیرهٔ تغییرات",
-       "publishpage": "اÙ\86تشار صفحه",
-       "publishchanges": "اÙ\86تشار تغییرات",
+       "publishpage": "ذخÛ\8cرÙ\87 صفحه",
+       "publishchanges": "ذخÛ\8cرÙ\87 تغییرات",
        "preview": "پیش‌نمایش",
        "showpreview": "پیش‌نمایش",
        "showdiff": "نمایش تغییرات",
        "anontalkpagetext": "----<em>این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمی‌کند.\nبنا بر این برای شناسایی‌اش مجبوریم از نشانی آی‌پی عددی استفاده کنیم.</em>\nچنین نشانی‌های آی‌پی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور می‌کنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:CreateAccount|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].",
        "noarticletext": "این صفحه هم‌اکنون دارای هیچ متنی نیست.\nشما می‌توانید در صفحه‌های دیگر [[Special:Search/{{PAGENAME}}|عنوان این صفحه را جستجو کنید]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهه‌های مرتبط را جستجو کنید]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} این صفحه را ایجاد کنید]</span>.",
        "noarticletext-nopermission": "این صفحه هم‌اکنون متنی ندارد.\nشما می‌توانید در دیگر صفحات [[Special:Search/{{PAGENAME}}|این عنوان را جستجو کنید]]،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهه‌های مرتبط را بگردید]</span> ولی شما اجازه ایجاد این صفحه را ندارید.",
-       "missing-revision": "ویرایش #$1 از صفحهٔ «{{FULLPAGENAME}}» موجود نیست.\n\nمعمولاً در اثر پیوند به تاریخچهٔ به‌روز نشدهٔ صفحهٔ حذف شده است.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
+       "missing-revision": "ویرایش #$1 از صفحهٔ «{{FULLPAGENAME}}» موجود نیست.\n\nاین اتفاق معمولاً در اثر دنبال کردن پیوندی به تاریخچهٔ یک صفحهٔ حذف‌شده پیش می‌آید.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
        "userpage-userdoesnotexist": "حساب کاربر «<nowiki>$1</nowiki>» ثبت نشده‌است.\nلطفاً مطمئن شوید که می‌خواهید این صفحه را ایجاد یا ویرایش کنید.",
        "userpage-userdoesnotexist-view": "حساب کاربری «$1» ثبت نشده‌است.",
        "blocked-notice-logextract": "دسترسی این کاربر در حال حاضر بسته است.\nآخرین مورد سیاهه قطع دسترسی در زیر آمده‌است:",
        "diff-multi-sameuser": "({{PLURAL:$1|یک نسخهٔ میانی|$1 نسخهٔ میانی}}ِ همین کاربر نمایش داده نشده است)",
        "diff-multi-otherusers": "({{PLURAL:$1|۱ نسخهٔ میانی|$1 نسخه‌ٔ میانی}} ویرایش شده توسط {{PLURAL:$2|۱ کاربر|$2 کاربر}} نشان داده نشده)",
        "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}}}} سیاههٔ حذف] بیابید.",
+       "difference-missing-revision": "{{PLURAL:$2|یک ویرایش|$2 ویرایش}}  از تفاوت نسخه‌ها ($1) {{PLURAL:$2|یافت|یافت}}  نشد.\n\nاین اتفاق معمولاً در اثر دنبال کردن پیوند تفاوتی به یک صفحهٔ حذف‌شده پیش می‌آید.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
        "searchresults": "نتایج جستجو",
        "searchresults-title": "نتایج جستجو برای «$1»",
        "titlematches": "تطبیق عنوان مقاله",
        "notvisiblerev": "آخرین نسخه توسط کاربری دیگر حذف شده‌است",
        "watchlist-details": "بدون احتساب صفحه‌های جداگانهٔ بحث، {{PLURAL:$1|$1 صفحه|$1 صفحه}} در فهرست پی‌گیری‌های شما قرار {{PLURAL:$1|دارد|دارند}}.",
        "wlheader-enotif": "ایمیل‌های اعلان فعال است.",
-       "wlheader-showupdated": "صفحه‌هایی که پس از آخرین بازدید شما تغییر کرده‌اند '''پررنگ''' نمایش داده شده‌اند.",
+       "wlheader-showupdated": "صفحه‌هایی که پس از آخرین بازدید شما تغییر کرده‌اند <strong>پررنگ</strong> نمایش داده شده‌اند.",
        "wlnote": "در زیر {{PLURAL:$1|تغییری|<strong>$1</strong> تغییری}} که در {{PLURAL:$2|ساعت|<strong>$2</strong> ساعت}} گذشته انجام شده موجود است، تاریخ آخرین بازیابی: $3، $4",
        "wlshowlast": "نمایش آخرین $1 ساعت $2 روز",
        "watchlist-hide": "نهفتن",
        "actionfailed": "عمل ناموفق بود",
        "deletedtext": "«$1» حذف شد.\nبرای سابقهٔ حذف‌های اخیر به $2 مراجعه کنید.",
        "dellogpage": "سیاههٔ حذف",
-       "dellogpagetext": "فهرست زیر فهرستی از آخرین حذف‌هاست.\nهمهٔ زمان‌های نشان‌داده‌شده زمان خادم (وقت گرینویچ) است.",
+       "dellogpagetext": "فهرست زیر فهرستی از آخرین حذف‌هاست.\nهمهٔ زمان‌های نشان‌داده‌شده زمان کارساز (وقت گرینویچ) است.",
        "deletionlog": "سیاههٔ حذف",
        "reverted": "به نسخهٔ قدیمی‌تر واگردانده شد",
        "deletecomment": "دلیل:",
        "protect-default": "همهٔ کاربرها",
        "protect-fallback": "فقط به کاربرهایی که دسترسی «$1» دارند، اجازه داده می‌شود",
        "protect-level-autoconfirmed": "تنها کاربران تأییدشده",
-       "protect-level-sysop": "فقط مدیران",
+       "protect-level-sysop": "تنها مدیران",
        "protect-summary-cascade": "آبشاری",
        "protect-expiring": "زمان سرآمدن $1 (UTC)",
        "protect-expiring-local": "منقضی $1",
        "confirmrecreate-noreason": "کاربر [[User:$1|$1]] ([[User talk:$1|بحث]]) این صفحه را پس از شروع ویرایش‌تان {{GENDER:$1|پاک}} کرده‌است.  لطفاً تأیید کنید که شما واقعاً می‌خواهید آن را دوباره ایجاد کنید.",
        "recreate": "باز ایجاد",
        "confirm_purge_button": "تأیید",
-       "confirm-purge-top": "پاککردن نسخهٔ حافظهٔ نهانی (Cache) این صفحه را تأیید می‌کنید؟",
+       "confirm-purge-top": "پاک کردن نسخهٔ حافظهٔ نهانی (Cache) این صفحه را تأیید می‌کنید؟",
        "confirm-purge-bottom": "خالی کردن میانگیر یک صفحه باعث می‌شود که آخرین نسخهٔ آن نمایش یابد.",
        "confirm-watch-button": "تأیید",
        "confirm-watch-top": "این صفحه به فهرست پی‌گیری‌های شما افزوده شود؟",
index 07869da..dda086c 100644 (file)
        "tagline": "Kohteesta {{SITENAME}}",
        "help": "Ohje",
        "search": "Haku",
+       "search-ignored-headings": "#<!-- jätä tämä rivi sellaiseksi kuin se on --> <pre>\n# Otsikot, jotka haku ohittaa.\n# Muutokset tulevat voimaan heti, kun otsikon sivu indeksoidaan.\n# Voit pakottaa sivun indeksoimisen tekemällä nollamuokkauksen.\n# Syntaksi on seuraava:\n#   * Kaikki \"#\"-merkistä rivin loppuun asti on kommenttia\n#   * Kaikki ei-tyhjät rivit ovat otsikoita, jotka ohitetaan.\nLähteet\nAiheesta muualla\nKatso myös\n#</pre> <!-- jätä tämä rivi sellaiseksi kuin se on -->",
        "searchbutton": "Hae",
        "go": "Siirry",
        "searcharticle": "Siirry",
index 0b7a358..116ae3a 100644 (file)
                        "Psychoslave",
                        "Trial",
                        "Matma Rex",
-                       "Dcausse"
+                       "Dcausse",
+                       "Lucas"
                ]
        },
        "tog-underline": "Soulignement des liens :",
        "tagline": "De {{SITENAME}}",
        "help": "Aide",
        "search": "Rechercher",
+       "search-ignored-headings": " #<!-- laisser cette ligne comme telle --> <pre>\n# Titres des sections qui seront ignorés par la recherche\n# Les changements effectués ici prennent effet dès lors que la page avec le titre est indexée.\n# Vous pouvez forcer la réindexation de la page en effectuant une modification vide\n# La syntaxe est la suivante :\n#   * Toute ligne précédée d’un « # » est un commentaire\n#   * Toute ligne non-vide est le titre exact à ignorer, casse comprise\nRéférences\nLiens externes\nVoir aussi\n #</pre> <!-- laisser cette ligne comme telle -->",
        "searchbutton": "Rechercher",
        "go": "Consulter",
        "searcharticle": "Lire",
        "missing-article": "La base de données n’a pas trouvé le texte d’une page qu’elle aurait dû trouver, intitulée « $1 » $2.\n\nGénéralement, cela survient en suivant un lien vers un diff périmé ou vers l’historique d’une page supprimée.\n\nSi ce n’est pas le cas, il peut s’agir d’une anomalie dans le programme.\nVeuillez la signaler à un [[Special:ListUsers/sysop|administrateur]] sans oublier de lui indiquer l’URL de la page.",
        "missingarticle-rev": "(numéro de version : $1)",
        "missingarticle-diff": "(diff : $1, $2)",
-       "readonly_lag": "La base de données a été automatiquement verrouillée pendant que les serveurs secondaires rattrapent leur retard sur le serveur principal.",
-       "nonwrite-api-promise-error": "L’entête HTTP « <code>Promise-Non-Write-API-Action:<code> » a été envoyé mais la requête a été faite à un module d’écriture de l’API.",
+       "readonly_lag": "La base de données a été automatiquement verrouillée pendant que les serveurs secondaires se réalignent sur le serveur principal.",
+       "nonwrite-api-promise-error": "L’entête HTTP « <code>Promise-Non-Write-API-Action:</code> » a été envoyé mais la requête a été faite à un module d’écriture de l’API.",
        "internalerror": "Erreur interne",
        "internalerror_info": "Erreur interne : $1",
        "internalerror-fatal-exception": "Erreur fatale de type « $1 »",
        "filecopyerror": "Impossible de copier le fichier « $1 » vers « $2 ».",
        "filerenameerror": "Impossible de renommer le fichier « $1 » en « $2 ».",
        "filedeleteerror": "Impossible de supprimer le fichier « $1 ».",
-       "directorycreateerror": "Impossible de créer le dossier « $1 ».",
+       "directorycreateerror": "Impossible de créer le répertoire « $1 ».",
        "directoryreadonlyerror": "Le répertoire « $1 » est en lecture seule.",
        "directorynotreadableerror": "Le répertoire « $1 » n’est pas lisible.",
        "filenotfound": "Impossible de trouver le fichier « $1 ».",
        "resetpass-expired": "Votre mot de passe a expiré. Veuillez en fournir un nouveau pour vous connecter.",
        "resetpass-expired-soft": "Votre mot de passe a expiré, et doit être réinitialisé. Veuillez en choisir un nouveau maintenant ou cliquer sur « {{int:authprovider-resetpass-skip-label}} » pour le faire plus tard.",
        "resetpass-validity-soft": "Votre mot de passe n’est pas valide : $1\n\nVeuillez choisir un nouveau mot de passe maintenant, ou cliquez sur « {{int:authprovider-resetpass-skip-label}} » pour le réinitialiser plus tard.",
-       "passwordreset": "Remise à zéro du mot de passe",
+       "passwordreset": "Réinitialisation du mot de passe",
        "passwordreset-text-one": "Remplissez ce formulaire pour réinitialiser votre mot de passe.",
        "passwordreset-text-many": "{{PLURAL:$1|Remplissez un des champs pour recevoir un mot de passe temporaire par courriel.}}",
        "passwordreset-disabled": "La réinitialisation des mots de passe a été désactivée sur ce wiki.",
        "passwordreset-capture-help": "Si vous cochez cette case, le courriel (avec le mot de passe temporaire) vous sera affiché en même temps qu’il sera envoyé à l’utilisateur.",
        "passwordreset-email": "Adresse de courriel :",
        "passwordreset-emailtitle": "Détails du compte sur {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Quelqu’un (probablement vous, depuis l’adresse IP $1) a demandé un réinitialisation de votre mot de passe pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :\n\n$2\n\n{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. Vous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous avez retrouvé votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
+       "passwordreset-emailtext-ip": "Quelqu’un (probablement vous, depuis l’adresse IP $1) a demandé un réinitialisation de votre mot de passe pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :\n\n$2\n\n{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. \nVous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous avez retrouvé votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
        "passwordreset-emailtext-user": "L’utilisateur $1 sur {{SITENAME}} a demandé une réinitialisation de votre mot de passe pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :\n\n$2\n\n{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. \nVous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou si vous avez retrouvé votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
        "passwordreset-emailelement": "Nom d’utilisateur : \n$1\n\nMot de passe temporaire : \n$2",
        "passwordreset-emailsentemail": "Si cette adresse de courriel est associée à votre compte, alors un courriel de réinitialisation de mot de passe sera envoyé.",
        "passwordreset-nosuchcaller": "L’appelant n’existe pas : $1",
        "passwordreset-ignored": "La réinitialisation du mot de passe n’a pas été gérée. Peut-être qu’aucun fournisseur n’a été configuré ?",
        "passwordreset-invalideamil": "Adresse de messagerie non valide",
-       "passwordreset-nodata": "Ni un nom d’utilisateur ni une adresse de messagerie n’a  été fourni",
+       "passwordreset-nodata": "Aucun nom d’utilisateur ou adresse de messagerie n’a été fourni",
        "changeemail": "Changer ou supprimer l’adresse de courriel",
        "changeemail-header": "Complétez ce formulaire pour modifier votre adresse de courriel. Si vous voulez supprimer l’association d’une adresse de courriel avec votre compte, laissez la nouvelle adresse de courriel vide lors de la soumission du formulaire.",
        "changeemail-passwordrequired": "Vous devrez saisir votre mot de passe pour confirmer cette modification.",
        "post-expand-template-argument-warning": "<strong>Attention :</strong> cette page contient au moins un paramètre de modèle dont la taille après expansion est trop importante. \nCes arguments n’ont donc pas été inclus.",
        "post-expand-template-argument-category": "Pages contenant des paramètres de modèle non évalués",
        "parser-template-loop-warning": "Modèle en boucle détecté : [[$1]]",
-       "parser-template-recursion-depth-warning": "Limite de profondeur des appels de modèles dépassée ($1)",
+       "parser-template-recursion-depth-warning": "Limite de profondeur des appels récursifs de modèles dépassée ($1)",
        "language-converter-depth-warning": "Limite de profondeur du convertisseur de langue dépassée ($1)",
        "node-count-exceeded-category": "Pages dépassant le nombre de nœuds maximal",
        "node-count-exceeded-category-desc": "Ces pages dépassent le nombre maximal de nœuds.",
        "parser-unstrip-loop-warning": "Boucle non démontable détectée",
        "parser-unstrip-recursion-limit": "Limite de récursion non démontable dépassée ($1)",
        "converter-manual-rule-error": "Erreur détectée dans la règle manuelle de conversion de langue",
-       "undo-success": "Cette modification va être défaite. \nVeuillez vérifier les différences ci-dessous, puis publier l'annulation si c’est bien ce que vous voulez faire.",
+       "undo-success": "Cette modification va être annulée.\nVeuillez vérifier les différences ci-dessous, puis publier l’annulation si c’est bien ce que vous voulez faire.",
        "undo-failure": "Cette modification ne peut pas être défaite : cela entrerait en conflit avec les modifications intermédiaires.",
        "undo-norev": "La modification n’a pas pu être défaite parce qu’elle est inexistante ou qu’elle a été supprimée.",
        "undo-nochange": "Il semblerait que la modification ait déjà été annulée.",
        "undo-summary": "Annulation des modifications $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]])",
        "undo-summary-username-hidden": "Annuler la révision $1 par un utilisateur masqué",
        "cantcreateaccounttitle": "Vous ne pouvez pas créer de compte.",
-       "cantcreateaccount-text": "La création de compte depuis cette adresse IP (<b>$1</b>) a été bloquée par [[User:$3|$3]].\n\nLa raison donnée était ''$2''.",
-       "cantcreateaccount-range-text": "La création de compte depuis les adresses IP dans la plage <strong>$1</strong>, qui comprend votre adresse IP (<strong>$4</strong>), ont été bloquées par [[User:$3|$3]].\n\nLe motif fourni par $3 est <em>$2</em>",
+       "cantcreateaccount-text": "La création de compte depuis cette adresse IP (<strong>$1</strong>) a été bloquée par [[User:$3|$3]]. \n\nLa raison donnée par $3 était : <em>$2</em>",
+       "cantcreateaccount-range-text": "La création de compte depuis les adresses IP de la plage <strong>$1</strong>, où se trouve votre adresse IP (<strong>$4</strong>), a été bloquée par [[User:$3|$3]].\n\nLe motif fourni par $3 est <em>$2</em>",
        "viewpagelogs": "Voir les opérations sur cette page",
        "nohistory": "Il n’existe pas d’historique des modifications pour cette page.",
        "currentrev": "Version actuelle",
        "logdelete-selected": "{{PLURAL:$1|Événement d'historique sélectionné|Événements d'historique sélectionnés}} :",
        "revdelete-text-text": "Les révisions supprimées continueront à apparaître dans l’historique de la page, mais une partie de leur contenu sera inaccessible au public.",
        "revdelete-text-file": "Les versions de fichier supprimées continueront à apparaître dans l’historique des fichiers, mais une partie de leur contenu sera indisponible au public.",
-       "logdelete-text": "Les évènements du journal supprimés continueront à apparaître dans les journaux, mais une partie de leur contenu sera indisponible au public.",
+       "logdelete-text": "Les évènements supprimés du journal continueront à apparaître dans les journaux, mais une partie de leur contenu sera indisponible au public.",
        "revdelete-text-others": "Les autres administrateurs seront toujours en mesure d'accéder au contenu caché et le restaurer, à moins que des restrictions supplémentaires soient fixées.",
        "revdelete-confirm": "Confirmez que vous voulez effectuer cette action, que vous en comprenez les conséquences, et que vous le faites en accord avec [[{{MediaWiki:Policy-url}}|les règles]].",
        "revdelete-suppress-text": "La suppression ne doit être utilisée <strong>que</strong> dans les cas suivants :\n* informations potentiellement diffamatoires\n* informations personnelles inappropriées\n*: <em>adresse, numéro de téléphone, numéro de sécurité sociale, …</em>",
        "revdelete-radio-same": "(ne pas changer)",
        "revdelete-radio-set": "Masqué",
        "revdelete-radio-unset": "Visible",
-       "revdelete-suppress": "Masquer également les données pour les administrateurs",
+       "revdelete-suppress": "Supprimer également les données des administrateurs",
        "revdelete-unsuppress": "Enlever les restrictions sur les versions restaurées",
        "revdelete-log": "Motif :",
        "revdelete-submit": "Appliquer {{PLURAL:$1|à la révision sélectionnée|aux révisions sélectionnées}}",
        "revdelete-no-change": "'''Attention :''' L'élément daté du $1 à $2 a déjà les paramètres de visibilité demandés.",
        "revdelete-concurrent-change": "Erreur lors de la modification de l'élément daté du $1 à $2 : son statut a été changé par quelqu'un d'autre pendant que vous le modifiez.\nVérifiez les journaux.",
        "revdelete-only-restricted": "Erreur lors de la suppression de l'entrée datée du $1 à $2 : vous ne pouvez pas supprimer ces éléments aux administrateurs sans également sélectionner les autres options de suppression.",
-       "revdelete-reason-dropdown": "* Raisons courantes de suppression :\n** Violation des droits d'auteurs ;\n** Commentaires ou renseignements personnels inappropriés ;\n** Informations potentiellement diffamatoires.",
+       "revdelete-reason-dropdown": "* Raisons courantes de suppression \n** Violation des droits d'auteurs \n** Commentaires ou renseignements personnels inappropriés \n** Nom d'utilisateur inapproprié\n** Informations potentiellement diffamatoires",
        "revdelete-otherreason": "Autre raison / raison supplémentaire :",
        "revdelete-reasonotherlist": "Autre raison",
        "revdelete-edit-reasonlist": "Modifier les motifs fréquents de suppression",
        "mergehistory-from": "Page d'origine :",
        "mergehistory-into": "Page de destination :",
        "mergehistory-list": "Historique fusionnable des modifications",
-       "mergehistory-merge": "Les versions suivantes de [[:$1]] peuvent être fusionnées avec [[:$2]]. Utilisez la colonne de boutons radio pour fusionner uniquement les versions créées du début jusqu'à la date indiquée. Notez bien que l'utilisation des liens de navigation réinitialisera cette colonne.",
+       "mergehistory-merge": "Les versions suivantes de [[:$1]] peuvent être fusionnées avec [[:$2]]. \nUtilisez la colonne de boutons radio pour fusionner uniquement les versions créées du début jusqu'à la date indiquée. \nNotez bien que l'utilisation des liens de navigation réinitialisera cette colonne.",
        "mergehistory-go": "Voir les modifications qui peuvent être fusionnées",
        "mergehistory-submit": "Fusionner les versions",
        "mergehistory-empty": "Aucune version ne peut être fusionnée.",
        "nextn-title": "$1 {{PLURAL:$1|résultat suivant|résultats suivants}}",
        "shown-title": "Afficher $1 résultat{{PLURAL:$1||s}} par page",
        "viewprevnext": "Voir ($1 {{int:pipe-separator}} $2) ($3).",
-       "searchmenu-exists": "'''Il existe une page nommée « [[:$1]] » sur ce wiki.''' {{PLURAL:$2|0=|Voyez également les autres résultats de votre recherche.}}",
-       "searchmenu-new": "<strong>Créer la page « [[:$1|$1]] » sur ce wiki !</strong> {{PLURAL:$2|0=|Voyez également la page trouvée avec votre recherche.|Voyez également les résultats de votre recherche.}}",
+       "searchmenu-exists": "<strong>Il existe une page nommée « [[:$1]] » sur ce wiki.</strong> {{PLURAL:$2|0=|Voyez également les autres résultats de votre recherche.}}",
+       "searchmenu-new": "<strong>Créer la page « [[:$1|$1]] » sur ce wiki !</strong> {{PLURAL:$2|0=Voyez également la page trouvée avec votre recherche.|Voyez également les résultats de votre recherche.}}",
        "searchprofile-articles": "Pages de contenu",
        "searchprofile-images": "Multimédia",
        "searchprofile-everything": "Tout",
        "searchprofile-articles-tooltip": "Rechercher dans $1",
        "searchprofile-images-tooltip": "Rechercher des fichiers multimédias",
        "searchprofile-everything-tooltip": "Rechercher dans tout le site (y compris dans les pages de discussion)",
-       "searchprofile-advanced-tooltip": "Choisir les espaces de noms pour la recherche",
+       "searchprofile-advanced-tooltip": "Chercher dans les espaces de noms clients",
        "search-result-size": "$1 ($2 mot{{PLURAL:$2||s}})",
        "search-result-category-size": "$1 membre{{PLURAL:$1||s}} ($2 sous-catégorie{{PLURAL:$2||s}}, $3 fichier{{PLURAL:$3||s}})",
        "search-redirect": "(redirection depuis $1)",
        "prefs-editwatchlist-clear": "Effacer la liste de suivi",
        "prefs-watchlist-days": "Nombre de jours à afficher dans la liste de suivi :",
        "prefs-watchlist-days-max": "(maximum $1 jour{{PLURAL:$1||s}})",
-       "prefs-watchlist-edits": "Nombre de modifications à afficher dans la liste de suivi étendue :",
+       "prefs-watchlist-edits": "Nombre maximum de modifications à afficher dans la liste de suivi étendue :",
        "prefs-watchlist-edits-max": "Nombre maximum : 1000",
        "prefs-watchlist-token": "Jeton pour la liste de suivi :",
        "prefs-misc": "Préférences diverses",
        "prefs-emailconfirm-label": "Confirmation du courriel :",
        "youremail": "Courriel :",
        "username": "{{GENDER:$1|Nom d'utilisateur|Nom d'utilisatrice}} :",
-       "prefs-memberingroups": "{{GENDER:$2|Membre}} {{PLURAL:$1|du groupe|des groupes}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Membre}} {{PLURAL:$1|du groupe|des groupes}} :",
        "prefs-registration": "Date d'inscription :",
        "yourrealname": "Nom réel :",
        "yourlanguage": "Langue :",
        "yourvariant": "Variante de la langue du contenu :",
-       "prefs-help-variant": "Votre variante ou orthographe préféré dans lequel afficher les pages de contenu de ce wiki.",
-       "yournick": "Signature pour les discussions :",
+       "prefs-help-variant": "Votre variante ou orthographe préférée dans laquelle afficher les pages de contenu de ce wiki.",
+       "yournick": "Nouvelle signature :",
        "prefs-help-signature": "Les commentaires sur les pages de discussion doivent être signés avec « <nowiki>~~~~</nowiki> », qui sera remplacé par votre signature et un horodatage.",
        "badsig": "Signature brute incorrecte.\nVérifiez les balises HTML.",
        "badsiglength": "Votre signature est trop longue.\nElle ne doit pas dépasser $1 caractère{{PLURAL:$1||s}}.",
        "gender-unknown": "Lorsqu’il fera mention de vous, le logiciel utilisera des mots de genre neutre, quand c’est possible",
        "gender-male": "Il modifie des pages du wiki",
        "gender-female": "Elle modifie des pages du wiki",
-       "prefs-help-gender": "Définir cette préférence est facultatif.\nCe logiciel utilise sa valeur pour s’adresser à vous et vous mentionner aux autres en utilisant le bon genre grammatical.\nCette information sera publique.",
+       "prefs-help-gender": "Définir cette préférence est facultatif.\nLe logiciel utilise la valeur pour s’adresser à vous ou pour vous mentionner aux autres en utilisant le bon genre grammatical.\nCette information sera publique.",
        "email": "Courriel",
        "prefs-help-realname": "Le vrai nom est facultatif.\nS’il est fourni, il sera utilisé pour vous attribuer vos contributions.",
        "prefs-help-email": "L'adresse de courriel est facultative, mais elle est nécessaire pour réinitialiser votre mot de passe, si vous veniez à l'oublier.",
-       "prefs-help-email-others": "Vous pourriez aussi choisir de laisser les autres vous contacter sur votre page de discussion utilisateur sans que soit nécessaire de révéler votre identité.",
+       "prefs-help-email-others": "Vous pouvez aussi choisir de laisser les autres vous contacter par courriel via un lien sur votre page de discussion ou page utilisateur. \nVotre adresse courriel n'est pas révélée quand les autres utilisateurs vous contactent.",
        "prefs-help-email-required": "Une adresse de courriel est requise.",
        "prefs-info": "Informations de base",
        "prefs-i18n": "Internationalisation",
        "userrights-groupsmember-auto": "Membre implicite de :",
        "userrights-groups-help": "Vous pouvez modifier les groupes auxquels appartient {{GENDER:$1|cet utilisateur|cette utilisatrice}} :\n* Une case cochée signifie que l’utilisat{{GENDER:$1|eur|rice}} se trouve dans ce groupe.\n* Une case non cochée signifie qu’{{GENDER:$1|il|elle}} ne s’y trouve pas.\n* Un astérisque (*) indique que vous ne pouvez pas retirer ce groupe une fois que vous l’avez ajouté, ou vice-versa.",
        "userrights-reason": "Motif :",
-       "userrights-no-interwiki": "Vous n'avez pas la permission de modifier des droits d'utilisateurs sur d'autres wikis.",
-       "userrights-nodatabase": "La base de donnée « $1 » n'existe pas ou n'est pas locale.",
-       "userrights-nologin": "Vous devez vous [[Special:UserLogin|connecter]] avec un compte d'administrateur pour modifier des droits d'utilisateur.",
-       "userrights-notallowed": "Vous n’avez pas la permission d’ajouter ou supprimer des droits d’utilisateur.",
+       "userrights-no-interwiki": "Vous n'avez pas la permission de modifier les droits utilisateur sur d'autres wikis.",
+       "userrights-nodatabase": "La base de données « $1 » n'existe pas ou n'est pas locale.",
+       "userrights-nologin": "Vous devez vous [[Special:UserLogin|connecter]] avec un compte d'administrateur pour modifier les droits utilisateur.",
+       "userrights-notallowed": "Vous n’avez pas la permission d’ajouter ou de supprimer des droits utilisateur.",
        "userrights-changeable-col": "Les groupes que vous pouvez modifier",
        "userrights-unchangeable-col": "Les groupes que vous ne pouvez pas modifier",
-       "userrights-conflict": "Conflit de modification de droits utilisateur ! Veuillez relire et confirmer vos modifications.",
+       "userrights-conflict": "Conflit de modification des droits utilisateur ! Veuillez relire et confirmer vos modifications.",
        "userrights-removed-self": "Vous avez supprimé vos propres droits. Par conséquent, vous ne pouvez plus accéder à cette page.",
        "group": "Groupe :",
        "group-user": "Utilisateurs",
        "right-createtalk": "Créer des pages de discussion",
        "right-createaccount": "Créer des comptes utilisateur",
        "right-autocreateaccount": "Connexion automatique avec un compte utilisateur externe",
-       "right-minoredit": "Marquer ses modifications comme mineures",
+       "right-minoredit": "Marquer les modifications comme mineures",
        "right-move": "Renommer des pages",
        "right-move-subpages": "Renommer des pages avec leurs sous-pages",
        "right-move-rootuserpages": "Renommer la page principale d'un utilisateur",
        "right-move-categorypages": "Renommer des pages de catégorie",
        "right-movefile": "Renommer des fichiers",
-       "right-suppressredirect": "Ne pas créer de redirection depuis le titre d'origine en renommant une page",
+       "right-suppressredirect": "Ne pas créer de redirection depuis le titre d'origine en renommant les pages",
        "right-upload": "Importer des fichiers",
        "right-reupload": "Écraser un fichier existant",
        "right-reupload-own": "Écraser un fichier que l'on a soi-même importé",
-       "right-reupload-shared": "Écraser localement un fichier présent sur un dépôt partagé",
+       "right-reupload-shared": "Écraser localement des fichiers présents sur un dépôt partagé",
        "right-upload_by_url": "Importer un fichier depuis une adresse URL",
-       "right-purge": "Purger le cache des pages sans demande de confirmation",
+       "right-purge": "Effacer une page du cache local sans demander de confirmation",
        "right-autoconfirmed": "Ne pas être affecté par les limitations de débit liées aux adresses IP",
        "right-bot": "Être traité comme un processus automatisé",
        "right-nominornewtalk": "Ne pas déclencher la notification de nouveau message lorsqu'on effectue une modification mineure sur la page de discussion d'un utilisateur",
        "right-writeapi": "Utiliser l'API de modification du wiki",
        "right-delete": "Supprimer des pages",
        "right-bigdelete": "Supprimer des pages ayant un gros historique",
-       "right-deletelogentry": "Supprimer et restaurer une entrée particulière du journal",
-       "right-deleterevision": "Supprimer ou restaurer une version particulière d'une page",
+       "right-deletelogentry": "Supprimer et restaurer des entrées particulières du journal",
+       "right-deleterevision": "Supprimer ou restaurer des versions particulières de pages",
        "right-deletedhistory": "Voir les entrées des historiques supprimées, mais sans leur texte",
        "right-deletedtext": "Voir le texte supprimé et les différences entre les versions supprimées",
        "right-browsearchive": "Rechercher des pages supprimées",
        "right-editmyuserjs": "Modifier vos propres fichiers JavaScript utilisateur",
        "right-viewmywatchlist": "Afficher votre propre liste de suivi",
        "right-editmywatchlist": "Modifier votre propre liste de suivi. Remarquez que certaines actions ajouteront encore des pages sans ce droit.",
-       "right-viewmyprivateinfo": "Voir vos données personnelles (exemple adresse, vrai nom)",
-       "right-editmyprivateinfo": "Modifier vos données personnelles (exemple adresse, vrai nom)",
+       "right-viewmyprivateinfo": "Voir vos données personnelles (par exemple votre adresse, votre vrai nom)",
+       "right-editmyprivateinfo": "Modifier vos données personnelles (par exemple votre adresse, votre vrai nom)",
        "right-editmyoptions": "Modifier vos préférences",
        "right-rollback": "Révoquer rapidement les modifications du dernier contributeur d'une page particulière",
        "right-markbotedits": "Marquer des modifications révoquées comme ayant été faites par un robot.",
        "right-noratelimit": "Ne pas être affecté par les limites de taux",
        "right-import": "Importer des pages depuis d'autres wikis",
        "right-importupload": "Importer des pages depuis un fichier",
-       "right-patrol": "Marquer des modifications des autres comme relues",
+       "right-patrol": "Marquer les modifications des autres comme étant relues",
        "right-autopatrol": "Avoir ses modifications automatiquement marquées comme relues",
        "right-patrolmarks": "Voir les marquages de relecture dans les modifications récentes",
        "right-unwatchedpages": "Voir la liste des pages non suivies",
        "right-mergehistory": "Fusionner les historiques des pages",
        "right-userrights": "Modifier tous les droits d'un utilisateur",
-       "right-userrights-interwiki": "Modifier les droits d'utilisateurs qui sont sur un autre wiki",
+       "right-userrights-interwiki": "Modifier les droits des utilisateurs qui sont sur d'autres wikis",
        "right-siteadmin": "Verrouiller ou déverrouiller la base de données",
        "right-override-export-depth": "Exporter les pages en incluant les pages liées jusqu'à une profondeur de 5 niveaux",
        "right-sendemail": "Envoyer un courriel aux autres utilisateurs",
        "grant-editprotected": "Modifier des pages protégées",
        "grant-highvolume": "Modification de gros volumes",
        "grant-oversight": "Masquer les utilisateurs et supprimer les révisions",
-       "grant-patrol": "Patrouiller les modifications aux pages",
+       "grant-patrol": "Vérifier les modifications de pages",
        "grant-protect": "Protéger et déprotéger des pages",
        "grant-rollback": "Révoquer des modifications sur des pages",
        "grant-sendemail": "Envoyer des courriels aux autres utilisateurs",
        "action-applychangetags": "appliquer les balises avec vos modifications",
        "action-changetags": "ajouter et supprimer de façon arbitraire des balises sur des révisions individuelles et des entrées de journal",
        "action-deletechangetags": "supprimer des balises de la base de données",
+       "action-purge": "purger cette page",
        "nchanges": "$1 modification{{PLURAL:$1||s}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|depuis la dernière visite}}",
        "enhancedrc-history": "historique",
        "newsectionsummary": "/* $1 */ nouvelle section",
        "rc-enhanced-expand": "Voir les détails",
        "rc-enhanced-hide": "Masquer les détails",
-       "rc-old-title": "créé avec le titre « $1 »",
+       "rc-old-title": "créé initialement avec le titre « $1 »",
        "recentchangeslinked": "Suivi des pages liées",
        "recentchangeslinked-feed": "Suivi des pages liées",
        "recentchangeslinked-toolbox": "Suivi des pages liées",
        "recentchangeslinked-title": "Suivi des pages associées à « $1 »",
-       "recentchangeslinked-summary": "Cette page spéciale montre les modifications récentes sur les pages qui sont liées. Les pages de votre liste de suivi sont '''en gras'''.",
+       "recentchangeslinked-summary": "Voici les modifications faites récemment sur des pages liées depuis une page spécifique ou vers des membres d'une catégorie spécifique. \nLes pages de [[Special:Watchlist|votre liste de suivi]] sont <strong>en gras</strong>.",
        "recentchangeslinked-page": "Nom de la page :",
        "recentchangeslinked-to": "Afficher les modifications des pages qui comportent un lien vers la page donnée plutôt que l'inverse",
        "recentchanges-page-added-to-category": "[[:$1]] ajouté à la catégorie",
        "autochange-username": "Modification automatique de MediaWiki",
        "upload": "Importer un fichier",
        "uploadbtn": "Importer le fichier",
-       "reuploaddesc": "Annuler et retourner au formulaire d'import",
+       "reuploaddesc": "Annuler l'importation et retourner au formulaire d'import",
        "upload-tryagain": "Envoyer la description du fichier modifiée",
        "uploadnologin": "Non connecté",
        "uploadnologintext": "Vous devez vous $1 pour importer des fichiers.",
        "upload_directory_missing": "Le répertoire d’import de fichier ($1) est introuvable et n’a pas pu être créé par le serveur web.",
-       "upload_directory_read_only": "Le répertoire d’import de fichier ($1) n’est pas accessible en écriture depuis le serveur web.",
+       "upload_directory_read_only": "Le serveur web n’a pas accès en écriture au répertoire d’import de fichier ($1).",
        "uploaderror": "Erreur lors de l’import",
        "upload-recreate-warning": "'''Attention : Un fichier portant ce nom a été supprimé ou déplacé.'''\n\nLe journal des suppressions et celui des déplacements de cette page sont affichés ici pour informations :",
        "uploadtext": "Utilisez ce formulaire pour importer des fichiers sur le serveur.\nPour voir ou rechercher des images précédemment envoyées, consultez la [[Special:FileList|liste des images]]. L’import est aussi enregistré dans le [[Special:Log/upload|journal d’import des fichiers]], et les suppressions dans le [[Special:Log/delete|journal des suppressions]].\n\nPour inclure un fichier dans une page, utilisez un lien de la forme :\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.jpg]]</nowiki></code>''', pour afficher le fichier en pleine résolution (dans le cas d’une image) ;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.png|200px|thumb|left|texte descriptif]]</nowiki></code>''' pour utiliser une miniature de 200 pixels de large dans une boîte à gauche avec « texte descriptif » comme description ;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:fichier.ogg]]</nowiki></code>''' pour lier directement vers le fichier sans l’afficher.",
        "upload-preferred": "{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|préféré|préférés}} : $1.",
        "upload-prohibited": "‎{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|interdit|interdits}} : $1.",
        "uploadlogpage": "Journal d’import de fichiers",
-       "uploadlogpagetext": "Voici la liste des derniers fichiers importés sur le serveur.\nVoyez la [[Special:NewFiles|galerie des nouvelles images]] pour une présentation plus visuelle.",
+       "uploadlogpagetext": "Voici les derniers fichiers téléversés.\nVoyez la [[Special:NewFiles|galerie des nouveaux fichiers]] pour une représentation plus visuelle.",
        "filename": "Nom du fichier",
        "filedesc": "Description",
        "fileuploadsummary": "Description :",
        "filestatus": "Statut du droit d'auteur :",
        "filesource": "Source :",
        "ignorewarning": "Ignorer l'avertissement et sauvegarder le fichier quand même",
-       "ignorewarnings": "Ignorer les avertissements",
-       "minlength1": "Le noms de fichiers doivent comprendre au moins une lettre.",
-       "illegalfilename": "Le nom de fichier « $1 » contient des caractères interdits dans les titres de pages. Merci de le renommer et de l'importer à nouveau.",
-       "filename-toolong": "Le nom du fichier ne peut pas dépasser 240 octets.",
+       "ignorewarnings": "Ignorer tous les avertissements",
+       "minlength1": "Les noms de fichiers doivent comprendre au moins une lettre.",
+       "illegalfilename": "Le nom de fichier « $1 » contient des caractères interdits dans les titres de pages. \nMerci de le renommer et de l'importer à nouveau.",
+       "filename-toolong": "Les noms de fichier ne peuvent pas dépasser 240 octets.",
        "badfilename": "Le fichier a été renommé en « $1 ».",
        "filetype-mime-mismatch": "L'extension du fichier « .$1 » ne correspond pas au type MIME détecté du fichier ($2).",
-       "filetype-badmime": "Les fichiers du type MIME « $1 » ne peuvent pas être importés.",
+       "filetype-badmime": "Les fichiers de type MIME « $1 » ne peuvent pas être importés.",
        "filetype-bad-ie-mime": "Le fichier ne peut pas être importé parce qu'il serait détecté comme « $1 » par Internet Explorer, ce qui correspond à un type de fichier interdit car potentiellement dangereux.",
-       "filetype-unwanted-type": "'''« .$1 »''' est un format de fichier non désiré.\n{{PLURAL:$3|Le type de fichier préconisé est|Les types de fichiers préconisés sont}} $2.",
-       "filetype-banned-type": "''' « .$1 » '''{{PLURAL:$4|n'est pas un type de fichier autorisé|ne sont pas des types de fichiers autorisés}}. \n{{PLURAL:$3|le type de fichier autorisé est |les types de fichiers autorisés sont}} $2.",
+       "filetype-unwanted-type": "<strong>« .$1 »</strong> est un format de fichier non désiré.\n{{PLURAL:$3|Le type de fichier préconisé est|Les types de fichiers préconisés sont}} $2.",
+       "filetype-banned-type": "<strong>« .$1 »</strong>{{PLURAL:$4|n'est pas un type de fichier autorisé|ne sont pas des types de fichiers autorisés}}. \n{{PLURAL:$3|Le type de fichier autorisé est |Les types de fichiers autorisés sont}} $2.",
        "filetype-missing": "Le fichier n'a aucune extension (comme « .jpg » par exemple).",
        "empty-file": "Le fichier que vous avez soumis était vide.",
        "file-too-large": "Le fichier que vous avez soumis était trop grand.",
        "fileexists": "Un fichier existe déjà sous ce nom.\nMerci de vérifier <strong>[[:$1]]</strong> si vous n'êtes pas certain{{GENDER:||e|}} de vouloir le remplacer.\n[[$1|thumb]]",
        "filepageexists": "La page de description pour ce fichier a déjà été créée ici <strong>[[:$1]]</strong>, mais aucun fichier n'existe actuellement sous ce nom.\nLe résumé que vous allez spécifier n'apparaîtra pas sur la page de description.\nPour que ce soit le cas, vous devrez modifier manuellement la page. [[$1|thumb]]",
        "fileexists-extension": "Un fichier existe avec un nom proche : [[$2|thumb]]\n* Nom du fichier à importer : <strong>[[:$1]]</strong>\n* Nom du fichier existant : <strong>[[:$2]]</strong>\nPeut-être voulez-vous utiliser un nom plus explicite ?",
-       "fileexists-thumbnail-yes": "Le fichier semble être une image en taille réduite ''(vignette)''. [[$1|thumb]]\nVeuillez vérifier le fichier <strong>[[:$1]]</strong>.\nSi le fichier vérifié est la même image avec la taille initiale, il n'y a pas besoin d'importer une version réduite.",
-       "file-thumbnail-no": "Le nom du fichier commence par <strong>$1</strong>.\nIl est possible qu'il s'agisse d'une version réduite ''(vignette)''.\nSi vous disposez du fichier en haute résolution, importez-le, sinon veuillez modifier son nom.",
-       "fileexists-forbidden": "Un fichier avec ce nom existe déjà et ne peut pas être écrasé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. [[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Un fichier portant ce nom existe déjà dans le dépôt de fichiers partagé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. [[File:$1|thumb|center|$1]]",
+       "fileexists-thumbnail-yes": "Le fichier semble être une image en taille réduite <em>(vignette)</em>. \n[[$1|thumb]]\nVeuillez vérifier le fichier <strong>[[:$1]]</strong>.\nSi le fichier vérifié est la même image avec la taille initiale, il n'y a pas besoin d'importer une version réduite.",
+       "file-thumbnail-no": "Le nom du fichier commence par <strong>$1</strong>.\nIl est possible qu'il s'agisse d'une version réduite <em>(vignette)</em>.\nSi vous disposez du fichier en haute résolution, importez-le, sinon veuillez modifier son nom.",
+       "fileexists-forbidden": "Un fichier avec ce nom existe déjà et ne peut pas être écrasé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. \n[[File:$1|thumb|center|$1]]",
+       "fileexists-shared-forbidden": "Un fichier portant ce nom existe déjà dans le dépôt de fichiers partagé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. \n[[File:$1|thumb|center|$1]]",
        "file-exists-duplicate": "Ce fichier est un doublon {{PLURAL:$1|du fichier suivant|des fichiers suivants}} :",
-       "file-deleted-duplicate": "Un fichier identique à celui-ci ([[:$1]]) a déjà été supprimé. Vous devriez vérifier le journal des suppressions de ce fichier avant de l'importer à nouveau.",
+       "file-deleted-duplicate": "Un fichier identique à celui-ci ([[:$1]]) a déjà été supprimé. \nVous devriez vérifier le journal des suppressions de ce fichier avant de l'importer à nouveau.",
        "file-deleted-duplicate-notitle": "Un fichier identique à ce fichier a déjà été supprimé ainsi que le titre. \nVous devriez demander à quelqu'un la possibilité de vérifier le journal de ce fichier supprimé afin d'examiner la situation  avant de l'importer à nouveau.",
        "uploadwarning": "Attention !",
        "uploadwarning-text": "Modifiez la description du fichier et essayez de nouveau.",
        "watchthisupload": "Suivre ce fichier",
        "filewasdeleted": "Un fichier avec ce nom a déjà été importé, puis supprimé.\nVous devriez vérifier le $1 avant de l'importer à nouveau.",
        "filename-thumb-name": "Ce titre ressemble à celui d’une vignette. Évitez d’importer des vignettes d’une image déjà présente sur le wiki. Si ce n’est pas le cas, veuillez corriger le nom de fichier afin qu’il soit plus descriptif et qu’il ne commence pas comme un titre de vignette.",
-       "filename-bad-prefix": "Le nom du fichier commence par '''« $1 »''' qui est typiquement un nom attribué automatiquement par les appareils photo numériques.\nVeuillez choisir un nom de fichier descriptif.",
+       "filename-bad-prefix": "Le nom du fichier commence par <strong>« $1 »</strong> qui est typiquement un nom non-descriptif attribué automatiquement par les appareils photo numériques.\nVeuillez choisir un nom de fichier plus descriptif.",
        "filename-prefix-blacklist": " #<!-- laisser cette ligne telle quelle --><pre>\n# La syntaxe est la suivante :\n#  * Tout ce qui figure entre un caractère \"#\" jusqu’à la fin de la ligne est un commentaire ;\n#  * Toute ligne non vide est un préfixe typique de nom de fichier assigné automatiquement par les appareils numériques :\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # certains téléphones mobiles\nIMG # générique\nJD # Jenoptik\nMGP # Pentax\nPICT # divers\n #</pre><!-- laisser cette ligne telle quelle -->",
        "upload-proto-error": "Protocole incorrect",
        "upload-proto-error-text": "L’import requiert des URL commençant par <code>http://</code> ou <code>ftp://</code>.",
        "upload-file-error": "Erreur interne",
-       "upload-file-error-text": "Une erreur interne est survenue en voulant créer un fichier temporaire sur le serveur. Veuillez contacter un [[Special:ListUsers/sysop|administrateur]].",
+       "upload-file-error-text": "Une erreur interne est survenue en voulant créer un fichier temporaire sur le serveur. \nVeuillez contacter un [[Special:ListUsers/sysop|administrateur]].",
        "upload-misc-error": "Erreur d’import inconnue",
        "upload-misc-error-text": "Une erreur inconnue est survenue pendant l’import.\nVeuillez vérifier que l’URL est valide et accessible, puis essayer à nouveau.\nSi le problème persiste, contactez un [[Special:ListUsers/sysop|administrateur]].",
        "upload-too-many-redirects": "L’URL contient trop de redirections.",
        "watchnologin": "Non connecté",
        "addwatch": "Ajouter à la liste de suivi",
        "addedwatchtext": "La page « [[:$1]] » et sa page de discussion ont été ajoutées à votre [[Special:Watchlist|liste de suivi]].",
+       "addedwatchtext-talk": "« [[:$1]] » et sa page associée ont été ajoutés à votre [[Special:Watchlist|liste de suivi]].",
        "addedwatchtext-short": "La page « $1 » a été ajoutée à votre liste de suivi.",
        "removewatch": "Supprimer de la liste de suivi",
        "removedwatchtext": "La page « [[:$1]] » et sa page de discussion ont été retirées de votre [[Special:Watchlist|liste de suivi]].",
+       "removedwatchtext-talk": "« [[:$1]] » et sa page associée ont été supprimés de votre [[Special:Watchlist|liste de suivi]].",
        "removedwatchtext-short": "La page « $1 » a été supprimée de votre liste de suivi.",
        "watch": "Suivre",
        "watchthispage": "Suivre cette page",
index 24b6f55..f729895 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Axuda",
        "search": "Procura",
+       "search-ignored-headings": " #<!-- Deixe esta liña tal e como está --> <pre>\n# Cabeceiras que serán ignoradas nas buscas.\n# Os cambios feitos aquí realízanse en canto se indexa a páxina coa cabeceira.\n# Pode forzar o reindexado da páxina facendo unha edición baleira.\n# A sintaxe é a seguinte:\n#   * Todo o que vaia despois dun carácter \"#\" ata o final da liña é un comentario\n#   * Toda liña que non estea en branco é o título exacto que ignorar, coas maiúsculas e minúsculas\nReferencias\nLigazóns externas\nVéxase tamén\n #</pre> <!-- Deixe esta liña tal e como está -->",
        "searchbutton": "Procurar",
        "go": "Mostrar",
        "searcharticle": "Artigo",
        "action-applychangetags": "aplicar etiquetas xunto cos cambios",
        "action-changetags": "engadir e quitar etiquetas arbitrarias a revisións individuais e entradas do rexistro",
        "action-deletechangetags": "borrar etiquetas da base de datos",
+       "action-purge": "purgar esta páxina",
        "nchanges": "$1 {{PLURAL:$1|modificación|modificacións}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
        "enhancedrc-history": "historial",
        "recentchanges": "Cambios recentes",
        "recentchanges-legend": "Opcións dos cambios",
-       "recentchanges-summary": "Nesta páxina pode seguir as modificacións máis recentes feitas no wiki.",
+       "recentchanges-summary": "Nesta páxina podes seguir as modificacións máis recentes feitas no wiki.",
        "recentchanges-noresult": "Non se produciron cambios que coincidisen con eses criterios durante o período especificado.",
        "recentchanges-feed-description": "Nesta fonte de novas pode seguir as modificacións máis recentes feitas no wiki.",
        "recentchanges-label-newpage": "Esta edición creou unha nova páxina",
        "watchnologin": "Non accedeu ao sistema",
        "addwatch": "Engadir á lista vixilancia",
        "addedwatchtext": "A páxina \"[[:$1]]\" e mais a súa conversa foron engadidas á súa [[Special:Watchlist|lista de vixilancia]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" xunto coa súa páxina asociada foron engadidas á túa [[Special:Watchlist|lista de vixilancia]].",
        "addedwatchtext-short": "A páxina \"$1\" foi engadida á súa lista de vixilancia.",
        "removewatch": "Eliminar da lista de vixilancia",
        "removedwatchtext": "A páxina \"[[:$1]]\" e mais a súa conversa foron eliminadas da súa [[Special:Watchlist|lista de vixilancia]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" xunto coa súa páxina asociada foron eliminadas da túa [[Special:Watchlist|lista de vixilancia]].",
        "removedwatchtext-short": "A páxina \"$1\" foi eliminada da súa lista de vixilancia.",
        "watch": "Vixiar",
        "watchthispage": "Vixiar esta páxina",
        "notvisiblerev": "A revisión foi borrada",
        "watchlist-details": "Hai {{PLURAL:$1|unha páxina|$1 páxinas}} na súa lista de vixilancia, sen contar as de conversa.",
        "wlheader-enotif": "A notificación por correo electrónico está activada.",
-       "wlheader-showupdated": "As páxinas que cambiaron desde a súa última visita móstranse en '''negra'''.",
+       "wlheader-showupdated": "As páxinas que cambiaron desde a súa última visita móstranse en <strong>letra grosa</strong>.",
        "wlnote": "A continuación {{PLURAL:$1|está a última modificación|están as últimas <strong>$1</strong> modificacións}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} ata o $3 ás $4.",
        "wlshowlast": "Mostrar as últimas $1 horas e os últimos $2 días",
        "watchlist-hide": "Agochar",
index 0b88513..090585a 100644 (file)
@@ -12,7 +12,7 @@
                ]
        },
        "tog-previewonfirst": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽 𐌰𐍄 𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽",
-       "underline-always": "Sinteino",
+       "underline-always": "𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐍉",
        "underline-never": "𐌽𐌹 𐌰𐌹𐍅",
        "sunday": "𐌰𐍆𐌰𐍂𐍃𐌰𐌱𐌱𐌰𐍄𐍉",
        "monday": "𐌼𐌴𐌽𐌹𐌽𐍃 𐌳𐌰𐌲𐍃",
@@ -73,7 +73,7 @@
        "pagecategories": "{{PLURAL:$1|𐌺𐌿𐌽𐌹|𐌺𐌿𐌽𐌾𐌰}}",
        "category_header": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌹𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
        "subcategories": "𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰",
-       "category-media-header": "𐌼𐌴𐌳𐌾𐌰 𐌹𐌽𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
+       "category-media-header": "𐌼𐌴𐌳𐌾𐌰 𐌹𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
        "hidden-categories": "{{PLURAL:$1|𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽 𐌺𐌿𐌽𐌹|𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}",
        "hidden-category-category": "𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽𐌰 𐌺𐌿𐌽𐌾𐌰",
        "category-subcat-count": "{{PLURAL:$2|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌸𐌰𐍄𐌴𐌹𐌽𐌴𐌹 𐌹𐍆𐍄𐌿𐌼 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 {{PLURAL:$1|𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌹𐍆𐍄𐌿𐌼𐌰 $1 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}, 𐌰𐌻𐌻𐌰𐌹𐌶𐌴 $2 𐌺𐌿𐌽𐌾𐌴.}}",
        "projectpage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆",
        "viewhelppage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆",
        "otherlanguages": "𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐍂𐌰𐌶𐌳𐍉𐌼",
-       "redirectedfrom": "(𐌹𐍃 𐍄𐌹𐌿𐌷𐌰𐌽𐍃/𐍄𐌹𐌿𐌷𐌰𐌽𐌰 𐌷𐌹𐌳𐍂𐌴 𐍆𐍂𐌰𐌼 $1)",
+       "redirectedfrom": "(𐌹𐍃 {{GENDER:𐍄𐌹𐌿𐌷𐌰𐌽𐍃|𐍄𐌹𐌿𐌷𐌰𐌽𐌰}} 𐌷𐌹𐌳𐍂𐌴 𐍆𐍂𐌰𐌼 $1)",
        "redirectpagesub": "𐌰𐌻𐌾𐌰𐍂 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "lastmodifiedat": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌸𐌰𐍄𐌰 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌸𐍃 𐍅𐌰𐍃 ($1) ($2).",
        "protectedpage": "𐍆𐍂𐌹𐌸𐍉𐌽𐍃 𐌻𐌰𐌿𐍆𐍃",
        "pool-errorunknown": "𐌽𐌰𐍃𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆",
        "aboutsite": "𐌱𐌹 {{SITENAME}}",
        "aboutpage": "Project:𐌱𐌹",
-       "copyrightpage": "{{ns:project}}:ð\90\8c¼ð\90\8c°ð\90\8c½ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c¹ð\90\8d\84ð\90\8d\89ð\90\8c¸ð\90\8c°",
-       "currentevents": "ð\90\8c½ð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c° 𐍅𐌰𐌹𐌷𐍄𐍃",
-       "currentevents-url": "Project:ð\90\8c½ð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c° 𐍅𐌰𐌹𐌷𐍄𐍃",
+       "copyrightpage": "{{ns:project}}:ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8d\82ð\90\8c°ð\90\8c¹ð\90\8c·ð\90\8d\84ð\90\8c´ð\90\8c¹ð\90\8d\83",
+       "currentevents": "ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8d\89ð\90\8d\83 ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c¸ð\90\8c°ð\90\8c½ð\90\8d\89ð\90\8d\83 𐍅𐌰𐌹𐌷𐍄𐍃",
+       "currentevents-url": "Project:ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8d\89ð\90\8d\83 ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c¸ð\90\8c°ð\90\8c½ð\90\8d\89ð\90\8d\83 𐍅𐌰𐌹𐌷𐍄𐍃",
        "disclaimers": "𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
        "disclaimerpage": "Project:𐌲𐌰𐌼𐌰𐌹𐌽𐌰 𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
-       "edithelp": "𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌷𐌹𐌻𐍀𐌰",
+       "edithelp": "ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8c·ð\90\8c¹ð\90\8c»ð\90\8d\80ð\90\8c°",
        "mainpage": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "mainpage-description": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "portal": "𐌱𐌰𐌿𐍂𐌲𐍃 𐌲𐌰𐍅𐌹",
        "hidetoc": "𐌰𐍆𐍆𐌹𐌻𐌷",
        "confirmable-yes": "𐌾𐌰",
        "confirmable-no": "𐌽𐌴",
-       "site-rss-feed": "$1 RSS Miþnatifodjan",
-       "site-atom-feed": "$1 ð\90\8c°ð\90\8d\84ð\90\8d\89ð\90\8c¼ ð\90\8d\86ð\90\8d\89ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\83",
+       "site-rss-feed": "$1 RSS 𐍂𐌹𐌽𐌽𐍉",
+       "site-atom-feed": "$1 ð\90\8c°ð\90\8d\84ð\90\8d\89ð\90\8c¼ ð\90\8d\82ð\90\8c¹ð\90\8c½ð\90\8c½ð\90\8d\89",
        "page-atom-feed": "\"$1\" 𐌰𐍄𐍉𐌼 𐍂𐌹𐌽𐌽𐍉",
        "red-link-title": "$1 (𐌻𐌰𐌿𐍆𐍃 𐌽𐌹𐍃𐍄)",
        "nstab-main": "𐌻𐌰𐌿𐍆𐍃",
        "nstab-special": "𐌿𐍃𐍃𐌹𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "nstab-project": "𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆𐍃",
        "nstab-image": "𐍆𐌴𐌹𐌻𐌰",
-       "nstab-template": "ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c°ð\90\8c¼ð\90\8c´ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8c½𐍃",
+       "nstab-template": "ð\90\8d\83ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8d\82ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8d\86ð\90\8d\82ð\90\8c¹ð\90\8d\83ð\90\8c°ð\90\8c·ð\90\8d\84𐍃",
        "nstab-help": "𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆𐍃",
        "nstab-category": "𐌺𐌿𐌽𐌹",
        "mainpage-nstab": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "createacct-yourpassword-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰",
-       "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰/𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰",
+       "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}",
        "login": "𐌰𐍄𐌲𐌰𐌲𐌲",
-       "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 / 𐌲𐌰𐌻𐌰𐌽𐌲𐌾𐌰𐌽 𐌽𐌹𐌿𐍄𐌰𐌽𐌳𐌹𐍃",
-       "userlogin": "Atgaggan / gaskapjan niutandis",
+       "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
+       "userlogin": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "userloginnocreate": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "logout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "userlogin-noaccount": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽?",
-       "userlogin-joinproject": "ð\90\8c²ð\90\8c°ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c½𐌴𐌹 {{SITENAME}}",
+       "userlogin-joinproject": "ð\90\8c²ð\90\8c°ð\90\8c³ð\90\8c°ð\90\8c¹ð\90\8c»𐌴𐌹 {{SITENAME}}",
        "nologinlink": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "gotaccount": "𐌾𐌿 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽 𐌷𐌰𐌱𐌰𐌹𐍃? $1.",
        "extlink_tip": "𐌿𐍄𐌰𐌲𐌰𐍅𐌹𐍃𐍃 (𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 http:// 𐍆𐌰𐌿𐍂𐌰𐌻𐌰𐌲𐌴𐌹𐌽𐍃)",
        "headline_sample": "𐌿𐍆𐌰𐍂𐍃𐍄𐍂𐌹𐌺𐌰𐌱𐍉𐌺𐍉𐍃",
        "headline_tip": "𐌷𐌰𐌿𐌷𐌹𐌸𐌰 •𐌱• 𐌿𐍆𐌰𐍂𐍃𐍄𐍂𐌹𐌺𐍃",
-       "nowiki_sample": "ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c¾ð\90\8c´ð\90\8c¹ ð\90\8c¿ð\90\8c½ð\90\8d\83ð\90\8c½ð\90\8c´ð\90\8c¹ð\90\8c¸ð\90\8c¾ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\83 ð\90\8d\84ð\90\8c´ð\90\8cºð\90\8d\83ð\90\8d\84 ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ð\90\8c°ð\90\8c¼ ð\90\8c·ð\90\8c¹ð\90\8d\84",
+       "nowiki_sample": "ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c´ð\90\8c¹ ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8d\89ð\90\8d\83 ð\90\8c¹ð\90\8c½ð\90\8c¿ð\90\8c· ð\90\8c²ð\90\8c°ð\90\8d\82ð\90\8d\85ð\90\8c¹ ð\90\8c·ð\90\8c´ð\90\8d\82",
        "nowiki_tip": "𐌿𐌽𐍅𐌹𐍄𐌾𐌹𐍃 𐍅𐌹𐌺𐌹𐍃𐌽𐌴𐌹𐌸𐌾𐌰𐌽𐌳𐍃",
        "image_tip": "𐌹𐌽𐌽𐌱𐍉𐌳𐌰𐌽𐍃 𐍆𐌴𐌹𐌻𐌰",
        "media_tip": "𐍄𐌰𐌹𐌺𐌾𐌰𐌱𐌰𐌽𐌳𐌾𐌹𐍃 𐍆𐌴𐌹𐌻𐌰𐌽𐌹𐍃",
        "sig_tip": "𐌸𐌴𐌹𐌽𐌰 𐌿𐍆𐌼𐌴𐌻𐌴𐌹𐌽𐍃 𐌼𐌹𐌸 𐌲𐌻𐌰𐌲𐌲𐍅𐌰𐌼𐌼𐌰 𐌼𐌴𐌻𐌰",
-       "hr_tip": "𐍂𐌰𐌹𐌷𐍄𐍃𐌱𐌰𐌿𐍂𐌳 (𐌱𐍂𐌿𐌺𐌾𐌰𐌽 𐌼𐌹𐌸 𐌽𐌹𐌿𐍆𐌰𐍂𐌿𐍃𐍃𐌿𐍃)",
+       "hr_tip": "𐍂𐌰𐌹𐌷𐍄𐍃 𐍃𐍄𐍂𐌹𐌺𐍃 (𐌽𐌹 𐌱𐍂𐌿𐌺𐌴𐌹 𐌿𐍆𐌰𐍂𐍆𐌹𐌻𐌿)",
        "summary": "𐌼𐌰𐌿𐍂𐌲𐌿𐍃 𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐍃:",
        "subject": "𐌿𐍆𐍅𐌰𐌿𐍂𐍀𐌰:",
        "minoredit": "𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌼𐌹𐌽𐌽𐌹𐌶𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃",
        "updated": "(𐌰𐌽𐌰𐌽𐌹𐍅𐌹𐌸)",
        "previewnote": "<strong>𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 𐌸𐌰𐍄𐌴𐌹 𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐍃.</strong>\n𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽𐍉𐍃 𐍃𐌹𐌽𐌳!",
        "editing": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
-       "creating": "𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃/𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹 $1",
+       "creating": "{{GENDER:𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃|𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
        "editingsection": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌳𐌰𐌹𐌻)",
-       "editingcomment": "𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃/𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹 $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)",
-       "yourdiff": "ð\90\8c¼ð\90\8c¹ð\90\8d\83ð\90\8d\83ð\90\8c°ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8cº𐍉𐍃",
+       "editingcomment": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)",
+       "yourdiff": "ð\90\8c²ð\90\8c°ð\90\8d\83ð\90\8cºð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½𐍉𐍃",
        "template-protected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌼𐌿𐌽𐌳)",
-       "template-semiprotected": "(halb-gabaírgjan)",
+       "template-semiprotected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌷𐌰𐌻𐌱𐌰𐌼𐌿𐌽𐌸)",
        "hiddencategories": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌹𐍃𐍄 𐌲𐌰𐌳𐌰𐌹𐌻𐌰 {{PLURAL:$1|1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌹𐍃 𐌺𐌿𐌽𐌾𐌹𐍃|$1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌰𐌹𐌶𐌴 𐌺𐌿𐌽𐌾𐌴}}:‎",
        "permissionserrorstext-withaction": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 $2, 𐌹𐌽 {{PLURAL:$1|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉 𐍅𐌰𐌹𐌷𐍄𐌴}}:",
        "moveddeleted-notice": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌿𐍃𐌽𐌿𐌼𐌰𐌽𐍃 𐌹𐍃𐍄. 𐌿𐍃𐌽𐌿𐌼𐍄𐍃 𐌾𐌰𐌷 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃 𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹𐌽𐌰𐌹𐍃 𐌿𐍆 𐍃𐌹𐌽𐌳 𐌿𐍃𐍄𐌰𐌹𐌺𐌽𐌴𐌹𐌽𐌰𐌹.",
        "post-expand-template-inclusion-warning": "'''𐌷𐍅𐍉𐍄𐌾𐌰𐌽𐌳𐍃:''' 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍃 𐍃𐌹𐌽𐌳 𐌿𐍆𐌰𐍂𐌼𐌹𐌺𐌹𐌻𐍃. 𐍃𐌿𐌼𐍃 𐍆𐌰𐌿𐍂𐌴𐌼𐌴𐌻𐌴𐌹𐌽𐍉𐍃 𐌽𐌹 𐌼𐌰𐌲 𐍅𐌹𐍃𐌰𐌽 𐌸𐌰𐍂",
        "post-expand-template-inclusion-category": "𐍃𐌴𐌹𐌳𐍉𐌽𐍃 𐌸𐌰𐍂 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍃 𐍃𐌹𐌽𐌳 𐌿𐍆𐌰𐍂𐌼𐌹𐌺𐌹𐌻𐍃",
        "viewpagelogs": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐌹𐌽𐍃 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰",
-       "currentrev": "ð\90\8c½ð\90\8c¿ ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³𐌴𐌹𐌽𐍃",
+       "currentrev": "ð\90\8c°ð\90\8d\86ð\90\8d\84ð\90\8c¿ð\90\8c¼ð\90\8c¹ð\90\8d\83ð\90\8d\84ð\90\8c° ð\90\8c²ð\90\8c°ð\90\8c±ð\90\8d\89ð\90\8d\84𐌴𐌹𐌽𐍃",
        "currentrev-asof": "𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰 𐌲𐌰𐌱𐍉𐍄𐌴𐌹𐌽𐍃 𐍆𐍂𐌰𐌼 $1",
        "revisionasof": "𐌲𐌰𐌱𐍉𐍄𐌴𐌹𐌽𐍃 𐍆𐍂𐌰𐌼 $1",
        "revision-info": "𐌲𐌰𐌱𐍉𐍄𐌴𐌹𐌽𐍃 𐌹𐌽 $1 𐍆𐍂𐌰𐌼 {{GENDER:$6|$2}}$7",
        "searchall": "𐌰𐌻𐌻𐍃",
        "search-showingresults": "{{ZPLURAL:$4|𐍄𐌰𐌿𐌹 <strong>$1 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3|𐍄𐍉𐌾𐌰 <strong>$1 - $2 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3}}",
        "search-nonefound": "𐌽𐌹 𐍄𐌰𐌿𐌹 𐍅𐌰𐍃 𐍃𐌰𐌼𐌰𐌽𐌰 𐍃𐍅𐌰 𐍃𐍉𐌺𐌴𐌹𐌽.",
-       "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹𐌸",
+       "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹",
        "preferences": "𐌼𐌴𐌹𐌽𐍉𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌴𐌹𐍃",
        "mypreferences": "𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
-       "prefs-skin": "Seidofill",
+       "prefs-skin": "𐍆𐌹𐌻𐌻",
        "skin-preview": "Faúrsaiƕa",
-       "saveprefs": "Melja",
-       "searchresultshead": "Sokeiþ",
+       "saveprefs": "𐌲𐌰𐍆𐌰𐍃𐍄",
+       "searchresultshead": "𐍃𐍉𐌺𐌴𐌹",
        "grouppage-sysop": "{{ns:project}}:𐍃𐌴𐌹𐌳𐍉𐍆𐌰𐌸𐍃",
        "right-writeapi": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 API 𐌼𐌴𐌻𐌴𐌹𐌽𐌰𐌹𐍃",
        "rightslog": "Niutandis stutjanlog",
        "diff": "𐌼𐌹𐍃𐍃",
        "hist": "𐍃𐍀𐌹𐌻𐌻",
        "hide": "𐍆𐌹𐌻𐌷𐌰𐌽",
-       "show": "ð\90\8c·ð\90\8c¿ð\90\8c»ð\90\8c¾ð\90\8c°ð\90\8c½",
+       "show": "ð\90\8c°ð\90\8d\84ð\90\8c°ð\90\8c¿ð\90\8c²ð\90\8c´ð\90\8c¹",
        "minoreditletter": "l",
        "newpageletter": "N",
        "boteditletter": "b",
        "imagelinks": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 𐍆𐌰𐌴𐌹𐌻𐌴",
        "linkstoimage": "𐌰𐍆𐍄𐌿𐌼𐌰 {{PLURAL:$1|𐍃𐍉 𐍃𐌴𐌹𐌳𐍉 𐌻𐌴𐌹𐌽𐌺𐍉𐌸|𐌸𐍉𐍃 𐍃𐌴𐌹𐌳𐍉𐌽𐍃 𐌻𐌴𐌹𐌽𐌺𐍉𐌽𐌳}} 𐌸𐌹𐌶𐍉𐌶𐌿𐌷 𐍆𐌴𐌹𐌻𐍉𐍃",
        "sharedupload-desc-here": "𐍃𐍉 𐌳𐌰𐍄𐌰 𐌹𐍃𐍄 𐍆𐍂𐌰𐌼 $1 𐌾𐌰𐌷 𐌼𐌰𐌲 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐍆𐍂𐌰𐌼 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐍉𐌼.\n𐌲𐌰𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐍃 𐌰𐌽𐌰 𐍃𐌴𐌹𐌽𐌰𐌼𐌼𐌰 [$2 𐌳𐌰𐍄𐌰 𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐌱𐌰] 𐌾𐌰𐌹𐌽𐌰𐍂 𐌰𐍄𐌰𐌿𐌲𐌹𐌸𐍃 𐌹𐍃𐍄 𐌿𐍆.",
-       "filedelete-submit": "Taíran",
-       "mimesearch": "MIME sokeiþ",
+       "filedelete-submit": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹",
+       "mimesearch": "MIME 𐍃𐍉𐌺𐌴𐌹",
        "listredirects": "𐍄𐌰𐌻𐌰 𐌰𐍆 𐍄𐌰𐌹𐌺𐌾𐌰𐌽𐍃𐌴𐌹𐌳𐍉𐍃",
        "randompage": "𐌸𐌿𐍃 𐌿𐌽𐌺𐌿𐌽𐌸𐍃 𐌻𐌰𐌿𐍆𐍃",
-       "statistics": "ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89ð\90\8d\83ð\90\8d\84ð\90\8c°ð\90\8d\84ð\90\8c¹ð\90\8d\83ð\90\8d\84ð\90\8c¹ð\90\8cº",
-       "brokenredirects-edit": "(𐌼𐌰𐌹𐌳𐌾𐌰𐌽)",
+       "statistics": "ð\90\8d\82ð\90\8c°ð\90\8c¸ð\90\8c¾ð\90\8d\89ð\90\8c½ð\90\8d\83",
+       "brokenredirects-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹",
        "brokenredirects-delete": "(𐍄𐌰𐌹𐍂𐌰𐌽)",
        "nbytes": "$1 {{PLURAL:$1|𐌱𐌹𐍄|𐌱𐌰𐍄𐌰}}",
        "ncategories": "$1 {{PLURAL:$1|𐌺𐌿𐌽𐌾𐌰|𐌺𐌿𐌽𐌾𐍉𐍃}}",
-       "nlinks": "$1 {{PLURAL:$1|táikjanbandi|táikjanbandja}}",
+       "nlinks": "$1 {{PLURAL:$1|𐌲𐌰𐍅𐌹𐍃𐍃|𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃}}",
        "nmembers": "$1 {{PLURAL:$1|niutand|niutanda}}",
        "wantedpages": "𐌲𐌰𐌹𐍂𐌽𐌹𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
-       "shortpages": "ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8d\84ð\90\8c¹ð\90\8c»ð\90\8c° ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³𐍉𐍃",
+       "shortpages": "ð\90\8c¼ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c²ð\90\8c°ð\90\8c¹ ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±𐍉𐍃",
        "longpages": "𐌻𐌰𐌲𐌲𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "listusers": "𐍂𐌴𐌲𐌹𐍃𐍄𐍂𐌴𐍂𐌰𐌳𐌴 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃",
        "newpages": "𐌽𐌹𐌿𐌾𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "allpagessubmit": "𐌲𐌰𐌲𐌲",
        "categories": "𐌺𐌿𐌽𐌾𐌰",
        "linksearch-ns": "𐍃𐌴𐌹𐌳𐍉𐍆𐌴𐍂𐌰:",
-       "emailuser": "𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌸𐍉 𐌽𐌹𐌿𐍄𐌰𐌽𐌳 𐌱𐍉𐌺𐍉𐌼",
+       "emailuser": "{{GENDER: 𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 𐌸𐌰𐌼𐌼𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳|𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 𐌸𐌹𐌶𐌰𐌹 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌾𐌰𐌹}}",
        "watchlist": "𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉",
        "mywatchlist": "𐌻𐌰𐌹𐍃𐍄𐌰𐌻𐌴𐌹𐍃𐍄𐌰",
        "watch": "𐍅𐌰𐍂𐌰𐌽",
-       "watchthispage": "ð\90\8d\85ð\90\8c°ð\90\8d\82ð\90\8c°ð\90\8c½ ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89",
+       "watchthispage": "ð\90\8c°ð\90\8d\84ð\90\8d\85ð\90\8c¹ð\90\8d\84 ð\90\8c¸ð\90\8c°ð\90\8c¼ð\90\8c¼ð\90\8c° ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±ð\90\8c°",
        "unwatch": "𐌽𐌹𐍅𐌰𐍂𐌰𐌽",
        "watchlist-details": "{{PLURAL:$1|$1 𐌻𐌰𐌿𐍆𐍃|$1 𐌻𐌰𐌿𐌱𐍉𐍃}} 𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽, 𐌽𐌹 𐍃𐌿𐌽𐌳𐍂𐍉 𐍂𐌰𐌷𐌽𐌾𐌰𐌽𐌳𐌰 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐌱𐍉𐍃.",
        "watching": "Wita...",
        "rollbacklink": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹",
        "rollbacklinkcount": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹 $1 {{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃}}",
        "protectlogpage": "Log af Baírgjan",
-       "prot_1movedto2": "[[$1]] skiubiþ du [[$2]]",
+       "prot_1movedto2": "[[$1]] 𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌸 𐌳𐌿 [[$2]]",
        "protect-level-sysop": "𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍂𐌴𐌹𐌺𐍃",
-       "protect-expiring": "bláuþiþ $1 (UTC)",
+       "protect-expiring": "𐌿𐍃𐍄𐌹𐌿𐌷𐌹𐌸 $1 (UTC)",
        "restriction-type": "Freihals:",
-       "restriction-edit": "ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c¾ð\90\8c°ð\90\8c½",
+       "restriction-edit": "ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹",
        "restriction-move": "𐍃𐌺𐌹𐌿𐌱𐌰𐌽",
        "undeletebtn": "𐌰𐍆𐍄𐍂𐌰 𐌲𐌰𐌱𐍉𐍄𐌾𐌰𐌽",
        "undeletelink": "𐍃𐌰𐌹𐍈𐌰𐌽/𐌰𐍆𐍄𐍂𐌰𐌲𐌰𐍃𐌰𐍄𐌾𐌰𐌽",
        "undeleteviewlink": "𐍃𐌰𐌹𐍈𐌹𐍃",
-       "undelete-search-submit": "Sokeiþ",
+       "undelete-search-submit": "𐍃𐍉𐌺𐌴𐌹",
        "namespace": "𐌽𐌰𐌼𐌰𐍂𐌿𐌼:",
-       "invert": "Afwandjan kustus",
+       "invert": "𐌲𐌰𐍅𐌰𐌽𐌳𐌴𐌹 𐌸𐌰𐍄𐌰 𐌲𐌰𐍅𐌰𐌻𐌹𐌳𐍉",
        "blanknamespace": "(𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐍃)",
        "contributions": "𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃 {{{{GENDER:$1|User}}",
        "mycontris": "𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃",
        "istemplate": "ináukan",
        "whatlinkshere-prev": "{{PLURAL:$1|aftuma|aftumans $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|iftuma|iftumans $1}}",
-       "whatlinkshere-links": "← táikajanbandja",
+       "whatlinkshere-links": "← 𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃",
        "whatlinkshere-hidelinks": "$1 𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃",
        "blockip": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹 {{GENDER:$1|user}}",
        "ipbreason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
        "ipboptions": "𐌱 𐌰𐍅𐍂𐌰:2 hours, 𐌰 𐌳𐌰𐌲𐍃:1 day, 𐌲 𐌳𐌰𐌲𐍉𐍃:3 days, 𐌰 𐍅𐌹𐌺𐍉:1 week, 𐌱 𐍅𐌹𐌺𐍉𐌽𐍃:2 weeks, 𐌰 𐌼𐌴𐌽𐍉𐌸𐍃:1 month, 𐌲 𐌼𐌴𐌽𐍉𐌸𐍉𐍃:3 months, 𐌵 𐌼𐌴𐌽𐍉𐌸𐍉𐍃:6 months, 𐌰 𐌾𐌴𐍂:1 year, 𐌹𐌽𐌿𐍄𐍂𐌹𐌲𐌲𐌴𐌽𐌳𐌴𐌹𐍃:infinite",
-       "ipblocklist-submit": "Sokeiþ",
-       "infiniteblock": "ajukduþs",
+       "ipblocklist-submit": "𐍃𐍉𐌺𐌴𐌹",
+       "infiniteblock": "𐌰𐌽𐌳𐌰𐌻𐌰𐌿𐍃",
        "blocklink": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹",
        "unblocklink": "𐍅𐌰𐌽𐌳𐌾𐌰𐌽",
        "change-blocklink": "𐌲𐌰𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐍅𐌰𐌿𐍂𐌾𐌰𐍅𐌰𐌳𐌳𐌾𐌿𐍃",
        "contribslink": "𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃",
-       "blocklogpage": "ð\90\8c»ð\90\8d\89ð\90\8c²ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8c° ð\90\8c°ð\90\8d\86 ð\90\8c°ð\90\8d\86ð\90\8c³ð\90\8d\82ð\90\8c°ð\90\8c¿ð\90\8d\83ð\90\8c¾ð\90\8c°ð\90\8c½",
+       "blocklogpage": "ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ð\90\8c°ð\90\8c¼ð\90\8c¼ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c°ð\90\8c¹ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8d\86ð\90\8c°ð\90\8d\83ð\90\8d\84ð\90\8c°ð\90\8c¹ð\90\8c½ð\90\8d\83.",
        "blocklogentry": "𐌰𐍆𐌳𐍂𐌰𐌿𐍃𐌹𐌸 [[$1]] 𐍆𐌰𐌿𐍂 $2 $3",
        "newtitle": "𐌽𐌹𐌿𐌾𐌹 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹:",
-       "move-watch": "ð\90\8d\85ð\90\8c¹ð\90\8d\84ð\90\8c°ð\90\8c½ ð\90\8d\83ð\90\8d\89 ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89",
+       "move-watch": "ð\90\8c°ð\90\8d\84ð\90\8d\85ð\90\8c¹ð\90\8d\84 ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8c½ð\90\8c½ð\90\8c°ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±ð\90\8c° ð\90\8c¾ð\90\8c°ð\90\8c· ð\90\8c¼ð\90\8c¿ð\90\8c½ð\90\8c³ð\90\8d\82ð\90\8c´ð\90\8c¹ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±ð\90\8c°",
        "movepagebtn": "𐍃𐌺𐌹𐌿𐌱𐌰 𐍃𐌴𐌹𐌳𐍉",
-       "movelogpage": "Log af skiubans",
+       "movelogpage": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽",
        "movereason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
        "revertmove": "𐍂𐌰𐌹𐌳𐌾𐌰𐌽",
        "export": "𐌿𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌱𐌰𐌽𐍃",
        "thumbnail-more": "\n𐌼𐌹𐌺𐌹𐌻𐌴𐌹",
        "tooltip-pt-userpage": "{{GENDER:|Your user}} 𐌻𐌰𐌿𐍆𐍃",
-       "tooltip-pt-mytalk": "{{GENDER:|Your}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃",
+       "tooltip-pt-mytalk": "{{GENDER:|𐌸𐌴𐌹𐌽𐍃}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃",
        "tooltip-pt-preferences": "{{GENDER:|Your}} 𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
        "tooltip-pt-watchlist": "𐍅𐌹𐌺𐍉 𐌻𐌰𐌿𐌱𐌴 𐌸𐌹𐌶𐌴𐌴𐌹 𐌰𐍄𐍅𐌰𐌹𐍃𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌼",
        "tooltip-pt-mycontris": "A list of {{GENDER:|your}} 𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃",
        "tooltip-ca-delete": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰",
        "tooltip-ca-move": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆",
        "tooltip-ca-watch": "𐌱𐌹𐌰𐌹𐌰𐌿𐌺 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆 𐌳𐌿 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽",
-       "tooltip-search": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c¾ð\90\8c°ð\90\8c½ {{SITENAME}}",
+       "tooltip-search": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ {{SITENAME}}",
        "tooltip-search-go": "𐌾𐌰𐌱𐌰𐌹 𐌹𐍃𐍄, 𐌲𐌰𐌲𐌲 𐌳𐌿 𐌻𐌰𐌿𐌱𐌰 𐌼𐌹𐌸 𐍃𐌰𐌼𐌹𐌽 𐌽𐌰𐌼𐌹𐌽.",
        "tooltip-search-fulltext": "𐍃𐍉𐌺𐌴𐌹 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼",
        "tooltip-p-logo": "𐌲𐌰𐍅𐌴𐌹𐍃 𐌷𐌰𐌿𐌱𐌹𐌳𐌰𐌻𐌰𐌿𐌱𐌹𐍃",
        "tooltip-ca-nstab-special": "𐍃𐌰 𐌹𐍃𐍄 𐌿𐍃𐍃𐌹𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃 𐌾𐌰𐌷 𐌽𐌹 𐌼𐌰𐌲 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌳𐌰.",
        "tooltip-ca-nstab-project": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆",
        "tooltip-ca-nstab-image": "𐍃𐌰𐌹𐍈 𐍆𐌰𐌴𐌹𐌻𐌰𐌻𐌰𐌿𐍆",
-       "tooltip-ca-nstab-template": "𐍃𐌰𐌹𐍈𐌹𐍃 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽",
+       "tooltip-ca-nstab-template": "𐍃𐌰𐌹𐍈 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽",
        "tooltip-ca-nstab-category": "𐍃𐌰𐌹𐍈 𐌺𐌿𐌽𐌾𐌰𐌻𐌰𐌿𐍆",
        "tooltip-save": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃",
-       "tooltip-preview": "ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8d\83ð\90\8c°ð\90\8d\88ð\90\8c¹ð\90\8d\83 ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c¾ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8c¸ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c°, ð\90\8c±ð\90\8c¹ð\90\8c³ð\90\8c¾ð\90\8c° ð\90\8c¸ð\90\8c¿ð\90\8cº ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8cºð\90\8c¾ð\90\8c°ð\90\8c½ ð\90\8c¸ð\90\8c°ð\90\8d\84ð\90\8c° ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c° ð\90\8c¼ð\90\8c´ð\90\8c»ð\90\8c¾ð\90\8c¹ð\90\8d\83!",
+       "tooltip-preview": "ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c°ð\90\8d\83ð\90\8c°ð\90\8c¹ð\90\8d\88 ð\90\8c¸ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83. ð\90\8c±ð\90\8c¹ð\90\8c³ð\90\8c¾ð\90\8c°ð\90\8c¼ ð\90\8c¸ð\90\8c¿ð\90\8cº, ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8cºð\90\8c´ð\90\8c¹ ð\90\8c¸ð\90\8c¹ð\90\8d\83 ð\90\8c¸ð\90\8c°ð\90\8d\84ð\90\8c° ð\90\8d\86ð\90\8d\82ð\90\8c¿ð\90\8c¼ð\90\8c¹ð\90\8d\83ð\90\8d\84 ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c¸ð\90\8c¹ð\90\8c¶ð\90\8c´ð\90\8c¹ ð\90\8c²ð\90\8c°ð\90\8d\86ð\90\8c°ð\90\8d\83ð\90\8d\84ð\90\8c°ð\90\8c¹ð\90\8d\83.",
        "tooltip-diff": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍈𐌹𐌻𐌴𐌹𐌺𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃 𐌲𐌰𐍄𐌰𐍅𐌹𐌳𐌴𐍃 𐌳𐌿 𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼",
        "tooltip-rollback": "\"𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹\" 𐌲𐌰𐌽𐌰𐍃𐌾𐌹𐌸 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽(𐍉𐍃) 𐌳𐌿 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌹𐍃 𐌱𐌹𐌰𐌿𐌺𐌰𐌽𐌳𐌹𐍃/𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹𐌶𐍉𐍃 𐌱𐌹𐌰𐌿𐌺𐌰𐌽𐌳𐌾𐍉𐍃 𐌹𐌽 𐌰𐌹𐌽𐌰𐌼𐌼𐌰 𐍃𐌹𐌽𐌸𐌰",
        "tooltip-undo": "\"𐌽𐌹𐌿𐍃𐌺𐌰𐍀𐌾𐌰𐌽\" 𐌱𐌰𐌺𐌼𐌰𐌹𐌳𐌾𐌹𐌸 𐌹𐌽𐌼𐌰𐌹𐌳𐌲𐌴𐌹𐌽𐍃 𐌾𐌰𐌷 𐌿𐍃𐌻𐌿𐌺𐍉𐌸 𐌼𐌰𐌹𐌳𐌾𐌰𐍆𐍉𐍂𐌼𐍉𐌽 𐍃𐍅𐌴 𐍆𐌰𐌿𐍂𐍃𐌰𐌹𐍈𐌰 𐌷𐌹𐍅𐌾𐌰. 𐌸𐌰𐍄𐌰 𐌻𐌴𐍄 𐌰𐌽𐌰𐌿𐌺𐌰𐌽𐌰𐌽 𐍃𐌰𐌿𐌸𐌰 𐌹𐌽 𐌹𐌽𐌽𐌰𐌷𐌰𐌻𐌳𐌰𐌰𐌽𐌲𐌰𐌱𐌰.",
        "tooltip-summary": "𐌰𐍄𐌲𐌰𐌲𐌲𐌹𐍃 𐌹𐌽𐌽𐌰𐌷𐌰𐌻𐌳𐌰𐌰𐌽𐌲𐌰𐌱𐌰 𐌼𐌰𐌿𐍂𐌲𐌾𐌰",
        "pageinfo-toolboxlink": "𐌺𐌿𐌽𐌸𐌹 𐌻𐌰𐌿𐌱𐌹𐍃",
-       "previousdiff": "â\86\90 ð\90\8c°ð\90\8d\86ð\90\8d\84ð\90\8c¿ð\90\8c¼ð\90\8c° ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¹𐍃",
+       "previousdiff": "â\86\90 ð\90\8d\86ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c½ð\90\8c¹ð\90\8c¶ð\90\8c´ð\90\8c¹ ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½𐍃",
        "nextdiff": "𐌽𐌹𐌿𐌾𐌹𐌶𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃 →",
        "file-info-size": "$1 × $2 𐍀𐌹𐌺𐍃𐌴𐌻𐌰, 𐍆𐌴𐌹𐌻𐍅𐌰𐌷𐍃𐍄𐌿𐍃: $3, 𐌼𐌹𐌼𐌴 𐌺𐌿𐌽𐌹: $4",
        "show-big-image": "𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐌰 𐌳𐌰𐍄𐌰",
        "show-big-image-preview": "𐌼𐌹𐌺𐌹𐌻𐌴𐌹 𐌸𐌹𐌶𐍉𐍃 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐌰𐌹𐍃: $1.",
        "show-big-image-size": "$1 × $2 𐍆𐍂𐌹𐍃𐌰𐌷𐍄𐌹𐍃𐍄𐌰𐌱𐌴𐌹𐍃",
-       "ilsubmit": "Sokeiþ",
+       "ilsubmit": "𐍃𐍉𐌺𐌴𐌹",
        "metadata": "𐌿𐍆𐌰𐍂𐌳𐌰𐍄𐌰",
        "exif-colorspace": "𐍆𐌰𐍂𐍅𐌰𐍂𐌿𐌼",
        "exif-orientation-1": "𐌱𐌹 𐌱𐌹𐌿𐌷𐍄𐌾𐌰",
        "namespacesall": "𐌰𐌻𐌻",
-       "monthsall": "𐌰𐌻𐌻𐌹𐍃",
-       "imgmultigo": "Afgaggan!",
+       "monthsall": "𐌰𐌻𐌻",
+       "imgmultigo": "𐌲𐌰𐌲𐌲!",
        "table_pager_limit_submit": "Affgaggan",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰]])",
        "version-other": "Anþar",
        "tags-create-reason": "𐌳𐌿𐌸𐌸𐌴:",
        "tags-create-submit": "𐍃𐌺𐌰𐍀𐌴𐌹",
        "tags-create-warnings-below": "𐍅𐌹𐌻𐌴𐌹𐌶𐌿 𐌸𐌰𐌹𐍂𐍈𐌹𐍃𐌰𐌽 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐍃𐍉𐌺𐌰𐍅𐌰𐌿𐍂𐌳?",
-       "tags-delete-title": "ð\90\8c¿ð\90\8d\83ð\90\8c½ð\90\8c¹ð\90\8c¼ ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c°𐍅𐌰𐌿𐍂𐌳",
+       "tags-delete-title": "ð\90\8c¿ð\90\8d\83ð\90\8c½ð\90\8c¹ð\90\8c¼ ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹𐍅𐌰𐌿𐍂𐌳",
        "tags-delete-explanation-initial": "𐍅𐌰𐌹𐍂𐌸𐌰𐌹𐍃 𐍃𐍉𐌺𐌰𐍅𐌰𐌿𐍂𐌳 \"$1\" 𐌿𐍃𐌽𐌹𐌼𐌰𐌽 𐌿𐍃 𐌲𐌹𐌱𐌰𐌲𐌰𐍃𐌰𐍄𐌴𐌹𐌽𐌰𐌹.",
        "tags-delete-reason": "𐌳𐌿𐌸𐌸𐌴:",
-       "tags-delete-not-found": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c°𐍅𐌰𐌿𐍂𐌳 \"$1\" 𐌽𐌹𐍃𐍄.",
-       "tags-activate-title": "ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¹ð\90\8c¿ð\90\8c´ð\90\8c¹ ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c°𐍅𐌰𐌿𐍂𐌳",
-       "tags-activate-question": "ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8c°ð\90\8c¹ð\90\8d\83 ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ \"$1\" ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c°ð\90\8c½.",
+       "tags-delete-not-found": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹𐍅𐌰𐌿𐍂𐌳 \"$1\" 𐌽𐌹𐍃𐍄.",
+       "tags-activate-title": "ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¹ð\90\8c¿ð\90\8c´ð\90\8c¹ ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹𐍅𐌰𐌿𐍂𐌳",
+       "tags-activate-question": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ \"$1\" ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c¹ð\90\8d\83.",
        "tags-activate-reason": "𐌳𐌿𐌸𐌸𐌴:",
        "tags-activate-not-found": "𐍃𐍉𐌺𐌰𐍅𐌰𐌿𐍂𐌳 \"$1\" 𐌽𐌹𐍃𐍄.",
        "tags-activate-submit": "𐌲𐌰𐌵𐌹𐌿𐌴𐌹",
        "tags-deactivate-reason": "𐌳𐌿𐌸𐌸𐌴:",
        "tags-deactivate-submit": "𐌿𐌽𐌲𐌰𐌵𐌹𐌿𐌴𐌹",
        "logentry-delete-delete": "$1 {{GENDER:$2|𐌿𐍃𐌽𐌰𐌼}} 𐌻𐌰𐌿𐍆 $3",
-       "logentry-move-move": "$1 {{GENDER:$2|𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌳𐌰}} 𐌻𐌰𐌿𐍆𐍃 $3 𐌳𐌿 $4",
+       "logentry-move-move": "$1 {{GENDER:$2|𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌳𐌰}} 𐌻𐌰𐌿𐍆 $3 𐌳𐌿 $4",
        "logentry-newusers-create": "𐌱𐍂𐌿𐌺𐌾𐌰𐌺𐌰𐍅𐍄𐍃𐌾𐍉 $1 𐍅𐌰𐍃 {{{{GENDER:$2|𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰}}",
-       "rightsnone": "(ni áinshun)",
+       "rightsnone": "(𐌽𐌹)",
        "searchsuggest-search": "𐍃𐍉𐌺𐌴𐌹"
 }
index 8e09dd7..807ce58 100644 (file)
        "november-date": "નવેમ્બર $1",
        "december-date": "ડિસેમ્બર $1",
        "pagecategories": "{{PLURAL:$1|શ્રેણી|શ્રેણીઓ}}",
-       "category_header": "શ્રેણી \"$1\"માં પાના",
+       "category_header": "શ્રેણી \"$1\" ના પાનાં",
        "subcategories": "ઉપશ્રેણીઓ",
        "category-media-header": "શ્રેણી \"$1\"માં દ્રશ્ય કે શ્રાવ્ય સભ્યો",
        "category-empty": "''આ શ્રેણીમાં હાલમાં કોઇ લેખ કે અન્ય સભ્ય નથી.''",
        "minoredit": "આ એક નાનો સુધારો છે",
        "watchthis": "આ પાનાને ધ્યાનમાં રાખો",
        "savearticle": "પાનું સાચવો",
+       "publishpage": "પાનું પ્રકાશિત કરો",
+       "publishchanges": "ફેરફારો પ્રકાશિત કરો",
        "preview": "પૂર્વાવલોકન",
        "showpreview": "ઝલક જુવો",
        "showdiff": "ફેરફારો દર્શાવો",
        "special-characters-group-thai": "થાઈ",
        "special-characters-group-lao": "લાઓ",
        "special-characters-group-khmer": "ખ્મેર",
-       "mw-widgets-titleinput-description-new-page": "પાનું અસ્તિત્વ ધરાવતું નથી.",
-       "api-error-blacklisted": "મહેરબાની કરી વધુ વિસ્તૃત અર્થ સભર શીર્ષક આપો."
+       "mw-widgets-titleinput-description-new-page": "પાનું અસ્તિત્વ ધરાવતું નથી."
 }
index 1779eb9..b4b9c89 100644 (file)
        "tagline": "מתוך {{SITENAME}}",
        "help": "עזרה",
        "search": "חיפוש",
+       "search-ignored-headings": " #<!-- יש להשאיר את השורה הזאת ללא שינוי --> <pre>\n# בשורות ההסבר בעברית בהערה הזאת יש תווי כיווניות לשם סידור סימני פיסוק.‏\n# כותרות של פסקאות שהחיפוש יתעלם מהן.‏\n# שינויים כאן ייכנסו לתוקף כשדף עם הכותרת הזאת ייכנס לאינדקס החיפוש.‏\n# אפשר לכפות מפתוח חוזר של דפים על־ידי עשיית עריכה אפסית.‏\n# התחביר הוא:‏\n# * כל דבר מהתו \"#\" עד סוף השורה הוא הערה.‏\n# * כל שורה שאינה ריקה היא כותרת שיש להתעלם ממנה, רגישות לאותיות רישיות וקטנות וכו'.‏\nהערות שוליים\nקישורים חיצוניים\nלקריאה נוספת\n #</pre> <!-- יש להשאיר את השורה הזאת ללא שינוי -->",
        "searchbutton": "חיפוש",
        "go": "הצגה",
        "searcharticle": "לדף",
        "pt-login-continue-button": "המשך כניסה לחשבון",
        "pt-createaccount": "יצירת חשבון",
        "pt-userlogout": "יציאה מהחשבון",
-       "php-mail-error-unknown": "שגיאה לא ידועה בפונקציה mail()‎ של PHP",
+       "php-mail-error-unknown": "שגיאה לא ידועה בפונקציה mail()‎ של PHP.",
        "user-mail-no-addy": "ניסיון לשלוח דוא\"ל ללא כתובת דוא\"ל.",
        "user-mail-no-body": "ניסיון לשלוח דוא\"ל עם תוכן ריק או קצר מאוד.",
        "changepassword": "שינוי סיסמה",
        "editingsection": "עריכת הדף \"$1\" (פסקה)",
        "editingcomment": "עריכת הדף \"$1\" (פסקה חדשה)",
        "editconflict": "התנגשות עריכה: $1",
-       "explainconflict": "משתמש אחר שינה את הדף מאז שהתחלתם לערוך אותו.\nחלון העריכה העליון מציג את הטקסט בדף כפי שהוא כרגע.\nהשינויים שלכם מוצגים בחלון העריכה התחתון.\nעליכם למזג את השינויים שלכם לתוך הטקסט הקיים.\n<strong>רק</strong> הטקסט בחלון העריכה העליון יישמר כשתלחצו על \"{{int:savearticle}}\".",
+       "explainconflict": "משתמש אחר שינה את הדף מאז שהתחלת לערוך אותו.\nתיבת העריכה העליונה מכילה את הטקסט בדף כפי שהוא כרגע.\nהשינויים שלך מוצגים בתיבת העריכה התחתונה.\nיש למזג את השינויים שלך מתיבת העריכה התחתונה לתיבת העריכה העליונה.\n<strong>רק</strong> הטקסט בתיבת העריכה העליונה יישמר לאחר לחיצה על \"{{int:savearticle}}\".",
        "yourtext": "הטקסט שלך",
        "storedversion": "גרסה שמורה",
        "nonunicodebrowser": "'''אזהרה: הדפדפן שלך אינו תואם לתקן יוניקוד.'''\nכדי למנוע בעיות הנוצרות כתוצאה מכך ולאפשר לך לערוך דפים בבטחה, תווים שאינם ב־ASCII יוצגו בתיבת העריכה כקודים הקסדצימליים.",
        "prefs-help-prefershttps": "העדפה זו תיכנס לתוקף בכניסה הבאה לחשבון.",
        "prefswarning-warning": "ביצעת שינויים בהעדפות שלך, והם עדיין לא נשמרו.\nעזיבת דף זה ללא לחיצה על \"$1\" תגרום לכך שההעדפות שלך לא יעודכנו.",
        "prefs-tabs-navigation-hint": "טיפ: ניתן להשתמש במקשי החצים הימני והשמאלי כדי לנווט בין הלשוניות ברשימת הלשוניות.",
-       "userrights": "ניהול הרשאות {{GENDER:{{BASEPAGENAME}}|משתמש|משתמשת}}",
+       "userrights": "ניהול הרשאות משתמש",
        "userrights-lookup-user": "ניהול קבוצות משתמש",
        "userrights-user-editname": "שם משתמש:",
        "editusergroup": "עריכת הקבוצות של ה{{GENDER:$1|משתמש}}",
        "right-reupload-own": "העלאת גרסאות חדשות של קבצים קיימים שהועלו על־ידי המשתמש עצמו",
        "right-reupload-shared": "דריסה מקומית של קבצים מאתר קובצי המדיה המשותף",
        "right-upload_by_url": "העלאת קבצים מכתובת אינטרנט (URL)",
-       "right-purge": "רענ×\95×\9f ×\96×\99×\9bר×\95×\9f ×\94×\9e×\98×\9e×\95×\9f ×©×\9c ×\94×\90תר ללא מעבר בדף אישור",
+       "right-purge": "× ×\99ק×\95×\99 ×\96×\99×\9bר×\95×\9f ×\94×\9e×\98×\9e×\95×\9f ×©×\9c ×\93×£ ללא מעבר בדף אישור",
        "right-autoconfirmed": "עקיפת ההגבלה על קצב הפעולות שניתן לבצע מכתובת IP מסוימת",
        "right-bot": "התייחסות לעריכות כאוטומטיות",
        "right-nominornewtalk": "ביטול שליחת התראה על הודעה חדשה למשתמש בעת עריכה משנית בדף השיחה שלו",
        "action-applychangetags": "להחיל תגיות יחד עם שינויים",
        "action-changetags": "להוסיף או להסיר תגיות מגרסאות ומרשומות יומן",
        "action-deletechangetags": "למחוק תגיות מבסיס הנתונים",
+       "action-purge": "לנקות את זיכרון המטמון של דף זה",
        "nchanges": "{{PLURAL:$1|שינוי אחד|$1 שינויים}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|מאז ביקורך האחרון}}",
        "enhancedrc-history": "היסטוריה",
        "watchnologin": "לא נכנסת לחשבון",
        "addwatch": "הוספה לרשימת המעקב",
        "addedwatchtext": "הדף \"[[:$1]]\" ודף השיחה שלו נוספו ל[[Special:Watchlist|רשימת המעקב]] שלך.",
+       "addedwatchtext-talk": "הדף \"[[:$1]]\" ודף התוכן המשויך אליו נוספו ל[[Special:Watchlist|רשימת המעקב]] שלך.",
        "addedwatchtext-short": "הדף \"$1\" נוסף לרשימת המעקב.",
        "removewatch": "הסרה מרשימת המעקב",
        "removedwatchtext": "הדף \"[[:$1]]\" ודף השיחה שלו הוסרו מ[[Special:Watchlist|רשימת המעקב]] שלך.",
+       "removedwatchtext-talk": "הדף \"[[:$1]]\" ודף התוכן המשויך אליו הוסרו מ[[Special:Watchlist|רשימת המעקב]] שלך.",
        "removedwatchtext-short": "הדף \"$1\" הוסר מרשימת המעקב.",
        "watch": "מעקב",
        "watchthispage": "מעקב אחרי דף זה",
        "protect-expiring-local": "פוקעת ב{{GRAMMAR:תחילית|$1}}",
        "protect-expiry-indefinite": "בלתי מוגבלת בזמן",
        "protect-cascade": "הגנה על כל הדפים המוכללים בדף זה (הגנה מדורגת)",
-       "protect-cantedit": "אין באפשרותך לשנות את רמת ההגנה על דף זה כיוון שאין לך הרשאה לערוך אותו.",
+       "protect-cantedit": "אין {{GENDER:|באפשרותך|באפשרותך|באפשרותכם}} לשנות את רמת ההגנה של דף זה כיוון שאין {{GENDER:|לך|לך|לכם}} הרשאה לערוך אותו.",
        "protect-othertime": "זמן אחר:",
        "protect-othertime-op": "זמן אחר",
        "protect-existing-expiry": "זמן פקיעה נוכחי: $3, $2",
        "monthsall": "הכול",
        "confirmemail": "אימות כתובת דוא\"ל",
        "confirmemail_noemail": "אין לך כתובת דוא\"ל תקפה המוגדרת ב[[Special:Preferences|העדפות המשתמש]] שלך.",
-       "confirmemail_text": "אתר זה דורש שתאמתו את כתובת הדוא\"ל שלכם לפני שתשתמשו בשירותי הדוא\"ל. לחצו על הכפתור למטה כדי לשלוח דוא\"ל עם קוד אימות לכתובת הדוא\"ל שהזנתם. טענו את הקישור בדפדפן שלכם כדי לאשר שכתובת הדוא\"ל תקפה.",
-       "confirmemail_pending": "ק×\95×\93 ×\90×\99×\9e×\95ת ×\93×\95×\90\"×\9c ×\9b×\91ר × ×©×\9c×\97 ×\90×\9c×\99×\9b×\9d; ×\90×\9d ×\99צרת×\9d ×\90ת ×\94×\97ש×\91×\95×\9f ×\9c×\90×\97ר×\95× ×\94, ×\99×\99ת×\9b×\9f ×©×ª×¨×¦×\95 ×\9c×\97×\9b×\95ת ×\9eספר ×\93ק×\95ת ×¢×\93 ×©×\99×\92×\99×¢ ×\9cפנ×\99 ×©×ª× ×¡×\95 ×\9c×\91קש קוד חדש.",
+       "confirmemail_text": "{{GENDER:|עליך|עלייך|עליכם}} לאמת את כתובת הדוא\"ל {{GENDER:|שלך|שלך|שלכם}} לפני ש{{GENDER:|תוכל|תוכלי|תוכלו}} להשתמש בשירותי הדוא\"ל של {{SITENAME}}.\n{{GENDER:|לחץ|לחצי|לחצו}} על הכפתור שלמטה כדי לשלוח קוד אימות לכתובת הדוא\"ל ש{{GENDER:|הזנת|הזנת|הזנתם}}.\n{{GENDER:|פתח|פִתחי|פִתחו}} את הקישור בדפדפן {{GENDER:|שלך|שלך|שלכם}} כדי לאשר שכתובת הדוא\"ל תקפה.",
+       "confirmemail_pending": "ק×\95×\93 ×\94×\90×\99×\9e×\95ת ×\9b×\91ר × ×©×\9c×\97 ×\9c×\93×\95×\90ר ×\94×\90×\9cק×\98ר×\95× ×\99 {{GENDER:|ש×\9c×\9a|ש×\9c×\9a|ש×\9c×\9b×\9d}};\n×\90×\9d {{GENDER:|×\99צרת|×\99צרת|×\99צרת×\9d}} ×\90ת ×\94×\97ש×\91×\95×\9f ×\9c×\90×\97ר×\95× ×\94, ×\9b×\93×\90×\99 ×\9c×\94×\9eת×\99×\9f ×\9eספר ×\93ק×\95ת ×¢×\93 ×©×\94×\93×\95×\90\"×\9c ×\99×\92×\99×¢ ×\9cפנ×\99 ×\91קשת קוד חדש.",
        "confirmemail_send": "לשלוח קוד אימות",
        "confirmemail_sent": "הדוא\"ל עם קוד האימות נשלח.",
        "confirmemail_oncreate": "קוד אימות דוא\"ל נשלח לכתובת הדוא\"ל שלכם. הקוד הזה אינו נדרש לכניסה, אך תצטרכו לספקו כדי להשתמש בכל תכונה מבוססת דוא\"ל באתר זה.",
-       "confirmemail_sendfailed": "{{SITENAME}} לא הצליח לשלוח לכם הודעת דוא\"ל עם קוד האימות.\nאנא בדקו שאין תווים שגויים בכתובת הדוא\"ל.\n\nתוכנת שליחת הדוא\"ל החזירה את ההודעה הבאה: $1",
+       "confirmemail_sendfailed": "אתר {{SITENAME}} לא הצליח לשלוח דוא\"ל האימות שלך.\nנא לבדוק שבכתובת הדוא\"ל שלך אין תווים בלתי־תקינים.\n\nמערכת שליחת הדוא\"ל החזירה את ההודעה הבאה: $1",
        "confirmemail_invalid": "קוד האימות שגוי. ייתכן שפג תוקפו.",
        "confirmemail_needlogin": "נדרשת $1 כדי לאמת את כתובת הדוא\"ל שלך.",
        "confirmemail_success": "כתובת הדוא\"ל שלך אושרה.\nכעת באפשרותך [[Special:UserLogin|להיכנס לחשבון שלך]] וליהנות מהאתר.",
index 68eb647..17f116b 100644 (file)
@@ -70,7 +70,7 @@
        "tog-watchlisthidebots": "Sakrij uređivanja botova s popisa praćenja",
        "tog-watchlisthideminor": "Sakrij manje promjene s popisa praćenja",
        "tog-watchlisthideliu": "Sakrij uređivanja prijavljenih s popisa praćenja",
-       "tog-watchlistreloadautomatically": "Automatski ponovno pokreni nadzornu listu kad god dođe do promjene filtra (potreban JavaScript)",
+       "tog-watchlistreloadautomatically": "Ponovno učitaj popis praćenja kad god dođe do promjene filtra (potreban JavaScript)",
        "tog-watchlisthideanons": "Sakrij uređivanja neprijavljenih s popisa praćenja",
        "tog-watchlisthidepatrolled": "Sakrij pregledane izmjene u popisu praćenja",
        "tog-watchlisthidecategorization": "Sakrij kategorizaciju stranica",
        "botpasswords-label-create": "Stvori",
        "botpasswords-label-update": "Ažuriraj",
        "botpasswords-label-cancel": "Odustani",
-       "botpasswords-label-resetpassword": "Reset lozinke",
+       "botpasswords-label-resetpassword": "Ponovno postavljanje lozinke",
        "botpasswords-insert-failed": "Nije moguće dodavanje imena bota \"$1\". Možda je već dodano?",
        "resetpass_forbidden": "Lozinka ne može biti promijenjena",
        "resetpass-no-info": "Morate biti prijavljeni da biste izravno pristupili ovoj stranici.",
        "prefs-advancedwatchlist": "Napredne mogućnosti",
        "prefs-displayrc": "Prikaži opcije",
        "prefs-displaywatchlist": "Mogućnosti prikaza",
-       "prefs-diffs": "razl",
+       "prefs-diffs": "Razlike između inačica uređivanja",
        "prefs-help-prefershttps": "Ova mogućnost će stupiti na snagu kod sljedeće prijave.",
        "prefswarning-warning": "Napravili ste promjene u Vašim postavkama koje još nisu snimljene.\nAko napustite ovu stranicu bez pritiska na \"$1\", postavke neće biti ažurirane.",
        "prefs-tabs-navigation-hint": "Savjet: možete rabiti tipke sa strjelicama lijevo i desno za prebacivanje između kartica na popisu kartica.",
        "grant-blockusers": "Blokiraj i odblokiraj korisnike",
        "grant-createaccount": "Otvori račune",
        "grant-createeditmovepage": "Stvori, uredi i premjesti stranice",
-       "grant-editmyoptions": "Izmjeni korisničke postavke",
+       "grant-editmyoptions": "Uredi korisničke postavke",
        "grant-highvolume": "Uređivanja velikog opsega",
        "grant-basic": "Osnovna prava",
        "grant-viewdeleted": "Prikaz izbrisanih datoteka i stranica",
        "recentchangeslinked-summary": "Ova posebna stranica pokazuje nedavne promjene na povezanim stranicama (ili stranicama određene kategorije). Stranice koje su na [[Special:Watchlist|Vašem popisu praćenja]] su '''podebljane'''.",
        "recentchangeslinked-page": "Naslov stranice:",
        "recentchangeslinked-to": "Pokaži promjene na stranicama s poveznicom na ovu stranicu",
-       "recentchanges-page-added-to-category": "[[:$1]] dodana u kategoriju",
+       "recentchanges-page-added-to-category": "[[:$1]] dodano u kategoriju",
        "recentchanges-page-removed-from-category": "[[:$1]] uklonjeno iz kategorije",
        "upload": "Postavi datoteku",
        "uploadbtn": "Postavi datoteku",
        "protectedpages-reason": "Razlog",
        "protectedpages-submit": "Prikaži stranice",
        "protectedpages-unknown-timestamp": "Nepoznato",
-       "protectedpages-unknown-performer": "Nepoznati korisnik",
+       "protectedpages-unknown-performer": "Nepoznati suradnik",
        "protectedtitles": "Zaštićeni naslovi",
        "protectedtitlesempty": "Nijedan naslov nije trenutačno zaštićen s tim parametrima.",
        "protectedtitles-submit": "Prikaži nazive",
        "activeusers-hidebots": "Sakrij botove",
        "activeusers-hidesysops": "Sakrij administratore",
        "activeusers-noresult": "Niti jedan suradnik nije nađen.",
-       "activeusers-submit": "Prikaz aktivnih sudionika",
+       "activeusers-submit": "Prikaz aktivnih suradnika",
        "listgrouprights": "Prava suradničkih skupina",
        "listgrouprights-summary": "Ovo je popis suradničkih skupina određenih na ovoj wiki, s njihovim pripadajućim pravima.\nDodatne informacije o pojedinim pravim se mogu pronaći [[{{MediaWiki:Listgrouprights-helppage}}|ovdje]].",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Dodijeljeno pravo</span>\n* <span class=\"listgrouprights-revoked\">Ukinuto pravo</span>",
        "rollback-success": "uklonjeno uređivanje {{GENDER:$1|suradnika|suradnice}} $1\nvraćeno na posljednju inačicu {{GENDER:$2|suradnika|suradnice}} $2.",
        "sessionfailure-title": "Prekid sesije",
        "sessionfailure": "Uočili smo problem s Vašom prijavom. Zadnja naredba nije izvršena kako bi se izbjegla zloupotreba. Molimo Vas da se u pregledniku vratite natrag na prethodnu stranicu, ponovno je učitate i zatim pokušate opet.",
-       "changecontentmodel-legend": "Promjeni model sadržaja",
+       "changecontentmodel-legend": "Promijeni model sadržaja",
        "changecontentmodel-title-label": "Naziv stranice",
        "changecontentmodel-model-label": "Novi model sadržaja",
        "changecontentmodel-reason-label": "Razlog:",
        "exif-gaincontrol-3": "Malo smanjenje",
        "exif-gaincontrol-4": "Veliko smanjenje",
        "exif-contrast-0": "Normalno",
-       "exif-contrast-1": "Meko",
-       "exif-contrast-2": "Tvrdo",
+       "exif-contrast-1": "Slabo",
+       "exif-contrast-2": "Jako",
        "exif-saturation-0": "Normalno",
        "exif-saturation-1": "Niska saturacija",
        "exif-saturation-2": "Visoka saturacija",
        "revdelete-uname-unhid": "suradničko ime je otkriveno",
        "revdelete-restricted": "primijenjeno ograničenje za administratore",
        "revdelete-unrestricted": "uklonjeno ograničenje za administratore",
+       "logentry-merge-merge": "$1 je {{GENDER:$2|spojio|spojila}} $3 s $4 (izmjene do $5)",
        "logentry-move-move": "$1 je {{GENDER:$2|premjestio|premjestila}} stranicu $3 na $4",
        "logentry-move-move-noredirect": "$1 je {{GENDER:$2|premjestio|premjestila}} stranicu $3 na $4 bez preusmjeravanja",
        "logentry-move-move_redir": "$1 je {{GENDER:$2|premjestio|premjestila}} stranicu $3 na $4 preko preusmjeravanja",
index 567cf1a..b2daf38 100644 (file)
        "tagline": "z {{GRAMMAR:genitiw|{{SITENAME}}}}",
        "help": "Pomoc",
        "search": "Pytać",
+       "search-ignored-headings": " #<!-- njezměń tutu linku --> <pre>\n# Nadpisma, kotrež pytanje ignoruje.\n# Tute změny budu so wuskutkować, po tym zo strona bě so indikowała.\n# Móžeš indikowanje stronow wunuzować, přewjedujo prózdnu změnu.\n# Syntaksa:\n#   * Wšitko, štož znamješku \"#\" hač do kónca linki slěduje, je komentar\n#   * Kózda njeprózdna linka je eksaktny titul, kotryž dyrbi so ignorować\nŽórła\nEksterne wotkazy\nHlej tež\n #</pre> <!-- njezměń tutu linku -->",
        "searchbutton": "Pytać",
        "go": "Pytać",
        "searcharticle": "Pytać",
index 722d650..75ef088 100644 (file)
@@ -13,7 +13,7 @@
                        "Lucas"
                ]
        },
-       "tog-underline": "Souliyen lyen yo&nbsp;:",
+       "tog-underline": "Souliyen lyen yo :",
        "tog-hideminor": "Kache tout modifikasyon resan yo ki tou piti",
        "tog-hidepatrolled": "Kache modifikasyon yo ki fèk fèt pou moun ki ap veye yo",
        "tog-newpageshidepatrolled": "Kache paj ki siveye yo nan mitan lis nouvo paj yo",
        "skin-preview": "Voye kout je",
        "youremail": "Adrès imèl :",
        "username": "Non itilizatè a:",
-       "prefs-memberingroups": "Manm {{PLURAL:$1|nan gwoup sa|nan gwoup sa yo }} :",
+       "prefs-memberingroups": "{{GENDER:$2|Manm}} {{PLURAL:$1|nan gwoup sa|nan gwoup sa yo}} :",
        "yourrealname": "Vre non ou:",
        "yourlanguage": "Lang:",
        "yournick": "Siyati pou espas diskisyon :",
index 2bbaebe..c0acf2e 100644 (file)
        "tagline": "A {{SITENAME}} wikiből",
        "help": "Segítség",
        "search": "Keresés",
+       "search-ignored-headings": " #<!-- ezen a soron ne változtass --> <pre>\n# Az itt megadott szakaszokat figyelmen kívül hagyja a kereső.\n# Ha megváltoztatod ezt a listát, csak a változtatás után indexelt lapokra lesz hatása.\n# Ha újra akarsz indexelni egy adott oldalt, egy üres szerkesztéssel (megnyit-elment) megteheted.\n# Szintaxis:\n#   * A # jeltől a sor végéig tartó rész megjegyzés, a szoftver figyelmen kívül hagyja\n#   * Minden nem üres sor egy olyan szakasz címe, amit nem akarjuk, hogy indexeljen a kereső. (Csak a pontos egyezés számít, kisbetű/nagybetűt is beleértve.)\nForrások\nJegyzetek\nHivatkozások\nKülső hivatkozások\nLásd még\n #</pre> <!-- ezen a soron ne változtass -->",
        "searchbutton": "Keresés",
        "go": "Menj",
        "searcharticle": "Menj",
        "resetpass-abort-generic": "A jelszómódosítást megszakította egy kiterjesztés.",
        "resetpass-expired": "A jelszavad lejárt. Adjál meg egy új jelszót a bejelentkezéshez!",
        "resetpass-expired-soft": "A jelszavad lejárt, ezért újat kell beállítanod. Válassz most egy új jelszót, vagy kattints a {{int:authprovider-resetpass-skip-label}} gombra, ha később akarod csak beállítani.",
-       "resetpass-validity-soft": "Adj meg egy új jelszót most, vagy kattints a \"{{int:authprovider-resetpass-skip-label}}\" gombra, ha később akarod megadni.",
+       "resetpass-validity-soft": "A jelszavad érvénytelen: $1\n\nAdj meg egy új jelszót most, vagy kattints a „{{int:authprovider-resetpass-skip-label}}” gombra, ha később akarod megadni.",
        "passwordreset": "Jelszó visszaállítása",
        "passwordreset-text-one": "A jelszó átmeneti beállításához töltsd ki az űrlapot.",
        "passwordreset-text-many": "{{PLURAL:$1|Az átmeneti jelszó elküldéséhez töltsd ki az alábbi mezők egyikét.}}",
        "minoredit": "Apró változtatás",
        "watchthis": "A lap figyelése",
        "savearticle": "Lap mentése",
-       "publishpage": "Lap mentése",
+       "publishpage": "Lap közzététele",
+       "publishchanges": "Változtatások közzététele",
        "preview": "Előnézet",
        "showpreview": "Előnézet megtekintése",
        "showdiff": "Változtatások megtekintése",
        "userpage-userdoesnotexist": "Nincs „<nowiki>$1</nowiki>” nevű regisztrált felhasználónk.\nNézd meg, hogy valóban ezt a lapot szeretnéd-e létrehozni vagy szerkeszteni.",
        "userpage-userdoesnotexist-view": "Nincs regisztrálva „$1” szerkesztői azonosító.",
        "blocked-notice-logextract": "A felhasználó jelenleg blokkolva van.\nA blokkolási napló legutóbbi ide vonatkozó bejegyzése a következő:",
-       "clearyourcache": "'''Megjegyzés:''' mentés után frissítened kell a böngésződ gyorsítótárát, hogy lásd a változásokat.\n'''Firefox / Safari:''' tartsd lenyomva a Shift gombot és kattints a ''Frissítés'' gombra a címsorban, vagy használd a ''Ctrl–F5'' vagy ''Ctrl–R'' billentyűkombinációt (Mac-en ''Command–R'');\n'''Google Chrome:''' használd a ''Ctrl–Shift–R'' billentyűkombinációt (Mac-en ''Command–Shift–R'');\n'''Internet Explorer:''' tartsd nyomva a ''Ctrl''-t, és kattints a ''Frissítés'' gombra, vagy nyomj ''Ctrl–F5''-öt;\n'''Opera:''' ürítsd ki a gyorsítótárat a ''Beállítások / Haladó / Előzmények→Törlés most'' gombbal, majd frissítsd az oldalt.",
+       "clearyourcache": "<strong>Megjegyzés:</strong> mentés után frissítened kell a böngésződ gyorsítótárát, hogy lásd a változásokat.\n* <strong>Firefox / Safari:</strong> tartsd lenyomva a <em>Shift</em> gombot és kattints a <em>Frissítés</em> gombra a címsorban, vagy használd a <em>Ctrl–F5</em> vagy <em>Ctrl–R</em> (Macen <em>⌘–R</em>) billentyűkombinációt\n* <strong>Google Chrome:</strong> használd a <em>Ctrl–Shift–R</em> (Macen <em>⌘–Shift–R</em>) billentyűkombinációt\n* <strong>Internet Explorer:</strong> tartsd nyomva a <em>Ctrl</em>-t, és kattints a <em>Frissítés</em> gombra, vagy nyomj <em>Ctrl–F5</em>-öt\n* <strong>Opera:</strong> Nyisd meg a Beállításokat a <em>Menü</em>ből (Macen <em>Opera</em> menüből), majd válaszd az <em>Adatvédelem és biztonság → Böngészési adatok törlése → Gyorsítótáras képek és fájlok</em> opciót.",
        "usercssyoucanpreview": "'''Tipp:''' mentés előtt használd az „{{int:showpreview}}” gombot az új CSS-ed teszteléséhez.",
        "userjsyoucanpreview": "'''Tipp:''' mentés előtt használd az „{{int:showpreview}}” gombot az új JavaScipted teszteléséhez.",
        "usercsspreview": "'''Ne felejtsd el, hogy ez csak a felhasználói CSS-ed előnézete és még nincs elmentve!'''",
        "editingsection": "$1 szerkesztése (szakasz)",
        "editingcomment": "$1 szerkesztése (új szakasz)",
        "editconflict": "Szerkesztési ütközés: $1",
-       "explainconflict": "Valaki megváltoztatta a lapot, mióta elkezdted szerkeszteni. A felső szövegdobozban láthatod az oldal jelenlegi tartalmát. A te módosításaid az alsó dobozban találhatók. Át kell másolnod a módosításaidat a felsőbe! \n\n'''Csak''' a felső dobozban levő szöveg lesz elmentve, amikor a „{{int:savearticle}}” gombra kattintasz.",
+       "explainconflict": "Valaki megváltoztatta a lapot, mióta elkezdted szerkeszteni. A felső szövegdobozban láthatod az oldal jelenlegi tartalmát. A te módosításaid az alsó dobozban találhatók. Át kell másolnod a módosításaidat a felsőbe! \n\n<strong>Csak</strong> a felső dobozban levő szöveg lesz elmentve, amikor a „{{int:savearticle}}” gombra kattintasz.",
        "yourtext": "A te változatod",
        "storedversion": "A tárolt változat",
        "nonunicodebrowser": "'''Figyelem: A böngésződ nem Unicode kompatibilis. Egy kerülő megoldásként biztonságban szerkesztheted a cikkeket: a nem ASCII karakterek a szerkesztőablakban hexadeciális kódokként jelennek meg.'''",
index 2920310..761b3cf 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Adjuta",
        "search": "Recerca",
+       "search-ignored-headings": " #<!-- non modificar in alcun modo iste linea --> <pre>\n# Titulos de sectiones que essera ignorate per le recerca.\n# Cambiamentos in isto habera effecto post le indexation del paginas con iste sectiones.\n# Tu pote fortiar le re-indexation de un pagina per medio de un modification nulle.\n# Le syntaxe es:\n#   * Toto a partir de un character \"#\" usque al fin del linea es un commento\n#   * Cata linea non vacue es un titulo exacte a ignorar, con distinction inter majusculas e minusculas\nReferentias\nLigamines externe\nVide etiam\n #</pre> <!-- non modificar in alcun modo iste linea -->",
        "searchbutton": "Cercar",
        "go": "Va",
        "searcharticle": "Va",
        "action-applychangetags": "applicar etiquettas al proprie modificationes",
        "action-changetags": "adder e remover qualcunque etiquettas sur individual versiones e entratas de registro",
        "action-deletechangetags": "deler etiquettas del base de datos",
+       "action-purge": "purgar iste pagina",
        "nchanges": "$1 {{PLURAL:$1|modification|modificationes}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde le ultime visita}}",
        "enhancedrc-history": "historia",
        "watchnologin": "Tu non ha aperite un session",
        "addwatch": "Adder al observatorio",
        "addedwatchtext": "Le pagina \"[[:$1]]\", e su pagina de discussion, ha essite addite a [[Special:Watchlist|tu observatorio]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" e su pagina associate ha essite addite a tu [[Special:Watchlist|observatorio]].",
        "addedwatchtext-short": "Le pagina \"$1\" ha essite addite a tu observatorio.",
        "removewatch": "Remover del observatorio",
        "removedwatchtext": "Le pagina \"[[:$1]]\", e su pagina de discussion, ha essite removite de [[Special:Watchlist|tu observatorio]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" e su pagina associate ha essite removite de tu [[Special:Watchlist|observatorio]].",
        "removedwatchtext-short": "Le pagina \"$1\" ha essite removite de tu observatorio.",
        "watch": "Observar",
        "watchthispage": "Observar iste pagina",
index a9d4378..b585c93 100644 (file)
        "tagline": "Manipud iti {{SITENAME}}",
        "help": "Tulong",
        "search": "Biruken",
+       "search-ignored-headings": " #<!-- saan a kutkutien daytoy a linia --> <pre>\n# Dagiti paulo a saanto nga ikaskaso babaen ti panagbiruk.\n# Dagiti panagbalbaliw mabalinton intono ti panid nga addaan ti paulo ket maipasurotan.\n# Mabalinmo a piliten ti panangisurot manen iti panid babaen ti awan linaon a panagurnos.\n# Ti eskritu ket kasla dagiti sumaganad:\n#   * Amin manipud ti karater ti \"#\" aginggana ti gibus ti linia ket komentario.\n#   * Amin a saan a blanko a linia ket eksakto a titulo a saan nga maikaskaso, kadakkel ti letra ken amin.\nDagiti reperensia\nDagiti silpo ti ruar\nKitaen pay\n #</pre> <!-- saan a kutkutien daytoy a linia -->",
        "searchbutton": "Biruken",
        "go": "Inkan",
        "searcharticle": "Inkan",
        "mw-widgets-dateinput-placeholder-month": "TTTT-BB",
        "mw-widgets-titleinput-description-new-page": "awan pay ti panid",
        "mw-widgets-titleinput-description-redirect": "ibaw-ing iti $1",
-       "api-error-blacklisted": "Pangngaasi nga agpili iti sabali, a mangipalpalawag a titulo.",
        "sessionmanager-tie": "Saan a mabalin nga itipon dagiti nadumaduma kita ti kiddaw ti pammasingked: $1.",
        "sessionprovider-generic": "Dagiti sesion ti $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "dagiti sesion a naibatay iti galieta",
index 0ecc963..2a71972 100644 (file)
        "tagline": "Da {{SITENAME}}.",
        "help": "Aiuto",
        "search": "Ricerca",
+       "search-ignored-headings": " #<!-- lascia questa riga esattamente come è --> <pre>\n# Elenco delle intestazioni che saranno ignorate dalla ricerca.\n# Le modifiche a questa pagina saranno effettive non appena la pagina sarà indicizzata.\n# Puoi forzare la re-indicizzazione di una pagina effettuando una modifica nulla.\n# La sintassi è la seguente:\n#   * Tutto dal carattere \"#\" alla fine della riga è un commento\n#   * Tutte le righe non vuote sono le intestazioni esatte da ignorare, maiuscolo/minuscolo e tutto\nNote\nVoci correlate\nCollegamenti esterni\n #</pre> <!-- lascia questa riga esattamente come è -->",
        "searchbutton": "Ricerca",
        "go": "Vai",
        "searcharticle": "Vai",
        "action-applychangetags": "applicare delle etichette alle tue modifiche",
        "action-changetags": "aggiungere o rimuovere specifiche etichette su singole versioni o voci di registro",
        "action-deletechangetags": "cancellare le etichette dal database",
+       "action-purge": "aggiornare questa pagina",
        "nchanges": "$1 {{PLURAL:$1|modifica|modifiche}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dall'ultima visita}}",
        "enhancedrc-history": "cronologia",
index 37ad555..6a184d7 100644 (file)
        "tagline": "提供: {{SITENAME}}",
        "help": "ヘルプ",
        "search": "検索",
+       "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# 検索で無視される見出しを記述します。\n# この変更は、見出し付きページがインデックスされると同時に有効になります。\n# 空の編集を実行することで、強制的にページの再インデックスが行われます。\n# 文法は以下のとおり:\n#   * \"#\" で始まる行は、その行末までがすべてコメントです。\n#   * 非空白行が、無視したい見出しになります。大文字小文字の区別を含め、完全に一致するものが対象です。\nReferences\nExternal links\nSee also\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "検索",
        "go": "表示",
        "searcharticle": "表示",
        "watchnologin": "ログインしていません",
        "addwatch": "ウォッチリストに追加",
        "addedwatchtext": "「[[:$1]]」および付随する議論ページを、[[Special:Watchlist|ウォッチリスト]]に追加しました。",
+       "addedwatchtext-talk": "「[[:$1]]」および付随するページを[[Special:Watchlist|ウォッチリスト]]に追加しました。",
        "addedwatchtext-short": "ページ「$1」をウォッチリストに追加しました。",
        "removewatch": "ウォッチリストから除去",
        "removedwatchtext": "「[[:$1]]」および付随する議論ページを[[Special:Watchlist|ウォッチリスト]]から除去しました。",
+       "removedwatchtext-talk": "「[[:$1]]」および付随するページを[[Special:Watchlist|ウォッチリスト]]から除去しました。",
        "removedwatchtext-short": "ページ「$1」をウォッチリストから除去しました。",
        "watch": "ウォッチ",
        "watchthispage": "このページをウォッチする",
        "tooltip-ca-nstab-category": "カテゴリページを閲覧",
        "tooltip-minoredit": "この編集に細部の変更の印を付ける",
        "tooltip-save": "変更を保存する",
+       "tooltip-publish": "あなたによる変更を公開",
        "tooltip-preview": "変更内容をプレビューで確認できます。保存前に使用してください。",
        "tooltip-diff": "文章への変更箇所を表示する",
        "tooltip-compareselectedversions": "選択した2つの版の差分を表示する",
index f1d8048..8abca6a 100644 (file)
@@ -6,7 +6,8 @@
                        "Marmase",
                        "Mirzali",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Kumkumuk"
                ]
        },
        "tog-underline": "Bınê gırey de xete bonce:",
        "retypenew": "Parola newiye tekrar ke:",
        "resetpass_submit": "Parola ayar ke u cı kuye",
        "changepassword-success": "Parola sıma ebe serkotene vurriye! Nıka hesabê sıma beno ra...",
+       "botpasswords-label-cancel": "Bıtexelne",
        "resetpass_forbidden": "Paroley nêşikinê bıvurniyê",
        "resetpass-submit-loggedin": "Parola bıvurne",
        "resetpass-submit-cancel": "Bıtexelne",
        "watchthis": "Na pele de şêr ke",
        "savearticle": "Pele qeyd ke",
        "preview": "Verqayt",
-       "showpreview": "Verqayti bıasne",
+       "showpreview": "Verqayti bımocne",
        "showdiff": "Vurnaisun bıasne",
        "anoneditwarning": "'''Diqet:''' Tı cınêkota.\nTarixê vurnaena na pele de, hurêndia leqeme de numra tuya IPy qeyd bena.",
        "missingcommenttext": "Cêr de jü xulasa bınuse.",
        "upload-source": "Dosya çımey",
        "sourcefilename": "Namê dosya çımey:",
        "watchthisupload": "Na dosya de şêr ke",
+       "upload-dialog-button-cancel": "Bıtexelne",
        "license": "Lisans:",
        "license-header": "Lisansdais",
        "imgfile": "dosya",
        "blanknamespace": "(Ser)",
        "contributions": "İştıraqê {{GENDER:$1|karber}}i",
        "contributions-title": "$1 de iştırakê karberi",
-       "mycontris": "İştıraqi",
+       "mycontris": "İştıraki",
        "contribsub2": "Serba $1 ($2)",
        "uctop": "(rocane)",
        "month": "Asme ra (u ravêr):",
        "blocklink": "kilıt ke",
        "unblocklink": "ra ke",
        "change-blocklink": "mani bıvurne",
-       "contribslink": "iştıraqi",
+       "contribslink": "iştıraki",
        "emaillink": "e-poste bırusne",
        "autoblocker": "Sıma otomatikmen kılit biy, çıke adresa sımawa ''IP''y terefê \"[[User:$1|$1]]\" gurenina.\nSebebê kılitbiyaena $1'i \"$2\"o",
        "blocklogpage": "Protokolê kilıti",
        "compare-page1": "Pele 1",
        "compare-page2": "Pele 2",
        "rightsnone": "(qet jü)",
-       "revdelete-summary": "xulasa vurnaene"
+       "revdelete-summary": "xulasa vurnaene",
+       "feedback-cancel": "Bıtexelne"
 }
index b594b92..7480241 100644 (file)
                        "Ananth subray",
                        "MarcoAurelio",
                        "Macofe",
-                       "రహ్మానుద్దీన్"
+                       "రహ్మానుద్దీన్",
+                       "ಶಿವಕುಮಾರ್ ನಾಯಕ್",
+                       "Yogesh"
                ]
        },
        "tog-underline": "ಕೊಂಡಿಗಳ ಕೆಳಗೆ ಗೆರೆ ತೋರಿಸಿ",
        "tog-hideminor": "ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳಲ್ಲಿ ಚಿಕ್ಕಪುಟ್ಟ ಸಂಪಾದನೆಗಳನ್ನು ಅಡಗಿಸಿ",
        "tog-hidepatrolled": "ಪಹರೆಯಲ್ಲಿ ಆದ ಸಂಪಾದನೆಗಳನ್ನು ಇತ್ತೀಚೆಗಿನ ಬದಲಾವಣೆಗಳಲ್ಲಿ ಅಡಗಿಸು",
        "tog-newpageshidepatrolled": "ಪಹರೆಯಲ್ಲಿ ಆದ ಪುಟಗಳನ್ನು ಹೊಸ ಪುಟಗಳ ಪಟ್ಟಿಯಲ್ಲಿ ಅಡಗಿಸು",
-       "tog-extendwatchlist": "à²\95à³\87ವಲ à²\87ತà³\8dತà³\80à²\9aà³\86à²\97ಿನ à²¬à²¦à²²à²¾à²µà²£à³\86à²\97ಳಲà³\8dಲದà³\86, à²¸à²\82ಬà²\82ಧಿತ à²\8eಲà³\8dಲಾ à²¬à²¦à²²à²¾à²µà²£à³\86à²\97ಳನà³\8dನà³\81 à²¤à³\8bರà³\81ವà²\82ತà³\86 à²ªà²\9fà³\8dà²\9fಿಯನà³\8dನà³\81 à²µà²¿à²¸à³\8dತರಿಸಿ",
+       "tog-extendwatchlist": "ಕೇವಲ ಇತ್ತೀಚೆಗಿನ ಬದಲಾವಣೆಗಳಲ್ಲದೆ, ಎಲ್ಲಾ ಬದಲಾವಣೆಗಳನ್ನು ತೋರುವಂತೆ ಪಟ್ಟಿಯನ್ನು ವಿಸ್ತರಿಸಿ",
        "tog-usenewrc": "ಹೆಚ್ಚು ವರ್ಧಿಸಲಾದ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳು ಪುಟ ಬಳಸು",
        "tog-numberheadings": "ತಲೆಬರಹಗಳಿಗೆ ಅಂಕಿಗಳನ್ನು ತೋರಿಸು",
        "tog-showtoolbar": "ಸಂಪಾದನೆಯ ಉಪಕರಣಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರು",
        "faqpage": "Project:ಸಾಮಾನ್ಯವಾಗಿ ಕೇಳಲಾಗುವ ಪ್ರಶ್ನೆಗಳು",
        "actions": "ಕ್ರಿಯೆಗಳು",
        "namespaces": "ನಾಮವರ್ಗಗಳು",
-       "variants": "ಹಲವà³\81",
-       "navigation-heading": "ಸà²\82à²\9aರಣà³\86 à²®à³\86ನà³\81",
+       "variants": "ವà³\8dಯತà³\8dಯಾಸ à²¹à³\8aà²\82ದಿರà³\81ವ",
+       "navigation-heading": "ಸà²\82à²\9aರಣà³\86 à²ªà²\9fà³\8dà²\9fಿ",
        "errorpagetitle": "ದೋಷ",
        "returnto": "$1 ಗೆ ಹಿಂತಿರುಗಿ.",
        "tagline": "{{SITENAME}} ಇಂದ",
        "history_short": "ಇತಿಹಾಸ",
        "updatedmarker": "ನನ್ನ ಕೊನೆಯ ವೀಕ್ಷಣೆಯ ನಂತರ ಬದಲಾಗಿರುವವು",
        "printableversion": "ಪ್ರಿಂಟ್ ಆವೃತ್ತಿ",
-       "permalink": "ಸà³\8dಥಿರ à²¸à²\82ಪರà³\8dà²\95",
+       "permalink": "ಸà³\8dಥಿರ à²\95à³\8aà²\82ಡಿ",
        "print": "ಮುದ್ರಿಸು",
        "view": "ನೋಟ",
        "view-foreign": "$1 ರಲ್ಲಿ ನೋಡಿ",
        "undelete_short": "{{PLURAL:$1|ಒಂದು ಸಂಪಾದನೆಯ|$1 ಸಂಪಾದನೆಗಳ}} ಅಳಿಸುವಿಕೆಯನ್ನು ತೊಡೆದುಹಾಕು",
        "viewdeleted_short": "ನೋಟ {{PLURAL:$1|೧ ಅಳಿಸಲ್ಪಟ್ಟ ಸಂಪಾದನೆ|$1 ಅಳಿಸಲ್ಪಟ್ಟ ಸಂಪಾದನೆಗಳು}}",
        "protect": "ಸಂರಕ್ಷಿಸು",
-       "protect_change": "ಬದಲಾಯಿಸಿ",
+       "protect_change": "ಬದಲಾಯಿಸà³\81",
        "protectthispage": "ಈ ಪುಟವನ್ನು ಸಂರಕ್ಷಿಸಿ",
-       "unprotect": "ರà²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²µà²£à³\86",
-       "unprotectthispage": "à²\88 à²ªà³\81à²\9fದ à²°à²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²¯à²¿à²¸à²²à³\81",
+       "unprotect": "ರà²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²¯à²¿à²¸à³\81",
+       "unprotectthispage": "ಈ ಪುಟದ ರಕ್ಷಣೆಯನ್ನು ಬದಲಾಯಿಸು",
        "newpage": "ಹೊಸ ಪುಟ",
-       "talkpage": "à²\88 à²ªà³\81à²\9fದ à²¬à²\97à³\8dà²\97à³\86 à²\9aರà³\8dà²\9aà³\86 à²®à²¾à²¡ಿ",
+       "talkpage": "à²\88 à²ªà³\81à²\9fವನà³\8dನà³\81 à²\9aರà³\8dà²\9aಿಸಿ",
        "talkpagelinktext": "ಚರ್ಚೆ",
        "specialpage": "ವಿಶೇಷ ಪುಟ",
        "personaltools": "ವೈಯಕ್ತಿಕ ಉಪಕರಣಗಳು",
        "talk": "ಚರ್ಚೆ",
        "views": "ನೋಟಗಳು",
        "toolbox": "ಉಪಕರಣಗಳು",
-       "userpage": "ಸದಸ್ಯರ ಪುಟ ತೋರು",
+       "userpage": "ಸದಸ್ಯರ ಪುಟವನ್ನು ವೀಕ್ಷಿಸು",
        "projectpage": "ಯೋಜನೆಯ ಪುಟವನ್ನು ನೋಡು",
        "imagepage": "ಕಡತದ ಪುಟ ವೀಕ್ಷಿಸಿ",
        "mediawikipage": "ಸಂದೇಶ ಪುಟವನ್ನು ನೋಡು",
        "templatepage": "ಟೆಂಪ್ಲೇಟು ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "viewhelppage": "ಸಹಾಯ ಪುಟ ತೋರು",
-       "categorypage": "ವರ್ಗ ಪುಟ ತೋರು",
+       "categorypage": "ವರ್ಗದ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "viewtalkpage": "ಚರ್ಚೆಯನ್ನು ವೀಕ್ಷಿಸಿ",
        "otherlanguages": "ಇತರ ಭಾಷೆಗಳಲ್ಲಿ",
        "redirectedfrom": "($1 ಇಂದ ಪುನರ್ನಿರ್ದೇಶಿತ)",
        "copyrightpage": "{{ns:project}}:ಕೃತಿಸ್ವಾಮ್ಯತೆಗಳು",
        "currentevents": "ಪ್ರಚಲಿತ ಸಂಗತಿಗಳು",
        "currentevents-url": "Project:ಪ್ರಚಲಿತ ಸಂಗತಿಗಳು",
-       "disclaimers": "à²\85ಬಾಧà³\8dಯತೆಗಳು",
+       "disclaimers": "ಹà²\95à³\8dà²\95à³\81 à²¨à²¿à²°à²¾à²\95ರಣೆಗಳು",
        "disclaimerpage": "Project:ಸಾಮಾನ್ಯ ಅಬಾಧ್ಯತೆಗಳು",
        "edithelp": "ಸಂಪಾದನೆಗೆ ಸಹಾಯ",
        "helppage-top-gethelp": "ಸಹಾಯ",
        "policy-url": "Project:ನಿಯಮಾವಳಿಗಳು",
        "portal": "ಸಮುದಾಯ ಪುಟ",
        "portal-url": "Project:ಸಮುದಾಯ ಪುಟ",
-       "privacy": "à²\97à³\8cಪà³\8dಯತà³\86ಯ à²\95ಾರà³\8dಯನೀತಿ",
+       "privacy": "à²\97à³\8cಪà³\8dಯತಾ ನೀತಿ",
        "privacypage": "Project:ಗೌಪ್ಯತೆಯ ಕಾರ್ಯನೀತಿ",
        "badaccess": "ಅನುಮತಿ ದೋಷ",
        "badaccess-group0": "ನೀವು ಕೋರಿರುವ ಕ್ರಿಯೆಯನ್ನು ನಿರ್ವಹಿಲು ನಿಮಗೆ ಅನುಮತಿ ಇಲ್ಲ.",
        "minoredit": "ಇದು ಚುಟುಕಾದ ಬದಲಾವಣೆ",
        "watchthis": "ಈ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "savearticle": "ಪುಟವನ್ನು ಉಳಿಸಿ",
+       "publishpage": "ಪುಟವನ್ನು ಪ್ರಕಟಿಸು",
+       "publishchanges": "ಬದಲಾವಣೆಗಳನ್ನು ಪ್ರಕಟಿಸು",
        "preview": "ಮುನ್ನೋಟ",
        "showpreview": "ಮುನ್ನೋಟ ತೋರಿಸು",
        "showdiff": "ಬದಲಾವಣೆಗಳನ್ನು ತೋರಿಸು",
        "previousrevision": "←ಹಿಂದಿನ ಪರಿಷ್ಕರಣೆ",
        "nextrevision": "ಮುಂದಿನ ಪರಿಷ್ಕರಣೆ",
        "currentrevisionlink": "ಈಗಿನ ಪರಿಷ್ಕರಣೆ",
-       "cur": "ಸಧ್ಯದ",
+       "cur": "ಸದ್ಯದ",
        "next": "ಮುಂದಿನದು",
        "last": "ಕೊನೆಯ",
        "page_first": "ಮೊದಲ",
        "recentchangeslinked-summary": "ಒಂದು ನಿರ್ದಿಷ್ಟ ಪುಟದಿಂದ (ಅಥವ ನಿರ್ದಿಷ್ಟ ವರ್ಗಕ್ಕೆ ಸೇರಿರುವ ಪುಟಗಳಿಂದ) ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿ ಇತ್ತೀಚೆಗೆ ಮಾಡಲಾಗಿರುವ ಬದಲಾವಣೆಗಳನ್ನು ಈ ಕೆಳಗೆ ಪಟ್ಟಿ ಮಾಡಲಾಗಿದೆ.\n[[Special:Watchlist|ನಿಮ್ಮ ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ]] ಇರುವ ಪುಟಗಳು '''ದಪ್ಪ ಅಕ್ಷರ'''ಗಳಲ್ಲಿ ಇವೆ.",
        "recentchangeslinked-page": "ಪುಟದ ಹೆಸರು:",
        "recentchangeslinked-to": "ಇದರ ಬದಲಿಗೆ ನೇಮಿತ ಪುಟಕ್ಕೆ ಕೊಂಡಿಯನ್ನು ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿನ ಬದಲಾವಣೆಗಳನ್ನು ತೋರು",
-       "upload": "ಫà³\88ಲà³\8d à²\85ಪà³\8dಲà³\8bಡà³\8d",
+       "upload": "ಫà³\88ಲà³\8d à²®à³\87ಲà²\95à³\8dà²\95à³\86ರಿಸಿ",
        "uploadbtn": "ಫೈಲನ್ನು ಅಪ್ಲೋಡ್ ಮಾಡಿ",
        "reuploaddesc": "ಅಪ್ಲೋಡ್ ಅನ್ನು ನಿಲ್ಲಿಸಿ ಮತ್ತೆ ಅಪ್ಲೋಡ್ ವಕ್ಕಣೆಗೆ ಹಿಂದಿರುಗಿ",
        "uploadnologin": "ಲಾಗಿನ್ ಆಗಿಲ್ಲ",
        "unusedtemplates": "ಉಪಯೋಗದಲ್ಲಿರದ ಟೆಂಪ್ಲೇಟುಗಳು",
        "unusedtemplatestext": "ಯಾವ ಪುಟದಲ್ಲೂ ಉಪಯೋಗದಲ್ಲಿ ಇರದ ಟೆಂಪ್ಲೇಟುಗಳನ್ನು ಇಲ್ಲಿ ಪಟ್ಟಿ ಮಾಡಲಾಗಿದೆ. ಇವನ್ನು ಅಳಿಸುವ ಮುನ್ನ ಟೆಂಪ್ಲೇಟುಗಳಿಗೆ ಇತರ ಲಿಂಕುಗಳಿದೆಯೆ ಎಂದು ಪರೀಕ್ಷಿಸಲು ಮರೆಯದಿರಿ.",
        "unusedtemplateswlh": "ಇತರ ಕೊಂಡಿಗಳು",
-       "randompage": "ಯಾದà³\83à²\9aà³\8dà²\9bಿà²\95 ಪುಟ",
+       "randompage": "ಯಾವà³\81ದಾದರà³\81 à²\92à²\82ದà³\81 ಪುಟ",
        "randompage-nopages": "ಈ ಪುಟಪ್ರಬೇಧದಲ್ಲಿ ಯಾವ ಪುಟವೂ ಇಲ್ಲ.",
        "randomincategory-category": "ವರ್ಗ:",
        "randomincategory-submit": "ಹೋಗು",
        "tooltip-search": "{{SITENAME}} ಅನ್ನು ಹುಡುಕಿ",
        "tooltip-search-go": "ಇದೇ ಹೆಸರಿನ ಪುಟವಿದ್ದಲ್ಲಿ ಅಲ್ಲಿಗೆ ಹೋಗು",
        "tooltip-search-fulltext": "ಈ ಪಠ್ಯವನ್ನು ಹೊಂದಿರುವ ಪುಟಗಳನ್ನು ಹುಡುಕು",
-       "tooltip-p-logo": "ಮುಖ್ಯ ಪುಟ",
+       "tooltip-p-logo": "ಮುಖ್ಯ ಪುಟಕ್ಕೆ ಭೇಟಿ ಕೊಡಿ",
        "tooltip-n-mainpage": "ಮುಖ್ಯ ಪುಟ ನೋಡಿ",
        "tooltip-n-mainpage-description": "ಮುಖ್ಯ ಪುಟ ನೋಡಿ",
        "tooltip-n-portal": "ಯೋಜನೆಯ ಬಗ್ಗೆ, ನೀವು ಏನು ಮಾಡಬಹುದು, ಎಲ್ಲಿ ಇದರ ಬಗ್ಗೆ ತಿಳಿದುಕೊಳ್ಳಬಹುದು",
        "tooltip-n-currentevents": "ಪ್ರಸಕ್ತ ಆಗುಹೋಗುಗಳ ಬಗ್ಗೆ ಹಿನ್ನಲೆ ಮಾಹಿತಿ ಪಡೆಯಿರಿ",
        "tooltip-n-recentchanges": "ವಿಕಿಯಲ್ಲಿನ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳ ಪಟ್ಟಿ.",
-       "tooltip-n-randompage": "ಯದà³\83à²\9aà³\8dà²\9bಿà²\95 ಪುಟವೊಂದನ್ನು ತೋರಿಸು",
+       "tooltip-n-randompage": "ಯಾವà³\81ದಾದರà³\81 ಪುಟವೊಂದನ್ನು ತೋರಿಸು",
        "tooltip-n-help": "ಇದರ ಬಗ್ಗೆ ತಿಳಿದುಕೊಳ್ಳಲು ಜಾಗ.",
        "tooltip-t-whatlinkshere": "ಇಲ್ಲಿಗೆ ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಎಲ್ಲಾ ವಿಕಿ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-t-recentchangeslinked": "ಈ ಪುಟದಿಂದ ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿನ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳು",
        "tooltip-feed-atom": "ಈ ಪುಟಕ್ಕೆ Atom ಫೀಡು",
        "tooltip-t-contributions": "ಈ ಸದಸ್ಯರ ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸು",
        "tooltip-t-emailuser": "ಈ ಸದಸ್ಯರಿಗೆ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸು",
-       "tooltip-t-upload": "ಫà³\88ಲನà³\8dನà³\81 à²\85ಪà³\8dಲà³\8bಡà³\8d à²®à²¾à²¡ಿ",
+       "tooltip-t-upload": "ಫà³\88ಲನà³\8dನà³\81 à²®à³\87ಲà²\95à³\8dà²\95à³\86ರಿಸಿ",
        "tooltip-t-specialpages": "ಎಲ್ಲಾ ವಿಶೇಷ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-t-print": "ಈ ಪುಟದ ಮುದ್ರಣ ಮಾಡಬಹುದಾದಂತ ಆವೃತ್ತಿ",
        "tooltip-t-permalink": "ಪುಟದ ಈ ಆವೃತ್ತಿಗೆ ಶಾಶ್ವತ ಕೊಂಡಿ",
        "file-nohires": "ಇದಕ್ಕಿಂತ ಹೆಚ್ಚಿನ ವಿವರವಾದ ನೋಟ ಇಲ್ಲ.",
        "svg-long-desc": "SVG ಫೈಲು, ಸುಮಾರಾಗಿ $1 × $2 ಚಿತ್ರಬಿಂದುಗಳು, ಫೈಲಿನ ಗಾತ್ರ: $3",
        "show-big-image": "ಮೂಲ ಕಡತ",
+       "show-big-image-preview": "ಈ ಮುನ್ನೋಟ ಗಾತ್ರ:$1.",
+       "show-big-image-other": "ಇತರೆ{{PLURAL:$2|resolution|resolutions}}: $1.",
        "show-big-image-size": "$1 × $2 ಪಿಕ್ಸೆಲ್‌ಗಳು",
        "file-info-gif-looped": "ಲೂಪ್",
        "file-info-png-looped": "ಲೂಪ್",
        "specialpages-group-pages": "ಪುಟಗಳ ಪಟ್ಟಿ",
        "specialpages-group-redirects": "ವಿಶೇಷ ಪುಟಗಳನ್ನು ಪುನರ್ನಿರ್ದೇಶಿಸಲಾಗುತ್ತಿದೆ",
        "blankpage": "ಖಾಲಿ ಪುಟ",
-       "tag-filter": "[[ವಿಶೇಷ:ಟ್ಯಾಗ್‌ಗಳು|ಟ್ಯಾಗ್]] ಶೋಧಕ:",
+       "tag-filter": "[[Special:Tags|Tag]] ಶೋಧಕ:",
        "tag-filter-submit": "ಶೋಧಕ",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ಟ್ಯಾಗ್|ಟ್ಯಾಗ್‌ಗಳು}}]]: $2)",
        "tags-title": "ಅಂಕಿತಗಳು",
index 2053fd6..f548224 100644 (file)
@@ -93,7 +93,7 @@
        "tog-oldsig": "현재 서명:",
        "tog-fancysig": "서명을 위키텍스트로 취급 (자동으로 링크를 걸지 않음)",
        "tog-uselivepreview": "실시간 미리 보기 사용하기",
-       "tog-forceeditsummary": "편집 요약을 쓰지 않았을 때 알려주기",
+       "tog-forceeditsummary": "편집 요약을 쓰지 않았을 때 물어보기",
        "tog-watchlisthideown": "주시문서 목록에서 내 편집을 숨기기",
        "tog-watchlisthidebots": "주시문서 목록에서 봇 편집을 숨기기",
        "tog-watchlisthideminor": "주시문서 목록에서 사소한 편집을 숨기기",
        "tagline": "{{SITENAME}}",
        "help": "도움말",
        "search": "검색",
+       "search-ignored-headings": " #<!-- 이 줄은 그대로 두십시오 --> <pre>\n# 검색에서 무시되는 문단 제목입니다.\n# 이 문서에 대한 바뀜은 즉시 문단 제목으로 된 문서가 다시 색인됩니다.\n# null 편집을 하여 문서 다시 색인을 강제할 수 있습니다.\n# 문법은 다음과 같습니다:\n#   * \"#\" 문자에서 줄의 끝까지는 주석입니다\n#   * 빈 줄이 아닌 줄은 무시할 정확한 제목이며, 대소문자를 무시합니다\n각주\n참조\n참고\n출처\n바깥 링크\n바깥 고리\n같이 보기\n함께 보기\n #</pre> <!-- 이 줄은 그대로 두십시오 -->",
        "searchbutton": "검색",
        "go": "보기",
        "searcharticle": "보기",
        "botpasswords-label-delete": "삭제",
        "botpasswords-label-resetpassword": "비밀번호 재설정",
        "botpasswords-label-grants": "적용할 수 있는 부여:",
-       "botpasswords-help-grants": "ê°\9cê°\9cì\9d\98 ë¶\80ì\97¬ ê¸°ë\8a¥ì\9d\80 ì\82¬ì\9a©ì\9e\90 ê³\84ì \95ì\9d´ ì\9d´ë¯¸ ì\86\8cì\9c í\95\98ê³  ì\9e\88ë\8a\94 ì\82¬ì\9a©ì\9e\90 ê¶\8cí\95\9cì\97\90 ë\8c\80í\95\9c ì \91ê·¼ì\9d\84 ì \9cê³µí\95©ë\8b\88ë\8b¤. ì\9e\90ì\84¸í\95\9c ì\82¬í\95­ì\9d\80 [[Special:ListGrants|ë¶\80ì\97¬ ëª©ë¡\9d]]ì\9d\84 í\99\95ì\9d¸í\95´ ì£¼ì\8b­ì\8b\9cì\98¤.",
+       "botpasswords-help-grants": "ê°\81ê°\81 ë¶\80ì\97¬ë\90\9c ê°\92ì\9d\80 ëª©ë¡\9dì\97\90ì\84\9c ì\82¬ì\9a©ì\9e\90 ê³\84ì \95ì\9d\84 ì\9d´ë¯¸ ê°\96ê³  ì\9e\88ë\8a\94 ì\82¬ì\9a©ì\9e\90 ê¶\8cí\95\9cì\97\90 ì \91ê·¼í\95  ì\88\98 ì\9e\88ë\8a\94 ê¶\8cí\95\9cì\9d\84 ì¤\8dë\8b\88ë\8b¤. ì\9e\90ì\84¸í\95\9c ì \95ë³´ë\8a\94 [[Special:ListGrants|ë¶\80ì\97¬ í\91\9c]]ì\9d\84 ë³´ì\84¸ì\9a\94.",
        "botpasswords-label-restrictions": "사용 제한:",
        "botpasswords-label-grants-column": "승인됨",
        "botpasswords-bad-appid": "\"$1\"이라는 봇 이름은 유효하지 않습니다.",
        "permissionserrors": "권한 오류",
        "permissionserrorstext": "해당 명령을 수행할 권한이 없습니다. 다음 {{PLURAL:$1|이유}}를 확인해보세요:",
        "permissionserrorstext-withaction": "$2 권한이 없습니다. 다음 {{PLURAL:$1|이유}}를 확인해주세요:",
-       "contentmodelediterror": "ì\82¬ì\9a©ì\9e\90ë\8a\94 ì\9d´ í\8c\90ì\9d\84 í\8e¸ì§\91í\95  ì\88\98 ì\97\86ì\8aµë\8b\88ë\8b¤. ì½\98í\85\90츠 ëª¨ë\8d¸ì\9d\80 <code>$1</code>ì\9d´ë©°, ì\9d´ ë¬¸ì\84\9cì\9d\98 í\98\84 콘텐츠 모델은 <code>$2</code>이므로 차이가 있습니다.",
+       "contentmodelediterror": "ì\9d´ í\8c\90ì\9d\84 í\8e¸ì§\91í\95  ì\88\98 ì\97\86ì\8aµë\8b\88ë\8b¤. ì½\98í\85\90츠 ëª¨ë\8d¸ì\9d\80 <code>$1</code>ì\9d´ë©°, ì\9d´ ë¬¸ì\84\9cì\9d\98 í\98\84ì\9e¬ 콘텐츠 모델은 <code>$2</code>이므로 차이가 있습니다.",
        "recreate-moveddeleted-warn": "<strong>경고: 삭제된 문서를 다시 만들고 있습니다.</strong>\n\n이 문서를 계속 편집하는 것이 적합한 것인지 확인해주세요.\n편의를 위해 삭제와 이동 기록을 다음과 같이 제공합니다:",
        "moveddeleted-notice": "이 문서는 삭제되었습니다.\n이 문서의 삭제 및 이동 기록은 다음과 같습니다.",
        "moveddeleted-notice-recent": "죄송합니다, 이 문서는 최근 (24시간 내)에 삭제된 적이 있습니다.\n삭제와 이동 기록이 참고를 위해 남겨져 있습니다.",
        "currentrev": "최신판",
        "currentrev-asof": "$1 기준 최신판",
        "revisionasof": "$1 판",
-       "revision-info": "{{GENDER:$6|$2}} 사용자의 $1 판$7",
+       "revision-info": "{{GENDER:$6|$2}}의 $1 판$7",
        "previousrevision": "← 이전 판",
        "nextrevision": "다음 판 →",
        "currentrevisionlink": "최신판",
        "right-applychangetags": "자신이 편집할 때 [[Special:Tags|태그]]를 적용하기",
        "right-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 [[Special:Tags|태그]]를 추가하거나 제거하기",
        "right-deletechangetags": "데이터베이스에서 [[Special:Tags|태그]]를 지우기",
-       "grant-generic": "\"$1\" ê¶\8cí\95\9c ë²\88ë\93¤",
+       "grant-generic": "\"$1\" ê¶\8cí\95\9c ë¬¶ì\9d\8c",
        "grant-group-page-interaction": "문서로 상호 작용",
        "grant-group-file-interaction": "미디어로 상호 작용",
        "grant-group-watchlist-interaction": "당신의 주시문서로 상호작용",
        "action-applychangetags": "당신이 편집할 때 태그를 적용하기",
        "action-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 태그를 추가하거나 제거하기",
        "action-deletechangetags": "데이터베이스에서 태그를 지우기",
+       "action-purge": "이 문서 새로 고침",
        "nchanges": "$1개 {{PLURAL:$1|바뀜}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|마지막 방문 이후}} $1개",
        "enhancedrc-history": "역사",
        "watchnologin": "로그인하지 않음",
        "addwatch": "주시문서 목록에 추가",
        "addedwatchtext": "\"[[:$1]]\" 문서와 그 토론 문서가 [[Special:Watchlist|주시문서 목록]]에 추가되었습니다.",
+       "addedwatchtext-talk": "\"[[:$1]]\" 문서와 관련 문서가 [[Special:Watchlist|주시문서 목록]]에 추가되었습니다.",
        "addedwatchtext-short": "\"$1\" 문서를 주시문서 목록에 추가했습니다.",
        "removewatch": "주시문서 목록에서 제거",
        "removedwatchtext": "\"[[:$1]]\" 문서와 그 토론 문서가 [[Special:Watchlist|주시문서 목록]]에서 제거되었습니다.",
+       "removedwatchtext-talk": "\"[[:$1]]\" 문서와 관련 문서가 [[Special:Watchlist|주시문서 목록]]에서 제거되었습니다.",
        "removedwatchtext-short": "\"$1\" 문서를 주시문서 목록에 제거했습니다.",
        "watch": "주시",
        "watchthispage": "주시하기",
        "protectlogtext": "아래의 목록은 문서 보호에 관한 바뀜에 대한 기록입니다.\n현재 보호된 문서의 목록에 대해서는 [[Special:ProtectedPages|보호된 문서 목록]]을 참조하세요.",
        "protectedarticle": "님이 \"[[$1]]\" 문서를 보호했습니다",
        "modifiedarticleprotection": "님이 \"[[$1]]\" 문서의 보호 설정을 바꿨습니다",
-       "unprotectedarticle": "님이 \"[[$1]]\" 문서를 보호 해제했습니다",
+       "unprotectedarticle": "\"[[$1]]\" 문서를 보호 해제했습니다",
        "movedarticleprotection": "님이 문서의 보호 설정을 \"[[$2]]\"에서 \"[[$1]]\"(으)로 이동했습니다",
        "protect-title": "\"$1\" 보호하기",
        "protect-title-notallowed": "\"$1\" 문서의 보호 수준 보기",
        "unblockip": "사용자 차단 해제",
        "unblockiptext": "아래의 양식에 차단 해제하려는 IP 주소나 사용자 이름을 입력하세요.",
        "ipusubmit": "차단 해제",
-       "unblocked": "[[User:$1|$1]] 사용자의 차단을 해제했습니다.",
+       "unblocked": "[[User:$1|$1]]의 차단을 해제했습니다.",
        "unblocked-range": "$1 대역이 차단 해제되었습니다.",
        "unblocked-id": "$1 차단이 해제되었습니다.",
        "unblocked-ip": "[[Special:Contributions/$1|$1]]님이 차단 해제되었습니다.",
        "revdelete-restricted": "관리자에게 제한을 적용함",
        "revdelete-unrestricted": "관리자에 대한 제한을 해제함",
        "logentry-block-block": "$1님이 {{GENDER:$4|$3}}님을 $5 {{GENDER:$2|차단했습니다}} $6",
-       "logentry-block-unblock": "$1님이 {{GENDER:$4|$3}} 사용자의 {{GENDER:$2|차단을 해제했습니다}}",
+       "logentry-block-unblock": "$1님이 {{GENDER:$4|$3}}의 {{GENDER:$2|차단을 해제했습니다}}",
        "logentry-block-reblock": "$1님이 {{GENDER:$4|$3}}님의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
        "logentry-suppress-block": "$1님이 {{GENDER:$4|$3}} 사용자를 $5 {{GENDER:$2|차단했습니다}} $6",
        "logentry-suppress-reblock": "$1님이 {{GENDER:$4|$3}}님의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
        "logentry-protect-modify": "$1님이 $3 문서의 보호 수준을 {{GENDER:$2|바꾸었습니다}} $4",
        "logentry-protect-modify-cascade": "$1님이 $3 문서의 보호 수준을 {{GENDER:$2|바꾸었습니다}} $4 [연쇄적]",
        "logentry-rights-rights": "$1님이 {{GENDER:$6|$3}}님의 권한을 $4에서 $5(으)로 {{GENDER:$2|바꾸었습니다}}",
-       "logentry-rights-rights-legacy": "$1님이 $3 사용자의 권한을 {{GENDER:$2|바꾸었습니다}}",
+       "logentry-rights-rights-legacy": "$1님이 $3의 권한을 {{GENDER:$2|바꾸었습니다}}",
        "logentry-rights-autopromote": "$1님이 권한을 자동적으로 $4에서 $5(으)로 {{GENDER:$2|바꾸었습니다}}",
        "logentry-upload-upload": "$1님이 $3 파일을 {{GENDER:$2|올렸습니다}}",
        "logentry-upload-overwrite": "$1님이 $3의 새 판을 {{GENDER:$2|올렸습니다}}",
        "expand_templates_generate_rawhtml": "원본 HTML 보이기",
        "expand_templates_preview": "미리 보기",
        "expand_templates_preview_fail_html": "<em>{{SITENAME}}에서 순수 HTML 입력을 허용한 상태에서 세션 데이터가 분실되었습니다. 그러므로 자바스크립트 공격을 예방하기 위해 미리 보기는 숨겨져 있습니다.</em>\n\n<strong>적합하게 미리 보기를 시도했다면 다시 시도해 주십시오.</strong>\n그래도 되지 않으면 [[Special:UserLogout|로그아웃]]한 다음 다시 로그인하여 사용자의 브라우저가 이 사이트에서 쿠키를 허용하는지 확인해 주십시오.",
-       "expand_templates_preview_fail_html_anon": "<em>{{SITENAME}}에서 순수 HTML 입력을 허용한 상태에서 사용자는 로그인되어 있지 않습니다. 그러므로 자바스크립트 공격을 예방하기 위해 미리 보기는 숨겨져 있습니다.</em>\n\n<strong>적합하게 미리 보기를 시도했다면 [[Special:UserLogin|로그인]]한 다음 다시 시도해 주십시오.",
+       "expand_templates_preview_fail_html_anon": "<em>{{SITENAME}}에서 순수 HTML 입력을 허용한 상태에서 사용자는 로그인되어 있지 않습니다. 그러므로 자바스크립트 공격을 예방하기 위해 미리 보기는 숨겨져 있습니다.</em>\n\n<strong>적합하게 미리 보기를 시도했다면 [[Special:UserLogin|로그인]]한 다음 다시 시도해 주십시오.</strong>",
        "expand_templates_input_missing": "전개할 내용을 입력해야 합니다.",
        "pagelanguage": "문서 언어 바꾸기",
        "pagelang-name": "문서",
index 17f733d..af6b90c 100644 (file)
@@ -89,7 +89,7 @@
        "listingcontinuesabbrev": "jatkuu",
        "about": "Tietuo",
        "article": "Šivu",
-       "newwindow": "(avautuu uuvešša ikkunašša)",
+       "newwindow": "(avautuu uuvvešša ikkunašša)",
        "cancel": "Keškeytä",
        "moredotdotdot": "Lisyä...",
        "mypage": "Šivu",
        "retrievedfrom": "Lähte - \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|Šiula on}} $1 ($2).",
        "editsection": "kohentele",
-       "editold": "kohenna",
+       "editold": "kohentele",
        "viewsourceold": "näytä wikiteksti",
        "editlink": "kohentele",
        "viewsourcelink": "näytä lähtehkoodi",
        "nstab-main": "Šivu",
        "nstab-user": "Käyttäjäšivu",
        "nstab-media": "Mediašivu",
-       "nstab-special": "Toimintosivu",
+       "nstab-special": "Toimintošivu",
        "nstab-project": "Projektišivu",
        "nstab-image": "Faili",
        "nstab-template": "Malli",
        "databaseerror-query": "Kyšely: $1",
        "databaseerror-error": "Hairahuš: $1",
        "badtitle": "Šivun nimi ei kelpua",
-       "badtitletext": "Šiun annetti šivunimi oli virheellini, tyhjä tahi viärin linkitetty kielienvälini tahi wikienvälini nimi.\nSiinä suattau olla yksi tahi usiempi sellani merkki, kumpasta ei voi käyttyä šivujen nimissä.",
+       "badtitletext": "Šiun pyytämä šivunimi oli virhiellini, tyhjä tahi viärin linkitetty kielienvälini tahi wikienvälini nimi.\nŠiinä šuattau olla yksi tahi ušiempi šemmoni merkki, kumpaista ei voi käyttyä šivujen nimilöissä.",
        "viewsource": "näytä lähtehkoodi",
        "yourname": "Käyttäjänimi:",
        "userlogin-yourname": "Käyttäjänimi",
        "userlogin-yourname-ph": "Kirjuta käyttäjänimi",
        "yourpassword": "Tunnuššana:",
-       "userlogin-yourpassword": "Tunnuššana",
-       "userlogin-yourpassword-ph": "Kirjuta tunnuššana",
-       "createacct-yourpassword-ph": "Kirjuta tunnuššana",
-       "createacct-yourpasswordagain": "Vahvista tunnuššana",
-       "createacct-yourpasswordagain-ph": "Kirjuta tunnuššana uuvveštah",
+       "userlogin-yourpassword": "Šalašana",
+       "userlogin-yourpassword-ph": "Kirjuta šalašana",
+       "createacct-yourpassword-ph": "Kirjuta šalašana",
+       "createacct-yourpasswordagain": "Vahvista šalašana",
+       "createacct-yourpasswordagain-ph": "Kirjuta šalašana uuvveštah",
        "userlogin-remembermypassword": "Pijä miut kirjuttautunuona",
        "login": "Kirjauvu šiämeh",
        "nav-login-createaccount": "Kirjauvu šiämeh / rekisteriyvy",
        "userlogin-joinproject": "Liity {{SITENAME}}",
        "createaccount": "Luaji käyttäjätili",
        "gotaccountlink": "Kirjauvu šiämeh",
-       "userlogin-resetpassword-link": "Unohitko tunnuššanan?",
+       "userlogin-resetpassword-link": "Unohitko šalašanan?",
        "userlogin-helplink2": "Apu kirjuttautumiseh",
-       "createacct-emailoptional": "Sähköpostiadressi (ei tarviče vältämättäh kirjuttua)",
-       "createacct-email-ph": "Kirjuta oma sähkopostiadressi",
+       "createacct-emailoptional": "Šähköpoštiošoiteh (ei tarviče välttämättä kirjuttua)",
+       "createacct-email-ph": "Kirjuta oma šähköpoštiošoiteh",
        "createaccountreason": "Šyy:",
        "createacct-reason": "Šyy",
        "createacct-submit": "Luaji oma käyttäjätunnuš",
        "passwordreset": "Kirjuta šalašana uuvveštah",
        "passwordreset-username": "Käyttäjänimi:",
        "passwordreset-domain": "Domain:",
-       "bold_sample": "Sankie teksta",
-       "bold_tip": "Sankie teksta",
+       "bold_sample": "Lihavointa",
+       "bold_tip": "Lihavointa",
        "italic_sample": "Kuršivoitu teksti",
        "italic_tip": "Kuršivointa",
        "link_sample": "Linkki",
        "link_tip": "Šiämilinkki",
        "extlink_sample": "http://www.example.com linkin nimi",
-       "extlink_tip": "Ulkohini linkki (musta http:// alkuh)",
-       "headline_sample": "Rupriekkatekšta",
-       "headline_tip": "Tašon 2 rupriekka",
+       "extlink_tip": "Ulkopuolini linkki (muissa laittua http:// alkuh)",
+       "headline_sample": "Očikkoteksti",
+       "headline_tip": "Tašon 2 očikko",
        "nowiki_sample": "Lisyä täh teksti, kumpaista ei pijä korjata",
        "nowiki_tip": "Penkuo wiki-korjaušta",
        "image_tip": "Tallennettu faili",
        "media_tip": "Linkki failih",
        "sig_tip": "Teijän allakirjutuš ta aika",
-       "hr_tip": "Horišontualini viiva (älä käytä liijakši)",
+       "hr_tip": "Vuakašuora viiva (elä käytä liijakši)",
        "summary": "Yhtehveto",
-       "minoredit": "Tämä on pieni muutoš",
+       "minoredit": "Tämä on pieni kohennuš",
        "watchthis": "Tarkkaile tätä šivuo",
        "savearticle": "Tallenna šivu",
        "showpreview": "Esikačo",
        "blockednoreason": "ei šyytä annettu",
        "loginreqlink": "kirjauvu šiämeh",
        "newarticle": "(Uuši)",
-       "newarticletext": "Olet piätynyn šivulla, kumpasta ei ole. Ku luatie šivu, rupie kirjuttamah alla olijah juaššiekkah (kačo [$1 ohjavošivulta] lisätietuo).\nKu ollet piätynyn tänne petties, käytä livaimen <strong>mennä järilleh</strong>-toimintuo.",
+       "newarticletext": "Linkki toi šivulla, kumpaista ei vielä ole.\nVoit luuvva šivun kirjuttamalla alla olijah ikkunah (kačo [$1 ohješivulta] lisätietoja). \nJoš et haluo luuvva šivuo, käytä šelaimen paluutoimintuo.",
        "noarticletext": "Tällä šivulla ei ole juuri nyt tekstie.\nVoit [[Special:Search/{{PAGENAME}}|eččie šivun nimellä]] muilta šivuilta,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} eččie šitä koškijua logie],\ntahi [{{fullurl:{{FULLPAGENAME}}|action=edit}} luuvva tämän šivun]</span>.",
        "noarticletext-nopermission": "Tällä šivulla ei ole juuri nyt tekstie.\nVoit [[Special:Search/{{PAGENAME}}|eččie šivun nimellä]] muilta šivuilta, tahi <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} eččie šivuo koškijua logie]</span>, ka šiula ei ole oikeutta luuvva tätä šivuo.",
-       "editing": "Kohennellah sivuu $1",
-       "creating": "Luajitah šivuu \"$1\"",
+       "editing": "Kohennellah šivuo $1",
+       "creating": "Luajitah šivuo \"$1\"",
        "editingsection": "Kohennellah $1 (alaluku)",
        "templatesused": "Tällä šivulla {{PLURAL:$1|käytetty malli|käytetyt mallit}}:",
        "template-protected": "(šuojattu)",
        "template-semiprotected": "(ošittain šuojattu)",
        "hiddencategories": "Tämä šivu kuuluu {{PLURAL:$1|1 peitettyh kategorijah|$1 peitettylöih kategorijoih}}:",
        "permissionserrorstext-withaction": "Šiula ei ole oikeutta {{lcfirst:$2}} {{PLURAL:$1|šeuruavašta šyyštä|šeuruavista šyistä}}:",
-       "moveddeleted-notice": "Tämä šivu on otettu iäre. Šivun iäreotanta- ta siirtoistorija ollah annettu alla viittavuksena.",
+       "moveddeleted-notice": "Tämä šivu on poistettu.\nAlla on tämän šivun poisto- ta šiirtoistorija.",
        "viewpagelogs": "Näytä tämän šivun lokit",
        "currentrev-asof": "Nykyni versija $1",
        "revisionasof": "Versija $1",
        "difference-title": "Ero šivun ”$1” versijien välillä",
        "lineno": "Rivi $1:",
        "editundo": "lakauttua",
-       "diff-multi-sameuser": "({{PLURAL:$1|Yksi keskitason versija |$1 keskitason versijua}} samalta käyttäjältä ei näytetty)",
+       "diff-multi-sameuser": "({{PLURAL:$1|Yksi keškitasšon versija |$1 keškitašon versijua}} šamalta käyttäjältä ei näytetty)",
        "searchresults": "Eččimisen tulokšet",
        "searchresults-title": "Eči \"$1\"",
        "prevn": "iellini {{PLURAL:$1|$1}}",
        "nextn-title": "Šeuruava $1 {{PLURAL:$1|tuloš|tulokšet}}",
        "shown-title": "Näytä $1 {{PLURAL:$1|tuloš|tulošta}} šivulla",
        "viewprevnext": "Näytä ($1 {{int:pipe-separator}} $2) ($3)",
-       "searchmenu-new": "<strong>Luaji šivu \"[[:$1]]\" täh wikih!</strong> {{PLURAL:$2|0=|Kačo niise šiun eččolla löyvetyt šivut.|Kačo niise löyvetyt ečon tulokšet.}}",
+       "searchmenu-new": "<strong>Luaji šivu \"[[:$1]]\" täh wikih!</strong> {{PLURAL:$2|0=|Kačo niise šiun ečolla löyvetyt šivut.|Kačo niise löyvetyt ečon tulokšet.}}",
        "searchprofile-articles": "Šisältöšivut",
        "searchprofile-images": "Multimedija",
        "searchprofile-everything": "Kaikki",
        "search-result-size": "$1 ({{PLURAL:$2|1 šana|$2 šanua}})",
        "search-redirect": "(šiirretty $1)",
        "search-section": "(alaluku $1)",
-       "search-suggest": "Tarkoititko: $1",
+       "search-suggest": "Tarkotitko: $1",
        "searchall": "kaikki",
        "search-showingresults": "{{PLURAL:$4|Tuloš <strong>$1</strong> / <strong>$3</strong>|Tulokšet <strong>$1 - $2</strong> / <strong>$3</strong>}}",
        "search-nonefound": "Kyšelyh ei löytyn tulokšie.",
        "newpageletter": "U",
        "boteditletter": "b",
        "rc-change-size-new": "$1 {{PLURAL:$1|baitti|baittie}} muutokšien jälkeh",
-       "recentchangeslinked": "Toini toišeh liittyjät kohennukšet",
+       "recentchangeslinked": "Toini toiseh liittyjät kohennukšet",
        "recentchangeslinked-toolbox": "Toini toiseh liittyjät kohennukšet",
        "recentchangeslinked-title": "Šivuo \"$1\" koškijat muutokšet",
        "recentchangeslinked-summary": "Tämä on niijen šivujen korjaukšien luvettelo, kumpasih viittuau tämä šivu (tahi šiih luokkah kuulujat). Šivut, kumpaset kuulutah [[Special:Watchlist|teijän valvontaluvetteloh]], ollah kirjutettu <strong>lihavalla</strong>.",
        "booksources-search-legend": "Eči kirjalähtehie",
        "booksources-search": "Eči",
        "log": "Lokit",
-       "allarticles": "Kai artikkelit",
+       "allarticles": "Kaikki šivut",
        "allpagessubmit": "Mäne",
        "categories": "Kategorijat",
        "linksearch-ok": "Ečindy",
        "watchlist": "Kaččuolistu",
        "mywatchlist": "Valvontaluvettelo",
        "watch": "Valvo",
-       "dellogpage": "Iäreotantaistorija",
+       "dellogpage": "Poistoloki",
        "rollbacklink": "Tuo entini versija",
        "rollbacklinkcount": "palauta $1 {{PLURAL:$1|muutoš|muutošta}}",
-       "protectlogpage": "Šuojavusistorija",
+       "protectlogpage": "Šuojaušloki",
        "protectcomment": "Šyy",
        "restriction-edit": "Kohennuš",
        "undelete-search-submit": "Ečindy",
        "tooltip-namespace_association": "Valiče tämä kohta, još haluot lisätä niise valittuh nimitilah liittyjät pakina- tahi aihenimitilat",
        "blanknamespace": "(Piä)",
        "contributions": "{{GENDER:$1|Käyttäjän}} panoš",
-       "mycontris": "Omat kohennukšet",
+       "mycontris": "Kirjutukšet",
        "anoncontribs": "Omat kohennukšet",
-       "month": "Täššä kuušša (tahi aijempi)",
+       "month": "Kuukauši",
        "year": "Vuosi",
        "sp-contributions-submit": "Ečindy",
        "whatlinkshere": "Linkit tänne",
-       "whatlinkshere-title": "Šivut, kumpaset košketah šivuu \"$1\"",
+       "whatlinkshere-title": "Šivut, kumpaset viitatah šivulla \"$1\"",
        "whatlinkshere-page": "Šivu:",
        "linkshere": "Šeuruavilta šivuilta on linkki šivulla <strong>[[:$1]]</strong>:",
        "isredirect": "ohjauššivu",
        "istemplate": "šisällytetty",
        "isimage": "failin linkki",
-       "whatlinkshere-prev": "{{PLURAL:$1|iellini|iellini $1}}",
-       "whatlinkshere-next": "{{PLURAL:$1|tulija|tulija $1}}",
+       "whatlinkshere-prev": "{{PLURAL:$1|iellini|iellistä $1}}",
+       "whatlinkshere-next": "{{PLURAL:$1|tulija|tulijua $1}}",
        "whatlinkshere-links": "← linkit",
        "whatlinkshere-hideredirs": "$1 ohjaukšet",
        "whatlinkshere-hidetrans": "$1 šisällytykšet",
        "allmessages-filter-translate": "Kiännä",
        "thumbnail-more": "Šuurenna",
        "tooltip-pt-userpage": "{{GENDER:|Oma käyttäjäšivu}}",
-       "tooltip-pt-mytalk": "Oma paginsivu",
-       "tooltip-pt-preferences": "{{GENDER:|Omat ašetukset}}",
+       "tooltip-pt-mytalk": "Oma pakinašivu",
+       "tooltip-pt-preferences": "{{GENDER:|Omat ašetukšet}}",
        "tooltip-pt-watchlist": "Lista šivuista, kumpasien muutokšie valvot",
        "tooltip-pt-mycontris": "Luvettelo {{GENDER:|šiun}} kirjutukšista",
        "tooltip-pt-login": "Täššä voit kirjuttautuo, ka še ei ole välttämätöintä",
        "tooltip-n-help": "Täštä voit kyšyö apuo",
        "tooltip-t-whatlinkshere": "Kaikkien šivujen luvettelo, kumpasista on linkki täh šivuh",
        "tooltip-t-recentchangeslinked": "Viimesimmät muokkaukšet šivuloilla, kumpasih viitatah tältä šivulta",
-       "tooltip-feed-atom": "Atom-šyöte tällä sivulla",
+       "tooltip-feed-atom": "Atom-šyöteh tällä šivulla",
        "tooltip-t-contributions": "Lista tämän käyttäjän kirjutukšista {{GENDER:$1|this user}}",
        "tooltip-t-upload": "Tallenna failija",
        "tooltip-t-specialpages": "Kaikkien erikoisien šivujen luvettelo",
        "tooltip-preview": "Esikačo muutokšet. Ole hyvä, luaji šitä aina ennen tallennušta.",
        "tooltip-diff": "Näytä luajitut muutokšet",
        "tooltip-rollback": "Pyyhi pois viimesen kohentelijan luatimat muutokšet yhellä kertua",
-       "tooltip-undo": "Kumoamini palauttau tämän muutokšen ta avuau artikkelin esikaččelussa. Yhtehvetokenttäh voi kirjuttua palautukšen šyyn.",
+       "tooltip-undo": "Kumuomini palauttau tämän muutokšen ta avuau artikkelin esikaččelušša. Yhtehvetokenttäh voi kirjuttua palautukšen šyyn.",
        "tooltip-summary": "Kirjuta lyhyt kuvauš",
        "simpleantispam-label": "Anti-spam-tarkissuš. \n<strong>älä</strong> täytä tätä!",
        "pageinfo-toolboxlink": "Šivun tiijot",
        "svg-long-desc": "SVG-faili, oletuštarkkuš $1 × $2 pikselie, failin koko: $3",
        "show-big-image": "Alkuperäni faili",
        "show-big-image-preview": "Tämän failin koko: $1.",
-       "show-big-image-other": "{{PLURAL:$2|Toini resolutija|Toiset resolutijat}}: $1.",
+       "show-big-image-other": "{{PLURAL:$2|Toini resol'uutijo|Toiset resol'uutijot}}: $1.",
        "show-big-image-size": "$1 × $2 kuvapistehtä",
        "ilsubmit": "Ečintä",
        "metadata": "Metatiijoštot",
        "metadata-help": "Failih kuulutah lisätiijot, kumpasie tavan mukah lisätäh digikameralla tahi skannerilla. Još kuvua on muokattu šen alkuperäsen luonnan jälkeh, niin eryähät parametrit voijah erota nykyseštä kuvašta.",
        "metadata-fields": "Šeuruavat metatietojen kentät ruvetah näkymäh kuvašivulla, konša metatietojen taulukko ei ole näkyvissä.\nMuut kentät ollah automattisešti piilotettuja.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "exif-orientation": "Šuunta",
-       "exif-xresolution": "Kuvan resoluutijo vuakašuorašša",
-       "exif-yresolution": "Vertikualini resolutsija",
+       "exif-xresolution": "Kuvan resol'uutijo vuakašuorašša",
+       "exif-yresolution": "Pistyšuora resol'uutijo",
        "exif-datetime": "Failin muutokšen päivä ta aika",
        "exif-make": "Kameran valmistaja",
        "exif-model": "Kameran malli",
index d3c0687..139dabe 100644 (file)
        "tagline": "Uß {{GRAMMAR:Dativ | {{ucfirst:{{SITENAME}}}}}}",
        "help": "Hölp",
        "search": "Söhke",
+       "search-ignored-headings": " #<!-- Lohß heh di Reih jenou esu, wi se es --> <pre>\n# Övverschreffte, di beim Söhke överjange wähde.\n# Änderonge werke vun däm Momang aan, woh di Sigg met dä Övverschreff neu önersöhk weed.\n# Dat kann De sellver aanstivvelle, endäm dat De di Sigg afscheijschere deihß, derbei moß De nix draan verändert han.\n# Syntax:\n#   * Alles, wat en ener reih henger „#“ schteiht, bedüüg nix.\n#   * Läddeje Reihje bedüüge nix.\n#   * Reije met jät dren sin jenou de Övverschreffte, di nit opjenumme wääde, met jruuße un kleine Schreff.\nWäbsigge\nLohr och noh\n #</pre> <!-- Lohß heh di Reihj jenou esu, wi se es -->",
        "searchbutton": "em Tex",
        "go": "Lohß Jonn!",
        "searcharticle": "Sigg",
index b8ab58d..9479f3c 100644 (file)
        "minoredit": "Haec est recensio minor",
        "watchthis": "Hanc paginam observare",
        "savearticle": "Hanc redactionem servare",
+       "publishpage": "Hanc paginam edere",
+       "publishchanges": "Hanc recensionem edere",
        "preview": "Praevidere",
        "showpreview": "Prospectum ostendere",
        "showdiff": "Mutationes ostendere",
        "tooltip-ca-nstab-category": "Videre paginam categoriae",
        "tooltip-minoredit": "Indicare hanc recensionem minorem",
        "tooltip-save": "Servare mutationes tuas",
+       "tooltip-publish": "Hanc recensionem edere",
        "tooltip-preview": "Sinet prospicere, quod mutationes tuas effecerint. Utere, quaesumus, hac facultate, antequam servas!",
        "tooltip-diff": "Comparabit hanc redactionem cum superiore earumque differentias notabit",
        "tooltip-compareselectedversions": "Inspicere, quatenus contenta redactionum selectarum inter se distent",
index ef6e3ba..bff977d 100644 (file)
@@ -53,6 +53,7 @@
        "tog-watchlisthidebots": "Ännerunge vu Botten op menger Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthideminor": "Kleng Ännerungen op menger Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthideliu": "Ännerunge vun ugemellte Benotzer verstoppen",
+       "tog-watchlistreloadautomatically": "D'Iwwerwaachungslëscht nei lueden esoubal wéi e Filter geännert ass (JavaScript gëtt gebraucht)",
        "tog-watchlisthideanons": "Ännerunge vun anonyme Benotzer (IP-Adressen) verstoppen",
        "tog-watchlisthidepatrolled": "Iwwerkuckten Ännerungen op der Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthidecategorization": "Kategorisatioun vu Säite verstoppen",
        "tagline": "Vu {{SITENAME}}",
        "help": "Hëllef",
        "search": "Sichen",
+       "search-ignored-headings": " #<!-- dës Zeil net änneren --> <pre>\n# Iwwerschrëften, déi vun der Sich ignoréiert ginn.\n# Dës Ännerunge gi wirksam, soubal déi Säit mat der Iwwerschrëft indexéiert gouf.\n# Dir kënnt déi Säitenindexéierung erzwéngen, andeem dir eng Nullännerung maacht.\n# Syntax:\n# * Alles, wat no enger Raut („#“) bis zum Ënn vun der Zeil steet, ass eng Bemierkung.\n# * All net-eidel Zeil ass de geneeën Titel fir z'ignoréieren.\nReferenzen\nWeblinken\nKuckt och\n #</pre> <!-- dës Zeil net änneren -->",
        "searchbutton": "Volltext-Sich",
        "go": "Lass",
        "searcharticle": "Säit",
        "mergehistory-fail-bad-timestamp": "Zäitstempel ass net valabel.",
        "mergehistory-fail-invalid-source": "Quellsäit ass net valabel.",
        "mergehistory-fail-invalid-dest": "Zilsäit ass net valabel.",
+       "mergehistory-fail-self-merge": "Quell an Zilsäit sinn déi selwecht.",
        "mergehistory-fail-toobig": "D'zesummeleeë vun der Lëscht vun de Versioune konnt net gemaach ginn well méi wéi d'Limite vun $1 {{PLURAL:$1|Versioun|Versioune}} geréckelt géife ginn",
        "mergehistory-no-source": "Originalsäit \"$1\" gëtt et net.",
        "mergehistory-no-destination": "Zilsäit \"$1\" gëtt et net.",
        "action-createpage": "dës Säit uleeën",
        "action-createtalk": "dës Diskussiounssäit uleeën",
        "action-createaccount": "dëse Benotzerkont unzeleeën",
+       "action-autocreateaccount": "automatesch dësen externe Benotzerkont opzemaachen",
        "action-history": "d'Versioune vun dëser Säit weisen",
        "action-minoredit": "dës Ännerung als kleng Ännerung ze markéieren",
        "action-move": "dës Säit ze réckelen",
        "action-viewmyprivateinfo": "Är privat Informatioune kucken",
        "action-editmyprivateinfo": "Är privat Informatiounen änneren",
        "action-editcontentmodel": "de Modell vum Inhalt vun enger Säit änneren",
+       "action-purge": "dës Säit eidelzemaachen",
        "nchanges": "$1 {{PLURAL:$1|Ännerung|Ännerungen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|zanter dem leschte Passage}}",
        "enhancedrc-history": "Versiounen",
index e22617c..bd20fa3 100644 (file)
        "viewcount": "'Sta paggina a l'è stæta vista {{PLURAL:$1|solo 'na vòtta|$1 vòtte}}.",
        "protectedpage": "Paggina protetta",
        "jumpto": "Vanni a:",
-       "jumptonavigation": "Navegaçión",
+       "jumptonavigation": "navegaçión",
        "jumptosearch": "çerca",
        "view-pool-error": "Scuza ma a-o momento i server sono stracarreghi.\nTroppi utenti çercan d' amiâ sta paggina.\nAspeta quarche menuto primma de çercâ torna d'accede a sta pagina.\n\n$1",
        "generic-pool-error": "Scuza ma a-o momento i server sono stracarreghi.\nTroppi utenti çercan d' amiâ sta risorsa.\nAspeta quarche menuto primma de çercâ torna d'accede a sta risorsa.",
        "userpage-userdoesnotexist": "L'utensa \"$1\" a no corisponde a un utente registròu.\nTi veu davei creâ o modificâ sta paggina?",
        "userpage-userdoesnotexist-view": "L'utensa \"$1\" a no l'è registrâ.",
        "blocked-notice-logextract": "St'utente o l'è attualmente bloccòu.\nL'urtimo elemento into registro di blocchi o l'è riportòu chì appreuvo pe informassion:",
-       "clearyourcache": "<strong>Notta:</strong> doppo avei salrvou, poriæ ese necessaio netezâ a cache do proppio browser pe vedde i cangiamenti. \n*<strong>Firefox / Safari:</strong> tegni sciacou o tasto de maiuscole <em>Shift</em> e clicca <em>Recarega</em>, oppû sciacca <em>Ctrl-F5</em> ò <em>Ctrl-R</em> (<em>⌘-R</em> su Mac)\n*<strong>Google Chrome:</strong> sciacca <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> insce un Mac)\n*<strong>Internet Explorer:</strong> tegni sciacou o tasto <em>Ctrl</em> e clicca <em>Aggiorna</em>, oppû sciacca <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Vanni into <em>Menu → Impostaçioin</em> (<em>Opera → Preferençe</em> insce 'n Mac) e dapoeu inte <em>Privacy & segueçça → Nettezza dæti do browser → Inmaggine e file inta cache</em>.",
+       "clearyourcache": "<strong>Notta:</strong> doppo avei sarvou, poriæ ese necessaio netezâ a cache do proppio browser pe vedde i cangiamenti. \n*<strong>Firefox / Safari:</strong> tegni sciacou o tasto de maiuscole <em>Shift</em> e clicca <em>Recarega</em>, oppû sciacca <em>Ctrl-F5</em> ò <em>Ctrl-R</em> (<em>⌘-R</em> su Mac)\n*<strong>Google Chrome:</strong> sciacca <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> insce un Mac)\n*<strong>Internet Explorer:</strong> tegni sciacou o tasto <em>Ctrl</em> e clicca <em>Aggiorna</em>, oppû sciacca <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Vanni into <em>Menu → Impostaçioin</em> (<em>Opera → Preferençe</em> insce 'n Mac) e dapoeu inte <em>Privacy & segueçça → Nettezza dæti do browser → Inmaggine e file inta cache</em>.",
        "usercssyoucanpreview": "'''Suggerimento:''' adeuvia o pomello 'Amia l'anteprimma' per provâ o to neuvo CSS primma de sarvâlo.",
        "userjsyoucanpreview": "'''Suggerimento:''' adeuvia o pomello 'Amia l'anteprimma' per provâ o to neuvo JavaScript primma de sarvâlo.",
        "usercsspreview": "'''Questa a l'è solo un'anteprimma do proppio CSS personâ. E modiffiche no son ancon stæte sarvæ!'''",
        "currentrevisionlink": "Ûrtima revixon",
        "cur": "cor",
        "next": "Proscimo",
-       "last": "Ûrtima",
+       "last": "prec",
        "page_first": "primma",
        "page_last": "ûrtima",
        "histlegend": "Confronto tra verscioîn: selession-a e cascette corispondenti a-e verscioîn dexidiæ e schissa Invio oppû o pomello da basso.\n\nLegenda: (corr) = differense co-a verscion corrente, (prec) = differense co-a verscion precedente, '''m''' = modiffica minô",
        "lineno": "Linia $1:",
        "compareselectedversions": "Confronta e verscioîn selessionæ",
        "showhideselectedversions": "Mostra/ascondi verscioin seleçionæ",
-       "editundo": "Anùlla",
+       "editundo": "anùlla",
        "diff-empty": "(Nisciun-a diferença)",
        "diff-multi-sameuser": "({{PLURAL:$1|Una verscion intermedia|$1 De verscioin intermedie}} de 'n mæximo utente {{PLURAL:$1|a no l'è mostrâ|no son mostræ}})",
        "diff-multi-otherusers": "({{PLURAL:$1|Una verscion intermedia|$1 De verscioin intermedie}} de {{PLURAL:$2|'n atro utente|$2 utenti}} {{PLURAL:$1|a no l'è mostrâ|no son mostræ}})",
        "next-page": "paggina succesciva",
        "prevn-title": "{{PLURAL:$1|rezoltato precedénte|rezoltati precedénti}}",
        "nextn-title": "{{PLURAL:$1|Risultou succescivo|$1 risultæ succescivi}}",
-       "shown-title": "Fanni védde {{PLURAL:$1|in rizoltato|$1 rizoltati}} pe pàgina",
+       "shown-title": "Fanni védde {{PLURAL:$1|un rizultou|$1 rizultæ}} pe pàgina",
        "viewprevnext": "Veddi ($1 {{int:pipe-separator}} $2) ($3).",
        "searchmenu-exists": "'''Inte questa wiki gh'è za 'na pàgina co-o nómme \"[[:$1]]\"'''",
        "searchmenu-new": "<strong>Crea a paggina \"[[:$1]]\" insce questo wiki!</strong> {{PLURAL:$2|0=|Amia ascì a paggina trovâ co-a teu riçerca|Amia ascì i risultæ da riçerca}}",
        "booksources-search-legend": "Çerca e fonti",
        "booksources-isbn": "Codice ISBN:",
        "booksources-search": "Çerca",
-       "booksources-text": "De sotta unn-a lista de inganci a di ätri sciti che vendan libbri neuvi e vegi e che porrieivan avei ciu informaçioin in scî libbri che ti te çerchi",
+       "booksources-text": "De sotta unn-a lista d'inganci a di ätri sciti che vendan libbri neuvi e vegi e che porrieivan avei ciu informaçioin in scî libbri che ti çerchi",
        "booksources-invalid-isbn": "O ISBN inserio pâ no ese vallido; controlla che no ghe segge stæto di ari into copiâlo da-a fonte originale.",
        "specialloguserlabel": "Açion effettuâ da:",
        "speciallogtitlelabel": "Açion effettuâ sciu (tittolo da paggina ò {{ns:user}}:Nomme utente):",
        "emailsend": "Spèdi",
        "emailccme": "Mandame unn-a copia do messagio co unn-a lettìa elettronega.",
        "emailccsubject": "Coppia do messaggio inviou a $1: $2",
-       "emailsent": "Lettìa elettronega spèdïa",
-       "emailsenttext": "A teu lettìa elettronega a l'è stæta spedïa.",
+       "emailsent": "E-mail spedïa",
+       "emailsenttext": "A teu e-mail a l'è stæta spedïa.",
        "emailuserfooter": "Questa email a l'è stæta {{GENDER:$1|inviâ}} da $1 a {{GENDER:$2|$2}} a traverso a fonçion \"{{int:emailuser}}\" insce {{SITENAME}}.",
        "usermessage-summary": "Messaggio de scistema",
        "usermessage-editor": "Messaggê de scistema",
        "tooltip-ca-edit": "Modiffica sta paggina.",
        "tooltip-ca-addsection": "Inça 'na seçión nêuva",
        "tooltip-ca-viewsource": "'Sta pagina a l'è protetta, ma ti peu védde o sêu còdice sorgente.",
-       "tooltip-ca-history": "Verscioìn précedenti da pàgina",
+       "tooltip-ca-history": "Verscioìn precedente da pàgina",
        "tooltip-ca-protect": "Protezi 'sta paggina",
        "tooltip-ca-unprotect": "Càngia a proteçión de sta paggina",
        "tooltip-ca-delete": "Scancella sta pàgina",
        "file-info": "dimenscion do file: $1, tipo MIME: $2",
        "file-info-size": "$1 × $2 pixel, dimenscioîn: $3, tippo MIME: $4",
        "file-info-size-pages": "$1 × $2 pixel, dimenscion do file: $3, tipo MIME: $4, $5 {{PLURAL:$5|paggina|paggine}}",
-       "file-nohires": "No ghe son verscioìn a rezoluçion ciù âta.",
+       "file-nohires": "Verscioìn co-a resoluçion ciù âta no ghe n'è.",
        "svg-long-desc": "file in formato SVG, dimenscioìn nominâli $1 × $2 pixel, dimenscioin do file: $3",
        "svg-long-desc-animated": "file in formato SVG animou, dimenscion nominale $1 × $2 pixel, dimenscion do file: $3",
        "svg-long-error": "File SVG non vallido: $1",
index 39466e0..041c73f 100644 (file)
@@ -7,7 +7,8 @@
                        "Mjbmr",
                        "Macofe",
                        "Huji",
-                       "Miladrahimi"
+                       "Miladrahimi",
+                       "Ebraminio"
                ]
        },
        "tog-underline": "کڕ(خط)کیشائن ژێر پیوندەل:",
        "tagline": "دۀربارۀ {{SITENAME}}",
        "help": "یاری کردن",
        "search": "مِنِی کِردِن(گێردین)",
+       "search-ignored-headings": "#<!-- این صفحه را درست همانطور که هست رها کنید --> <pre>\n#سر‌فصل‌هایی که توسط تحقیق نادیده گرفته خواهندشد.‌\n#به محض اینکه صفحه با سرفصل، فهرست شده‌است،تغییرات متاثر می‌شود.\n#شما می‌توانید با انجام یک ویرایش پوچ صفحه را وادار به دوباره فهرست کردن کنید.\n#نحو به شرح زیر است:\n#  *همه چیز از یک خصیصهٔ \"#\" گرفته تا آخر خط، یک نظر است\n#  *هر خط بدون فاصله، عنوان دقیق برای نادیده گرفتن،موضوع و همه چیز منابع است\nاتصالات خارجی\nهمچنین مشاهده کنید\n#</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "مِنِی کِردِن(گێردین)",
        "go": "بِچۆ",
        "searcharticle": "بِچۆ",
index 2933df5..319770c 100644 (file)
@@ -53,6 +53,7 @@
        "tog-watchdefault": "Pridėti puslapius, kuriuos aš redaguoju, į stebimų sąrašą",
        "tog-watchmoves": "Pridėti puslapius, kuriuos aš perkeliu, į stebimų sąrašą",
        "tog-watchdeletion": "Pridėti puslapius, kuriuos aš ištrinu, į stebimų sąrašą",
+       "tog-watchuploads": "Pridėti naujus failus, kurios aš įkeliu, į mano stebimųjų sąrašą",
        "tog-watchrollback": "Pridėti puslapius, kuriuose aš atlikau atmetimus į mano stebėjimo sąrašą",
        "tog-minordefault": "Pagal nutylėjimą pažymėti redagavimus kaip smulkius",
        "tog-previewontop": "Rodyti peržiūrą virš redagavimo lauko",
        "tagline": "Iš {{SITENAME}}.",
        "help": "Pagalba",
        "search": "Paieška",
+       "search-ignored-headings": " #<!-- palikite šią eilutę tiksliai tokią, kokia ji yra --> <pre>\n# Antraštės, kurios bus ignoruojamos paieškų.\n# Pakeitimai įsigalios iš karto, kai bus suindeksuota puslapio antraštė.\n# Galite priversti perindeksuoti puslapį atlikdami tuščią pakeitimą.\n# Sintaksė tokia:\n#   * Viskas nuo simbolio \"#\" iki eilutės pabaigos yra komentaras.\n#   * Kiekviena netuščia eilutė yra tikslus pavadinimas, kurį reikia ignoruoti, tipas ir visa kita.\nNuorodos\nIšorinės nuorodos\nTaip pat žr.\n #</pre> <!-- palikite šią eilutę tiksliai tokią, kokia ji yra -->",
        "searchbutton": "Paieška",
        "go": "Rodyti",
        "searcharticle": "Rodyti",
        "userlogin-resetpassword-link": "Pamiršote savo slaptažodį?",
        "userlogin-helplink2": "Padėti prisijungti",
        "userlogin-loggedin": "Jūs jau prisijungęs kaip {{GENDER:$1|$1}}.\nNaudokite žemiau pateiktą pavidalą, kad prisijungtumėte kaip kitas naudotojas.",
+       "userlogin-reauth": "Turite vėl prisijungti patvirtinimui, kad esate {{GENDER:$1|$1}}.",
        "userlogin-createanother": "Sukurti kitą paskyrą",
        "createacct-emailrequired": "Elektroninio pašto adresas",
        "createacct-emailoptional": "Elektroninio pašto adresas (neprivaloma)",
        "createacct-email-ph": "Įveskite savo elektroninio pašto adresą",
        "createacct-another-email-ph": "Įveskite elektroninio pašto adresą",
        "createaccountmail": "Naudokite laikiną atsitiktinį slaptažodį ir nusiųskite jį į elektroninį paštą, nurodytą žemiau.",
+       "createaccountmail-help": "Gali būti naudojamas paskyros sukūrimui kitam asmeniui, neatskleidžiant slaptažodžio.",
        "createacct-realname": "Vardas (neprivaloma)",
        "createaccountreason": "Priežastis:",
        "createacct-reason": "Priežastis",
        "createacct-reason-ph": "Kodėl kuriate kitą paskyrą",
+       "createacct-reason-help": "Pranešimas rodomas paskyros sukūrimo žurnale",
        "createacct-submit": "Sukurkite savo paskyrą",
        "createacct-another-submit": "Sukurti paskyrą",
        "createacct-continue-submit": "Tęsti paskyros kūrimą",
        "nocookiesnew": "Naudotojo paskyra buvo sukurta, bet jūs nesate prisijungęs. {{SITENAME}} naudoja slapukus, kad prijungtų naudotojus. Jūs esate išjungę slapukus. Prašome įjungti juos, tada prisijunkite su savo naujuoju naudotojo vardu ir slaptažodžiu.",
        "nocookieslogin": "{{SITENAME}} naudoja slapukus, kad prijungtų naudotojus. Jūs esate išjungę slapukus. Prašome įjungti juos ir pamėginkite vėl.",
        "nocookiesfornew": "Paskyra nebuvo sukurta, nes mums nepavyko nustatyti jos šaltinio.\nĮsitikinkite, kad įjungti slapukai (angl. cookies) ir tada bandykite dar kartą.",
+       "createacct-loginerror": "Paskyra buvo sėkmingai sukurta, bet nepavyko jūsų automatiškai prijungti. Prašome tęsti [[Special:UserLogin|prisijungiant rankiniu būdu]].",
        "noname": "Jūs nesate nurodęs teisingo naudotojo vardo.",
        "loginsuccesstitle": "Sėkmingai prisijungėte",
        "loginsuccess": "'''Dabar jūs prisijungęs prie {{SITENAME}} kaip „$1“.'''",
        "noemail": "Nėra jokio el. pašto adreso įvesto naudotojui „$1“.",
        "noemailcreate": "Jūs turite nurodyti veikiantį el. pašto adresą",
        "passwordsent": "Naujas slaptažodis buvo nusiųstas į el. pašto adresą,\nužregistruotą naudotojo „$1“.\nPrašome prisijungti vėl, kai jūs jį gausite.",
-       "blocked-mailpassword": "Jūsų IP adresas yra užblokuotas nuo redagavimo, taigi neleidžiama naudoti slaptažodžio priminimo funkcijos, kad apsisaugotume nuo piktnaudžiavimo.",
+       "blocked-mailpassword": "Jūsų IP adresas yra užblokuotas nuo redagavimo. Kad užkirstume kelią piktnaudžiavimui neleidžiama naudoti slaptažodžio priminimo funkcijos iš šio IP adreso.",
        "eauthentsent": "Patvirtinimo laiškas buvo nusiųstas į paskirtąjį el. pašto adresą.\nPrieš išsiunčiant kitą laišką į jūsų dėžutę, jūs turite vykdyti nurodymus laiške, kad patvirtintumėte, kad dėžutė tikrai yra jūsų.",
        "throttled-mailpassword": "Slaptažodžio priminimas jau buvo išsiųstas, per {{PLURAL:$1|$1 paskutinę valandą|$1 paskutines valandas|$1 paskutinių valandų}}.\n\nNorint apsisaugoti nuo piktnaudžiavimo, slaptažodžio priminimas gali būti išsiųstas tik kas {{PLURAL:$1|$1 valandą|$1 valandas|$1 valandų}}.",
        "mailerror": "Klaida siunčiant laišką: $1",
        "createaccount-title": "{{SITENAME}} paskyros kūrimas",
        "createaccount-text": "Projekte {{SITENAME}} ($4) kažkas sukūrė paskyrą „$2“ su slaptažodžiu „$3“ panaudodamas jūsų el. pašto adresą.\nJūs turėtumėte prisijungti ir pasikeisti savo slaptažodį.\n\nJūs galite nekreipti dėmesio į laišką, jei ši paskyra buvo sukurta per klaidą.",
        "login-throttled": "Jūs pernelyg daug kartų bandėte prisijungti.\nPalaukite $1 prieš bandant vėl.",
-       "login-abort-generic": "Jūsų prisijungimas buvo nesėkmingas - Nutraukta",
+       "login-abort-generic": "Jūsų prisijungimas nepavyko - Nutraukta",
        "login-migrated-generic": "Jūsų paskyra buvo perkelta ir jūsų naudotojo vardo šioje wiki daugiau nebėra.",
        "loginlanguagelabel": "Kalba: $1",
        "suspicious-userlogout": "Jūsų prašymas atsijungti buvo atmestas, nes, atrodo, jį klaidingai išsiuntė naršyklė arba spartinantysis tarpinis serveris.",
        "resetpass-no-info": "Jūs turite būti prisijungęs, kad pasiektumėte puslapį tiesiogiai.",
        "resetpass-submit-loggedin": "Keisti slaptažodį",
        "resetpass-submit-cancel": "Atšaukti",
-       "resetpass-wrong-oldpass": "Klaidingas laikinas ar esamas slaptažodis.\nJūs galbūt jau sėkmingai pakeitėte savo slaptažodį ar gavote naują laikiną slaptažodį.",
+       "resetpass-wrong-oldpass": "Klaidingas laikinas ar esamas slaptažodis.\nJūs galbūt jau sėkmingai pakeitėte savo slaptažodį ar jau prašėte naujo laikino slaptažodžio.",
        "resetpass-recycled": "Atkurkite savo slaptažodį kitokiu, nei buvo prieš tai.",
        "resetpass-temp-emailed": "Jūs prisijungęs laikinu slaptažodžiu, gautu per elektroninį paštą. Kad baigtumėte jungtis, čia turite nustatyti naują slaptažodį:",
        "resetpass-temp-password": "Laikinas slaptažodis:",
        "passwordreset-emailsentusername": "Jeigu buvo el. paštas susietas su šiuo naudotojo vardu, tai slaptažodžio atkūrimo el. laiškas bus išsiųstas.",
        "passwordreset-emailsent-capture": "Slaptažodžio priminimo laiškas bus išsiųstas, toks koks parodytas.",
        "passwordreset-emailerror-capture": "Priminimo elektroninis laiškas buvo sukurtas, toks, koks parodytas žemiau, bet pasiuntimas naudotojui buvo nesėkmingas: $1",
+       "passwordreset-emailsent-capture2": "Slaptažodžio keitimo {{PLURAL:$1|el. laiškas buvo išsiųstas|el. laiškai buvo išsiųsti}}. {{PLURAL:$1|vartotojo vardas ir slaptažodis rodomi|vartotojų vardų ir slaptažodžių sąrašas rodomas}} žemiau.",
+       "passwordreset-emailerror-capture2": "El. laiško siuntimas {{GENDER:$2|vartotojui}} nepavyko: $1 {{PLURAL:$3|vartotojo vardas ir slaptažodis rodomi|vartotojų vardų ir slaptažodžių sąrašas rodomas}} žemiau.",
+       "passwordreset-nocaller": "Skambinantysis turi būti nurodytas",
+       "passwordreset-nosuchcaller": "Skambinantysis neegzistuoja: $1",
        "passwordreset-invalideamil": "Neteisingas el. pašto adresas",
        "passwordreset-nodata": "Vartotojo vardas ir el. paštas buvo nepateikti",
        "changeemail": "Pakeisti ar pašalinti el. pašto adresą",
        "log-edit-tags": "Redaguoti žymes pasirinktuose žurnalo įrašuose",
        "checkbox-select": "Pasirinkti: $1",
        "checkbox-all": "Visi",
-       "checkbox-none": "Nieko",
-       "checkbox-invert": "Invertuoti",
+       "checkbox-none": "Nieka",
+       "checkbox-invert": "Apmainītė vėituom",
        "allpages": "Visi puslapiai",
        "nextpage": "Kitas puslapis ($1)",
        "prevpage": "Ankstesnis puslapis ($1)",
        "authprovider-confirmlink-ok-help": "Tęsti po susiejimo klaidos žinutės parodymo.",
        "authprovider-resetpass-skip-label": "Praleisti",
        "authprovider-resetpass-skip-help": "Praleisti slaptažodžio perstatymą.",
-       "specialpage-securitylevel-not-allowed-title": "Neleidžiama"
+       "specialpage-securitylevel-not-allowed-title": "Neleidžiama",
+       "cannotauth-not-allowed-title": "Teisė nesuteikta",
+       "cannotauth-not-allowed": "Jūs negalite naudotis šiuo puslapiu",
+       "linkaccounts": "Susieti paskyras",
+       "linkaccounts-success-text": "Paskyra buvo susieta.",
+       "linkaccounts-submit": "Susieti paskyras",
+       "unlinkaccounts": "Atsieti paskyras",
+       "unlinkaccounts-success": "Paskyra buvo atsieta."
 }
index e5d9c93..b20432e 100644 (file)
        "tagline": "No ''{{grammar:ģenitīvs|{{SITENAME}}}}''",
        "help": "Palīdzība",
        "search": "Meklēt",
+       "search-ignored-headings": " #<!-- atstāt šo rindiņu tādu, kāda tā ir --> <pre>\n#Virsraksti, kas tiks ignorēti meklējot.\n#Izmaiņas stāsies spēkā, kad lapa ar virsrakstiem ir indeksēta.\n#Jūs varat piespiest lapai tikt indeksētai vēlreiz ar nulles labojumu.\n#Sintakse:\n# * Jebkas no \"#\" zīmes līdz rindiņas beigām ir komentārs.\n# * Katra līnija ir precīzs ignorējamais virsraksts, ieskaitot lielos / mazos burtus.\nAtsauces\nĀrējās saites\nSkatīt arī\n #</pre> <!-- atstāt šo rindiņu tādu, kāda tā ir -->",
        "searchbutton": "Meklēt",
        "go": "Aiziet!",
        "searcharticle": "Aiziet!",
index f7332f9..29737f4 100644 (file)
@@ -22,7 +22,8 @@
                        "सरोज कुमार ढकाल",
                        "Bijay chaurasia",
                        "Tulsi Bhagat",
-                       "Macofe"
+                       "Macofe",
+                       "राम प्रसाद जोशी"
                ]
        },
        "tog-underline": "लिङ्कके रेखाङ्कित करी:",
        "sqlite-has-fts": "$1 पूर्ण-पाठ खोज सहायता युक्त",
        "sqlite-no-fts": "$1 बिन पूर्ण-पाठ खोज सहायताक",
        "logentry-delete-delete": "$1 पृष्ठ $3 {{GENDER:$2|मेटौलक}}",
-       "logentry-delete-restore": "$1 {{लिंग:$2|restored}} page $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|restored}} page $3",
        "logentry-delete-event": "$1 {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा वृत्तलेख|$5 वृत्तलेख}}  $3: $4 केँ",
        "logentry-delete-revision": "$1 {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा संशोधन|$5 संशोधन}}  पन्ना $3: $4 पर",
-       "logentry-delete-event-legacy": "$1 {{लिंग:$2|changed}}  $3 पर वृत्तलेख दृश्य",
-       "logentry-delete-revision-legacy": "$1 {{लिंग:$2|changed}}  $3 पर वृत्तलेख संशोधन",
+       "logentry-delete-event-legacy": "$1 {{GENDER:$2|changed}}  $3 पर वृत्तलेख दृश्य",
+       "logentry-delete-revision-legacy": "$1 {{GENDER:$2|changed}}  $3 पर वृत्तलेख संशोधन",
        "logentry-suppress-delete": "$1 {{लिंग:$2|दबाएल}} page $3",
        "logentry-suppress-event": "$1 चोरिसँ {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा वृत्तलेख|$5 वृत्तलेख}}  $3: $4 पर",
        "logentry-suppress-revision": "$1 चोरिसँ {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा संशोधन|$5 संशोधन}}  $3: $4 पर",
-       "logentry-suppress-event-legacy": "$1 नुका कऽ {{लिंग:$2|changed}}  $3 पर वृत्तलेख दृश्य",
-       "logentry-suppress-revision-legacy": "$1 नुका कऽ {{लिंग:$2|changed}}  $3 पर संशोधन दृश्य",
+       "logentry-suppress-event-legacy": "$1 नुका क {{GENDER:$2|परिवर्तन}}  $3 पर वृत्तलेख दृश्य",
+       "logentry-suppress-revision-legacy": "$1 नुका कऽ {{GENDER:$2|changed}}  $3 पर संशोधन दृश्य",
        "revdelete-content-hid": "सामिग्री नुकाएल",
        "revdelete-summary-hid": "नुकाएल सारांश सम्पादन",
        "revdelete-uname-hid": "प्रयोक्तानाम नुकाएल",
        "logentry-import-interwiki": "$1 {{GENDER:$2|आयात केल गेल}} $3 कोनो और विकि सँ",
        "logentry-merge-merge": "$1 {{GENDER:$2|विलय केल गेल}} $3 के $4 में (संशोधन $5 धरि)",
        "logentry-move-move": "$1 हटाएल पन्ना $3 सँ $4",
-       "logentry-move-move-noredirect": "$1 {{लिंग:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआकेँ बिना छोड़ने",
-       "logentry-move-move_redir": "$1 {{लिंग:$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 {{लिंग:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआक अतितिक्त घुमौआकेँ बिना छोड़ने",
        "logentry-patrol-patrol": "$1 {{GENDER:$2|चिन्हित}} संशोधन $4 $3 पन्नाक निरीक्षित",
        "logentry-patrol-patrol-auto": "$1 स्वतः {{GENDER:$2|चिन्हित}} संशोधन $4 $3 पन्नाक निरीक्षित",
-       "logentry-newusers-newusers": "$1 {{लिंग:$2|बनाएल}} एकटा प्रयोक्ता खाता",
+       "logentry-newusers-newusers": "$1 {{GENDER:$2|बनाएल}} एकटा प्रयोक्ता खाता",
        "logentry-newusers-create": "प्रयोगकर्ता खाता $1 {{GENDER:$2|बनाएल}} गेल",
-       "logentry-newusers-create2": "$1 {{लिंग:$2|बनाएल}} {{लिंग:$4|एकटा प्रयोक्ता खाता}} $3",
+       "logentry-newusers-create2": "$1 {{GENDER:$2|बनाएल}} {{GENDER:$4|एकटा प्रयोक्ता खाता}} $3",
        "logentry-newusers-byemail": "$1 द्वारा प्रयोक्ता खाता $3 {{GENDER:$2|बनाओल}} गेल आ कूटशब्द ई-पत्र द्वारा भेजल गेल",
-       "logentry-newusers-autocreate": "खाता $1 छल {{लिंग:$2|बनाएल}} स्वतः",
+       "logentry-newusers-autocreate": "खाता $1 छल {{GENDER:$2|बनाएल}} स्वतः",
        "logentry-upload-upload": "$1 {{GENDER:$2|ए}} $3 अपलोड केलक",
        "log-name-tag": "ट्याग लग",
        "rightsnone": "(कोनो नै)",
index f0f3e1e..087ea59 100644 (file)
        "tagline": "Од {{SITENAME}}",
        "help": "Помош",
        "search": "Пребарај",
+       "search-ignored-headings": " #<!-- не менувајте ништо во овој ред --> <pre>\n# Заглавија што ќе се занемарат при пребарувањето.\n# Измените во ова ќе стапат на сила штом ќе се индексира страницата со заглавието.\n# Можете да наметнете преиндексирање на страницата ако извршите празно уредување.\n# Синтаксата е следнава:\n#   * Сето она што од знакот „#“ до крајот на редот е коментар\n#   * Секој непразен ред е точниот наслов што треба да се занемари, разликувајќи големи од мали букви и сето останато\nНаводи\nНадворешни врски\nПоврзано\n #</pre> <!-- не менувајте ништо во овој ред -->",
        "searchbutton": "Пребарај",
        "go": "Дај",
        "searcharticle": "Дај",
        "savearticle": "Зачувај",
        "savechanges": "Зачувај промени",
        "publishpage": "Објави ја страницата",
-       "publishchanges": "Ð\9eбÑ\98ави Ð¿Ñ\80омени",
+       "publishchanges": "Ð\9eбÑ\98ави Ð³Ð¸ Ð¿Ñ\80омениÑ\82е",
        "preview": "Преглед",
        "showpreview": "Преглед",
        "showdiff": "Прикажи промени",
        "prefs-skin": "Руво",
        "skin-preview": "Преглед",
        "datedefault": "Небитно",
-       "prefs-labs": "Ð\95кÑ\81пеÑ\80именÑ\82ални можности",
+       "prefs-labs": "Ð\9fÑ\80обни можности",
        "prefs-user-pages": "Кориснички страници",
        "prefs-personal": "Кориснички профил",
        "prefs-rc": "Скорешни промени",
        "action-applychangetags": "ставање на ознаки заедно со напревените промени",
        "action-changetags": "додавање и отстранување на произволни ознаки во поединечни преработки и дневнички записи",
        "action-deletechangetags": "бришење ознаки од базата",
+       "action-purge": "превчитување на оваа страница",
        "nchanges": "$1 {{PLURAL:$1|промена|промени}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|од последната посаета}}",
        "enhancedrc-history": "историја",
        "watchnologin": "Не сте најавени",
        "addwatch": "Додај во набљудувани",
        "addedwatchtext": "„[[:$1]]“ и нејзината страница за разговор се додадени во вашите [[Special:Watchlist|набљудувања]].",
+       "addedwatchtext-talk": "„[[:$1]]“ и нејзината поврзана страница се додадени во вашите [[Special:Watchlist|набљудувања]].",
        "addedwatchtext-short": "Страницата „$1“ е додадена во вашите набљудувања.",
        "removewatch": "Отстрани набљудуваните",
        "removedwatchtext": "„[[:$1]]“ и нејзината страница за разговор се отстранети од вашите [[Special:Watchlist|набљудувања]].",
+       "removedwatchtext-talk": "„[[:$1]]“ и нејзината поврзана страница се отстранети од вашите [[Special:Watchlist|набљудувања]].",
        "removedwatchtext-short": "Страницата „$1“ е отстранета од вашите набљудувања.",
        "watch": "Набљудувај",
        "watchthispage": "Набљудувај ја страницава",
index 5d9c024..793c5ab 100644 (file)
        "tagline": "{{SITENAME}} സംരംഭത്തിൽ നിന്ന്",
        "help": "സഹായം",
        "search": "തിരയൂ",
+       "search-ignored-headings": " #<!-- ഈ വരി ഇതേ പോലെ വിടുക --> <pre>\n# തിരച്ചിലിൽ അവഗണിക്കപ്പെടുന്ന തലക്കെട്ടുകൾ.\n# താളിന്റെ തലക്കെട്ടുകളുടെ സൂചികവത്കരണം നടന്നാലുടൻ ഇവിടെ വരുത്തുന്ന മാറ്റങ്ങൾ ഫലത്തിൽ വരുന്നതാണ്.\n# ശൂന്യമായ തിരുത്ത് ചെയ്ത് താൾ വീണ്ടും സൂചികാവത്കരിക്കാവുന്നതാണ്.\n# എഴുത്തുരീതി ഇനി കൊടുക്കുന്നു:\n#   * \"#\" അക്ഷരത്തിൽ തുടങ്ങി വരിയുടെ അവസാനം വരെയുള്ള എന്തും സൂചനാക്കുറിപ്പ് ആയിരിക്കും.\n#   * ശൂന്യമല്ലാത്ത ഓരോ വരിയും അക്ഷരവ്യത്യാസമില്ലാതെ അവഗണിക്കപ്പെടാനുള്ള തലക്കെട്ടായിരിക്കും\nഅവലംബം\nപുറത്തേക്കുള്ള കണ്ണികൾ\nഇതും കാണുക\n #</pre> <!-- ഈ വരി ഇതേ പോലെ വിടുക-->",
        "searchbutton": "തിരയൂ",
        "go": "പോകൂ",
        "searcharticle": "പോകൂ",
        "mw-widgets-dateinput-no-date": "തീയതി ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല",
        "mw-widgets-titleinput-description-new-page": "താൾ ഇപ്പോൾ നിലവിലില്ല",
        "mw-widgets-titleinput-description-redirect": "$1 എന്ന താളിലേക്കുള്ള തിരിച്ചുവിടൽ",
-       "api-error-blacklisted": "ദയവായി മറ്റൊരു വിവരണാത്മകമായ തലക്കെട്ട് തിരഞ്ഞെടുക്കുക.",
        "sessionmanager-tie": "വ്യത്യസ്ത തരത്തിലുള്ള അനുമതി നൽകൽ തരങ്ങൾ സംയോജിപ്പിക്കാനാവില്ല: $1.",
        "sessionprovider-generic": "$1 സെഷനുകൾ",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "കൂക്കി-അധിഷ്ഠിത സെഷനുകൾ",
index 59b50c3..ebb6a50 100644 (file)
@@ -67,6 +67,7 @@
        "tog-watchdefault": "मी संपादित केलेली पाने आणि संचिका माझ्या निरीक्षणसूचीत टाका",
        "tog-watchmoves": "मी स्थानांतर केलेली पाने आणि संचिका माझ्या निरीक्षणसूचीत टाका",
        "tog-watchdeletion": "मी वगळलेली पाने आणि संचिका माझ्या निरीक्षणसूचीत टाका",
+       "tog-watchuploads": "मी अपभारीलेल्या नविन संचिका माझ्या निरीक्षणसूचीत जोडा",
        "tog-watchrollback": "यात ज्या पानात मी माझ्या निरीक्षणसूचीत पुनर्परतीची (रोलबॅक) क्रिया केलेली आहे.",
        "tog-minordefault": "सर्व संपादने 'छोटा बदल' म्हणून आपोआप जतन करा.",
        "tog-previewontop": "झलक संपादन खिडकीच्या आधी दाखवा",
index f68b227..7f02a6c 100644 (file)
        "tagline": "Daripada {{SITENAME}}.",
        "help": "Bantuan",
        "search": "Cari",
+       "search-ignored-headings": " #<!-- jangan usik baris ini --> <pre>\n# Tajuk yang akan diabaikan oleh pencarian.\n# Suntingannya diperlakukan sebaik sahaja laman yang bertajuk ini diindekskan.\n# Anda boleh memaksakan pengindeksan semula laman dengan melakukan suntingan nol (null edit).\n# Sintaks adalah seperti berikut:\n#   * Semuanya dari aksara \"#\" ke hujung baris dikira komen.\n#   * Setiap baris tak kosong adalah tajuk yang setepatnya untuk diabaikan.\nRujukan\nPautan luar\nLihat juga\n #</pre> <!-- jangan usik baris ini -->",
        "searchbutton": "Cari",
        "go": "Pergi",
        "searcharticle": "Pergi",
index cb59019..591bdec 100644 (file)
        "thursday": "Īcmācuīlilhuitl",
        "friday": "Īcchicuacemilhuitl",
        "saturday": "Īcchicōmilhuitl",
-       "sun": "ilhui",
-       "mon": "ilhui",
-       "tue": "ilhui",
-       "wed": "ilhui",
-       "thu": "ilhui",
+       "sun": "Cemilhui",
+       "mon": "Ōmilhui",
+       "tue": "Ēyilhui",
+       "wed": "Nāuhilhui",
+       "thu": "Mācuililhui",
        "fri": "6 ilhui",
        "sat": "7 ilhui",
-       "january": "Īccēmētztli",
-       "february": "Īcōmēmētztli",
-       "march": "Īcyēyimētztli",
-       "april": "Īcnāuhtetlmētztli",
-       "may_long": "Īcmācuīllimētztli",
-       "june": "Īcchicuacemmētztli",
-       "july": "Īcchicōmemētztli",
-       "august": "Īcchicuēyimētztli",
-       "september": "Īcchiucnāhuimētztli",
-       "october": "Īcmahtlāctlimētztli",
-       "november": "Īcmahtlāctlioncēmētztli",
-       "december": "Īcmahtlāctliomōmemētztli",
-       "january-gen": "Īccēmētztli",
+       "january": "Ic cē mētztli",
+       "february": "Ic ōmemētztli",
+       "march": "Ic ēyi mētztli",
+       "april": "Ic nāuhtetl mētztli",
+       "may_long": "Ic mācuīlli mētztli",
+       "june": "Ic chicuacē mētztli",
+       "july": "Ic chicōme mētztli",
+       "august": "Ic chicuēyi mētztli",
+       "september": "Ic chiucnāhui mētztli",
+       "october": "Ic mahtlāctli mētztli",
+       "november": "Ic mahtlāctli oncē mētztli",
+       "december": "Ic mahtlāctli omōme mētztli",
+       "january-gen": "Ic cē mētztli",
        "february-gen": "Īcōmemētztli",
        "march-gen": "Īcyēyimētztli",
-       "april-gen": "Īcnāuhtetlmētztli",
+       "april-gen": "Ic nāuhtetl mētztli",
        "may-gen": "Īcmācuīllimētztli",
-       "june-gen": "Īcchicuacemmētztli",
-       "july-gen": "Īcchicōmemētztli",
+       "june-gen": "Ic chicuacemmētztli",
+       "july-gen": "Ic chicōme mētztli",
        "august-gen": "Īcchicuēyimētztli",
        "september-gen": "Īcchiucnāhuimētztli",
        "october-gen": "Īcmahtlāctetlmētztli",
        "november-gen": "Īcmahtlāctetloncēmētztli",
        "december-gen": "Īcmahtlāctetlomōmemētztli",
-       "jan": "1 Mētz",
-       "feb": "2 Mētz",
-       "mar": "3 Mētz",
-       "apr": "4 Mētz",
-       "may": "5 Mētz",
-       "jun": "6 Mētz",
-       "jul": "7 Mētz",
-       "aug": "8 Mētz",
-       "sep": "9 Mētz",
-       "oct": "10 Mētz",
-       "nov": "11 Mētz",
-       "dec": "12 Mētz",
+       "jan": "Ic cē",
+       "feb": "Ic ōme",
+       "mar": "Ic ēyi",
+       "apr": "Nāhui",
+       "may": "Mācuilli",
+       "jun": "Chicuacē",
+       "jul": "Chicōme",
+       "aug": "Chicuēyi",
+       "sep": "Chiucnāhui",
+       "oct": "Mahtlāctli",
+       "nov": "Mahtlāctlioncē",
+       "dec": "Mahtlāctliomōme",
        "january-date": "Īccēmētztli $1",
        "february-date": "Īcōmemētztli $1",
        "march-date": "Īquēyimētztli $1",
        "moredotdotdot": "Huehca ōmpa...",
        "mypage": "Noāmauh",
        "mytalk": "Nozānīl",
-       "anontalk": "Inīn IP ītēixnāmiquiliz",
+       "anontalk": "Tēixnāmiquiliztli",
        "navigation": "Nēnemōhualiztli",
        "and": "&#32;īhuān",
        "qbfind": "Xicahci",
        "tagline": "Īhuīcpa {{SITENAME}}",
        "help": "Tēpalēhuiliztli",
        "search": "Mà motèmo",
-       "searchbutton": "Xictēmo",
+       "searchbutton": "Tictēmōz",
        "go": "Xiyauh",
        "searcharticle": "Xiyauh",
        "history": "Tlaīxtli ītlahtōllo",
        "viewsource": "Xiquitta mēyalli",
        "viewsource-title": "Xiquitta in $1 īmēyal",
        "actionthrottled": "Tlachīhualiztli ōmotzacuili",
-       "viewsourcetext": "Tihuelīti tiquitta auh ticcopīna inīn zāzanilli ītlahtōlcaquiliztilōni:",
+       "viewsourcetext": "Tihuelīti tiquittaz auh ticcopīnaz inīn zāzanilli īmachiyōnecaquilizmēyal.",
        "namespaceprotected": "Ahmo tiquihuelīti tiquimpatla zāzaniltin īpan '''$1'''.",
        "ns-specialprotected": "In nònkuâkìskàtlaìxtlapaltìn awel ìmpan nemàtilòs mokinyèktlàlis.",
        "titleprotected": "Inīn zāzanilli ōmoquīxti ic tlachīhualiztli ic [[User:$1|$1]].\nŌquihto: <em>$2</em>",
        "userexists": "In tlatequitiltilīltōcāitl in ōquipehpen ye ia.\nTimitztlātlauhtiah xicpehpena occē.",
        "loginerror": "Ahcuallōtl tlacalaquiliztechcopa",
        "noname": "Ahmo ōtiquihto cualli tlatequitiltilīlli tōcāitl.",
-       "loginsuccesstitle": "Cualli calaquiliztli",
+       "loginsuccesstitle": "Ōticalac",
        "loginsuccess": "'''Ōticalac {{SITENAME}} quemeh \"$1\".'''",
-       "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitia \"$1\".\nIn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta in yēquihcuilōlli, ahnozo [[Special:CreateAccount|xicchīhua yancuīc cuenta]].",
+       "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitīlo «$1».\nn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta moyēquihcuilōl, ahnozo [[Special:CreateAccount|xicchīhua yancuīc cuentah]].",
        "nosuchusershort": "Ayāc tlatequitiltilīlli motōcāitia \"$1\". Xiquitta in tlein ōtitlahcuiloh melāhuacā cah.\nXiquitta moyēquihcuilōl.",
        "nouserspecified": "Mohuīquilia tiquihtoa cualli tlatequitiltilīltōcāitl.",
        "wrongpassword": "Ahcualli motlahtōlichtacāyo.\nTimitztlātlauhtia xicchīhua occeppa.",
        "newpassword": "Yancuīc motlahtōlichtacayo:",
        "retypenew": "Occeppa xiquihcuiloa yancuīc motlahtōlichtacayo:",
        "resetpass_submit": "Xicpatlāz motlahtōlichtacāyo auh xicalaquīz",
-       "changepassword-success": "Mochtacātlahtōl cualli ōtlapatlalo.",
+       "changepassword-success": "Moichtacātlahtōl ōmopatlac.",
        "resetpass_forbidden": "Tlahtōlichtacayōtl ahmo mohuelītih mopatlah",
        "resetpass-submit-loggedin": "Ticpatlāz motlahtōlichtacāyo",
        "resetpass-submit-cancel": "Xiccāhua",
        "sig_tip": "Motōcā īca cāhuitl",
        "hr_tip": "Pāntli",
        "summary": "Mopatlaliz:",
-       "subject": "Tōcāitl/Āmoxmachiyōtl:",
+       "subject": "Ītechpa:",
        "minoredit": "Ca tepitōn inīn tlapatlaliztli",
        "watchthis": "Xicpiya inīn tlaīxtli",
        "savearticle": "Xicpiya tlaīxtli",
        "accmailtext": "Ōquiyōcox zāzochtacātlahtōlli in [[User talk:$1|$1]] auh ōmoquitītlan īhuīc $2. Tihueliti ticpatlaz īpan ''[[Special:ChangePassword|Ticpatlaz in ]]'' in ōticalaco achtopa.",
        "newarticle": "(Yancuic)",
        "newarticletext": "Ōtictocac cētiliztli cē zāzanilhuīc oc ahmo ia. Intlā quiēlēhuia quichīhua, xitlahcuiloa niman (nō xiquitta [$1 tēpalēhuiliztli zāzanilli] huehca ōmpa tlapatlaliztli). Intlā ahmo, yāuh achtopa zāzanilli.",
-       "noarticletext": "In āxcān, ahmō onca tlahcuilōlli inīn zāzanilpan.\nTihuelīti [[Special:Search/{{PAGENAME}}|tictēmoa inīn zāzaniltōcācopa]] occequīntīn zāzanilpan,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} machiyōmacalpan], ahnozo [{{fullurl:{{FULLPAGENAME}}|action=edit}} ticpatla inīn zāzanilli]</span>.",
+       "noarticletext": "In āxcān, ahmō onca tlahcuilōlli inīn zāzanilpan.\nTihuelīti [[Special:Search/{{PAGENAME}}|tictēmōz inīn zāzanilli ītōca]] occequīntīn zāzanilpan,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} xictēmoa īpan in tlapōhualāmatechpa],\nahnozo [{{fullurl:{{FULLPAGENAME}}|action=edit}} xichīhua inīn zāzanilli]</span>.",
        "userpage-userdoesnotexist": "Ahmo ia cuentah \"<nowiki>$1</nowiki>\" ītōca. Timitztlātlauhtiah xitēchquinōtza intlā ticchīhuāz intlā nozo ticpatlāz inīn zāzanilli.",
        "usercsspreview": "'''Ca inīn moachtochīhualiz ītechcopa moCSS.'''\n'''¡Ahmo ōmochīuh nozan!'''",
        "userjspreview": "'''Ca inīn moachtochīhualiz ītechcopa moJavaScript.'''\n'''¡Ahmo ōmochīuh nozan!'''",
        "currentrev": "Āxcān tlapatlaliztli",
        "currentrev-asof": "Āxcān tlachiyaliztli īpan $1",
        "revisionasof": "Tlachiyaliztli īpan $1",
-       "revision-info": "Tlachiyaliztli īpan $1; $2",
+       "revision-info": "Tlachiyaliztli īpan $1 īpal {{GENDER:$6|$2}}$7",
        "previousrevision": "← Huēhueh tlapatlaliztli",
        "nextrevision": "Yancuīc tlapatlaliztli →",
        "currentrevisionlink": "Āxcān tlapatlaliztli",
        "shown-title": "Quinēxiltīz $1 {{PLURAL:$1|mochīhualiztli}} cece āmac",
        "viewprevnext": "Xiquintta ($1 {{int:pipe-separator}} $2) ($3).",
        "searchmenu-exists": "'''Ye ia zāzanilli ītōca \"[[$1]]\" inīn huiquipan'''",
-       "searchmenu-new": "'''Tihuelīti ticchīhuāz zāzanilli ītōca \"[[:$1]]\" inīn huiquipan'''",
+       "searchmenu-new": "<strong>Ticchīhuāz in zāzanilli «[[:$1]]» inīn huiquipan.</strong> {{PLURAL:$2|0=|Nō xiquitta in tlanāmiquiliztli in mochīhualiztli.}}",
        "searchprofile-articles": "Tlapiyaliztli zāzanilli",
        "searchprofile-images": "Nepapan media",
        "searchprofile-everything": "Mochi",
        "gender-male": "Oquichtli",
        "gender-female": "Cihuātl",
        "email": "E-mail",
-       "prefs-help-realname": "Melāhuac motōca.\nIntlā ticnequi, tlācah quimatīzqueh motequi.",
+       "prefs-help-realname": "In melāhuac tōcāitl mopehpenaliztli.\nIntlā ticmaca, momitztlaīxcoyantīz in motequi.",
        "prefs-help-email-required": "Tihuīquilia quihcuiloa mo e-mailcān.",
        "prefs-signature": "Motōcā",
        "userrights-user-editname": "Xihcuiloa cē tlatequitiltilīltōcāitl:",
-       "editusergroup": "Tiquimpatlāz tlatequitiltilīlli olōlli",
+       "editusergroup": "Tiquimpatlāz {{GENDER:$1|tlatequitiltilīlli}} īolōl",
        "userrights-editusergroup": "Tiquimpatlāz tlatequitiltilīlli olōlli",
-       "saveusergroups": "Tiquimpiyāz tlatequitiltilīlli olōlli",
+       "saveusergroups": "Tiquimpiyāz {{GENDER:$1|tlatequitiltilīlli}} īolōl",
        "userrights-groupsmember": "Olōlco:",
        "userrights-reason": "Īxtlamatiliztli:",
        "userrights-no-interwiki": "Ahmo tihuelīti ticpatla tlatequitiltilīlli huelītiliztli occequīntīn huiquipan.",
        "rightslog": "Tlatequitiltilīlli huelītiliztli tlahcuilōlloh",
        "action-read": "xāmapōhua inīn tlaīxtli",
        "action-edit": "xicpatla inīn tlaīxtli",
-       "action-createpage": "xicchīhua tlaīxtli",
-       "action-createtalk": "tiquinchīhuāz tēixnāmiquiliztli zāzaniltin",
+       "action-createpage": "xicchīhua inīn āmatl",
+       "action-createtalk": "xicchīhuā inīn tēixnāmiquiliztli zāzaniltin",
        "action-createaccount": "ticchīhuaz inīn tlatequitiltilīlli īcuentah",
        "action-move": "ticpatlāz inīn zāzanilli",
        "action-move-subpages": "tiquimpatlāz inīn zāzanilli īhuān zāzaniltōn",
        "newpageletter": "Y",
        "boteditletter": "T",
        "number_of_watching_users_pageview": "[$1 tlatequitiltilīlli {{PLURAL:$1|tlachiya|tlachiyah}}]",
-       "rc_categories_any": "Zāzo",
+       "rc_categories_any": "Zāzo in tlaihittalli",
        "newsectionsummary": "Yancuīc tlahtōltzintli: /* $1 */",
        "recentchangeslinked": "Tlapatlaliztli tzonhuilizpan",
        "recentchangeslinked-feed": "Tlapatlaliztli tzonhuilizpan",
        "whatlinkshere-next": "{{PLURAL:$1|niman|$1 niman}}",
        "whatlinkshere-links": "← tzòwilistìn",
        "whatlinkshere-hideredirs": "$1 tlacuepaliztli",
-       "whatlinkshere-hidelinks": "$1 tzòwilistìn",
+       "whatlinkshere-hidelinks": "$1 tzonhuiliztli",
        "whatlinkshere-hideimages": "$1 tlahcuilōltzonhuīliztli",
        "whatlinkshere-filters": "Tlatzetzelōni",
        "blockip": "Tiquitzacuilīz tlatequitiltilīlli",
        "importbadinterwiki": "Ahcualli interhuiqui tzonhuiliztli",
        "import-upload": "Tiquinquetzāz XML tlahcuilōlli",
        "importlogpage": "Tiquincōhuāz tlahcuilōlloh",
-       "tooltip-pt-userpage": "Notlatequitiltilīlzāzanil",
-       "tooltip-pt-mytalk": "Mozānīl",
-       "tooltip-pt-preferences": "Mopanitlatlālīl",
+       "tooltip-pt-userpage": "{{GENDER:|Motlatequitiltilīlzāzanil}}",
+       "tooltip-pt-mytalk": "{{GENDER:|Motēīxnāmiquiliztli}}",
+       "tooltip-pt-preferences": "{{GENDER:|Motlaēlēhuiliz}}",
        "tooltip-pt-watchlist": "Zāzaniltin tiquintlachiya ic tlapatlaliztli",
-       "tooltip-pt-mycontris": "Notlahcuilōl",
+       "tooltip-pt-mycontris": "{{GENDER:|Motlahcuilōl}}",
        "tooltip-pt-login": "Tihuelīti timocalaqui, tēl ahmo tihuīquilia.",
        "tooltip-pt-logout": "Tiquīzāz",
        "tooltip-ca-talk": "Inīn tlahcuilōlli zānīllī ītechcopa",
        "tooltip-t-recentchangeslinked": "Yancuic tlapatlaliztli inīn zāzanilhuīcpa moquintzonhuilia",
        "tooltip-feed-rss": "RSS tlachicāhualiztli inīn zāzaniltechcopa",
        "tooltip-feed-atom": "Atom tlachicāhualiztli inīn zāzaniltechcopa",
-       "tooltip-t-contributions": "Xiquitta inīn tlatequitiltilīlli ītlahcuilōl",
+       "tooltip-t-contributions": "Tlapōhualmatl ītechpa {{GENDER:$1|inīn tlatequitiltilīlli}} ītlahcuilōl",
        "tooltip-t-emailuser": "Tiquihcuilōz inīn tlatequitiltililhuīc",
        "tooltip-t-upload": "Tiquinquetzāz tlahcuilōlli",
        "tooltip-t-specialpages": "Ìntlapòpòwaltekpànal mochtìn in nònkuâkìskàtlaìxtlapaltìn",
        "tooltip-t-print": "Tepoztlahcuilōlli",
        "tooltip-ca-nstab-main": "Xiquitta in tlamantlaīxtli",
        "tooltip-ca-nstab-user": "Xiquitta tlatequitiltilīlli īzāzanil",
-       "tooltip-ca-nstab-special": "Inìn sè nònkuâkìskàtlaìxtlapalli, yêìka awel nemàtilòs moyêyèktlàlis in tlaìxtlapalli",
+       "tooltip-ca-nstab-special": "Inīn nōncuahquīzqui āmatl, auh ahmohuelitizpatla",
        "tooltip-ca-nstab-project": "Xiquitta in tlatequipanōllaīxtli",
        "tooltip-ca-nstab-image": "Xiquittāz īxipzāzanilli",
        "tooltip-ca-nstab-mediawiki": "Xiquitta in tlahcuilōltzin",
index 76e6484..a39cb81 100644 (file)
        "tagline": "'A {{SITENAME}}.",
        "help": "Ajùto",
        "search": "Truova",
+       "search-ignored-headings": " #<!-- lassa sta linea comme sta --> <pre>\n# Testate ca se sarranno gnurate int' 'a ricerca.\n# Cagnamiente a chesto addeventarranno affettive quanno 'a paggena sarrà innecizzata.\n# Vuje putite forzà 'a reinnecezzazzione d' 'a paggena facenno nu cagnamiento abbacante.\n# 'A sintasse è 'a seguente:\n#   * Ogneccosa 'a 'o carattere \"#\" 'nzegna 'a fine d' 'a linea è 'nu cummanno\n#   * Ogne linea chiena è 'o titolo esatto 'a gnurà, case e tutteccose\nRiferimente\nJonte 'e fore\nVide pure\n #</pre> <!-- lassa sta linea comme sta  -->",
        "searchbutton": "Truova",
        "go": "Vàje",
        "searcharticle": "Vàje",
index 73eef2a..6332449 100644 (file)
@@ -48,7 +48,8 @@
                        "Tarjeimo",
                        "Matma Rex",
                        "SuperPotato",
-                       "Nemo bis"
+                       "Nemo bis",
+                       "Telaneo"
                ]
        },
        "tog-underline": "Strek under lenker:",
        "moredotdotdot": "Mer …",
        "morenotlisted": "Denne lista er ufullstendig.",
        "mypage": "Min brukerside",
-       "mytalk": "Min diskusjonsside",
+       "mytalk": "Diskusjon",
        "anontalk": "Brukerdiskusjon",
        "navigation": "Navigasjon",
        "and": "&#32;og",
        "minoredit": "Dette er en mindre endring",
        "watchthis": "Overvåk denne siden",
        "savearticle": "Lagre siden",
+       "publishpage": "Publiser siden",
+       "publishchanges": "Publiser endringene",
        "preview": "Forhåndsvisning",
        "showpreview": "Forhåndsvisning",
        "showdiff": "Vis endringer",
index 2e34b74..bda199e 100644 (file)
        "listgrouprights-group": "समूह",
        "listgrouprights-rights": "अधिकारहरु",
        "listgrouprights-helppage": "Help:सामूहिक अधिकारहरु",
-       "listgrouprights-members": "(सदसà¥\8dयहरà¥\81को सूची)",
+       "listgrouprights-members": "(सदसà¥\8dयहरà¥\82को सूची)",
        "listgrouprights-addgroup": "{{PLURAL:$2|समूह|समूहहरु}}: $1 थप्ने",
        "listgrouprights-removegroup": "{{PLURAL:$2|समूह|समूहहरु}}: $1 हटाउने",
        "listgrouprights-addgroup-all": "सबै समूह थप्ने",
        "contributions": "{{GENDER:$1|प्रयोगकर्ता}}का योगदानहरू",
        "contributions-title": "$1को प्रयोगकर्ता योगदानहरू",
        "mycontris": "योगदानहरू",
+       "anoncontribs": "योगदानहरू",
        "contribsub2": " {{GENDER:$3|$1}} ($2)को लागि",
        "contributions-userdoesnotexist": "प्रयोगकर्ता \"$1\" दर्ता गरिएको छैन् ।",
        "nocontribs": "यस मापदण्ड अनुसार परिवर्त पाइएन।",
        "tooltip-t-recentchangeslinked": "यस पृष्ठमा जोडिएका पृष्ठहरूमा हालैको परिवर्तन",
        "tooltip-feed-rss": "यो पृष्ठको लागि RSS फिड",
        "tooltip-feed-atom": "यो पृष्ठको लागि एटम फिड",
-       "tooltip-t-contributions": "यस प्रयोगकर्ताका योगदानहरूको सूची हेर्नुहोस्",
+       "tooltip-t-contributions": "{{GENDER:$1|यस प्रयोगकर्ता}}का योगदानहरूको सूची हेर्नुहोस्",
        "tooltip-t-emailuser": "यो प्रयोगकर्तालाई इमेल पठाउनुहोस्",
        "tooltip-t-info": "यस पृष्ठको बारेमा थप जानकारी",
        "tooltip-t-upload": "फाइल अपलोड गर्ने",
        "special-characters-title-emdash": "इएम ड्यास",
        "special-characters-title-minus": "घटाउने चिन्ह",
        "mw-widgets-titleinput-description-new-page": "हालसम्म पृष्ठ उपलब्ध छैन्",
-       "mw-widgets-titleinput-description-redirect": "$1 मा जाने",
-       "api-error-blacklisted": "एउटा फरक वर्णनात्मक शीर्षक चयन गर्नुहोस् ।"
+       "mw-widgets-titleinput-description-redirect": "$1 मा जाने"
 }
index ee99f80..3357ad2 100644 (file)
@@ -78,7 +78,8 @@
                        "Lemondoge",
                        "Dinosaur918",
                        "Jdforrester",
-                       "Jeleniccz"
+                       "Jeleniccz",
+                       "MrLeopold"
                ]
        },
        "tog-underline": "Koppelingen onderstrepen:",
        "tagline": "Uit {{SITENAME}}",
        "help": "Hulp",
        "search": "Zoeken",
+       "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# Koppen die worden genegeerd tijdens het zoeken.\n# Wijzigingen worden van kracht als een kop wordt geïndexeerd.\n# U kunt opnieuw indexeren afdwingen door het uitvoeren van een nullbewerking.\n# De syntaxis is al volgt:\n#   * All tekst vanaf het teken \"#\" tot het einde van de regel wordt gezien als een opmerking;\n#   * Iedere niet-lege regel is de precieze te negeren kop, inclusief hoofdlettergebruik en degelijke.\nReferenties\nExterne koppelingen\nZie ook\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Zoeken",
        "go": "OK",
        "searcharticle": "OK",
        "action-managechangetags": "labels aan te maken en te verwijderen",
        "action-applychangetags": "labels aan uw bewerkingen toe te voegen",
        "action-changetags": "willekeurige labels toe te voegen aan en te verwijderen van versies en logboekregels",
+       "action-purge": "Schoon deze pagina op",
        "nchanges": "$1 {{PLURAL:$1|bewerking|bewerkingen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sinds uw laatste bezoek}}",
        "enhancedrc-history": "geschiedenis",
index c08125f..2e7b628 100644 (file)
@@ -25,7 +25,8 @@
                        "Macofe",
                        "Chameleon222",
                        "Matma Rex",
-                       "Mortensson"
+                       "Mortensson",
+                       "Danmichaelo"
                ]
        },
        "tog-underline": "Strek under lenkjer:",
        "minoredit": "Småplukk",
        "watchthis": "Overvak sida",
        "savearticle": "Lagra sida",
+       "publishpage": "Publiser sida",
+       "publishchanges": "Publiser endringar",
        "preview": "Førehandsvising",
        "showpreview": "Førehandsvis",
        "showdiff": "Sjå skilnader",
index cb9ca86..66bf6a4 100644 (file)
        "october-date": "$1 ਅਕਤੂਬਰ",
        "november-date": "$1 ਨਵੰਬਰ",
        "december-date": "$1 ਦਸੰਬਰ",
+       "period-am": "ਏਐਮ",
+       "period-pm": "ਪੀਐਮ",
        "pagecategories": "{{PLURAL:$1|ਸ਼੍ਰੇਣੀ|ਸ਼੍ਰੇਣੀਆਂ}}",
        "category_header": "ਸ਼੍ਰੇਣੀ \"$1\" ਵਿੱਚ ਲੇਖ",
        "subcategories": "ਉਪਸ਼੍ਰੇਣੀਆਂ",
        "mypage": "ਸਫ਼ਾ",
        "mytalk": "ਗੱਲ-ਬਾਤ",
        "anontalk": "ਗੱਲ-ਬਾਤ",
-       "navigation": "ਫà©\87ਰà©\80 à¨ªà¨¾à¨\93",
+       "navigation": "ਨà©\87ਵà©\80à¨\97à©\87ਸ਼ਨ",
        "and": "&#32;ਅਤੇ",
        "qbfind": "ਖੋਜ",
        "qbbrowse": "ਝਲਕ",
        "yourdomainname": "ਤੁਹਾਡਾ ਡੋਮੇਨ:",
        "password-change-forbidden": "ਇਸ ਵਿਕੀ ਤੇ ਤੁਸੀਂ ਪਾਸਵਰਡ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।",
        "externaldberror": "ਜਾਂ ਤਾਂ ਪ੍ਰਮਾਣਕੀ ਡਾਟਾਬੇਸ ਦੋਸ਼ ਆਇਆ ਹੈ ਜਾਂ ਤੁਹਾਨੂੰ ਆਪਣੇ ਬਾਹਰੀ ਖਾਤੇ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
-       "login": "ਲਾà¨\97à¨\87ਨ",
+       "login": "ਦਾà¨\96ਲ",
        "login-security": "ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੜਤਾਲ ਕਰਵਾਉ",
        "nav-login-createaccount": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
        "userlogin": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
        "createaccount-title": "{{SITENAME}} ਲਈ ਅਕਾਊਂਟ ਬਣਾਉਣਾ",
        "createaccount-text": "ਕਿਸੇ ਨੇ \"$2\" ਮੈਂਬਰ-ਨਾਮ ਅਤੇ \"$3\" ਪਾਸਵਰਡ ਨਾਲ਼ {{SITENAME}} ($4) ਤੇ, ਤੁਹਾਡਾ ਈ-ਮੇਲ ਪਤਾ ਵਰਤਦੇ ਹੋਏ, ਖਾਤਾ ਬਣਾਇਆ ਹੈ।\nਤੁਹਾਨੂੰ ਹੁਣੇ ਲਾਗਇਨ ਕਰਕੇ ਆਪਣਾ ਪਾਸਵਰਡ ਬਦਲਣਾ ਚਾਹੀਦਾ ਹੈ।\n\nਜੇ ਇਹ ਖਾਤਾ ਗ਼ਲਤੀ ਨਾਲ਼ ਬਣ ਗਿਆ ਹੈ ਤਾਂ ਤੁਸੀਂ ਇਸ ਸੁਨੇਹੇ ਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰ ਸਕਦੇ ਹੋ।",
        "login-throttled": "ਤੁਸੀਂ ਬਹੁਤ ਸਾਰੀਆਂ ਤਾਜ਼ਾ ਲਾਗਇਨ ਕੋਸ਼ਿਸ਼ਾਂ ਕੀਤੀਆਂ ਹਨ।\nਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ $1 ਉਡੀਕ ਕਰੋ ਜੀ।",
-       "login-abort-generic": "ਤà©\81ਹਾਡਾ à¨¦à¨¾à¨\96਼ਲਾ à¨¨à¨¾à¨\95ਾਮ ਸੀ - ਅਧੂਰਾ ਛੱਡਿਆ",
+       "login-abort-generic": "ਤà©\81ਹਾਡਾ à¨¦à¨¾à¨\96਼ਲਾ à¨\85ਸਫਲ ਸੀ - ਅਧੂਰਾ ਛੱਡਿਆ",
        "login-migrated-generic": "ਤੁਹਾਡੇ ਖਾਤੇ ਦੀ ਥਾਂ ਬਦਲ ਦਿੱਤੀ ਗਈ ਹੈ ਅਤੇ ਤੁਹਾਡਾ ਵਰਤੋਂਕਾਰ-ਨਾਂ ਹੁਣ ਇਸ ਵਿਕੀ 'ਤੇ ਮੌਜੂਦ ਨਹੀਂ ਹੈ।",
        "loginlanguagelabel": "ਭਾਸ਼ਾ: $1",
        "suspicious-userlogout": "ਤੁਹਾਡੀ ਵਿਦਾਇਗੀ ਦੀ ਬੇਨਤੀ ਨਕਾਰ ਦਿੱਤੀ ਗਈ ਕਿਉਂਕਿ ਲੱਗਦਾ ਹੈ ਕਿ ਇਹ ਕਿਸੇ ਟੁੱਟੇ ਹੋਏ ਬਰਾਊਜ਼ਰ ਜਾਂ ਕੈਸ਼ ਹੋਈ ਪ੍ਰਾਕਸੀ ਤੋਂ ਭੇਜੀ ਗਈ ਸੀ।",
        "createacct-another-realname-tip": "ਅਸਲੀ ਨਾਂ ਚੋਣਵਾਂ ਹੈ।\nਜੇਕਰ ਤੁਸੀਂ ਇਹ ਦਿੱਤਾ ਹੈ ਤਾਂ ਤੁਹਾਡੇ ਕੰਮ ਵਾਸਤੇ ਗੁਣ ਦੇ ਤੌਰ ਉੱਤੇ ਵਰਤਿਆ ਜਾਵੇਗਾ।",
-       "pt-login": "ਲਾà¨\97 à¨\87ਨ",
-       "pt-login-button": "ਲਾà¨\97 à¨\87ਨ",
+       "pt-login": "ਦਾà¨\96ਲ",
+       "pt-login-button": "ਦਾà¨\96ਲ",
        "pt-createaccount": "ਖਾਤਾ ਬਣਾਓ",
        "pt-userlogout": "ਬਾਹਰ ਆਉ",
        "php-mail-error-unknown": "PHP ਦੇ ਮੇਲ() ਕਰਜ ਵਿੱਚ ਅਣਜਾਣ ਦੋਸ਼",
        "resetpass_submit": "ਪਾਸਵਰਡ ਸੈੱਟ ਕਰੋ ਅਤੇ ਲਾਗਇਨ ਕਰੋ",
        "changepassword-success": "ਤੁਹਾਡਾ ਪਾਸਵਰਡ ਠੀਕ ਤਰ੍ਹਾਂ ਬਦਲਿਆ ਜਾ ਚੁੱਕਾ ਹੈ!",
        "changepassword-throttled": "ਤੁਸੀਂ ਦਾਖ਼ਲ ਹੋਣ ਦੀਆਂ ਬਹੁਤ ਸਾਰੀਆਂ ਤਾਜ਼ਾ ਕੋਸ਼ਿਸ਼ਾਂ ਕੀਤੀਆਂ ਹਨ।\nਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ $1 ਉਡੀਕ ਕਰੋ ਜੀ।",
+       "botpasswords": "ਬੌਟ ਪਾਸਵਰਡ",
+       "botpasswords-label-appid": "ਬੌਟਾ ਨਾੰ:",
+       "botpasswords-label-create": "ਬਣਾਓ",
+       "botpasswords-label-update": "ਨਵਿਆਉ",
+       "botpasswords-label-cancel": "ਰੱਦ ਕਰੋ",
+       "botpasswords-label-delete": "ਮਿਟਾਓ",
+       "botpasswords-label-resetpassword": "ਪਾਸਵਰਡ ਮੁੜ-ਸੈੱਟ ਕਰੋ",
        "resetpass_forbidden": "ਪਾਸਵਰਡ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ",
        "resetpass-no-info": "ਇਸ ਸਫ਼ੇ ਨੂੰ ਸਿੱਧੇ ਹੀ ਵੇਖਣ ਲਈ ਤੁਹਾਨੂੰ ਲਾਗਇਨ ਕਰਨਾ ਪਵੇਗਾ।",
        "resetpass-submit-loggedin": "ਪਛਾਣ-ਸ਼ਬਦ ਬਦਲੋ",
        "passwordreset-emailsentemail": "ਇੱਕ ਪਾਸਵਰਡ ਮੁੜ-ਸੈੱਟ ਈ-ਮੇਲ ਭੇਜੀ ਜਾ ਚੁੱਕੀ ਹੈ।",
        "passwordreset-emailsent-capture": "ਇੱਕ ਯਾਦ-ਦਹਾਨੀ ਈ-ਮੇਲ, ਜਿਹੜੀ ਕਿ ਹੇਠਾਂ ਦਿੱਸ ਰਹੀ ਹੈ, ਭੇਜੀ ਜਾ ਚੁੱਕੀ ਹੈ।",
        "passwordreset-emailerror-capture": "ਪਛਾਣ-ਸ਼ਬਦ ਮੁੜ ਬਣਾਉਣ ਵਾਸਤੇ ਈਮੇਲ ਤਿਆਰ ਹੋ ਗਈ ਸੀ, ਜੋ ਹੇਠਾਂ ਵਿਖਾਈ ਗਈ ਹੈ, ਪਰ ਇਹਨੂੰ {{GENDER:$2|ਵਰਤੋਂਕਾਰ}} ਵੱਲ ਨਹੀਂ ਘੱਲਿਆ ਜਾ ਸਕਿਆ: $1",
-       "changeemail": "ਈ-ਮੇਲ ਸਿਰਨਾਵਾਂ ਬਦਲੋ",
+       "passwordreset-invalideamil": "ਗ਼ਲਤ ਈਮੇਲ ਪਤਾ",
+       "changeemail": "ਈ-ਮੇਲ ਸਿਰਨਾਵਾਂ ਬਦਲੋ ਜਾੰ ਹਟਾਓ",
        "changeemail-header": "ਖਾਤੇ ਵਾਲਾ ਈ-ਮੇਲ ਸਿਰਨਾਵਾਂ ਬਦਲੋ",
        "changeemail-no-info": "ਇਸ ਸਫ਼ੇ ਨੂੰ ਸਿੱਧੇ ਹੀ ਵੇਖਣ ਲਈ ਤੁਹਾਨੂੰ ਲਾਗਇਨ ਕਰਨਾ ਪਵੇਗਾ।",
        "changeemail-oldemail": "ਮੌਜੂਦਾ ਈਮੇਲ ਸਿਰਨਾਵਾਂ:",
        "minoredit": "ਇਹ ਇੱਕ ਛੋਟੀ ਸੋਧ ਹੈ",
        "watchthis": "ਇਸ ਸਫ਼ੇ ’ਤੇ ਨਜ਼ਰ ਰੱਖੋ",
        "savearticle": "ਸਫ਼ਾ ਸਾਂਭੋ",
+       "savechanges": "ਤਬਦੀਲੀਆਂ ਸਾਂਭੋ",
        "preview": "ਝਲਕ",
        "showpreview": "ਝਲਕ ਵਿਖਾਓ",
        "showdiff": "ਤਬਦੀਲੀਆਂ ਵਿਖਾਉ",
        "missingsummary": "'''ਯਾਦ-ਦਹਾਨੀ:''' ਤੁਸੀਂ ਸੋਧ ਸਾਰ ਮੁਹੱਈਆ ਨਹੀਂ ਕਰਵਾਇਆ। ਜੇ ਤੁਸੀਂ \"{{int:savearticle}}\" ਤੇ ਦੁਬਾਰਾ ਕਲਿੱਕ ਕੀਤਾ ਤਾਂ ਤੁਹਾਡਾ ਸਫ਼ਾ ਇਸਦੇ ਬਿਨਾਂ ਹੀ ਸਾਂਭਿਆ ਜਾਵੇਗਾ।",
        "missingcommenttext": "ਹੇਠਾਂ ਇੱਕ ਟਿੱਪਣੀ ਦਿਓ।",
        "summary-preview": "ਸੋਧ ਸਾਰ ਦੀ ਝਲਕ:",
-       "subject-preview": "ਵਿਸ਼ੇ/ਸਿਰਨਾਵੇਂ ਦੀ ਝਲਕ:",
+       "subject-preview": "ਵਿਸ਼ੇ ਦੀ ਝਲਕ:",
        "previewerrortext": "ਤੁਹਾਡੀਆਂ ਤਬਦੀਲੀਆਂ ਦੀ ਝਲਕ ਵਿਖਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਗ਼ਲਤੀ ਆ ਗਈ।",
        "blockedtitle": "ਵਰਤੋਂਕਾਰ ਉੱਤੇ ਪਾਬੰਦੀ ਲੱਗੀ ਹੋਈ ਹੈ",
        "blockedtext": "'''ਤੁਹਾਡੇ ਮੌਮਬਰ ਨਾਮ ਜਾਂ IP ਪਤੇ ’ਤੇ ਪਾਬੰਦੀ ਲੱਗ ਚੁੱਕੀ ਹੈ।'''\n\nਪਾਬੰਦੀ $1 ਨੇ ਲਾਈ ਹੈ।\nਦਿੱਤਾ ਗਿਆ ਕਾਰਨ ਇਹ ਹੈ, ''$2''।\n\n* ਪਾਬੰਦੀ ਸ਼ੁਰੂ: $8\n* ਪਾਬੰਦੀ ਖਤਮ: $6\n* ਪਾਬੰਦੀ ਲਾਉਣ ਵਾਲੇ ਦਾ ਇਰਾਦਾ: $7\n\nਪਾਬੰਦੀ ਬਾਰੇ ਚਰਚਾ ਕਰਨ ਲਈ ਤੁਸੀਂ $1 ਜਾਂ ਕਿਸੇ ਹੋਰ\n[[{{MediaWiki:Grouppage-\nsysop}}|administrator]] ਨਾਲ ਰਾਬਤਾ ਕਰ ਸਕਦੇ ਹੋ।\nਤੁਸੀਂ 'ਇਸ ਮੈਂਬਰ ਨੂੰ ਈ-ਮੇਲ ਭੇਜੋ' ਸਹੂਲਤ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਸਕਦੇ ਜੇ ਤੁਹਾਡੀਆਂ [[Special:Preferences|ਖਾਤਾ ਪਸੰਦਾਂ]] ਵਿੱਚ ਇੱਕ ਸਹੀ ਈ-ਮੇਲ ਪਤਾ ਨਹੀਂ ਦਿੱਤਾ ਗਿਆ ਜਾਂ ਜੇ ਤੁਹਾਡੇ ਇਸਨੂੰ ਵਰਤਣ ਤੇ ਪਾਬੰਦੀ ਹੈ।\nਤੁਹਾਡਾ ਚਾਲੂ IP ਪਤਾ $3 ਹੈ,\nਅਤੇ ਪਾਬੰਦੀ ਪਤਾ #$5 ਹੈ।\nਮਿਹਰਬਾਨੀ ਕਰਕੇ ਆਪਣੇ ਕਿਸੇ ਵੀ ਸਵਾਲ ਜਾਂ ਪੁੱਛ-ਗਿੱਛ ਵਿਚ ਇਹ ਉੱਪਰਲੀ ਤਫ਼ਸੀਲ ਜ਼ਰੂਰ ਸ਼ਾਮਲ ਕਰੋ।",
        "nosuchsectiontitle": "ਭਾਗ ਲੱਭ ਨਹੀਂ ਰਿਹਾ",
        "nosuchsectiontext": "ਤੁਸੀਂ ਨਾ-ਮੌਜੂਦ ਭਾਗ ਨੂੰ ਸੋਧਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ।\nਸ਼ਾਇਦ ਤੁਹਾਡੇ ਸਫ਼ੇ ਨੂੰ ਵੇਖਣ ਦੇ ਦੌਰਾਨ ਇਹ ਮਿਟਾਇਆ ਜਾਂ ਇਸਦਾ ਸਿਰਲੇਖ ਬਦਲਿਆ ਜਾ ਚੁੱਕਾ ਹੈ।",
        "loginreqtitle": "ਲਾਗਇਨ ਚਾਹੀਦਾ ਹੈ",
-       "loginreqlink": "ਲਾà¨\97à¨\87ਨ",
+       "loginreqlink": "ਦਾà¨\96ਲ",
        "loginreqpagetext": "ਹੋਰ ਸਫ਼ੇ ਵੇਖਣ ਲਈ ਤੁਹਾਨੂੰ $1 ਕਰਨਾ ਪਵੇਗਾ।",
        "accmailtitle": "ਪਾਸਵਰਡ ਭੇਜਿਆ।",
        "accmailtext": "[[User talk:$1|$1]] ਲਈ ਰਲ਼ਵੇਂ ਤੌਰ ’ਤੇ ਬਣਿਆ ਪਾਸਵਰਡ $2 ਨੂੰ ਭੇਜਿਆ ਜਾ ਚੁੱਕਾ ਹੈ।\nਇਸ ਨਵੇਂ ਖਾਤੇ ਲਈ ਲਾਗਇਨ ਕਰਨ ਤੋਂ ਬਾਅਦ ''[[Special:ChangePassword|ਪਾਸਵਰਡ ਬਦਲੋ]]'' ’ਤੇ ਜਾ ਕੇ ਪਾਸਵਰਡ ਬਦਲਿਆ ਜਾ ਸਕਦਾ ਹੈ।",
        "history-feed-empty": "ਦਰਖ਼ਾਸਤਸ਼ੁਦਾ ਸਫ਼ਾ ਮੌਜੂਦ ਨਹੀਂ ਹੈ।\nਸ਼ਾਇਦ ਇਸਨੂੰ ਵਿਕੀ ਤੋਂ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਾਮ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ।\nਵਿਕੀ ਦੇ ਨਵੇਂ ਮੁਨਾਸਿਬ ਸਫ਼ਿਆਂ ਵਿਚ [[Special:Search|ਲੱਭਣ]] ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
        "rev-deleted-comment": "(ਸੋਧ ਸਾਰ ਹਟਾਇਆ)",
        "rev-deleted-user": "(ਵਰਤੋਂਕਾਰ ਨਾਂ ਹਟਾਇਆ)",
-       "rev-deleted-event": "(ਲਾà¨\97 à¨\95ਾਰਵਾà¨\88 à¨¹à¨\9fਾà¨\88 à¨\97à¨\88)",
+       "rev-deleted-event": "(ਲਾà¨\97 à¨µà©\87ਰਵਾ à¨¹à¨\9fਾà¨\87à¨\86 à¨\97ਿà¨\86)",
        "rev-deleted-user-contribs": "[ਮੈਂਬਰ-ਨਾਂ ਜਾਂ IP ਪਤਾ ਹਟਾਇਆ - ਸੋਧ ਯੋਗਦਾਨਾਂ ਵਿਚੋਂ ਓਹਲੇ ਕੀਤੀ]",
        "rev-deleted-text-permission": "ਸਫ਼ੇ ਦੀ ਇਹ ਰੀਵਿਜ਼ਨ '''ਮਿਟਾਈ''' ਜਾ ਚੁੱਕੀ ਹੈ।\nਤਫ਼ਸੀਲ [{{fullurl:{{#Special:Log}}/delete|\npage={{FULLPAGENAMEE}}}} ਮਿਟਾਉਣ ਦੇ ਚਿੱਠੇ] ਵਿਚ ਵੇਖੀ ਜਾ ਸਕਦੀ ਹੈ।",
        "rev-deleted-text-unhide": "ਸਫ਼ੇ ਦੀ ਇਹ ਰੀਵਿਜ਼ਨ '''ਮਿਟਾਈ''' ਜਾ ਚੁੱਕੀ ਹੈ।\nਤਫ਼ਸੀਲ [{{fullurl:{{#Special:Log}}/delete|\npage={{FULLPAGENAMEE}}}} ਮਿਟਾਉਣ ਦੇ ਚਿੱਠੇ] ਵਿਚ ਵੇਖੀ ਜਾ ਸਕਦੀ ਹੈ।\nਜੇ ਤੁਸੀਂ ਅੱਗੇ ਵਧਣਾ ਚਾਹੋ ਤਾਂ ਹਾਲੇ ਵੀ [$1 ਇਹ ਰੀਵਿਜ਼ਨ ਵੇਖ] ਸਕਦੇ ਹੋ।",
        "mergehistory-submit": "ਰੀਵਿਜ਼ਨਾਂ ਰਲ਼ਾਓ",
        "mergehistory-empty": "ਕੋਈ ਰੀਵਿਜ਼ਨ ਰਲ਼ਾਈ ਨਹੀ ਜਾ ਸਕਦੀ।",
        "mergehistory-done": "$1 {{PLURAL:|ਦੀ|ਦੀਆਂ}} $3 {{PLURAL:$3|ਰੀਵਿਜ਼ਨ|ਰੀਵਿਜ਼ਨਾਂ}} ਕਾਮਯਾਬੀ ਨਾਲ਼ [[:$2]] ਵਿਚ {{PLURAL:$3|ਰਲ਼ਾਈ|ਰਲ਼ਾਈਆਂ}}।",
+       "mergehistory-fail-bad-timestamp": "ਸਮਾੰਮੋਹਰ ਗਲਤ ਹੈ।",
+       "mergehistory-fail-invalid-source": "ਸਰੋਤ ਸਫ਼ਾ ਗਲਤ ਹੈ।",
        "mergehistory-no-source": "ਸਰੋਤ ਸਫ਼ਾ $1 ਮੌਜੂਦ ਨਹੀਂ ਹੈ।",
        "mergehistory-no-destination": "ਨੀਯਤ ਸਫ਼ਾ $1 ਮੌਜੂਦ ਨਹੀਂ ਹੈ।",
        "mergehistory-invalid-source": "ਸਰੋਤ ਸਫ਼ਾ ਇੱਕ ਸਹੀ ਸਿਰਲੇਖ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।",
        "prefs-rc": "ਹਾਲੀਆ ਤਬਦੀਲੀਆਂ",
        "prefs-watchlist": "ਨਿਗਰਾਨ-ਸੂਚੀ",
        "prefs-editwatchlist": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਸੋਧੋ",
+       "prefs-editwatchlist-clear": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਸਾਫ ਕਰੋ",
        "prefs-watchlist-days": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚ ਦਿਖਾਉਣ ਲਈ ਦਿਨ:",
        "prefs-watchlist-days-max": "ਵੱਧ ਤੋਂ ਵੱਧ $1 {{PLURAL:$1|ਦਿਨ|ਦਿਨ}}",
        "prefs-watchlist-edits": "ਵਧਾਈ ਹੋਈ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚ ਦਿਖਾਉਣ ਲਈ ਵੱਧ ਤੋਂ ਵੱਧ ਤਬਦੀਲੀਆਂ:",
        "prefs-watchlist-token": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਟੋਕਨ:",
        "prefs-misc": "ਫੁਟਕਲ",
        "prefs-resetpass": "ਪਛਾਣ-ਸ਼ਬਦ ਬਦਲੋ",
-       "prefs-changeemail": "ਈ-ਮੇਲ ਪਤਾ ਬਦਲੋ",
+       "prefs-changeemail": "ਈ-ਮੇਲ ਪਤਾ ਬਦਲੋ ਜਾੰ ਹਟਾਓ",
        "prefs-setemail": "ਈ-ਮੇਲ ਪਤਾ ਸੈੱਟ ਕਰੋ",
        "prefs-email": "ਈਮੇਲ ਚੋਣਾਂ",
        "prefs-rendering": "ਦਿੱਖ",
        "right-upload_by_url": "URL ਤੋਂ ਫਾਇਲਾਂ ਅੱਪਲੋਡ ਕਰੋ",
        "right-autoconfirmed": "ਨੀਮ-ਸੁਰੱਖਿਅਤ ਸਫ਼ਿਆਂ ਨੂੰ ਸੋਧਣਾ",
        "right-bot": "ਇੱਕ ਸਵੈ-ਚਾਲਤ ਅਮਲ ਵਜੋਂ ਗਿਣਿਆ ਜਾਣਾ",
-       "right-writeapi": "à¨\8fਪà©\80à¨\86à¨\88(API) à¨¦à©\80 à¨µà¨°à¨¤à©\8bà¨\82",
+       "right-writeapi": "ਲਿà¨\96ਾà¨\88 à¨\8fਪà©\80à¨\86à¨\88 à¨¦à©\80 à¨µà¨°à¨¤à©\8bà©°",
        "right-delete": "ਸਫ਼ੇ ਹਟਾਓ",
        "right-bigdelete": "ਵੱਡੇ ਅਤੀਤ ਵਾਲੇ ਪੰਨੇ ਮਿਟਾਉਣੇ",
        "right-browsearchive": "ਮਿਟਾਏ ਹੋਏ ਸਫ਼ੇ ਖੋਜੋ",
        "right-siteadmin": "ਡੈਟਾਬੇਸ ਨੂੰ ਤਾਲਾ ਲਾਉਣਾ ਤੇ ਖੋਲ੍ਹਣਾ",
        "right-sendemail": "ਦੂਜੇ ਮੈਂਬਰਾਂ ਨੂੰ ਈ-ਮੇਲ ਭੇਜਣਾ",
        "right-passwordreset": "ਪਾਸਵਰਡ ਮੁੜ-ਸੈੱਟ ਈਮੇਲ ਵੇਖੋ",
+       "grant-group-email": "ਈ-ਮੇਲ ਭੇਜੋ",
+       "grant-group-customization": "ਅਨੁਕੂਲਨ ਅਤੇ ਪਸੰਦਾੰ",
+       "grant-createaccount": "ਖਾਤੇ ਬਣਾਓ",
+       "grant-createeditmovepage": "ਸਫ਼ੇ ਬਣਾਓ, ਸੋਧ, ਅਤੇ ਹਿੱਲਾਓ",
+       "grant-editmywatchlist": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਸੋਧੋ",
+       "grant-editprotected": "ਸੁਰੱਖਿਅਤ ਸਫ਼ੇ ਸੋਧ",
+       "grant-uploadfile": "ਨਵੀਆੰ ਫਾਈਲਾੰ ਅੱਪਲੋਡ ਕਰੋ",
+       "grant-basic": "ਬੁਨਿਆਦੀ ਹੱਕ",
+       "grant-viewmywatchlist": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਸੂਚੀ ਵੇਖੋ",
        "newuserlogpage": "ਬਣਾਏ ਖਾਤਿਆਂ ਦਾ ਚਿੱਠਾ",
        "newuserlogpagetext": "ਇਹ ਬਣੇ ਮੈਂਬਰਾਂ ਦਾ ਚਿੱਠਾ ਹੈ।",
        "rightslog": "ਵਰਤੋਂਕਾਰ ਹੱਕਾਂ ਦਾ ਚਿੱਠਾ",
        "rightslogtext": "ਇਹ ਮੈਂਬਰ ਹੱਕਾਂ ਵਿਚ ਹੋਈਆਂ ਤਬਦੀਲੀਆਂ ਦਾ ਚਿੱਠਾ ਹੈ।",
        "action-read": "ਇਹ ਸਫ਼ਾ ਪੜ੍ਹੋ",
        "action-edit": "ਇਹ ਸਫ਼ਾ ਸੋਧੋ",
-       "action-createpage": "ਸਫ਼à©\87 ਬਣਾਓ",
-       "action-createtalk": "à¨\9aਰà¨\9aਾ à¨¸à¨«à¨¼à©\87 ਬਣਾਉਣ",
+       "action-createpage": "à¨\87ਹ à¨¸à¨«à¨¼à¨¾ ਬਣਾਓ",
+       "action-createtalk": "à¨\87ਹ à¨\9aਰà¨\9aਾ à¨¸à¨«à¨¼à¨¾ ਬਣਾਉਣ",
        "action-createaccount": "ਇਹ ਵਰਤੋਂਕਾਰ ਖਾਤਾ ਬਣਾਓ",
        "action-history": "ਇਸ ਸਫ਼ੇ ਦਾ ਅਤੀਤ ਵੇਖੋ",
        "action-minoredit": "ਇਹ ਸੋਧ ਨੂੰ ਛੋਟੀ ਤੌਰ ਉੱਤੇ ਮੰਨੋ",
        "action-block": "ਇਸ ਮੈਂਬਰ ਦੇ ਸੋਧ ਕਰਨ ਤੇ ਪਾਬੰਦੀ ਲਾਓ",
        "action-protect": "ਇਸ ਸਫ਼ੇ ਦੀ ਸੁਰੱਖਿਆ ਬਦਲੋ",
        "action-import": "ਹੋਰ ਵਿਕੀ ਤੋਂ ਇਹ ਸਫ਼ਾ ਲਵੋ",
-       "action-importupload": "ਫ਼ਾà¨\88ਲ à¨\85ੱਪਲà©\8bਡ à¨¤à©\8bà¨\82 à¨\87ਹ à¨¸à¨«à¨¼à¨¾ ਮੰਗਾਓ",
+       "action-importupload": "ਫ਼ਾà¨\88ਲ à¨\85ੱਪਲà©\8bਡ à¨¤à©\8bà¨\82 à¨¸à¨«à©\87 ਮੰਗਾਓ",
        "action-unwatchedpages": "ਨਜ਼ਰ ਨਾ ਰੱਖੇ ਜਾ ਰਹੇ ਸਫ਼ਿਆਂ ਦੀ ਸੂਚੀ ਵੇਖੋ",
        "action-mergehistory": "ਇਸ ਸਫ਼ੇ ਦੇ ਅਤੀਤ ਨੂੰ ਰਲ਼ਾਉਣ",
        "action-userrights": "ਵਰਤੋਂਕਾਰ ਦੇ ਸਾਰੇ ਹੱਕ ਸੋਧਣ",
        "recentchanges-feed-description": "ਇਸ ਵਿਕੀ ’ਤੇ ਹਾਲ ‘ਚ ਹੋਈਆਂ ਤਬਦੀਲੀਆਂ ਇਸ ਫ਼ੀਡ ’ਚ ਵੇਖੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ।",
        "recentchanges-label-newpage": "ਇਸ ਸੋਧ ਨਾਲ਼ ਨਵਾਂ ਸਫ਼ਾ ਬਣਿਆ ਹੈ",
        "recentchanges-label-minor": "ਇਹ ਇੱਕ ਛੋਟੀ ਸੋਧ ਹੈ",
-       "recentchanges-label-bot": "à¨\87ਹ à¨¸à©\8bਧ à¨\87ੱà¨\95 à¨¬à©\8bਟ ਦੁਆਰਾ ਕੀਤੀ ਗਈ ਸੀ",
+       "recentchanges-label-bot": "à¨\87ਹ à¨¸à©\8bਧ à¨\87ੱà¨\95 à¨¬à©\8cਟ ਦੁਆਰਾ ਕੀਤੀ ਗਈ ਸੀ",
        "recentchanges-label-unpatrolled": "ਇਹ ਫੇਰ-ਬਦਲ ਹਾਲੇ ਵੇਖਿਆ ਨਹੀਂ ਗਿਆ",
        "recentchanges-label-plusminus": "ਸਫ਼ੇ ਵਿੱਚ ਇੰਨੀਆਂ ਬਾਈਟਾਂ ਦੀ ਤਬਦੀਲੀ ਹੋਈ",
        "recentchanges-legend-heading": "<strong>ਟੀਕਾ:</strong>",
        "rcshowhidemine": "ਮੇਰੀਆਂ ਤਬਦੀਲੀਆਂ  $1",
        "rcshowhidemine-show": "ਵੇਖੋ",
        "rcshowhidemine-hide": "ਓਹਲੇ",
+       "rcshowhidecategorization-show": "ਦਿਖਾਓ",
+       "rcshowhidecategorization-hide": "ਲੁਕਾਉ",
        "rclinks": "ਪਿਛਲੇ $2 ਦਿਨਾਂ ਵਿੱਚ ਹੋਈਆਂ $1 ਤਬਦੀਲੀਆਂ ਵਖਾਓ<br /> $3",
        "diff": "ਫ਼ਰਕ",
        "hist": "ਅਤੀਤ",
        "upload-file-error": "ਅੰਦਰੂਨੀ ਗਲਤੀ",
        "upload-misc-error": "ਅਣਪਛਾਤੀ ਅੱਪਲੋਡ ਗਲਤੀ",
        "upload-http-error": "ਇੱਕ HTTP ਗ਼ਲਤੀ ਹੋਈ: $1",
+       "upload-dialog-title": "ਫ਼ਾਈਲ ਅਪਲੋਡ ਕਰੋ",
+       "upload-dialog-button-cancel": "ਰੱਦ ਕਰੋ",
+       "upload-dialog-button-done": "ਮੁਕੰਮਲ",
+       "upload-dialog-button-save": "ਸਾਂਭੋ",
+       "upload-dialog-button-upload": "ਅੱਪਲੋਡ",
+       "upload-form-label-infoform-title": "ਵੇਰਵਾ",
+       "upload-form-label-infoform-name": "ਨਾਂ",
+       "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": "ਤਾਰੀਖ਼",
        "backend-fail-notexists": "ਫ਼ਾਈਲ $1 ਮੌਜੂਦ ਨਹੀਂ ਹੈ।",
        "backend-fail-delete": "ਫ਼ਾਈਲ \"$1\" ਮਿਟਾਈ ਨਹੀਂ ਜਾ ਸਕੀ।",
        "backend-fail-create": "\"$1\" ਫ਼ਾਈਲ ਲਿਖੀ ਨਾ ਜਾ ਸਕੀ।",
        "zip-wrong-format": "ਦੱਸੀ ਗਈ ਫ਼ਾਈਲ ਜ਼ਿੱਪ ਫ਼ਾਈਲ ਨਹੀਂ ਸੀ।",
        "uploadstash-refresh": "ਫ਼ਾਈਲਾਂ ਦੀ ਲਿਸਟ ਨੂੰ ਤਾਜ਼ਾ ਕਰੋ",
+       "uploadstash-thumbnail": "ਥੰਮਨੇਲ ਵੇਖੋ",
        "img-auth-accessdenied": "ਪਹੁੰਚ ਨਕਾਰੀ ਗਈ",
        "img-auth-nofile": "ਫ਼ਾਈਲ \"$1\" ਮੌਜੂਦ ਨਹੀਂ ਹੈ।",
+       "http-invalid-url": "ਗਲਤ URL: $1",
        "upload-curl-error6": "URL ’ਤੇ ਪਹੁੰਚਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ।",
        "upload-curl-error6-text": "ਦਿੱਤੇ ਹੋਏ URL ’ਤੇ ਪਹੁੰਚਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ।\nਮਿਹਰਬਾਨੀ ਕਰਕੇ ਦੁਬਾਰਾ ਜਾਂਚ ਕਰੋ ਕਿ URL ਸਹੀ ਹੈ ਅਤੇ ਸਾਈਟ ਉਪਲੱਬਧ ਹੈ।",
        "upload-curl-error28": "ਅੱਪਲੋਡ ਟਾਈਮ-ਆਉਟ",
        "uploadnewversion-linktext": "ਇਸ ਫਾਇਲ ਦਾ ਇੱਕ ਨਵਾਂ ਵਰਜਨ ਅੱਪਲੋਡ ਕਰੋ",
        "shared-repo-from": "$1 ਤੋਂ",
        "shared-repo": "ਕੋਈ ਸਾਂਝਾ ਕੀਤਾ ਭੰਡਾਰ",
-       "upload-disallowed-here": "ਤà©\81ਸà©\80à¨\82 à¨\87ਸ à¨«à¨¼à¨¾à¨\88ਲ à¨\89ੱਤà©\87 à¨¨à¨¹à©\80à¨\82 à¨¨à¨¹à©\80à¨\82 à¨²à¨¿à¨\96 à¨¸à¨\95ਦà©\87।",
+       "upload-disallowed-here": "ਤੁਸੀਂ ਇਸ ਫ਼ਾਈਲ ਉੱਤੇ ਨਹੀਂ ਲਿਖ ਸਕਦੇ।",
        "filerevert": "$1 ਰੀਵਰਟ",
        "filerevert-legend": "ਫਾਇਲ ਰੀਵਰਟ",
        "filerevert-comment": "ਕਾਰਨ:",
        "randomincategory-nopages": "[[:Category:$1|$1]] ਸ਼੍ਰੇਣੀ ਵਿਚ ਕੋਈ ਸਫ਼ਾ ਨਹੀਂ ਹੈ।",
        "randomincategory-category": "ਵਰਗ:",
        "randomincategory-legend": "ਵਰਗ ਵਿਚਲਾ ਰਲ਼ਵਾਂ ਸਫ਼ਾ",
+       "randomincategory-submit": "ਜਾਓ",
        "randomredirect": "ਰਲ਼ਵਾਂ ਰੀਡਿਰੈਕਟ",
        "statistics": "ਅੰਕੜੇ",
        "statistics-header-pages": "ਸਫ਼ਾ ਅੰਕੜੇ",
        "pager-newer-n": "{{PLURAL:$1|1 ਨਵਾਂ|$1 ਨਵੇਂ}}",
        "pager-older-n": "{{PLURAL:$1|1 ਪੁਰਾਣਾ|$1 ਪੁਰਾਣੇ}}",
        "suppress": "ਨਿਗਰਾਨ",
+       "apihelp": "API ਮਦਦ",
+       "apihelp-no-such-module": "ਮੌਡੂਲ \"$1\" ਨਹੀਂ ਲੱਭਾ।",
+       "apisandbox-unfullscreen": "ਸਫ਼ਾ ਵੇਖਾਓ",
+       "apisandbox-reset": "ਸਾਫ਼ ਕਰੋ",
+       "apisandbox-retry": "ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰੋ",
+       "apisandbox-helpurls": "ਮਦਦ ਜੋੜ",
+       "apisandbox-examples": "ਮਿਸਾਲਾਂ",
+       "apisandbox-results": "ਨਤੀਜੇ",
        "booksources": "ਪੁਸਤਕਾਂ ਦੇ ਸਰੋਤ",
        "booksources-search-legend": "ਕਿਤਾਬਾਂ ਦੇ ਸਰੋਤ ਖੋਜੋ",
        "booksources-search": "ਭਾਲ਼",
        "listgrouprights-removegroup-self-all": "ਆਪਣੇ ਖਾਤੇ ਤੋਂ ਸਾਰੇ ਸਮੂਹ ਹਟਾਓ",
        "listgrouprights-namespaceprotection-header": "ਨਾਂ-ਥਾਂ ਦੀਆਂ ਬੰਧੇਜਾਂ",
        "listgrouprights-namespaceprotection-namespace": "ਨਾਂ-ਥਾਂ",
+       "listgrants-rights": "ਹੱਕ",
        "trackingcategories": "ਵਰਗਾਂ ਦੀ ਪੈੜ",
        "trackingcategories-msg": "ਵਰਗ ਦੀ ਪੈੜ",
        "trackingcategories-name": "ਸੁਨੇਹੇ ਦਾ ਨਾਂ",
        "watchlist-details": "ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਨਾ ਗਿਣਦੇ ਹੋਏ, ਤੁਹਾਡੀ ਨਿਗਰਾਨੀ-ਸੂਚੀ ਵਿਚ{{PLURAL:$1|$1 ਸਫ਼ਾ ਹੈ|$1 ਸਫ਼ੇ ਹਨ}}।",
        "wlheader-enotif": "ਈਮੇਲ ਸੂਚਨਾ ਚਾਲੂ ਹੈ।",
        "wlnote": "$3, $4 ਮੁਤਾਬਕ ਆਖ਼ਰੀ {{PLURAL:$2|ਘੰਟੇ|'''$2''' ਘੰਟਿਆਂ}} ਵਿਚ {{PLURAL:\n$1|ਤਬਦੀਲੀ ਹੋਈ|'''$1''' ਤਬਦੀਲੀਆਂ ਹੋਈਆਂ}}, ਹੇਠਾਂ ਵੇਖੋ।",
-       "wlshowlast": "ਪਿਛਲੇ $1 ਘੰਟੇ $2 ਦਿਨ  ਵਖਾਓ",
+       "wlshowlast": "ਪਿਛਲੇ $1 ਘੰਟੇ $2 ਦਿਨ ਵਖਾਓ",
+       "watchlist-hide": "ਲੁਕਾਓ",
        "watchlist-submit": "ਦਿਖਾਓ",
+       "wlshowhideminor": "ਨਿੱਕੀਆਂ ਸੋਧਾਂ",
+       "wlshowhidebots": "ਬੌਟ",
+       "wlshowhideanons": "ਗੁਮਨਾਮ ਵਰਤੋਂਕਾਰ",
+       "wlshowhidepatr": "ਜਾਂਚੀਆਂ ਸੋਧਾੰ",
+       "wlshowhidemine": "ਮੇਰੀਆਂ ਸੋਧਾਂ",
        "watchlist-options": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਦੀਆਂ ਚੋਣਾਂ",
        "watching": "ਨਿਗ੍ਹਾ (ਵਾਚ) ਰੱਖੀ ਜਾ ਰਹੀ ਹੈ...",
        "unwatching": "ਨਿਗ੍ਹਾ ਰੱਖਣੀ (ਵਾਚ) ਬੰਦ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..",
        "sessionfailure-title": "ਇਜਲਾਸ ਫੇਲ੍ਹ",
        "changecontentmodel-title-label": "ਸਫ਼ੇ ਦਾ ਸਿਰਲੇਖ",
        "changecontentmodel-reason-label": "ਕਾਰਨ:",
+       "changecontentmodel-submit": "ਬਦਲੋ",
        "protectlogpage": "ਸੁਰੱਖਿਆ ਚਿੱਠਾ",
        "protectedarticle": "\"[[$1]]\" ਸੁਰੱਖਿਅਤ ਕੀਤਾ",
        "modifiedarticleprotection": "\"[[$1]]\" ਦੀ ਸੁਰੱਖਿਆ ਬਦਲੀ",
        "sp-contributions-username": "IP ਪਤਾ ਜਾਂ ਵਰਤੋਂਕਾਰਨਾਮ:",
        "sp-contributions-toponly": "ਸਿਰਫ ਉਹ ਸੋਧਾਂ ਵਿਖਾਓ ਜੋ ਸਭ ਤੋਂ ਤਾਜ਼ੀਆਂ ਰਿਵੀਜਨਾਂ ਹਨ",
        "sp-contributions-newonly": "ਸਿਰਫ਼ ਉਹ ਸੋਧਾਂ ਵਿਖਾਉ ਜਿਹਨਾਂ ਨਾਲ਼ ਨਵੇਂ ਸਫ਼ੇ ਬਣੇ ਹਨ",
+       "sp-contributions-hideminor": "ਛੋਟੀਆਂ ਤਬਦੀਲੀਆਂ ਲੁਕਾਓ",
        "sp-contributions-submit": "ਖੋਜ",
        "whatlinkshere": "ਇੱਥੇ ਕੀ ਆ ਕੇ ਜੁੜਦਾ ਹੈ",
        "whatlinkshere-title": "$1 ਨਾਲ ਜੋੜਨ ਵਾਲੇ ਸਫ਼ੇ",
        "tooltip-pt-mycontris": "ਤੁਹਾਡੇ ਯੋਗਦਾਨਾਂ ਦੀ ਸੂਚੀ",
        "tooltip-pt-login": "ਤੁਹਾਨੂੰ ਦਾਖ਼ਲ ਹੋਣ ਲਈ ਪ੍ਰੇਰਿਆ ਜਾਂਦਾ ਹੈ; ਪਰ ਇਹ ਕੋਈ ਲਾਜ਼ਮੀ ਨਹੀਂ",
        "tooltip-pt-logout": "ਸਾਈਟ ਤੋਂ ਬਾਹਰ ਆਉ",
-       "tooltip-pt-createaccount": "ਤà©\81ਹਾਨà©\82à©° à¨\96ਾਤਾ à¨¬à¨£à¨¾à¨\89ਣ à¨¤à©\8bà¨\82 à¨¬à¨¾à¨\85ਦ à¨²à¨¾à¨\97 à¨\87ਨ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ; ਹਾਲਾਂਕਿ ਇਹ ਲਾਜ਼ਮੀ ਨਹੀਂ",
+       "tooltip-pt-createaccount": "ਤà©\81ਹਾਨà©\82à©° à¨\96ਾਤਾ à¨¬à¨£à¨¾à¨\89ਣ à¨¤à©\8bà¨\82 à¨¬à¨¾à¨\85ਦ à¨¦à¨¾à¨\96ਲ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ; ਹਾਲਾਂਕਿ ਇਹ ਲਾਜ਼ਮੀ ਨਹੀਂ",
        "tooltip-ca-talk": "ਸਮਗੱਰੀ ਸਫ਼ੇ ਬਾਰੇ ਚਰਚਾ",
        "tooltip-ca-edit": "ਇਹ ਸਫ਼ਾ ਸੋਧੋ",
        "tooltip-ca-addsection": "ਨਵਾਂ ਭਾਗ ਸ਼ੁਰੂ ਕਰੋ",
        "tooltip-ca-unprotect": "ਇਸ ਸਫ਼ੇ ਦੀ ਸੁਰੱਖਿਆ ਬਦਲੋ",
        "tooltip-ca-delete": "ਇਸ ਸਫ਼ੇ ਨੂੰ ਹਟਾਓ",
        "tooltip-ca-move": "ਇਹ ਸਫ਼ਾ ਭੇਜੋ",
-       "tooltip-ca-watch": "à¨\87ਸ à¨¸à¨«à¨¼à©\87 à¨¨à©\82à©° à¨\86ਪਣà©\80 à¨¨à¨¿à¨\97ਰਾਨà©\80-ਲਿਸà¨\9f ਵਿਚ ਜੋੜੋ",
+       "tooltip-ca-watch": "à¨\87ਸ à¨¸à¨«à¨¼à©\87 à¨¨à©\82à©° à¨\86ਪਣà©\80 à¨¨à¨¿à¨\97ਰਾਨà©\80-ਸà©\82à¨\9aà©\80 ਵਿਚ ਜੋੜੋ",
        "tooltip-ca-unwatch": "ਇਹ ਸਫ਼ਾ ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ’ਚੋਂ ਹਟਾਓ",
        "tooltip-search": "{{SITENAME}} ’ਤੇ ਖੋਜੋ",
        "tooltip-search-go": "ਠੀਕ ਇਸ ਨਾਮ ਵਾਲੇ ਪੰਨੇ ’ਤੇ ਜਾਉ, ਜੇ ਮੌਜੂਦ ਹੈ ਤਾਂ",
        "tooltip-n-mainpage-description": "ਮੁੱਖ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ",
        "tooltip-n-portal": "ਪ੍ਰੋਜੈਕਟ ਬਾਰੇ, ਤੁਸੀਂ ਕੀ ਕਰ ਸਕਦੇ ਹੋ, ਕਿੱਥੇ ਕੁਝ ਲੱਭਣਾ ਹੈ",
        "tooltip-n-currentevents": "ਹਾਲ ਦੀਆਂ ਘਟਨਾਵਾਂ ਬਾਰੇ ਪਿਛੋਕੜੀ ਜਾਣਕਾਰੀ ਲੱਭੋ",
-       "tooltip-n-recentchanges": "ਵਿਕੀ ਵਿਚ ਹਾਲ ਵਿੱਚ ਹੋਈਆਂ ਤਬਦੀਲੀਆਂ ਦੀ ਸੂਚੀ",
+       "tooltip-n-recentchanges": "ਵਿà¨\95à©\80 à¨µà¨¿à©±à¨\9a à¨¹à¨¾à¨² à¨µà¨¿à©±à¨\9a à¨¹à©\8bà¨\88à¨\86à¨\82 à¨¤à¨¬à¨¦à©\80ਲà©\80à¨\86à¨\82 à¨¦à©\80 à¨¸à©\82à¨\9aà©\80",
        "tooltip-n-randompage": "ਇੱਕ ਰਲ਼ਵਾਂ ਸਫ਼ਾ ਲੋਡ ਕਰੋ",
        "tooltip-n-help": "ਖੋਜਣ ਲਈ ਥਾਂ",
        "tooltip-t-whatlinkshere": "ਵਿਕੀ ਦੇ ਸਾਰੇ ਸਫ਼ਿਆ ਦੀ ਸੂਚੀ, ਜੋ ਇੱਥੇ ਜੋੜਦੇ ਹਨ",
        "pageinfo-length": "ਸਫ਼ੇ ਦੀ ਲੰਬਾਈ (ਬਾਈਟਾਂ ਵਿਚ)",
        "pageinfo-article-id": "ਸਫ਼ੇ ਦੀ ਸ਼ਨਾਖ਼ਤ",
        "pageinfo-language": "ਸਫ਼ੇ ਦੀ ਸਮੱਗਰੀ ਦੀ ਭਾਸ਼ਾ",
-       "pageinfo-robot-policy": "à¨\87à©°à¨\9cਨ à¨¦à©\80 à¨¹à¨¾à¨²à¨¤ à¨\96à©\8bà¨\9cà©\8b",
+       "pageinfo-robot-policy": "ਰà©\8bਬà©\8bà¨\9f à¨¦à©\81à¨\86ਰਾ à¨\87ੰਡà©\88à¨\95ਸਿੰà¨\97",
        "pageinfo-robot-index": "ਮਨਜ਼ੂਰ ਹੈ",
        "pageinfo-robot-noindex": "ਨਾ-ਮਨਜ਼ੂਰ",
        "pageinfo-watchers": "ਸਫ਼ੇ ’ਤੇ ਨਜ਼ਰ ਰੱਖਣ ਵਾਲਿਆਂ ਦੀ ਗਿਣਤੀ",
        "watchlistedit-raw-done": "ਤੁਹਾਡੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਅੱਪਡੇਟ ਹੋ ਗਈ ਹੈ।",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕੀਤਾ|$1 ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕੀਤੇ}}:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 ਸਿਰਲੇਖ ਹਟਾਇਆ|$1 ਸਿਰਲੇਖ ਹਟਾਏ}}:",
+       "watchlistedit-clear-title": "ਨਿਗਰਾਨ-ਸੂਚੀ ਸਾਫ਼ ਕਰੋ",
+       "watchlistedit-clear-legend": "ਨਿਗਰਾਨ-ਸੂਚੀ ਸਾਫ਼ ਕਰੋ",
        "watchlistedit-clear-titles": "ਸਿਰਲੇਖ:",
        "watchlistedit-clear-submit": "ਨਿਗਰਾਨ-ਸੂਚੀ ਸਾਫ਼ ਕਰੋ (ਇਹ ਪੱਕੇ ਤੌਰ 'ਤੇ ਹੈ!)",
        "watchlistedit-clear-done": "ਤੁਹਾਡੀ ਨਿਗਰਾਨ-ਸੂਚੀ ਸਾਫ਼ ਕਰ ਦਿੱਤੀ ਗਈ ਹੈ।",
        "watchlisttools-edit": "ਨਿਗਰਾਨੀ-ਸੂਚੀ ਵੇਖੋ ’ਤੇ ਸੋਧੋ",
        "watchlisttools-raw": "ਕੱਚੀ ਨਿਗਰਾਨ-ਸੂਚੀ ਸੋਧੋ",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ਗੱਲ-ਬਾਤ]])",
+       "timezone-local": "ਸਥਾਨਕ",
        "duplicate-defaultsort": "ਪੁਰਾਣੀ ਮੂਲ ਕਰਮਾਂਕਨ ਕੁੰਜੀ $1 ਦੇ ਬਜਾਏ ਹੁਣ ਮੂਲ ਕਰਮਾਂਕਨ ਕੁੰਜੀ $2 ਹੋਵੇਗੀ।",
        "version": "ਵਰਜਨ",
        "version-skins": "ਥਾਪੀਆਂ ਖੱਲਾਂ",
        "version-software-version": "ਵਰਜਨ",
        "version-entrypoints-header-entrypoint": "ਦਾਖ਼ਲਾ ਬਿੰਦੂ",
        "version-entrypoints-header-url": "ਯੂ.ਆਰ.ਐੱਲ",
+       "version-libraries-library": "ਪੁਸਤਕਾਲਾ",
+       "version-libraries-version": "ਵਰਜਨ",
+       "version-libraries-license": "ਲਸੰਸ",
+       "version-libraries-description": "ਵੇਰਵਾ",
+       "version-libraries-authors": "ਲੇਖਕ",
        "redirect-submit": "ਜਾਓ",
        "redirect-lookup": "ਲੱਭੋ:",
        "redirect-value": "ਮੁੱਲ:",
        "specialpages-group-wiki": "ਸਮੱਗਰੀ ਅਤੇ ਸੰਦ",
        "specialpages-group-redirects": "ਖ਼ਾਸ ਸਫ਼ੇ ਰੀਡਿਰੈਕਟ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ",
        "specialpages-group-spam": "ਸਪੈਮ ਦੇ ਸੰਦ",
+       "specialpages-group-developer": "ਡਿਵੈਲਪਰ ਸੰਦ",
        "blankpage": "ਖ਼ਾਲੀ ਸਫ਼ਾ",
        "intentionallyblankpage": "ਇਹ ਸਫ਼ਾ ਜਾਣ-ਬੁੱਝ ਕੇ ਖ਼ਾਲੀ ਛੱਡਿਆ ਗਿਆ ਹੈ।",
        "external_image_whitelist": " #ਇਸ ਲਾਈਨ ਨੂੰ ਇੰਝ ਹੀ ਰਹਿਣ ਦਿਓ <pre>\n#ਹੇਠਾਂ ਓਹੀ ਐਕਸਪ੍ਰੈਸ਼ਨ ਪਾਓ (ਜਿਹੜਾ ਹਿੱਸਾ // ਦੇ ਵਿਚਾਲੇ ਹੈ)\n#ਇਹ ਬਾਹਰੀ ਤਸਵੀਰਾਂ ਦੇ URLs (ਹੌਟਲਿੰਕਡ) ਨਾਲ ਮਿਲਣਗੀਆਂ\n#ਜਿਹੜੀਆਂ ਮਿਲਣਗੀਆਂ ਓਹ ਬਤੌਰ ਤਸਵੀਰਾਂ ਦਿੱਸਣਗੀਆਂ ਨਹੀਂ ਤਾਂ ਤਸਵੀਰ ਦਾ ਸਿਰਫ਼ ਲਿੰਕ ਨਜ਼ਰ ਆਵੇਗਾ\n#'#' ਨਾਲ਼ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲ਼ੀਆਂ ਲਾਈਨਾਂ ਟਿੱਪਣੀਆਂ ਵਾਂਗ ਲਈਆਂ ਜਾਂਦੀਆਂ ਹਨ\n#ਇਹ ਕੇਸ-ਇਨਸੈਂਸਟਿਵ ਹੈ\n\n#ਸਾਰੇ ਰੈਜੈਕਸ ਫ਼ਰੈਗਮੈਂਟ ਇਸ ਲਾਈਨ ਤੋਂ ਉੱਪਰ ਪਾਓ। ਇਸ ਲਾਈਨ ਨੂੰ ਇੰਝ ਹੀ ਰਹਿਣ ਦਿਓ </pre>",
        "tags-title": "ਟੈਗ",
        "tags-tag": "ਟੈਗ ਦਾ ਨਾਮ",
        "tags-description-header": "ਅਰਥ ਦਾ ਪੂਰਾ ਬਿਓਰਾ",
+       "tags-source-header": "ਸਰੋਤ",
        "tags-active-header": "ਸਰਗਰਮ?",
        "tags-hitcount-header": "ਨਿਸ਼ਾਨਦੇਹ ਤਬਦੀਲੀਆਂ",
+       "tags-actions-header": "ਕਾਰਵਾਈਆਂ",
        "tags-active-yes": "ਹਾਂ",
        "tags-active-no": "ਨਹੀਂ",
        "tags-edit": "ਸੋਧੋ",
+       "tags-delete": "ਮਿਟਾਉ",
+       "tags-activate": "ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ",
        "tags-hitcount": "$1 {{PLURAL:$1|ਤਬਦੀਲੀ|ਤਬਦੀਲੀਆਂ}}",
+       "tags-create-reason": "ਕਾਰਨ:",
+       "tags-create-submit": "ਬਣਾਓ",
+       "tags-delete-reason": "ਕਾਰਨ:",
+       "tags-activate-reason": "ਕਾਰਨ:",
+       "tags-activate-submit": "ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ",
+       "tags-deactivate-reason": "ਕਾਰਨ:",
+       "tags-edit-title": "ਟੈਗ ਸੋਧੋ",
+       "tags-edit-remove-all-tags": "(ਸਾਰੇ ਟੈਗ ਹਟਾਓ)",
+       "tags-edit-reason": "ਕਾਰਨ:",
        "comparepages": "ਸਫ਼ੇ ਮਿਲਾਓ",
        "compare-page1": "ਸਫ਼ਾ ੧",
        "compare-page2": "ਸਫ਼ਾ ੨",
        "rightsnone": "(ਕੋਈ ਨਹੀਂ)",
        "revdelete-summary": "ਸੰਖੇਪ ਸੋਧ",
        "feedback-adding": "ਸਫ਼ੇ ਨਾਲ਼ ਵਿਚਾਰ ਜੁੜ ਰਹੇ ਹਨ...",
+       "feedback-back": "ਪਿੱਛੇ",
        "feedback-bugnew": "ਮੈਂ ਚੈੱਕ ਕੀਤਾ। ਇੱਕ ਨਵੇਂ ਦੋਸ਼ ਦੀ ਰਿਪੋਰਟ ਕਰੋ",
        "feedback-cancel": "ਰੱਦ ਕਰੋ",
        "feedback-close": "ਹੋ ਗਿਆ",
+       "feedback-error-title": "ਗ਼ਲਤੀ",
        "feedback-error2": "ਦੋਸ਼:ਸੋਧ ਫੇਲ੍ਹ ਹੋਈ",
        "feedback-error3": "ਦੋਸ਼:API ਵੱਲੋਂ ਕੋਈ ਜੁਆਬ ਨਹੀਂ",
        "feedback-message": "ਸੁਨੇਹਾ:",
        "feedback-subject": "ਵਿਸ਼ਾ:",
        "feedback-submit": "ਹਵਾਲੇ ਕਰੋ",
+       "feedback-thanks-title": "ਧੰਨਵਾਦ!",
+       "feedback-useragent": "ਉਪਭੋਗੀ ਏਜੰਟ:",
        "searchsuggest-search": "ਖੋਜ",
        "api-error-badaccess-groups": "ਤੁਹਾਨੂੰ ਇਸ ਵਿਕੀ ਉੱਤੇ ਫ਼ਾਈਲਾਂ ਅੱਪਲੋਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
        "api-error-badtoken": "ਅੰਦਰੂਨੀ ਦੋਸ਼: ਗ਼ਲਤ ਟੋਕਨ",
        "limitreport-walltime": "ਹਕੀਕੀ ਸਮੇਂ ਦੀ ਵਰਤੋਂ",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|ਸਕਿੰਟ|ਸਕਿੰਟ}}",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|ਬਾਈਟ|ਬਾਈਟ}}",
+       "expand_templates_input": "ਇੰਪੁੱਟ ਪਾਠ:",
        "expand_templates_output": "ਨਤੀਜਾ",
        "expand_templates_ok": "ਠੀਕ ਹੈ",
        "expand_templates_remove_comments": "ਟਿੱਪਣੀਆਂ ਹਟਾਓ",
        "pagelang-language": "ਭਾਸ਼ਾ",
        "pagelang-use-default": "ਮੂਲ ਭਾਸ਼ਾ ਵਰਤੋਂ",
        "pagelang-select-lang": "ਭਾਸ਼ਾ ਚੁਣੋ",
+       "pagelang-submit": "ਭੇਜੋ",
        "right-pagelang": "ਸਫ਼ੇ ਦੀ ਭਾਸ਼ਾ ਬਦਲੋ",
        "action-pagelang": "ਸਫ਼ੇ ਦੀ ਭਾਸ਼ਾ ਬਦਲੋ",
+       "mediastatistics": "ਮੀਡੀਆ ਅੰਕੜੇ",
+       "mediastatistics-table-mimetype": "MIME ਕਿਸਮ:",
        "mediastatistics-table-count": "ਫ਼ਾਈਲਾਂ ਦੀ ਗਿਣਤੀ",
        "mediastatistics-table-totalbytes": "ਮਿਲ਼ਵਾਂ ਅਕਾਰ",
        "mediastatistics-header-unknown": "ਅਣਪਛਾਤਾ",
        "mediastatistics-header-video": "ਵੀਡੀਓਆਂ",
        "mediastatistics-header-office": "ਦਫ਼ਤਰ",
        "mediastatistics-header-text": "ਲਿਖਤੀ",
+       "mediastatistics-header-total": "ਸਾਰੀਆੰ ਫਾਈਲਾੰ",
        "json-error-syntax": "ਵਾਕ-ਵਿਉਂਤ 'ਚ ਦੋਸ਼",
        "special-characters-group-latin": "ਲਾਤੀਨੀ",
        "special-characters-group-latinextended": "ਲਾਤੀਨੀ ਤੋਂ ਛੁੱਟ",
        "special-characters-title-endash": "ਅੰਗਰੇਜ਼ੀ ਡੈਸ਼",
        "special-characters-title-emdash": "em ਡੈਸ਼",
        "special-characters-title-minus": "ਘਟਾਓ ਦਾ ਨਿਸ਼ਾਨ",
+       "mw-widgets-dateinput-no-date": "ਕੋਈ ਮਿਤੀ ਨਹੀਂ ਚੁਣੀ",
+       "mw-widgets-titleinput-description-new-page": "ਸਫ਼ਾ ਹਜੇ ਮੌਜੂਦ ਨਹੀਂ ਹੈ",
+       "log-action-filter-all": "ਸਾਰੇ",
+       "log-action-filter-block-block": "ਪਾਬੰਦੀ",
+       "log-action-filter-block-unblock": "ਪਾਬੰਦੀ ਹਟਾਈ",
+       "authmanager-authplugin-setpass-bad-domain": "ਗਲਤ ਡੋਮੇਨ",
        "authmanager-password-help": "ਪ੍ਰਮਾਣਿਕਤਾ ਲਈ ਪਛਾਣ-ਸ਼ਬਦ।",
        "authmanager-email-label": "ਈਮੇਲ",
        "authmanager-email-help": "ਈਮੇਲ ਪਤਾ",
        "authmanager-realname-label": "ਅਸਲੀ ਨਾਂ",
+       "authmanager-realname-help": "ਇਸ ਉਪਭੋਗੀ ਦਾ ਅਸਲ ਨਾਮ",
+       "authmanager-provider-temporarypassword": "ਆਰਜ਼ੀ ਪਾਸਵਰਡ",
        "authprovider-resetpass-skip-label": "ਛੱਡ ਦਿਉ",
+       "authform-wrongtoken": "ਗਲਤ ਟੋਕਨ",
        "specialpage-securitylevel-not-allowed-title": "ਇਜਾਜ਼ਤ ਨਹੀਂ",
        "cannotauth-not-allowed-title": "ਪ੍ਰਵਾਨਗੀ ਨਹੀਂ ਮਿਲੀ",
        "credentialsform-account": "ਖਾਤੇ ਦਾ ਨਾਂ:"
index 1612248..2e10b6a 100644 (file)
        "tagline": "Z {{GRAMMAR:D.lp|{{SITENAME}}}}",
        "help": "Pomoc",
        "search": "Szukaj",
+       "search-ignored-headings": " #<!-- ten wiersz zostaw bez zmian --> <pre>\n# Umieszczone tutaj nagłówki będą ignorowane podczas wyszukiwania.\n# Zmiany wprowadzone tutaj zostaną zastosowane, gdy strona wykorzystująca odpowiedni nagłówek zostanie zindeksowana.\n# Można wymusić ponowne zindeksowanie strony wykonując na niej null edit.\n# Składnia jest następująca:\n#   * Wszystko począwszy od znaku „#” aż do końca wiersza jest komentarzem.\n#   * Każdy niepusty wiersz wprowadza dokładną treść nagłówka, który należy zignorować, wielkość liter ma znaczenie.\nLinki zewnętrzne\nZobacz też\n #</pre> <!-- ten wiersz zostaw bez zmian -->",
        "searchbutton": "Szukaj",
        "go": "Przejdź",
        "searcharticle": "Przejdź",
        "watchnologin": "Nie jesteś zalogowany",
        "addwatch": "Dodaj do listy obserwowanych",
        "addedwatchtext": "Strona „[[:$1|$1]]” wraz ze swoją stroną dyskusji została dodana do Twojej [[Special:Watchlist|listy obserwowanych]].",
+       "addedwatchtext-talk": "Strona „[[:$1]]” i strony z nią związane zostały dodane do Twojej [[Special:Watchlist|listy obserwowanych]].",
        "addedwatchtext-short": "Strona „$1” została dodana do twojej listy obserwowanych.",
        "removewatch": "Usuń z listy obserwowanych",
        "removedwatchtext": "Strona „[[:$1|$1]]” wraz ze swoją stroną dyskusji została usunięta z Twojej [[Special:Watchlist|listy obserwowanych]].",
+       "removedwatchtext-talk": "Strona „[[:$1]]” i strony z nią związane zostały usunięte z Twojej [[Special:Watchlist|listy obserwowanych]].",
        "removedwatchtext-short": "Strona „$1” została usunięta z twojej listy obserwowanych.",
        "watch": "Obserwuj",
        "watchthispage": "Obserwuj",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Usunąć tę stronę z listy obserwowanych?",
        "confirm-rollback-button": "OK",
+       "confirm-rollback-top": "Wycofać edycje tej strony?",
        "percent": "$1%",
        "quotation-marks": "„$1”",
        "imgmultipageprev": "← poprzednia strona",
        "timezone-local": "Czas lokalny",
        "duplicate-defaultsort": "Uwaga: Domyślnym kluczem sortowania będzie „$2” i zastąpi on wcześniej wykorzystywany klucz „$1”.",
        "duplicate-displaytitle": "<strong>Uwaga:</strong> Wyświetlenie tytułu „$2” powoduje nadpisanie wcześniej wyświetlanego tytułu „$1”.",
+       "restricted-displaytitle": "<strong>Ostrzeżenie:</strong> Tytuł do wyświetlania \"$1\" został zignorowany, ponieważ nie jest odpowiednikiem aktualnego tytułu tej strony.",
        "invalid-indicator-name": "<strong>Błąd:</strong> Atrybut stanu strony <code>name</code> nie może być pusty.",
        "version": "Wersja oprogramowania",
        "version-extensions": "Zainstalowane rozszerzenia",
        "tags-deactivate": "dezaktywuj",
        "tags-hitcount": "$1 {{PLURAL:$1|zmiana|zmiany|zmian}}",
        "tags-manage-no-permission": "Nie masz uprawnień do zarządzania znacznikami.",
+       "tags-manage-blocked": "Nie możesz zarządzać znacznikami zmian, kiedy jesteś zablokowany.",
        "tags-create-heading": "Utwórz nowy znacznik",
        "tags-create-explanation": "Nowe znaczniki będą dostępne domyślnie dla użytkowników i botów.",
        "tags-create-tag-name": "Nazwa znacznika:",
        "tags-delete-not-found": "Znacznik „$1” nie istnieje.",
        "tags-delete-too-many-uses": "Znacznik „$1” jest stosowany w więcej niż {{PLURAL:$2|jednej wersji|$2 wersjach}}, co oznacza, że nie może być usunięty.",
        "tags-delete-warnings-after-delete": "Znacznik „$1” został usunięty, ale {{PLURAL:$2|otrzymano następujące ostrzeżenie|otrzymano następujące ostrzeżenia}}:",
+       "tags-delete-no-permission": "Nie masz uprawnień do usuwania znaczników zmian.",
        "tags-activate-title": "Aktywacja znacznika",
        "tags-activate-question": "Zamierzasz aktywować znacznik „$1”.",
        "tags-activate-reason": "Powód:",
        "tags-deactivate-not-allowed": "Nie można dezaktywować znacznika „$1”.",
        "tags-deactivate-submit": "Dezaktywuj",
        "tags-apply-no-permission": "Nie masz uprawnień do wprowadzania znaczników wraz z własnymi zmianami.",
+       "tags-apply-blocked": "Nie możesz stosować znaczników do swoich zmian, gdy jesteś zablokowany.",
        "tags-apply-not-allowed-one": "Znacznik „$1” nie może zostać wprowadzony ręcznie.",
        "tags-apply-not-allowed-multi": "{{PLURAL:$2|Następujący znacznik nie może zostać wprowadzony ręcznie|Następujące znaczniki nie mogą zostać wprowadzone ręcznie}}: $1",
        "tags-update-no-permission": "Nie masz uprawnień do dodawania lub usuwania znaczników z poszczególnych wersji lub wpisów w rejestrze.",
+       "tags-update-blocked": "Nie możesz dodawać i usuwać znaczników zmian, kiedy jesteś zablokowany.",
        "tags-update-add-not-allowed-one": "Znacznik „$1” nie może zostać dodany ręcznie.",
        "tags-update-add-not-allowed-multi": "{{PLURAL:$2|Następujący znacznik nie może zostać dodany ręcznie|Następujące znaczniki nie mogą zostać dodane ręcznie}}: $1",
        "tags-update-remove-not-allowed-one": "Znacznika „$1” nie można usunąć.",
        "api-error-nomodule": "Błąd wewnętrzny – nie określono modułu przesyłania plików.",
        "api-error-ok-but-empty": "Błąd wewnętrzny – brak odpowiedzi od serwera.",
        "api-error-overwrite": "Nadpisanie istniejącego pliku nie jest dopuszczalne.",
+       "api-error-ratelimited": "Próbujesz przesłać więcej plików w krótszym odstępie czasowym, niż ta wiki na to pozwala.\nSpróbuj jeszcze raz za kilka minut.",
        "api-error-stashfailed": "Błąd wewnętrzny – serwer nie mógł zapisać pliku tymczasowego.",
        "api-error-publishfailed": "Błąd wewnętrzny: serwer nie mógł zapisać pliku tymczasowego.",
        "api-error-stasherror": "Wystąpił błąd podczas przesyłania pliku.",
        "mw-widgets-titleinput-description-new-page": "strona jeszcze nie istnieje",
        "mw-widgets-titleinput-description-redirect": "przekierowanie do $1",
        "sessionmanager-tie": "Nie można łączyć kilku rodzajów uwierzytelniania dla zapytania: $1.",
+       "sessionprovider-generic": "sesje $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesje na podstawie cookie",
        "sessionprovider-nocookies": "Być może cookies są wyłączone. Upewnij się, że masz włączone cookies i zacznij od nowa.",
        "randomrootpage": "Losowa strona (bez podstron)",
index c0018be..3ae5be0 100644 (file)
        "tagline": "Da {{SITENAME}}.",
        "help": "Agiut",
        "search": "Sërché",
+       "search-ignored-headings": " #<!-- lassé costa linia 'me ch'a l'é --> <pre>\n# Antestassion ch'a saran ignorà da l'arserca.\n# Le modìfiche a sòn a l'han efet pen-a che la pàgina con l'antestassion a l'é indicisà.\n# A peul forsé la riandesassion ëd la pàgina an fasend na modìfica veuida.\n# La sintassi a l'é costa-sì:\n#   * Tut a parte da 'n caràter «#» a l'é un coment.\n#   * Tuta linia nen veuida a l'é ël tìtol precis da ignoré, caràter majùscoj o minùscoj comprèis.\nArferiment\nLiure esterne\nVëdde ëdcò\n #</pre> <!-- lassé costa linia 'me ch'a l'é -->",
        "searchbutton": "Sërché",
        "go": "Andé",
        "searcharticle": "Andé",
        "special-characters-title-minus": "segn meno",
        "mw-widgets-dateinput-placeholder-day": "AAAA-MM-DD",
        "mw-widgets-dateinput-placeholder-month": "AAAA-MM",
-       "api-error-blacklisted": "Për piasì sern un tìtol diferent, descritiv.",
        "randomrootpage": "Pàgina root a cas"
 }
index 6589316..a7709b6 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ajuda",
        "search": "Pesquisa",
+       "search-ignored-headings": " #<!-- deixe esta linha exatamente como está --> <pre>\n# Subtítulos que serão ignorados pela busca.\n# Mudanças feitas aqui têm efeito quando a página com o subtítulo é indexada.\n# Você pode forçar a reindexação realizando uma edição nula.\n# A sintaxe é a seguinte:\n#   * Tudo a partir do caractere \"#\" até o final da linha é um comentário\n#   * Cada linha não vazia é o título exato a ser ignorado, inclusive no uso de maiúsculas\nReferências\nLigações externas\nVer também\n #</pre> <!-- deixe esta linha exatamente como está -->",
        "searchbutton": "Pesquisar",
        "go": "Ir",
        "searcharticle": "Ir",
        "minoredit": "Marcar como edição menor",
        "watchthis": "Vigiar esta página",
        "savearticle": "Salvar página",
+       "publishpage": "Publicar página",
+       "publishchanges": "Publicar alterações",
        "preview": "Pré-visualização",
        "showpreview": "Mostrar previsão",
        "showdiff": "Mostrar alterações",
        "feedback-thanks-title": "Obrigado!",
        "feedback-useragent": "Agente de usuário:",
        "searchsuggest-search": "Pesquisa",
-       "searchsuggest-containing": "contendo...",
+       "searchsuggest-containing": "páginas contendo…",
        "api-error-badaccess-groups": "Você não tem permissão para enviar arquivos para este wiki.",
        "api-error-badtoken": "Erro interno: token inválido.",
        "api-error-copyuploaddisabled": "O upload por URL está desativado neste servidor.",
index bcf24fd..3a0cfb0 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ajuda",
        "search": "Pesquisa",
+       "search-ignored-headings": " #<!-- deixe esta linha exatamente como ela está --> <pre>\n# Títulos de página que serão ignorados pela pesquisa.\n# Mudanças a esta lista terão efeito quando a página com o título referido for indexada.\n# Pode forçar a indexação de uma página realizando uma edição nula nessa página.\n# A sintaxe é a seguinte:\n#  * Tudo desde um símbolo de cardinal (#) até ao fim da linha é um comentário\n#  * Cada linha não vazia é o título exato a ignorar, respeitando o uso de maiúsculas\nReferências\nLinks externos\nVer também\n #</pre> <!-- deixe esta linha exatamente como ela está -->",
        "searchbutton": "Pesquisar",
        "go": "Ir",
        "searcharticle": "Ir",
        "title-invalid-interwiki": "O título da página solicitada contém uma ligação interlíngua que não pode ser utilizada em títulos.",
        "title-invalid-talk-namespace": "O título da página solicitada refere-se a uma página de discussão que não existe.",
        "title-invalid-characters": "O título da página solicitada contém carateres inválidos: \"$1\".",
+       "title-invalid-relative": "O título contém um caminho relativo. Os títulos relativos (./, ../) são inválidos porque estarão inacessíveis muitas vezes ao serem carregados pelo navegador do utilizador.",
        "title-invalid-magic-tilde": "O título da página solicitada possui uma sequência de tis inválida (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "O título da página solicitada é demasiado longo. Não deverá ser maior que $1 {{PLURAL:$1|byte|bytes}} na codificação UTF-8.",
        "title-invalid-leading-colon": "O título da página solicitada contém um erro de pontuação (:) no início.",
        "createaccountreason": "Motivo:",
        "createacct-reason": "Motivo",
        "createacct-reason-ph": "Porque está a criar outra conta",
+       "createacct-reason-help": "Mensagem mostrada no registo de criação de contas",
        "createacct-submit": "Crie a sua conta",
        "createacct-another-submit": "Criar conta",
        "createacct-continue-submit": "Continuar criação de conta",
        "nocookiesnew": "A conta de utilizador foi criada, mas neste momento não tem sessão iniciada.\nA {{SITENAME}} utiliza ''cookies'' para autenticar os utilizadores.\nOs ''cookies'' estão desativados no seu navegador.\nAtive-os e inicie sessão com o seu nome de utilizador e a sua palavra-passe, por favor.",
        "nocookieslogin": "A {{SITENAME}} utiliza ''cookies'' para autenticar os utilizadores.\nOs ''cookies'' estão desativados no seu navegador.\nAtive-os e tente novamente, por favor.",
        "nocookiesfornew": "A conta de utilizador não foi criada, porque não foi possível confirmar a sua origem.\nCertifique-se de que tem os ''cookies'' ativados, recarregue esta página e tente novamente.",
+       "createacct-loginerror": "A conta foi criada com êxito, mas não pôde ser autenticado automaticamente. Por favor, faça o [[Special:UserLogin|início de sessão manualmente]].",
        "noname": "Não especificou um nome de utilizador válido.",
        "loginsuccesstitle": "Autenticação bem sucedida",
        "loginsuccess": "'''Encontra-se agora ligado à {{SITENAME}} como \"$1\"'''.",
        "action-managechangetags": "criar e (des)ativar etiquetas",
        "action-applychangetags": "aplicar etiquetas juntamente com as suas alterações",
        "action-changetags": "adicionar e remover etiquetas arbitrárias em revisões e entradas de registo individuais",
+       "action-purge": "recarregar esta página",
        "nchanges": "$1 {{PLURAL:$1|alteração|alterações}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
        "enhancedrc-history": "histórico",
        "apisandbox-submit-invalid-fields-title": "Alguns campos são inválidos",
        "apisandbox-submit-invalid-fields-message": "Por favor, corrija os campos marcados e tente novamente.",
        "apisandbox-results": "Resultados",
+       "apisandbox-sending-request": "A enviar solicitação de API...",
+       "apisandbox-loading-results": "A receber resultados da API...",
        "apisandbox-request-url-label": "URL do pedido:",
        "apisandbox-request-time": "Tempo de processamento: {{PLURAL:$1|$1 ms}}",
        "apisandbox-alert-field": "O valor deste campo não é válido.",
        "watchnologin": "Não está autenticado(a)",
        "addwatch": "Adicionar às páginas vigiadas",
        "addedwatchtext": "\"[[:$1]]\" e a sua página de discussão foram adicionadas à sua [[Special:Watchlist|lista de páginas vigiadas]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" e a sua página associada foram adicionadas à sua lista de [[Special:Watchlist|páginas vigiadas]].",
        "addedwatchtext-short": "A página \"$1\" foi adicionada à sua lista de vigiadas.",
        "removewatch": "Remover das páginas vigiadas",
        "removedwatchtext": "\"[[:$1]]\" e a sua página de discussão foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" e a sua página associada foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
        "removedwatchtext-short": "A página \"$1\" foi removida da sua lista de vigiadas.",
        "watch": "Vigiar",
        "watchthispage": "Vigiar esta página",
        "changecontentmodel-success-text": "O tipo de conteúdo de [[:$1]] foi alterado.",
        "changecontentmodel-cannot-convert": "O conteúdo em [[:$1]] não pode ser convertido para um tipo de $2.",
        "changecontentmodel-nodirectediting": "O modelo de conteúdo $1 não suporta edição direta",
+       "changecontentmodel-emptymodels-title": "Não há modelos de conteúdo disponíveis",
+       "changecontentmodel-emptymodels-text": "O conteúdo em [[:$1]] não pode ser convertido para qualquer tipo.",
        "log-name-contentmodel": "Registo de alteração de modelo de conteúdo",
        "log-description-contentmodel": "Eventos relacionados com os modelos de conteúdo de uma página",
        "logentry-contentmodel-new": "$1 {{GENDER:$2|criou}} a página $3 com o modelo de conteúdo desconhecido \"$5\"",
        "lockdbsuccesstext": "A base de dados da {{SITENAME}} foi bloqueada.<br />\nLembre-se de [[Special:UnlockDB|remover o bloqueio]] após a manutenção.",
        "unlockdbsuccesstext": "A base de dados foi desbloqueada.",
        "lockfilenotwritable": "O ficheiro de bloqueio da base de dados não pode ser escrito.\nPara bloquear ou desbloquear a base de dados, este precisa de poder ser escrito pelo servidor de internet.",
+       "databaselocked": "A base de dados já está bloqueada.",
        "databasenotlocked": "A base de dados não está bloqueada.",
        "lockedbyandtime": "(por {{GENDER:$1|$1}} em $2 às $3)",
        "move-page": "Mover $1",
        "timezone-local": "Local",
        "duplicate-defaultsort": "<strong>Aviso:</strong> A chave de ordenação padrão \"$2\" sobrepõe-se à anterior \"$1\".",
        "duplicate-displaytitle": "<strong>Aviso:</strong> O título em exibição \"$2\" anula o título anteriormente em exibição \"$1\".",
+       "restricted-displaytitle": "<strong>Aviso</strong>: A apresentação do título \"$1\" foi ignorada porque não é equivalente ao título atual da página.",
        "invalid-indicator-name": "<strong>Erro:</strong> O atributo <code>name</code>, da página de estados, não deve estar em branco.",
        "version": "Versão",
        "version-extensions": "Extensões instaladas",
        "version-license-not-found": "Não foi encontrada informação detalhada da licença para esta extensão.",
        "version-credits-title": "Créditos de autoria da extensão $1",
        "version-credits-not-found": "Não foi encontrada informação detalhada dos créditos para esta extensão.",
-       "version-poweredby-credits": "Esta wiki é potenciada por <strong>[https://www.mediawiki.org/ MediaWiki]</strong>, copyright © 2001-$1 $2.",
+       "version-poweredby-credits": "Este é um wiki <strong>[https://www.mediawiki.org/ MediaWiki]</strong>, copyright © 2001-$1 $2.",
        "version-poweredby-others": "outros",
        "version-poweredby-translators": "os tradutores da translatewiki.net",
        "version-credits-summary": "Gostaríamos de reconhecer as seguintes pessoas pela sua contribuição para o [[Special:Version|MediaWiki]].",
        "tags-deactivate": "desativar",
        "tags-hitcount": "$1 {{PLURAL:$1|modificação|modificações}}",
        "tags-manage-no-permission": "Não possui permissão para gerir alterações de etiquetas.",
+       "tags-manage-blocked": "Não pode gerir alterações de etiquetas enquanto estiver bloqueado.",
        "tags-create-heading": "Criar nova etiqueta",
        "tags-create-explanation": "Por definição, etiquetas recém-criadas estarão disponíveis para utilização por utilizadores e robôs.",
        "tags-create-tag-name": "Nome da etiqueta:",
        "log-action-filter-managetags-delete": "Eliminação de etiqueta",
        "log-action-filter-managetags-activate": "Ativação de etiqueta",
        "log-action-filter-managetags-deactivate": "Desativação de etiqueta",
+       "log-action-filter-move-move": "Mover sem a substituição de páginas de redirecionamento",
+       "log-action-filter-move-move_redir": "Mover com a substituição de páginas de redirecionamento",
        "log-action-filter-newusers-create": "Criação por utilizador anónimo",
        "log-action-filter-newusers-create2": "Criação por utilizador registado",
        "log-action-filter-newusers-autocreate": "Criação automática",
        "log-action-filter-rights-rights": "Alteração manual",
        "log-action-filter-rights-autopromote": "Alteração automática",
        "log-action-filter-suppress-event": "Supressão de registo",
+       "log-action-filter-suppress-revision": "Supressão de revisões",
        "log-action-filter-suppress-delete": "Supressão de página",
+       "log-action-filter-suppress-block": "Supressão de utilizadores por bloqueio",
        "log-action-filter-upload-upload": "Novo carregamento",
        "log-action-filter-upload-overwrite": "Recarregar",
        "authmanager-create-disabled": "A criação de contas está desativada.",
        "authmanager-create-from-login": "Para criar a sua conta, por favor, preencha os campos abaixo.",
+       "authmanager-authplugin-setpass-failed-title": "A alteração de palavra-passe falhou",
+       "authmanager-authplugin-setpass-failed-message": "O plugin de autenticação negou a alteração de palavra-passe.",
+       "authmanager-authplugin-create-fail": "O plugin de autenticação negou a criação de conta.",
+       "authmanager-authplugin-setpass-denied": "O plugin de autenticação não permite a alteração de palavras-passe.",
        "authmanager-authplugin-setpass-bad-domain": "Domínio inválido.",
+       "authmanager-autocreate-noperm": "A criação automática de contas não é permitida.",
+       "authmanager-autocreate-exception": "A criação automática de contas foi temporariamente desativada devido a erros prévios.",
        "authmanager-userdoesnotexist": "A conta de utilizador(a) \"$1\" não está registada.",
        "authmanager-username-help": "Nome de utilizador(a) para autenticação.",
        "authmanager-password-help": "Palavra-passe para autenticação.",
        "authmanager-email-help": "Endereço de correio eletrónico",
        "authmanager-realname-label": "Nome verdadeiro",
        "authmanager-realname-help": "Nome verdadeiro do(a) utilizador(a)",
+       "authmanager-provider-password": "Autenticação baseada em palavra-passe",
+       "authmanager-provider-password-domain": "Autenticação baseada em palavra-passe e domínio",
+       "authmanager-provider-temporarypassword": "Palavra-passe temporária",
+       "authprovider-confirmlink-message": "Com base nas tuas últimas tentativas para iniciar sessão, as seguintes contas podem ser ligadas à tua conta wiki. Vinculá-las permite que inicie sessão através das mesmas. Selecione quais pretende vincular.",
+       "authprovider-confirmlink-success-line": "$1: Ligado com êxito.",
        "authprovider-resetpass-skip-label": "Ignorar",
+       "authprovider-resetpass-skip-help": "Ignorar redefinição de palavra-passe",
+       "authform-newtoken": "Chave em falta. $1",
+       "authform-notoken": "Chave em falta",
+       "authform-wrongtoken": "Chave errada",
+       "specialpage-securitylevel-not-allowed-title": "Não permitido",
+       "specialpage-securitylevel-not-allowed": "Desculpe, não tem permissão para utilizar esta página porque a sua identidade não pôde ser verificada.",
        "authpage-cannot-login": "Não é possível iniciar sessão.",
        "authpage-cannot-login-continue": "Não é possível continuar a iniciar sessão. A sua sessão pode ter expirado.",
        "authpage-cannot-create": "Não é possível iniciar a criação da conta.",
index 099504d..1e8db1e 100644 (file)
                        "Guycn2",
                        "2axterix2",
                        "Ата",
-                       "Matěj Suchánek"
+                       "Matěj Suchánek",
+                       "Chaduvari"
                ]
        },
        "sidebar": "{{notranslate}}",
        "tagline": "{{doc-important|Do not change <code><nowiki>{{SITENAME}}</nowiki></code>.}}\nUsed to identify the source of copied information.",
        "help": "General text (noun) used in the sidebar (by default).\n\nSee also {{msg-mw|Helppage}} and {{msg-mw|Edithelp}}.\n\nSee also:\n* {{msg-mw|Help}}\n* {{msg-mw|Accesskey-n-help}}\n* {{msg-mw|Tooltip-n-help}}\n{{Identical|Help}}",
        "search": "{{doc-special|Search}}\nNoun. Text of menu section shown on every page of the wiki above the search form.\n\nSee also:\n* {{msg-mw|Search}}\n* {{msg-mw|Accesskey-search}}\n* {{msg-mw|Tooltip-search}}\n{{Identical|Search}}",
+       "search-ignored-headings": "Headings that will be ignored by search. You can translate the text, including \"Leave this line exactly as it is\". Some lines of this messages have one (1) leading space.",
        "searchbutton": "The button you can see in the sidebar, below the search input box. The \"Go\" button is {{msg-mw|Searcharticle}}.\n{{Identical|Search}}",
        "go": "See also:\n* {{msg-mw|Go}}\n* {{msg-mw|Accesskey-search-go}}\n* {{msg-mw|Tooltip-search-go}}\n{{Identical|Go}}",
        "searcharticle": "Button description in the search menu displayed on every page. The \"Search\" button is {{msg-mw|Searchbutton}}.\n{{Identical|Go}}",
        "resetpass-abort-generic": "Generic error message shown on [[Special:ChangePassword]] when an extension aborts a password change from a hook.",
        "resetpass-expired": "Generic error message shown on [[Special:ChangePassword]] when a user's password is expired",
        "resetpass-expired-soft": "Generic warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, but they are not prevented from logging in at this time",
-       "resetpass-validity-soft": "Warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, because their password is not valid.\n\nRefers to {{msg-mw|Resetpass-submit-cancel}}.\n\nParameters:\n* $1 - error message",
+       "resetpass-validity-soft": "Warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, because their password is not valid.\n\nRefers to {{msg-mw|authprovider-resetpass-skip-label}}.\n\nParameters:\n* $1 - error message",
        "passwordreset": "Title of [[Special:PasswordReset]].\n{{Identical|Reset password}}",
        "passwordreset-text-one": "Text on [[Special:PasswordReset]] that appears when there is only one way of resetting the password.\n\n{{msg-mw|Passwordreset-text-many}} will be used, when there are multiple ways of resetting the password.",
        "passwordreset-text-many": "Text on [[Special:PasswordReset]] that appears when there are multiple ways of resetting the password.\n\nParameters:\n* $1 - the number of password reset routes\n\n{{msg-mw|Passwordreset-text-one}} will be used, when there is only one way of resetting the password.",
        "passwordreset-emailelement": "This is a body of a password reset email to allow them into the system with a new password. Parameters:\n* $1 - the user's login name. This parameter can be used for GENDER.\n* $2 - the temporary password given by the system",
        "passwordreset-emailsentemail": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-emailsentusername": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
-       "passwordreset-emailsent-capture": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
-       "passwordreset-emailerror-capture": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}",
        "passwordreset-emailsent-capture2": "Used in [[Special:PasswordReset]].\n\nParameters:\n* $1 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-emailerror-capture2": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\n* $3 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-nocaller": "Shown when a password reset was requested but the caller was not provided. This is an internal error.",
        "changeemail": "Title of [[Special:ChangeEmail|special page]]. This page also allows removing the user's email address.",
        "changeemail-summary": "{{ignored}}",
        "changeemail-header": "Text of [[Special:ChangeEmail]].",
-       "changeemail-passwordrequired": "Shown on [[Special:ChangeEmail]] if users are required to enter their password to change their email address..",
        "changeemail-no-info": "Error message for [[Special:ChangeEmail]].\n\nParameters:\n* $1 (unused) - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description",
        "changeemail-oldemail": "Label for e-mail address field in [[Special:ChangeEmail]].",
        "changeemail-newemail": "Label for e-mail address field in [[Special:ChangeEmail]]. See also {{msg-mw|changeemail-newemail-help}}",
        "watchthis": "Text of checkbox above {{msg-mw|Showpreview}} button in editor.\n\nSee also:\n* {{msg-mw|Watchthis}}\n* {{msg-mw|Accesskey-watch}}\n* {{msg-mw|Tooltip-watch}}\n{{Identical|Watch this page}}",
        "savearticle": "Text on the button to create a new page. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|savechanges}} for the label for the button when the page is being modified.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Save page}}",
        "savechanges": "Text on the button to save the changes to an existing page. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|savearticle}} for the label for the button when the page is being modified.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Save changes}}",
-       "publishpage": "Text on the button to create a new page on a public wiki. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|publishchanges}} for the label for the button when the page is being modified.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Publish page}}",
-       "publishchanges": "Text on the button to save the changes to an existing page on a public wiki. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|publishchanges}} for the label for the button when the page is being created.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Publish changes}}",
+       "publishpage": "పేజీని ప్రచురించు",
+       "publishchanges": "మార్పులను ప్రచురించు",
        "preview": "The title of the Preview page shown after clicking the \"Show preview\" button in the edit page. Since this is a heading, it should probably be translated as a noun and not as a verb.\n\n{{Identical|Preview}}",
        "showpreview": "The text of the button to preview the page you are editing. See also {{msg-mw|showdiff}} and {{msg-mw|savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showpreview}}\n* {{msg-mw|Accesskey-preview}}\n* {{msg-mw|Tooltip-preview}}\n{{Identical|Show preview}}",
        "showdiff": "Button below the edit page. See also {{msg-mw|Showpreview}} and {{msg-mw|Savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showdiff}}\n* {{msg-mw|Accesskey-diff}}\n* {{msg-mw|Tooltip-diff}}\n{{Identical|Show change}}",
        "undo-nochange": "Message appears if an attempt to revert an edit by clicking the \"undo\" link results in an edit making no change to the current version of the page.\n\nSee also:\n* {{msg-mw|Undo-failure}}\n* {{msg-mw|Undo-norev}}",
        "undo-summary": "Edit summary for an undo action. Parameters:\n* $1 - revision ID\n* $2 - username\n{{Identical|Undo}}",
        "undo-summary-username-hidden": "Edit summary for an undo action where the username of the old revision is hidden.\n\nParameters:\n* $1 - the revision ID being undone\nSee also:\n* {{msg-mw|Undo-summary}}",
-       "cantcreateaccounttitle": "Used as title of the error message {{msg-mw|Cantcreateaccount-text}}.",
-       "cantcreateaccount-text": "Used as error message, with the title {{msg-mw|Cantcreateaccounttitle}}.\n* $1 - target IP address\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\nSee also:\n* {{msg-mw|Cantcreateaccount-range-text}}",
+       "cantcreateaccount-text": "Used as error message when account creation is prevented by an IP block.\n* $1 - target IP address\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\nSee also:\n* {{msg-mw|Cantcreateaccount-range-text}}",
        "cantcreateaccount-range-text": "Used instead of the {{msg-mw|Cantcreateaccount-text}} when the block is a range block.\n* $1 - target IP address range\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\n* $4 - current user's IP address",
        "createaccount-hook-aborted": "Placeholder message to return with API errors on account create; passes through the message from a hook {{notranslate}}",
        "viewpagelogs": "Link displayed in history of pages",
        "action-applychangetags": "{{doc-action|applychangetags}}",
        "action-changetags": "{{doc-action|changetags}}",
        "action-deletechangetags": "{{doc-action|deletechangetags}}",
+       "action-purge": "{{doc-action|purge}}",
        "nchanges": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to a diff of the changes.\n\nParameters:\n* $1 - the number of changes on that day (2 or more)\nThree messages are shown side-by-side: ({{msg-mw|Nchanges}} | {{msg-mw|Enhancedrc-since-last-visit}} | {{msg-mw|Enhancedrc-history}}).",
        "enhancedrc-since-last-visit": "Appears on enhanced watchlist and recent changes when page has more than one change on given date and at least one that the user hasn't seen yet, linking to a diff of the unviewed changes.\n\nParameters:\n* $1 - the number of unviewed changes (1 or more)\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).",
        "enhancedrc-history": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to its history.\n\nThis is the same as {{msg-mw|hist}}, but not abbreviated.\n\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).\n{{Identical|History}}",
        "watchlistanontext": "Shown on Special:Userlogin when user tries to access their watchlist before logging in",
        "watchnologin": "Used as error page title.\n\nThe error message for this title is:\n* {{msg-mw|Watchnologintext}}\n{{Identical|Not logged in}}",
        "addwatch": "Link to a dialog box, displayed at the end of the list of categories at the foot of each page.\n\nSee also:\n* {{msg-mw|Removewatch}}",
-       "addedwatchtext": "Explanation shown when clicking on the {{msg-mw|Watch}} tab. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatch}}",
+       "addedwatchtext": "Message shown after clicking on the {{msg-mw|Watch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext}}\n* {{msg-mw|Addedwatchtext-talk}}",
+       "addedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Watch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext-talk}}\n* {{msg-mw|Addedwatchtext}}",
        "addedwatchtext-short": "Explanation shown when watching item from [[Special:UnwatchedPages]].\n\nSee also:\n* {{msg-mw|Removedwatchtext-short}}\n* {{msg-mw|Addedwatchtext}}",
        "removewatch": "Link to a dialog box, displayed at the end of the list of categories at the foot of each page.\n\nSee also:\n* {{msg-mw|Addwatch}}",
-       "removedwatchtext": "After a page has been removed from a user's watchlist by clicking the {{msg-mw|Unwatch}} tab at the top of an article, this message appears just below the title of the article.\n\nParameters:\n* $1 - the title of the article\nSee also:\n* {{msg-mw|Removedwatch}}\n* {{msg-mw|Addedwatchtext}}",
+       "removedwatchtext": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext}}\n* {{msg-mw|Removedwatchtext-talk}}",
+       "removedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext-talk}}\n* {{msg-mw|Removedwatchtext}}",
        "removedwatchtext-short": "Explanation shown when unwatching item from [[Special:UnwatchedPages]].\n\nSee also:\n* {{msg-mw|Addedwatchtext-short}}.\n* {{msg-mw|Removedwatchtext}}.",
        "watch": "{{doc-actionlink}}\nName of the Watch tab. Should be in the imperative mood.\n\nSee also:\n* {{msg-mw|Watch}}\n* {{msg-mw|Accesskey-ca-watch}}\n* {{msg-mw|Tooltip-ca-watch}}",
        "watchthispage": "Used as link text.\n\nSee also:\n* {{msg-mw|Unwatchthispage|link text}}\n* {{msg-mw|Notanarticle|error message}}\n{{Identical|Watch this page}}",
index 6171017..590fc20 100644 (file)
@@ -29,7 +29,8 @@
                        "ImGelu",
                        "Wintereu",
                        "Rsocol",
-                       "Nemo bis"
+                       "Nemo bis",
+                       "Turbojet"
                ]
        },
        "tog-underline": "Sublinierea legăturilor:",
        "tagline": "De la {{SITENAME}}",
        "help": "Ajutor",
        "search": "Căutare",
+       "search-ignored-headings": " #<!-- nu modificați acest rând --> <pre>\n# Titluri de secțiuni care vor fi ignorate de motorul de căutare.\n# Modificările efectuate aici își vor face efectul de îndată ce pagina care conține titlul de secțiune va fi indexată.\n# Puteți forța reindexarea paginii efectuând o modificare vidă.\n# Sintaxa este următoarea:\n#   * Orice rând precedat de caracterul „#” reprezintă un comentariu.\n#   * Orice rând nevid reprezintă exact titlu de secțiune de ignorat.\nReferințe\nLegături externe\nVezi și\n #</pre> <!-- nu modificați acest rând -->",
        "searchbutton": "Căutare",
        "go": "Salt",
        "searcharticle": "Du-te",
        "watchthis": "Urmărește această pagină",
        "savearticle": "Salvare pagină",
        "publishpage": "Publică pagina",
+       "publishchanges": "Publică modificările",
        "preview": "Previzualizare",
        "showpreview": "Previzualizare",
        "showdiff": "Afișare diferențe",
        "mw-widgets-dateinput-placeholder-month": "AAAA-LL",
        "mw-widgets-titleinput-description-new-page": "pagina nu există încă",
        "mw-widgets-titleinput-description-redirect": "redirecționare către $1",
-       "api-error-blacklisted": "Vă rugăm să alegeți un alt titlu, mai descriptiv.",
        "sessionmanager-tie": "Nu se pot combina multiple tipuri de cereri de autentificare: $1.",
        "sessionprovider-generic": "sesiuni $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesiuni pe bază de module cookie.",
index 27535c3..823d0bb 100644 (file)
        "tagline": "Da {{SITENAME}}",
        "help": "Ajute",
        "search": "Cirche",
+       "search-ignored-headings": " #<!-- lasse sta linèe accume ste --> <pre>\n# Testate ca avène scettate jndr'à le ricerche.\n# Le cangiaminde devendane effettive quanne 'a pàgene avène indicizzate.\n# Tu puè forzà 'a reindicizzazzione d'a pàgene facenne 'nu cangiamende vecande.\n# 'A sindasse jè 'a seguende:\n#   * Ogneccose da 'u carattere \"#\" 'nzigne a fine d'a linèe jè 'nu commende\n#   * Ogne linèa chiene jè 'u titole esatte da ignorà, case e ogneccose\nRefereminde\nCollegaminde de fore\n'Ndruche pure\n #</pre> <!-- lasse sta linèe accume ste -->",
        "searchbutton": "Cirche",
        "go": "Véje",
        "searcharticle": "Véje",
        "mw-widgets-dateinput-no-date": "Nisciune date scacchiate",
        "mw-widgets-titleinput-description-new-page": "'a pàgene non g'esiste angore",
        "mw-widgets-titleinput-description-redirect": "redirezionate sus a $1",
-       "api-error-blacklisted": "Pe piacere scacchie 'nu titole diverse, descrittive.",
        "randomrootpage": "Pàgene prengepàle a uecchije"
 }
index a08db09..7a266a8 100644 (file)
        "tagline": "Материал из {{grammar:genitive|{{SITENAME}}}}",
        "help": "Справка",
        "search": "Поиск",
+       "search-ignored-headings": " #<!-- оставьте эту строку как есть --> <pre>\n# Заголовки, которые будут игнорироваться поиском.\n# Изменения вступают в силу, как только страница с заголовком индексируется.\n# Вы можете принудить переиндексировать страницу с помощью нулевой правки.\n# Синтаксис выглядит следующим образом:\n#   * Всё, начинающееся на символ «#» и до конца строки представляет собой комментарий.\n#   * Каждая непустая строка — точное название того, что будет игнорироваться, включая регистр и пр.\nПримечания\nСсылки\nСм. также\n #</pre> <!-- оставьте эту строку как есть -->",
        "searchbutton": "Найти",
        "go": "Перейти",
        "searcharticle": "Перейти",
        "site-atom-feed": "$1 — Atom-лента",
        "page-rss-feed": "«$1» — RSS-лента",
        "page-atom-feed": "«$1» — Atom-лента",
-       "feed-atom": "Атом",
+       "feed-atom": "Atom",
        "red-link-title": "$1 (страница не существует)",
        "sort-descending": "Упорядочить по убыванию",
        "sort-ascending": "Упорядочить по возрастанию",
        "passwordreset-emailerror-capture": "Было создано электронное письмо с информацией о сбросе пароля, текст которого можно увидеть ниже, однако его не удалось отправить {{GENDER:$2|участнику|участнице}} по следующей причине: $1",
        "passwordreset-emailsent-capture2": "{{PLURAL:$1|Письмо|Письма}} для сброса пароля {{PLURAL:$1|было отправлено|были отправлены}}. {{PLURAL:$1|Логин и пароль показаны|Список логинов и паролей показан}} ниже.",
        "passwordreset-emailerror-capture2": "Отправка {{GENDER:$2|участнику}} письма по электронной почте не удалась: $1 В {{PLURAL:$3|логин и пароль показаны|список логинов и паролей показан}} ниже.",
+       "passwordreset-nocaller": "Должен быть предоставлен источник вызова",
+       "passwordreset-nosuchcaller": "Источник вызова не существует: $1",
+       "passwordreset-ignored": "Сброс пароля не был обработан. Может быть, не был настроен ни один провайдер?",
        "passwordreset-invalideamil": "Недопустимый адрес электронной почты",
        "passwordreset-nodata": "Ни имя участника, ни адрес электронной почты не были предоставлены",
        "changeemail": "Изменить или удалить адрес электронной почты",
        "watchthis": "Следить за этой страницей",
        "savearticle": "Записать страницу",
        "savechanges": "Сохранить изменения",
-       "publishpage": "издавать страницу",
-       "publishchanges": "Ð\9eпÑ\83бликоваÑ\82Ñ\8c Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f",
+       "publishpage": "Создать страницу",
+       "publishchanges": "Ð\97апиÑ\81аÑ\82Ñ\8c Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83",
        "preview": "Предпросмотр",
        "showpreview": "Предварительный просмотр",
        "showdiff": "Внесённые изменения",
        "content-json-empty-object": "Пустой объект",
        "content-json-empty-array": "Пустой массив",
        "deprecated-self-close-category": "Страницы, использующие недопустимые самозакрывающеся HTML-теги",
-       "deprecated-self-close-category-desc": "Страница содержит недопустимые самозакрывающиеся HTML-теги, такие как <code>&lt;b/></code> или <code>&lt;span/></code>. В скором времени их действие изменится, чтобы соответствовать спецификации HTML5, так что использование этих устаревших тегов в тексте нежелательно.",
+       "deprecated-self-close-category-desc": "Страница содержит недопустимые самозакрывающиеся HTML-теги, такие как <code>&lt;b/></code> или <code>&lt;span/></code>. В скором времени их действие изменится, чтобы соответствовать спецификации HTML5, так что использование этих устаревших тегов в вики-тексте нежелательно.",
        "duplicate-args-warning": "<strong>Внимание:</strong> [[:$1]] вызывает [[:$2]] с более чем одним значением параметра «$3». Будет использовано только последнее указанное значение.",
        "duplicate-args-category": "Страницы, использующие повторяющиеся аргументы в вызовах шаблонов",
        "duplicate-args-category-desc": "Страницы, содержащие вызовы шаблонов, использующие повторяющиеся аргументы, такие как <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> или <code><nowiki>{{foo|bar|1=bar}}</nowiki></code>.",
        "mergehistory-from": "Исходная страница:",
        "mergehistory-into": "Целевая страница:",
        "mergehistory-list": "Объединяемая история правок",
-       "mergehistory-merge": "СледÑ\83Ñ\8eÑ\89ие Ð²ÐµÑ\80Ñ\81ии [[:$1]] Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¾Ð±Ñ\8aединенÑ\8b Ð² [[:$2]]. Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е Ð¿ÐµÑ\80еклÑ\8eÑ\87аÑ\82ели Ð´Ð»Ñ\8f Ñ\82ого, чтобы объединить только выбранный диапазон правок. Учтите, что использование навигационных ссылок сбросит эту колонку.",
+       "mergehistory-merge": "СледÑ\83Ñ\8eÑ\89ие Ð²ÐµÑ\80Ñ\81ии [[:$1]] Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¿ÐµÑ\80енеÑ\81енÑ\8b Ð² [[:$2]]. Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е Ð¿ÐµÑ\80еклÑ\8eÑ\87аÑ\82ели, чтобы объединить только выбранный диапазон правок. Учтите, что использование навигационных ссылок сбросит эту колонку.",
        "mergehistory-go": "Показать объединяемые правки",
        "mergehistory-submit": "Объединить правки",
        "mergehistory-empty": "Не найдены правки для объединения.",
        "action-applychangetags": " применять теги наряду с Вашими изменениями",
        "action-changetags": "Добавлять и удалять произвольные теги на отдельных изменениях и записях в журнале",
        "action-deletechangetags": "удаление меток из базы данных",
+       "action-purge": "очистку кэша этой страницы",
        "nchanges": "$1 {{PLURAL:$1|изменение|изменения|изменений}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|с последнего посещения}}",
        "enhancedrc-history": "история",
        "log-action-filter-suppress-reblock": "Сокрытие пользователя через повторное блокирование",
        "log-action-filter-upload-upload": "Новая загрузка",
        "log-action-filter-upload-overwrite": "Повторно загрузить",
+       "authmanager-authn-not-in-progress": "Проверка подлинности не выполняется или данные сессии были утеряны. Пожалуйста, начните снова с самого начала.",
        "authmanager-authn-no-primary": "Предоставленные учётные данные не могут быть проверены на подлинность.",
        "authmanager-authn-no-local-user": "Предоставленные учётные данные не связаны ни с одним участником этой вики.",
        "authmanager-authn-no-local-user-link": "Предоставленные учётные данные корректны, но не связаны ни с одни участником этой вики. Войдите с помощью какого-то другого способа или создайте новую учётную запись, и у вас появится возможность привязать свои предыдущие учётные данные к этой учетной записи.",
        "authmanager-authn-autocreate-failed": "Автоматическое создание локальной учётной записи не удалось: $1",
+       "authmanager-change-not-supported": "Предоставленные учётные данные не могут быть изменены, так как они не будут использованы.",
        "authmanager-create-disabled": "Создание учётных записей отключено.",
        "authmanager-create-from-login": "Чтобы создать учётную запись, пожалуйста, заполните приведённые ниже поля.",
        "authmanager-create-not-in-progress": "Создание учётной записи не выполняется или данные сессии были утеряны. Пожалуйста, начните снова с самого начала.",
        "authmanager-autocreate-noperm": "Автоматическое создание учётных записей не разрешено.",
        "authmanager-autocreate-exception": "Автоматическое создание учётной записи временно отключено из-за предыдущих ошибок.",
        "authmanager-userdoesnotexist": "Не зарегистрировано учётной записи «$1».",
+       "authmanager-userlogin-remembermypassword-help": "Будет ли пароль запоминаться на время большее, чем продолжительность сессии.",
        "authmanager-username-help": "Имя участника для проверки подлинности.",
        "authmanager-password-help": "Пароль для проверки подлинности.",
        "authmanager-domain-help": "Домен для внешней аутентификации.",
        "authmanager-provider-password": "Аутентификация на основе пароля",
        "authmanager-provider-password-domain": "Проверка подлинности на основе пароля и домена",
        "authmanager-provider-temporarypassword": "Временный пароль",
+       "authprovider-confirmlink-message": "На основании ваших последних попыткок входа, учётные записи могут быть связаны с вашей учётной записью в вики. Их связывание даёт возможность входа через эти учётные записи. Пожалуйста, выберите, какие из них должны быть связаны между собой.",
        "authprovider-confirmlink-option": "$1 ($2)",
        "authprovider-confirmlink-request-label": "Учётные записи, которые должны быть связаны",
        "authprovider-confirmlink-success-line": "$1: успешно связан.",
        "linkaccounts-success-text": "Учетная запись была связана.",
        "linkaccounts-submit": "Связать учётные записи",
        "unlinkaccounts": "Отвязать учётные записи",
-       "unlinkaccounts-success": "Учетная запись была отвязан."
+       "unlinkaccounts-success": "Учетная запись была отвязан.",
+       "authenticationdatachange-ignored": "Изменение данных для проверки подлинности не было обработано. Может быть, не был настроен ни один провайдер?"
 }
index b85a4d5..985eaa0 100644 (file)
        "tagline": "Fae {{SITENAME}}",
        "help": "Help",
        "search": "Rake",
+       "search-ignored-headings": " #<!-- lea this line exactly aes it is --> <pre>\n# Heidins that will be ignored bi rake.\n# Chynges til this tak effect aes suin aes the page wi the heiding is index't.\n# Ye can force page reindexin bi daeing ae null edit.\n# Syntax is aes follaes:\n#   * Awthin fae ae \"#\" chairacter til the end o the line is ae comment\n#   * Ilka no-blank line is the exact title tae ignore, case an awthin\nReferences\nExternal links\nSee ava\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Rake",
        "go": "Gang",
        "searcharticle": "Gang",
index 7b36ba3..4372c78 100644 (file)
        "newwindow": "(īr atverams naujam longė)",
        "cancel": "Pabengtė",
        "moredotdotdot": "Daugiau...",
-       "morenotlisted": "Tas sārošos ožbengts nie.",
+       "morenotlisted": "Tas sārašos ožbėngts nie.",
        "mypage": "Poslapis",
        "mytalk": "Aptarėms",
        "anontalk": "Aptarėms",
        "media_tip": "Nūruoda abruozdielin",
        "sig_tip": "Tamstas parašos ė čiesos",
        "hr_tip": "Golos briežis (nenauduokat ba rēkala)",
-       "summary": "Pāiškėnėms:",
+       "summary": "Keitėma paāškėnėms:",
        "subject": "Tema/ontraštė:",
        "minoredit": "Mažos pakeitėms",
        "watchthis": "Keravuotė ton poslapė",
-       "savearticle": "Ėšsauguotė poslapė",
+       "savearticle": "Ėšsauguotė poslapi",
        "preview": "Parveiza",
        "showpreview": "Ruodītė parveiza",
        "showdiff": "Ruodītė skėrtomus",
        "protectedpagewarning": "'''DIEMESĖ: Šėts poslapis īr ožrakints ėr anū redagoutė gal tėk admėnėstratuorė teises torėntīs prietelē.'''",
        "semiprotectedpagewarning": "'''Pastebiejėms:''' Šėts poslapis bova ožrakėnts ėr anuo gal redagoutė tėk regėstroutė nauduotojā.",
        "titleprotectedwarning": "'''DIEMESĖ: Tas poslapis bova ožrakėnts tēp, ka tėktās kāpkatrė nauduotuojē galietu ana sokortė.'''",
-       "templatesused": "{{PLURAL:$1|Šabluons, katros|Šabluonā, katrėi}}, īr nauduojamė tamė poslapi:",
+       "templatesused": "{{PLURAL:$1|Šabluons, katros|Šabluonā, katrėi}}, īr nauduojamė tamė poslapie:",
        "templatesusedpreview": "{{PLURAL:$1|Šabluons|Šabluonā}}, nauduotė šėtuo parvaizuo:",
        "templatesusedsection": "Šabluonā, nauduotė šėtom skėrsnelī:",
        "template-protected": "(apsergiets)",
        "permissionserrorstext": "Tamsta netorėt teisiu šėta darītė diel {{PLURAL:$1|tuos prīžastėis|tū prīžastiū}}:",
        "permissionserrorstext-withaction": "Tamsta natorėt leidėma $2 dielē {{PLURAL:$1|tuokės dingstėis|tuokiū dingstiū}}:",
        "recreate-moveddeleted-warn": "'''Parspiejėms: Tamsta ikeliat faila, katros onkstiau bova ėštrėnts.'''\n\nTamsta torietomiet nusprēstė, a īr naudėnga tuoliau ikeldinietė ta faila.\nTuo faila pašalinėma istuorėjė īr pateikta dielē patuogoma:",
-       "moveddeleted-notice": "Tas poslapis bova ėštrints.\nĖštrinta poslapė atmainū sārošos īr douts paveiziejėmō apatiuo.",
+       "moveddeleted-notice": "Tas poslapis bova ėštrints.\nĖštrinta poslapė atmainū sārašos īr douts paveiziejėmō apatiuo.",
        "log-fulllog": "Veizietė vėskon",
        "edit-conflict": "Do keitėmo nesotink.",
        "postedit-confirmation-created": "Poslapis padėrbts.",
        "difference-title-multipage": "Skėrtoms terp poslapiu „$1“ ė „$2“",
        "difference-multipage": "(Skėtroms terp poslapiu)",
        "lineno": "Eilotė $1:",
-       "compareselectedversions": "Pamieruotė pasėrinktus atmainus",
+       "compareselectedversions": "Pamieruotė pasirinktus atmainus",
+       "showhideselectedversions": "Ruodītė/kavuotė atmainus, katrūs pasirinkuot",
        "editundo": "atgrōžintė",
        "diff-empty": "(Nie skėrtoma)",
        "diff-multi-sameuser": "({{PLURAL:$1|Vėins tarpėnis pakeitėms|$1 tarpėnē pakeitėmā|$1 tarpėniu pakeitėmu}}, padėrbtū tuo patė nauduotuojė, nie ruoduoma)",
        "prevn-title": "{{PLURAL:$1|Onkstesnis $1 rezoltats|Onkstesnio $1 rezoltato|Onkstesni $1 rezoltatā}}",
        "nextn-title": "{{PLURAL:$1|Kėts $1 gavėms|Kėtė $1 gavėmā|Kėtū $1 gavėmu}}",
        "shown-title": "Ruodītė $1 {{PLURAL:$1|gavėni|gavėnius|gavėniū}} ont poslapė",
-       "viewprevnext": "Veizėtė ($1 {{int:pipe-separator}} $2) ($3).",
+       "viewprevnext": "Veizietė ($1 {{int:pipe-separator}} $2) ($3).",
        "searchmenu-exists": "'''Poslapis pavadėnts „[[$1]]“ šėtuo wiki'''",
        "searchmenu-new": "<strong>Padėrbtė poslapi, katros vadėntos „[[:$1]]“</strong> {{PLURAL:$2|0=|Dā veiziekat paėiškuo rasta straipsni|Dā veiziekat paėiškuos gavėnius.}}",
        "searchprofile-articles": "Torėnė poslapē",
        "right-delete": "Trintė poslapius",
        "right-browsearchive": "Ėiškuotė ėštrintū poslapiu",
        "right-undelete": "Tou poslapi padėrbtė apent",
-       "newuserlogpage": "Nauduotuojė kūrėma sārošos",
+       "newuserlogpage": "Nauduotuojė kūrėma sārašos",
        "rightslog": "Nauduotuoju teisiu istuorėjė",
        "rightslogtext": "Pateikiams nauduotuoju teisiu pakeitėmu sārašos.",
        "action-read": "skaitītė ton poslapi",
        "enhancedrc-history": "istuorėjė",
        "recentchanges": "Vielībė̄jė pakeitėmā",
        "recentchanges-legend": "Vielībūju pakeitėmu pasėrinkėmā",
-       "recentchanges-summary": "Keravuokat patius vielībuosius wiki pakeitėmus tamė poslapi.",
+       "recentchanges-summary": "Keravuokat patius vielībuosius wiki pakeitėmus tamė poslapie.",
        "recentchanges-feed-description": "Keravuokėt patius vielībiausius pakeitėmus pruojektō tamė šaltėnī.",
        "recentchanges-label-newpage": "Šėtuo keitėmuo padėrbts naus poslapis",
        "recentchanges-label-minor": "Tas īr mažos pataisīms",
        "rcshowhidemine": "$1 mona pakeitėmus",
        "rcshowhidemine-show": "Ruodītė",
        "rcshowhidemine-hide": "Kavuotė",
+       "rcshowhidecategorization": "$1, kap poslapiam doud kateguorėjės",
        "rclinks": "Ruodītė vielībus $1 pakeitėmu par paskuojės $2 dėinas<br />$3",
        "diff": "skėrt",
        "hist": "ist",
        "uploadlogpage": "Ožkruovėmu istuorėjė",
        "uploadlogpagetext": "Žemiau pateikiam paskotėniu failu ikielima istuorėjė.",
        "filename": "Abruozdėlė vards",
-       "filedesc": "Pāiškėnėms",
-       "fileuploadsummary": "Pāiškėnėms:",
+       "filedesc": "Pškėnėms",
+       "fileuploadsummary": "Tromps aprašīms:",
        "filereuploadsummary": "Abruozdielė pakeitėmāː",
        "filestatus": "Derbieju teisėsː",
        "filesource": "Šaltėnis:",
        "filehist-user": "Nauduotuos",
        "filehist-dimensions": "Mierā",
        "filehist-filesize": "Abruozdielė dėdloms",
-       "filehist-comment": "Pāiškėnėms",
+       "filehist-comment": "Pškėnėms",
        "imagelinks": "Abruozdieliu nauduojėms",
        "linkstoimage": "{{PLURAL:$1|Ons poslapis|Anėi poslapē}} ruod ton abruozdielin:",
        "nolinkstoimage": "Abruozdielėp neruod anėjuoks poslapis.",
        "filerevert": "Sogrōžėntė $1",
        "filerevert-legend": "Faila sogrōžinėms",
        "filerevert-intro": "<span class=\"plainlinks\">Tamsta grōžėnat '''[[Media:$1|$1]]''' i versėje $4 ($2, $3).</span>",
-       "filerevert-comment": "Pāiškėnėms:",
+       "filerevert-comment": "Dingstės:",
        "filerevert-submit": "Grōžėntė",
        "filedelete": "Trintė $1",
        "filedelete-legend": "Trintė faila",
        "statistics-users": "Ožsėregėstravosiu [[Special:ListUsers|nauduotuoju]]",
        "statistics-users-active": "Aktīviu nauduotuoju",
        "statistics-users-active-desc": "Nauduotuojē, katrėi par {{PLURAL:$1|paskiausė dėina|paskiausė 2 dėinė|paskiausės $1 dėinas|paskiausiu $1 dėinū}} padėrba keitėmu",
+       "pageswithprop": "Poslapē so apībriežtuom savībėm",
+       "pageswithprop-legend": "Poslapē so apībriežtuom savībėm",
        "pageswithprop-submit": "Ēk",
        "doubleredirects": "Dvėgobė nusokėmā",
        "doubleredirectstext": "Tėi paradresavėmā ruod i kėtus paradresavėma poslapius. Kuožnuo eilotē pamėnavuots pėrmasā ėr ontrasā paradresavėmā, tēpuogi ontrojė paradresavėma paskėrtis, katra paprastā ė paruod i tėkraji poslapi, i katra pėrmasā paradresavėms ė torietu ruodītė.",
        "protectedpages-unknown-performer": "Nežėnuoms nauduotuos",
        "protectedtitles": "Apsauguotė pavadinėmā",
        "protectedtitlesempty": "Šėtou čieso nier anėjuokė pavadinėma, katros apsauguots tās parametrās.",
-       "listusers": "Sārošos nauduotuoju",
+       "listusers": "Sārašos nauduotuoju",
        "listusers-editsonly": "Ruodītė tėktās nauduotuojus katrėi īr atlėkė pakeitėmus",
        "usereditcount": "{{PLURAL:$1|pataisīms|pataisīmā|pataisīmu}}",
        "usercreated": "{{GENDER:$3|Padėrba paskīra}} $1 $2",
        "logempty": "Istuorėjuo nier anėjuokiū atitinkontiu atsėtėkimu.",
        "log-title-wildcard": "Ėiškuotė pavadinėmu, katrė prasėded šėtuo teksto",
        "showhideselectedlogentries": "Ruodītė/kavuotė sāraša ponktus, katrūs pasėrėnkot",
+       "checkbox-select": "Rinktėis: $1",
+       "checkbox-all": "Viskos",
        "allpages": "Vėsė straipsnē",
        "nextpage": "Kėts poslapis ($1)",
        "prevpage": "Onkstesnis poslapis ($1)",
        "listgrouprights": "Nauduotuoju gropiu teisės",
        "listgrouprights-group": "Gropė",
        "listgrouprights-rights": "Teisės",
-       "listgrouprights-members": "(nariū sārošos)",
+       "listgrouprights-members": "(nariū sārašos)",
+       "trackingcategories": "Pruogramėnės keravuojėma kateguorėjės",
        "mailnologin": "Nier adresa",
        "mailnologintext": "Tamstā reik būtė [[Special:UserLogin|prisėjongosiam]]\nė tor būtė ivests teisings el. pašta adresos Tamstas [[Special:Preferences|nustatīmuos]],\nkū siōstomiet el. gruomatas kėtėm nauduotuojam.",
        "emailuser": "Rašītė gruomata šėtam nauduotuojō",
        "actioncomplete": "Vēksmos padėrbts īr",
        "actionfailed": "Vēksmos atšaukts īr",
        "deletedtext": "„$1“ ėštrints īr.\nVielībūju trīnėmu istuorėjė - $2.",
-       "dellogpage": "Ėštrīnėmu sārošos",
+       "dellogpage": "Ėštrīnėmu sārašos",
        "dellogpagetext": "Apatiuo gol patīs vielībė̄jė ėštrīnėmā.",
-       "deletionlog": "ėštrīnėmu sārošos",
+       "deletionlog": "ėštrīnėmu sārašos",
        "reverted": "Grōžinta tāp, kāp ėšruodė pėrmiou",
        "deletecomment": "Dingstės:",
        "deleteotherreason": "Kėta/papėlduoma dingstės:",
        "rollbackfailed": "Atmetėms nasėgava",
        "cantrollback": "Negalėma atmestė redagavėma; paskotinis keitės nauduotuos īr tuo poslapė autorius.",
        "alreadyrolled": "Nė̄šēn otgrōžintė pakeitėma, [[:$1]] katra padėrba [[User:$2|$2]] ([[User talk:$2|aptarėms]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nkažkas ton jau padėrba pėrmiou.\n\nVielībiausā ton poslapė pakeitėms padėrbts [[User:$3|$3]] ([[User talk:$3|aptarėms]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]) īr.",
-       "editcomment": "Padėrbėma pāiškėnėms bova: <em>$1</em>.",
+       "editcomment": "Padėrbėma pškėnėms bova: <em>$1</em>.",
        "revertpage": "Atmests [[Special:Contributions/$2|$2]] ([[User talk:$2|aptarėms]]) pakeitėms; sogrōžints atmains, katron padėrba nauduotuos [[User:$1|$1]]",
        "rollback-success": "Atmestė $1 padėrbtė keitėmā; grōžints $2 padėrbts atmains.",
        "sessionfailure": "Atruod ka īr biedū so Tamstas prėsėjongėmo; tas vēksmos bova grōžints kāp atsargoma prėimonė nu sesėjės vuogėma.\nPrašoum mīgtė „atgal“ ėr parkrautė poslapi ėš katruo atiejėt, ė pamieginkėt apent.",
        "undeleteextrahelp": "Nuoriedamė atkortė vėsa poslapi, palikit vėsas varnales napažīmietas ėr\nspauskėt '''''Atkortė'''''. Nuoriedamiė atlėktė pasirėnktini atstatīma, pažīmiekit varnales šėtū versėju, katras nuorietomiet atstatītė, ėr spauskėt '''''Atkortė'''''. Paspaudus\n'''''Ėš naujė''''' bos ėšvalītuos vėsos varnalės ėr kuomentara lauks.",
        "undeleterevisions": "$1 {{PLURAL:$1|versėjė|versėjės|versėju}} soarkīvouta",
        "undeletehistory": "Jē atstatīsėt straipsni, istuorėjuo bos atstatītuos vėsos versėjės.\nJē puo ėštrīnima bova sokuots straipsnis tuokiuo patio pavadėnėmo,\natstatītuos versėjės atsiras onkstesnie istuorėjuo, o dabartėnė\nversėjė lėks napakeista. Atkoriant īr prarondamė apribuojimā failu versėjuom.",
-       "undeleterevdel": "Atkorėms nebus ivīkdīts, jē šėtā nulems paskotėnės poslapė versėjės dalini ėštrīnima.\nTuokēs atvejās, Tamstā rēk atžīmietė a atkavuotė naujausēs ėštrintas versėjės.\nFailu versėjės, katrū netorėt teisiu veizėtė, nebus atkortas.",
+       "undeleterevdel": "Poslapė atstatīms nabūs padarīts, jēb dielē ton ėšsitrintom vielībė̄jė poslapė pakeitėmā.\nTūdie Tamstā rēk atžīmietė aba atkavuotė vielībuosius ėštrintus atmainus.",
        "undeletehistorynoadmin": "Šėts straipsnis bova ėštrints. Trīnima prižastis\nruodoma žemiau, teipuogi kas redagava poslapi\nlėgė trīnima. Ėštrintū poslapiu tekstos īr galėmas tėk admėnėstratuoriam.",
        "undelete-revision": "Ėštrėnta $1 versėjė, katra $4 d. $5 padėrba $3:",
        "undeleterevision-missing": "Neteisėnga a dėngosė versėjė. Tamsta mažo torėt bluoga nūruoda, a versėjė bova atkorta a pašalėnta ėš arkīva.",
        "undeletebtn": "Grōžintė",
        "undeletelink": "veizietė/grōžintė",
        "undeleteviewlink": "veizietė",
-       "undeleteinvert": "Žīmietė prīšėngā",
+       "undeleteinvert": "Žīmietė atvėrkštē",
        "undeletecomment": "Dingstės:",
        "undeletedrevisions": "$1 {{PLURAL:$1|pakeitėms sogrōžints|pakeitėmā sogrōžintė|pakeitėmu sogrōžintu}} īr",
        "undeletedrevisions-files": "sogrōžintaː $1 {{PLURAL:$1|pakeitėms|pakeitėmā|pakeitėmu}} ėr $2 {{PLURAL:$2|abruozdielis|abruozdielē|abruozdieliu}}",
        "undelete-show-file-confirm": "A ėš tėkrā nuorėt parveizietė ėštrėnta faila „<nowiki>$1</nowiki>“ $2 $3 versėjė?",
        "undelete-show-file-submit": "Tēp",
        "namespace": "Vardū srėtės:",
-       "invert": "Žīmietė prīšėngā",
+       "invert": "Žīmietė atvėrkštē",
        "tooltip-invert": "Pažīmiekat ton varnalė, ka pakavuotomiet pakeitėmus pasėrinktūs poslapiūs (ė prėgolontės vardū srėtis)",
        "namespace_association": "Prėgolontė vardū srėtės",
        "tooltip-namespace_association": "Pažīmiekat ton varnalė, ka prėgoldītomat aptarėmus, katrėi ī sosėjė so parinkta vardū srėtim",
        "uctop": " (vielībs)",
        "month": "Nug mienėsė (ėr onkstiau):",
        "year": "Nug metu (ėr onkstiau):",
-       "sp-contributions-newbies": "Ruodītė tėk naujū prieteliu duovios",
+       "sp-contributions-newbies": "Ruodītė tėktās naujū prieteliu duovius",
        "sp-contributions-newbies-sub": "Naujuoms paskīruoms",
        "sp-contributions-newbies-title": "Nauduotuoju keitėmā naujuoms paskīruoms",
        "sp-contributions-blocklog": "Bluokavėmu istuorėjė",
        "contribslink": "duovis",
        "emaillink": "siōstė pašta",
        "autoblocker": "Autuomatėnis ožbluokavėms, nes dalėnaties IP adreso so nauduotuojo \"$1\". Prīžastės - \"$2\".",
-       "blocklogpage": "Ožgīnėmu sārošos",
+       "blocklogpage": "Ožgīnėmu sārašos",
        "blocklog-showlog": "Nauduotuos jau bova ožgints pėrmiou.\nApatiuo veiziekat kas ė kāpː",
        "blocklogentry": "ožgīnė [[$1]] nug dėrbėma, tas vēk ton čiesa - $2 $3",
        "reblock-logentry": "pakeistė [[$1]] bluokavėma nustatīmā, naus bluokavėma čiesos īr $2 $3",
        "tooltip-pt-anonuserpage": "Nauduotuojė poslapis Tamstas IP adresō",
        "tooltip-pt-mytalk": "Tamstas aptarėma poslapis",
        "tooltip-pt-preferences": "Mona nustatīmā",
-       "tooltip-pt-watchlist": "Poslapiu, katrūs Tamsta pasėrėnkuot keravuotė, sārošos.",
+       "tooltip-pt-watchlist": "Poslapiu, katrūs Tamsta pasirinkuot keravuotė, sārašos.",
        "tooltip-pt-mycontris": "Tamstas dėrbtū keitėmu sārašos",
        "tooltip-pt-login": "Kvėitam prėsėjongtė, nuors tas ė nie būtėna.",
        "tooltip-pt-logout": "Atsėjongtė",
        "tooltip-save": "Ėšsauguotė pakeitėmus",
        "tooltip-preview": "Ta īr pakeitėmu parveiza. Prašuom parveizat prīš ėšsaugont!",
        "tooltip-diff": "Ruod, kū parkeitiet straipsni.",
-       "tooltip-compareselectedversions": "Veizėtė abodvėju pasėrėnktū poslapė versėju skėrtomos.",
+       "tooltip-compareselectedversions": "Veizietė abodvėju pasirinktū poslapė atmainu skėrtomus.",
        "tooltip-watch": "Pridietė šėta poslapi i keravuojamu sāraša",
        "tooltip-recreate": "Atkortė poslapi napaisant šėto, kū ans bova ėštrints",
        "tooltip-rollback": "Sogrōžintė poslapi tāp, kāp ons bova prīš vielībūs ton nauduotuojė pardėrbėmus",
        "watchlistedit-raw-explain": "Žemiau ruodomė poslapē Tamstas keravuojamu sārašė, ė gal būtė pridietė i a pašalėntė ėš sāraša; vėins poslapis eilotie. Bėngė paspauskėt „Atnaujėntė keravuojamu sāraša“. Tamsta tēpuogi galėt [[Special:EditWatchlist|nauduotė standartėni radaktuoriu]].",
        "watchlistedit-raw-titles": "Poslapē:",
        "watchlistedit-raw-submit": "Atnaujėntė keravuojamu sāraša",
-       "watchlistedit-raw-done": "Tamstas keravuojamu sārošos bova atnaujėnts.",
+       "watchlistedit-raw-done": "Tamstas keravuojamu poslapiu sārašos bova atnaujints.",
        "watchlistedit-raw-added": "$1 {{PLURAL:$1|poslapis bova pridiets|poslapē bova pridietė|poslapiu bova pridieta}}:",
        "watchlistedit-raw-removed": "$1 {{PLURAL:$1|poslapis bova pašalėnts|poslapē bova pašalėntė|poslapiu bova pašalėnta}}:",
        "watchlisttools-view": "Veizietė sosėjosius pakeitėmus",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|ožkruovė}} naujė $3 atmaina",
        "logentry-upload-revert": "$1 {{GENDER:$2|ožkruovė}} $3",
        "rightsnone": "(juokiū)",
-       "revdelete-summary": "keitėma pāiškėnėms",
+       "revdelete-summary": "keitėma pškėnėms",
        "feedback-close": "Padėrbt",
        "searchsuggest-search": "Ėiškuotė",
        "searchsuggest-containing": "katrėi tor...",
index 54c4e65..c146a73 100644 (file)
        "minoredit": "Ovo je manje uređenje",
        "watchthis": "Prati ovu stranicu",
        "savearticle": "Spremi stranicu",
+       "publishpage": "Objavi stranicu",
+       "publishchanges": "Objavi izmjene",
        "preview": "Pregled",
        "showpreview": "Prikaži pregled",
        "showdiff": "Prikaži izmjene",
index 3c18dc9..4f1d008 100644 (file)
        "tagline": "Iz {{GRAMMAR:rodilnik|{{SITENAME}}}}",
        "help": "Pomoč",
        "search": "Iskanje",
+       "search-ignored-headings": " #<!-- te vrstice ne spreminjajte --> <pre>\n# Poglavja, ki bodo prezrta pri iskanju.\n# Spremembe bodo začele veljati takoj, ko bo stran s poglavjem indeksirana.\n# Reindeksacijo strani lahko vsilite z ničelnim urejanjem.\n# Skladnja je sledeča:\n#   * Vse od znaka »#« do konca vrstice je pripomba.\n#   * Vsaka neprazna vrstica je natančen naslov, ki ga bomo prezrli, upoštevajoč velikost črk in ostalo.\nOpombe\nOpombe in sklici\nViri\nZunanje povezave\nGlej tudi\n #</pre> <!-- te vrstice ne spreminjajte -->",
        "searchbutton": "Iskanje",
        "go": "Pojdi na",
        "searcharticle": "Pojdi na",
        "action-applychangetags": "uveljavitev oznak skupaj z vašimi spremembami",
        "action-changetags": "dodajanje in odstranjevanje poljubnih oznak na posameznih redakcijah in dnevniških vnosih",
        "action-deletechangetags": "izbris oznak iz zbirke podatkov",
+       "action-purge": "počiščenje strani",
        "nchanges": "$1 {{PLURAL:$1|sprememba|spremembi|spremembe|sprememb|sprememb}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od zadnjega obiska}}",
        "enhancedrc-history": "zgodovina",
        "watchnologin": "Niste prijavljeni",
        "addwatch": "Dodaj na spisek nadzorov",
        "addedwatchtext": "»[[:$1]]« in pripadajočo pogovorno stran smo dodali na vaš [[Special:Watchlist|spisek nadzorov]].",
+       "addedwatchtext-talk": "»[[:$1]]« in pripadajočo stran smo dodali na vaš [[Special:Watchlist|spisek nadzorov]].",
        "addedwatchtext-short": "Stran »$1« smo dodali na vaš spisek nadzorov.",
        "removewatch": "Odstrani s spiska nadzorov",
        "removedwatchtext": "»[[:$1]]« in pripadajočo pogovorno stran smo odstranili z vašega [[Special:Watchlist|spiska nadzorov]].",
+       "removedwatchtext-talk": "»[[:$1]]« in pripadajočo stran smo odstranili z vašega [[Special:Watchlist|spiska nadzorov]].",
        "removedwatchtext-short": "Stran »$1« smo odstranili z vašega spiska nadzorov.",
        "watch": "Opazuj",
        "watchthispage": "Opazuj stran",
index 6295f84..0d938b6 100644 (file)
        "tagline": "Ka {{SITENAME}}",
        "help": "Caawinaad",
        "search": "Raadi",
+       "search-ignored-headings": " #<!-- Udaa sadarkaan sida uu yahay --> <pre>\n# Waxaa dhacaysa in la iska iloowo madaxqorkiisa inta lagu gudajiro raadinta.\n# Isbedeleda waxay aadi doonaan halkii loogu talo galay ee hordhaca bogga uu ku jiro madaxqorkiisa.\n# Waxaa kuu suurtagal ah inaad howl hordhac ah usameeyso bogga adigoo bedela bogga banaan.\n# Weeraynta waa sidaan soo socota:\n#   * wax kasta oo gadaasheeda lagu qoro \"#\" sadarka dhammaadkiis waxaa loo qaadanaa faallo\n#   * Sadarkasta ee banaan wuxuu qaadanayaa ciwaankii laga tagay, isagii iyo wax kabedelan\nReferences\nLinkiyada dibadda\nSidoo kale eeg\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Raadi",
        "go": "Soco",
        "searcharticle": "Soco",
index a49e46a..277baa3 100644 (file)
        },
        "tog-underline": "Nënvizimi i lidhjes:",
        "tog-hideminor": "Fshih redaktimet e vogla nga ndryshimet e fundit",
-       "tog-hidepatrolled": "Fshih redaktimet e paturlluara nga ndryshimet e fundit",
-       "tog-newpageshidepatrolled": "Fshih faqet e patrulluara nga lista e faqeve të reja",
+       "tog-hidepatrolled": "Fshih redaktimet e kontrolluara nga ndryshimet e fundit",
+       "tog-newpageshidepatrolled": "Fshih faqet e kontrolluara nga lista e faqeve të reja",
        "tog-hidecategorization": "Fshih kategorizimin e faqeve",
-       "tog-extendwatchlist": "Zgjero listën e faqeve të vëzhguara që t'i tregojë të gjitha ndryshimet, jo vetëm më të fundit.",
-       "tog-usenewrc": "Grupo ndryshimet sipas faqeve në ndryshime së fundmi dhe listën mbikqyrëse (kërkon JavaScript)",
-       "tog-numberheadings": "Numëro automatikish titujt",
+       "tog-extendwatchlist": "Zgjero listën e të gjitha faqeve të vëzhguara në mënyrë që t'i tregojë të gjitha ndryshimet, jo vetëm më të fundit.",
+       "tog-usenewrc": "Grupo ndryshimet sipas faqes në ndryshimet më të fundit dhe listën e vëzhgimit (kërkon JavaScript)",
+       "tog-numberheadings": "Numërim automatik i titujve",
        "tog-showtoolbar": "Shfaq shiritin e veglave të redaktorit",
        "tog-editondblclick": "Redakto faqe në klikim të dyfishtë",
        "tog-editsectiononrightclick": "Aktivizo redaktimin e seksioneve duke klikuar me të djathtën mbi titullin e seksionit",
@@ -52,8 +52,8 @@
        "tog-watchrollback": "Shto faqet ku unë kam kryer një rikthim tek lista ime mbikqyrëse",
        "tog-minordefault": "Shëno të gjitha redaktimet si të vogla automatikisht",
        "tog-previewontop": "Vendose kutinë e bocetit sipër kutisë së redaktimeve",
-       "tog-previewonfirst": "Tregoje bocetin në redaktimin e parë",
-       "tog-enotifwatchlistpages": "Më njofto me e-mail kur ndryshohet një faqe apo skedarë nga lista ime e faqeve nën mbikqyrje",
+       "tog-previewonfirst": "Trego se si do të duket faqja pos ta filloj redaktimin",
+       "tog-enotifwatchlistpages": "Më njofto me email kur ndryshohet një faqe apo skedë nga lista ime e faqeve nën mbikqyrje",
        "tog-enotifusertalkpages": "Kur faqja ime e diskutimeve e përdoruesit ndryshohet, më dërgo email",
        "tog-enotifminoredits": "Më njofto me e-mail edhe kur ka redaktime të vogla në faqe dhe skedave",
        "tog-enotifrevealaddr": "Tregoje adresën time të e-mail-it në e-mail-et njoftuese",
@@ -72,7 +72,7 @@
        "tog-ccmeonemails": "Më dërgo kopje të mesazheve që u dërgoj të tjerëve",
        "tog-diffonly": "Mos trego përmbajtjen e faqes nën diff-e",
        "tog-showhiddencats": "Trego kategoritë e fshehura",
-       "tog-norollbackdiff": "Ndryshimi pas rikthimit do të fshihet",
+       "tog-norollbackdiff": "Mos trego ndrysh pas kryerjes së një rikthkimi",
        "tog-useeditwarning": "Më paralajmëro kur unë lë një redaktim faqeje me ndryshime të paruajtura",
        "tog-prefershttps": "Gjithmonë përdorni një lidhje të sigurt kur të kyçur",
        "underline-always": "Gjithmonë",
@@ -80,7 +80,7 @@
        "underline-default": "Parapërcaktuar nga shfletuesi",
        "editfont-style": "Zgjidh stilin e gërmave të hapsirës:",
        "editfont-default": "Sipas rregullit në shfletues",
-       "editfont-monospace": "Gërma monospace",
+       "editfont-monospace": "Germa me hapësirë të barabartë",
        "editfont-sansserif": "Germa Sans-serif",
        "editfont-serif": "Gërma serif",
        "sunday": "E diel",
        "listingcontinuesabbrev": "vazh.",
        "index-category": "Faqe të indeksuara",
        "noindex-category": "Faqe jo të indeksuara",
-       "broken-file-category": "Faqet me lidhjet file thyer",
-       "about": "Rreth",
+       "broken-file-category": "Faqet me lidhje të parregullta",
+       "about": "Për",
        "article": "Faqja e përmbajtjes",
        "newwindow": "(hapet në një dritare të re)",
        "cancel": "Anulo",
        "createacct-another-realname-tip": "* Emri i vërtetë nuk është i domosdoshëm: Nëse e jepni do të përmendeni si kontribues për punën që ke bërë.",
        "pt-login": "Hyni",
        "pt-login-button": "Hyni",
+       "pt-login-continue-button": "Vazhdoidntifikohu",
        "pt-createaccount": "Krijo llogari",
        "pt-userlogout": "Dil",
        "php-mail-error-unknown": "Gabim i panjohur në funksionin e postës PHP ()",
        "newpassword": "I riu",
        "retypenew": "I riu përsëri",
        "resetpass_submit": "Ndrysho fjalëkalimin dhe hyni brenda",
-       "changepassword-success": "Fjalëkalimin juaj ka ndryshuar me sukses!",
+       "changepassword-success": "Fjalëkalimi yt është ndryshuar.",
        "changepassword-throttled": "Keni bërë shumë tentime të njëpasnjëshme në fjalëkalimin e kësaj llogarie. Ju lutemi prisni para se te tentoni përsëri.",
+       "botpasswords": "Bot fjalëkalimet",
+       "botpasswords-label-create": "Krijo",
+       "botpasswords-label-update": "Përditëso",
+       "botpasswords-label-cancel": "Anulo",
+       "botpasswords-label-delete": "Fshi",
+       "botpasswords-label-resetpassword": "Rivendos fjalëkalimin",
+       "botpasswords-update-failed": "Dështoi për të përditësuar emrin e bot \"$1\". Ishte fshirë?",
        "resetpass_forbidden": "Fjalëkalimet nuk mund të ndryshohen",
        "resetpass-no-info": "Duhet të jeni i kyçur që të keni qasje direkte në këtë faqe.",
        "resetpass-submit-loggedin": "Ndrysho fjalëkalimin",
        "watchthis": "Vëzhgoje këtë faqe",
        "savearticle": "Kryej ndryshimet",
        "publishpage": "Publiko faqen",
+       "publishchanges": "Publiko ndryshimet",
        "preview": "Shqyrto",
        "showpreview": "Shfaq për shqyrtim",
        "showdiff": "Trego ndryshimet",
        "special-characters-group-lao": "Lao",
        "special-characters-group-khmer": "Khmer",
        "mw-widgets-dateinput-placeholder-day": "VVVV-MM-DD",
-       "mw-widgets-dateinput-placeholder-month": "VVVV-MM",
-       "api-error-blacklisted": "Ju lutemi zgjidhni një titull të ndryshëm, përshkrues."
+       "mw-widgets-dateinput-placeholder-month": "VVVV-MM"
 }
index 6b1f4dd..941db3c 100644 (file)
        "tagline": "Från {{SITENAME}}",
        "help": "Hjälp",
        "search": "Sök",
+       "search-ignored-headings": "#<!-- lämna denna rad precis som den är --> <pre>\n# Rubriker som kommer att ignoreras av sökningen.\n# Ändringar till detta kommer att gälla så fort sidan med rubriken är indexerad.\n# Du kan tvinga sidan att indexeras om genom att göra en null-redigering.\n# Syntaxen är som följer:\n#  * Allt från ett \"#\" tecken till slutet av raden är en kommentar.\n#  * Varje icke-tom rad är den exakta titeln som ska ignoreras, shiftläge och allt.\nReferenser\nKällor\nExterna länkar\nSe även\n #</pre> <!-- lämna denna rad precis som den är -->",
        "searchbutton": "Sök",
        "go": "Gå till",
        "searcharticle": "Gå till",
        "action-applychangetags": "tillämpa märken tillsammans med dina ändringar",
        "action-changetags": "lägg till och ta bort godtyckliga märken på individuella sidversioner och loggposter",
        "action-deletechangetags": "radera märken från databasen",
+       "action-purge": "rensa denna sida",
        "nchanges": "$1 {{PLURAL:$1|ändring|ändringar}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sedan senaste besöket}}",
        "enhancedrc-history": "historik",
index c595457..3f5bf22 100644 (file)
@@ -17,7 +17,8 @@
                        "Tchoř",
                        "Timpul",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Uostofchuodnego"
                ]
        },
        "tog-underline": "Podsztrychńyńcy linkůw:",
        "listingcontinuesabbrev": "ć.d.",
        "index-category": "Indeksowane zajty",
        "noindex-category": "Ńyindeksowane zajty",
-       "broken-file-category": "Zajty ze linkomi lo ńyistniejących ůobrozkůw",
+       "broken-file-category": "Zajty z linkami do niyôbecnych zbiorōw",
        "about": "Uo serwiśe",
        "article": "zajta",
        "newwindow": "(uodwjyro śe we nowym uokńe)",
        "unprotectthispage": "Uodymkńij ta zajta",
        "newpage": "Nowy artikel",
        "talkpage": "Godej uo tym artiklu",
-       "talkpagelinktext": "Dyskusyjo",
+       "talkpagelinktext": "dyskusyjŏ",
        "specialpage": "Szpecyjolno zajta",
        "personaltools": "Perzōnŏlne",
        "articlepage": "Zajta artikla",
        "disclaimers": "Prawne informacyje",
        "disclaimerpage": "Project:Prawne informacyje",
        "edithelp": "Půmoc we půmjyńańy",
-       "mainpage": "Przodńo zajta",
+       "mainpage": "Przodniŏ zajta",
        "mainpage-description": "Przodńo zajta",
        "policy-url": "Project:Prawidła",
        "portal": "Portal używoczůw",
        "newmessageslinkplural": "{{PLURAL:$1|jedno nowina|999=nowiny}}",
        "newmessagesdifflinkplural": "{{PLURAL:$1|uostatńe sprowjyńe|999=uostatńe sprowjyńa}}",
        "youhavenewmessagesmulti": "Mosz nowe powjadůmjyńa: $1",
-       "editsection": "Sprowjej",
+       "editsection": "edytuj",
        "editold": "sprowjej",
        "viewsourceold": "pokoż zdrzůdło",
        "editlink": "sprowjej",
        "viewsourcelink": "zdrzůdłowy tekst",
-       "editsectionhint": "Sprowjej tajla: $1",
+       "editsectionhint": "Edytuj tajlã: $1",
        "toc": "Treść",
        "showtoc": "uobejrzij",
        "hidetoc": "schrůń",
        "nstab-template": "Muster",
        "nstab-help": "Zajta půmocy",
        "nstab-category": "Kategoryjo",
+       "mainpage-nstab": "Przodniŏ zajta",
        "nosuchaction": "Ńy mo takij uoperacyji",
        "nosuchactiontext": "Uoprogramowańy ńy rozpoznowo uoperacyji takij kej podano w URL.",
        "nosuchspecialpage": "Ńy mo takij szpecyjolnyj zajty",
        "resetpass-abort-generic": "Půmjyńańe hasła uostoła zatrzimane bez rozszyrzyńe.",
        "passwordreset": "Wyczyść hasło",
        "passwordreset-disabled": "No tyj wiki zamkńynto resytowańy hasył.",
-       "passwordreset-username": "Mjano używacza:",
+       "passwordreset-username": "Miano ôd używŏcza:",
        "passwordreset-domain": "Domyna:",
        "passwordreset-capture": "Pokozać treść e-brifa?",
        "passwordreset-capture-help": "Eli zaznaczysz to pole, uobejrzisz wjadůmość e-brifa ze hasłym.",
        "skin-preview": "podglůnd",
        "datedefault": "Důmyślny",
        "prefs-labs": "Funkcyje \"labs\"",
-       "prefs-user-pages": "Zajty używaczy",
+       "prefs-user-pages": "Zajty ôd używŏczōw",
        "prefs-personal": "Dane używocza",
        "prefs-rc": "Ńydowno pomjyńane",
        "prefs-watchlist": "Pozůrlista",
        "userrights-changeable-col": "Grupy, kere moges wybrać",
        "userrights-unchangeable-col": "Grupy, kerych ńy moges wybrać",
        "group": "Grupa:",
-       "group-user": "Używacze",
-       "group-autoconfirmed": "AutůmatyczÅ\84y zatwjerdzůne używacze",
+       "group-user": "Używŏcze",
+       "group-autoconfirmed": "AutÅ\8dmatycznie przituplowani używÅ\8fcze",
        "group-bot": "Boty",
        "group-sysop": "Admińi",
        "group-bureaucrat": "Bjurokraty",
        "group-suppress": "Rewizorze",
        "group-all": "(wszyjscy)",
-       "group-user-member": "{{GENDER:$1|używacz}}",
-       "group-autoconfirmed-member": "AutůmatyczÅ\84y zatwjerdzůny używacz",
+       "group-user-member": "{{GENDER:$1|używŏcz|używŏczka}}",
+       "group-autoconfirmed-member": "AutÅ\8dmatycznie {{GENDER:$1|przituplowany używÅ\8fcz|przituplowanÅ\8f używÅ\8fczka}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|admin}}",
        "group-bureaucrat-member": "{{GENDER:$1|bjurokrata}}",
        "group-suppress-member": "{{GENDER:$1|rewizůr}}",
-       "grouppage-user": "{{ns:project}}:Używacze",
-       "grouppage-autoconfirmed": "{{ns:project}}:AutůmatyczÅ\84y zatwjerdzyÅ\84i używacze",
+       "grouppage-user": "{{ns:project}}:Używŏcze",
+       "grouppage-autoconfirmed": "{{ns:project}}:AutÅ\8dmatycznie przituplowani używÅ\8fcze",
        "grouppage-bot": "{{ns:project}}:Boty",
        "grouppage-sysop": "{{ns:project}}:Admińistratory",
        "grouppage-bureaucrat": "{{ns:project}}:Bjurokraty",
        "nopagetitle": "Ńy ma sam zajty docelowyj",
        "nopagetext": "Wybrano zajta docelowo ńy istńeje.",
        "pager-newer-n": "{{PLURAL:$1|1 nowšy|$1 nowše|$1 nowšych}}",
-       "pager-older-n": "{{PLURAL:$1|1 staršy|$1 starše|$1 staršych}}",
+       "pager-older-n": "{{PLURAL:$1|1 starszy|$1 starsze|$1 starszych}}",
        "suppress": "Oversight",
        "booksources": "Kśůnžki",
        "booksources-search-legend": "Sznupej za zdrzůdłůma kśůnżkowymi",
        "listusers-noresult": "Ńy znejdźůno žodnygo užytkowńika.",
        "activeusers-hidebots": "Schrůń boty",
        "activeusers-hidesysops": "Schrůń adminy",
-       "activeusers-noresult": "Ńy sům używacze.",
+       "activeusers-noresult": "Niy szło znŏjść żŏdnych używŏczōw",
        "listgrouprights": "Uprawńyńo grup użytkowńikůw",
        "listgrouprights-summary": "Půńiży znojdowo śe spis grup użytkowńikůw zdefińjowanych na tyj wiki, s wyszczygůlńyńym przidźelůnych im prow dostympu.\nSprowdź zajta [[{{MediaWiki:Listgrouprights-helppage}}|s dodatkowymi informacjami]] uo uprowńyńach użytkowńikůw.",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Dane uprawńyńy</span>\n* <span class=\"listgrouprights-revoked\">Uodebrane uprawńyńy</span>",
        "mailnologintext": "Muśyš śe [[Special:UserLogin|zalůgować]] i mjeć wpisany aktualny adres e-brif w swojich [[Special:Preferences|preferyncyjach]], coby můc wysuać e-brif do inkšygo užytkowńika.",
        "emailuser": "Poślij tymu używoczowi e-brif",
        "emailpagetext": "Możesz użyć půńiższygo formularza, coby wysłać wjadůmość e-brif do tygo użytkowńika.\nAdres e-brifa, kery zostoł bez Ćebje wkludzůny we [[Special:Preferences|Twojich sztalowańach]], pojawi śe we polu „Uod”, bez cůż uodbjorca bydźe můg Ći uodpedźeć.",
-       "defemailsubject": "{{SITENAME}} - e-brif uod używacza \"$1\"",
-       "usermaildisabled": "E-brif używacza ńy załůnczony",
+       "defemailsubject": "{{SITENAME}} - e-mail ôd używŏcza \"$1\"",
+       "usermaildisabled": "E-mail ôd używŏcza je zastŏwiōny",
        "noemailtitle": "Brak adresu e-brif",
-       "noemailtext": "Tyn używacz ńy podoł dobrygo e-brifa, abo zadecydowoł, co ńy chce uotrzimywać wjadůmośći e-brif uod inkszych używaczy.",
-       "nowikiemailtext": "Tyn sprowjorz ńy chcy e-brifůw uod inkszych używaczy.",
+       "noemailtext": "Tyn używŏcz niy podoł nŏleżnyj adresy email.",
+       "nowikiemailtext": "Tyn używŏcz niy chce dostŏwać emaili ôd inkszych.",
        "emailtarget": "Podej adresata",
-       "emailusername": "Mjano używacza:",
+       "emailusername": "Miano ôd używŏcza:",
        "emailusernamesubmit": "Poślij",
        "email-legend": "Wyślij e-brif ku inkszymu użytkowńikowi {{GRAMMAR:MS.lp|{{SITENAME}}}}",
        "emailfrom": "Uod:",
        "delete-confirm": "Wyćep „$1”",
        "delete-legend": "Wyćep",
        "historywarning": "Pozor! Ta zajta kerům chceš wyćepnůńć mo historjo:",
-       "confirmdeletetext": "Chceš wyćepnůńć trwale artikel abo plik s bazy danych s historią. Pokož, aže wjyš co robdza, i to aže to je tak jak godojům [[{{MediaWiki:Policy-url}}|zasady]].",
+       "confirmdeletetext": "Zarŏz wyciepniesz artikel i cołkõ ôd niygo historyjõ. Przitupluj, iże na isto chcesz to zrobić, miarkujesz kōnsekwyncyje, i co robisz to podle [[{{MediaWiki:Policy-url}}|prawideł]].",
        "actioncomplete": "Fertig",
        "actionfailed": "Ńy udało sie.",
        "deletedtext": "Wyćepano \"$1\". Rejer uostatnio zrobiůnych wyćepań možeš uobejžyć tukej: $2.",
        "contribsub2": "Lo {{GENDER:$3|używocza|używoczki}} $1 ($2)",
        "nocontribs": "Brak pomjyńań uodpowjadajůncych tym kryterjům.",
        "uctop": "(teroźńo)",
-       "month": "Uod mjeśůnca (i downiyjše):",
-       "year": "Uod roku (i dowńijše):",
+       "month": "Do miesiōnca:",
+       "year": "Do roku:",
        "sp-contributions-newbies": "Pokoż ajnzac ino uod nowych użytkowńikůw",
        "sp-contributions-newbies-sub": "Dlo nowych užytkowńikůw",
        "sp-contributions-newbies-title": "Wkłod nowych użytkowńików",
        "tooltip-pt-logout": "Uodloguj śe ze wiki",
        "tooltip-pt-createaccount": "Namawjůmy do stworzyńo kůnta a zalogůwańo śa, atoli niy je to uobowjůnzkowe",
        "tooltip-ca-talk": "Dyskusyjo uo tym artiklu",
-       "tooltip-ca-edit": "Mogesz sprowjać ta zajta. Podwjela spamjyntosz půmjyńańo, klikńij we knefel \"Uobźyrej\".",
+       "tooltip-ca-edit": "Edytuj tã zajtã",
        "tooltip-ca-addsection": "Przidej nowy temat",
        "tooltip-ca-viewsource": "Ta zajta je zawrzito. Mogesz uobźyrać zdrzůdłowy tekst.",
        "tooltip-ca-history": "Storsze wersyje tyj zajty",
        "tooltip-ca-nstab-main": "Uobźyrej zajta artikla",
        "tooltip-ca-nstab-user": "Ukoż perzůnalno zajta używocza",
        "tooltip-ca-nstab-media": "Uobejřij zajta artikla",
-       "tooltip-ca-nstab-special": "To je ekstra zajta. Ńy moges jej sprowjać.",
+       "tooltip-ca-nstab-special": "To je ekstra zajta i niy idzie jij edytować",
        "tooltip-ca-nstab-project": "Uobejřij zajta projektu",
        "tooltip-ca-nstab-image": "Ukoż zajta grafiki",
        "tooltip-ca-nstab-mediawiki": "Zoboč komunikat systymowy",
        "tooltip-ca-nstab-template": "Uobźyrej muster",
-       "tooltip-ca-nstab-help": "Pokož zajte s půmocą",
+       "tooltip-ca-nstab-help": "Pokŏż zajtã pōmocy",
        "tooltip-ca-nstab-category": "Ukoż zajta kategoryje",
        "tooltip-minoredit": "Uoznacz ta zmjana za drobno",
        "tooltip-save": "Naszkryflej půmjyńańa",
        "exif-exposureprogram-5": "kreatywny (duža guymbja uostrośći)",
        "exif-exposureprogram-6": "aktywny (dužo gibkość migawki)",
        "exif-exposureprogram-7": "tryb portretowy (do zdjyńć s bliska, s ńyuostrym tuym)",
-       "exif-exposureprogram-8": "tryb krajobrazowy (dla zdjęć wykůnywanych s dužej uodlyguośći s uostrośćům ustavjůnům na tuo)",
+       "exif-exposureprogram-8": "tryb landszaftu (dlŏ bildōw ze ôstrościōm nasztalowanōm na zadek)",
        "exif-subjectdistance-value": "$1 metrůw",
        "exif-meteringmode-0": "ńyuokryślůny",
        "exif-meteringmode-1": "średńo",
        "exif-gpsdirection-t": "kerůnek geůgrafičny",
        "exif-gpsdirection-m": "kerůnek magnetyčny",
        "namespacesall": "wszyjske",
-       "monthsall": "wšyskie",
+       "monthsall": "wszyjske",
        "confirmemail": "Potwjerdź adres e-brif",
        "confirmemail_noemail": "Ńy podoužeś prawiduowygo adresa e-brifa we [[Special:Preferences|preferencyjach]].",
        "confirmemail_text": "Projekt {{SITENAME}} wymago weryfikacyji adresa e-brif před užyćym fůnkcyji kořistajůncych s počty.\nWćiś knefel půńižy coby wysúać na swůj adres list s linkym do zajty WWW.\nList bydźe zawjeroú link do zajty, w kerym zakodowany bydźe idyntyfikator.\nUodymkńij tyn link we přyglůndarce, čym potwjerdźiš, co ježeś užytkowńikym tygo adresa e-brif.",
index 068b570..4f78206 100644 (file)
        "template-protected": "(ಸಂರಕ್ಷಿತೊ)",
        "template-semiprotected": "(ಅರೆ-ಸಂರಕ್ಷಿತೊ)",
        "hiddencategories": "ಈ ಪುಟೊ {{PLURAL:$1|೧ ಗುಪ್ತ ವರ್ಗೊಗ್|$1 ಗುಪ್ತ ವರ್ಗೊಲೆಗ್}} ಸೇರ್ದ್‍ನ್ಡ್:",
+       "permissionserrors": "ಅನುಮತಿ ದೋಷ",
        "permissionserrorstext-withaction": "$2 ಗ್ ಇರೆಗ್ ಅನುಮತಿ ಇದ್ದಿ, ಅಯಿಕ್ {{PLURAL:$1|ಕಾರಣೊ|ಕಾರಣೊಲು}}:",
        "moveddeleted-notice": "ಈ ಪುಟೊ ಅಸ್ತಿತ್ವೊಡ್ ಇದ್ದಿ.\nಪುಟೊದ ಡಿಲೀಶನ್ ಅತ್ತ್ಂಡ್ ಕಡಪ್ಪುಡುನೆ ಲಾಗ್‍ನ್ ತೂಯರೆ ತಿರ್ತ್ ಕೊರ್ತ್ಂಡ್.",
+       "content-model-wikitext": "ವಿಕಿ ಪಠ್ಯ",
        "viewpagelogs": "ಈ ಪುಟೊತ ದಾಕಲೆಲೆನ್ ತೂಲೆ",
        "nohistory": "ಈ ಪುಟಕ್ ಬದಲಾವಣೆದ ಇತಿಹಾಸ ಇಜ್ಜಿ",
        "currentrev": "ಇತ್ತೆದ ಆವೃತ್ತಿ",
        "notextmatches": "ವಾ ಪುಟೊತ ಪಠ್ಯೊಡುಲಾ ಹೋಲಿಕೆ ಇಜ್ಜಿ",
        "prevn": "ದುಂಬು {{PLURAL:$1|$1}}",
        "nextn": "ಬೊಕ್ಕೊ {{PLURAL:$1|$1}}",
+       "prev-page": "ದುಂಬುತ ಪುಟೊ",
+       "next-page": "ನನತಾ ಪುಟ",
        "nextn-title": "ದುಂಬುದ $1 {{PLURAL:$1|result|ಪಲಿತಾಂಸೊಲು}}",
        "shown-title": "ಪ್ರತಿ ಪುಟೊಡುಲಾ $1 {{PLURAL:$1|result|ಪಲಿತಾಂಸೊ}} ತೋಜಿಪಾವು",
        "viewprevnext": "ತೂಲೆ($1 {{int:pipe-separator}} $2) ($3)",
        "prefs-skin": "ಸ್ಕಿನ್",
        "skin-preview": "ಮುನ್ನೋಟೊ",
        "datedefault": "ಒವ್ವೇ ಪ್ರಾಸಸ್ತ್ಯೊ ಇದ್ದಿ",
+       "prefs-user-pages": "ಸದಸ್ಯೆರೆನ ಪುಟೊ",
        "prefs-rc": "ಇಂಚಿಪದ ಬದಲಾವಣೆಲು",
+       "prefs-watchlist": "ವೀಕ್ಷಣಾಪಟ್ಟಿ",
        "prefs-resetpass": "ಪ್ರವೇಶಪದೊನ್ ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
        "prefs-changeemail": "ಇ-ಅಂಚೆ ವಿಳಾಸೊನು ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ ಅತ್ತಂಡ ದೆಪ್ಪುಲೆ",
        "prefs-setemail": "ಇ-ಅಂಚೆ ವಿಳಾಸೊನು ಸ್ತಾಪನೆ ಮಲ್ಪು",
        "prefs-tokenwatchlist": "ಟೊಕನ್",
        "userrights-lookup-user": "ಬಳಕೆದಾರೆರೆ ಗುಂಪುಲೆನ್ ನಿರ್ವಹಿಸಲ",
        "userrights-user-editname": "ಒಂಜಿ ಸದಸ್ಯ ಪುದರ್ ಬರೆಲೆ",
+       "userrights-reason": "ಕಾರಣೊ:",
        "group": "ಗುಂಪುಲು:",
        "group-user": "ಬಳಕೆದಾರೆರ್",
        "group-sysop": "ನಿರ್ವಾಹಕೆರ್",
        "right-writeapi": "ಬರೆಯಿನ ಎಪಿಐದ ಬಳಕೆ",
        "right-delete": "ಪುಟೊಕುಲೆನ್ ಮಾಜಾಲೆ",
        "right-undelete": "ಪುಟೊನ್ ಮಾಜಾವಡೆ",
+       "grant-group-email": "ಇ-ಅಂಚೆ ಕಡಪುಡುಲೆ",
        "newuserlogpage": "ಸದಸ್ಯೆರೆ ಸ್ರಿಸ್ಟಿದ ದಾಕಲೆ",
        "rightslog": "ಸದಸ್ಯೆರ್ನ ಹಕ್ಕು ದಾಖಲೆ",
        "action-read": "ಈ ಪುಟೊನು ಓದುಲೆ",
        "recentchanges-label-plusminus": "ಬೈಟ್ಸ್‌ದ ಲೆಕ್ಕೊಡು ಈ ಪಾಲೆದ ಗಾತ್ರೊ ಬದಲಾತ್ಂಡ್",
        "recentchanges-legend-heading": "<strong>ಲೆಜೆಂಡ್:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ಬೊಕ್ಕೊಲಾ ತೂಲೆ [[Special:NewPages|ಪೊಸ ಪುಟೊದ ಪಟ್ಟಿ]])",
+       "recentchanges-submit": "ತೋಜಾಲೆ",
        "rclistfrom": "$3 $2 ರ್ದ್ ಸುರುವಾತಿನ ಪೊಸ ಬದಲಾವಣೆಲೆನ್ ತೊಜ್ಪಾವು",
        "rcshowhideminor": "$1 ಎಲ್ಯೆಲ್ಯ ಬದಲಾವಣೆಲು",
        "rcshowhideminor-show": "ತೋಜಾಲೆ",
        "rcshowhidebots-show": "ತೊಜಾವು",
        "rcshowhidebots-hide": "ಅಡೆಂಗಾವು",
        "rcshowhideliu": "ನೋಂದವಣೆ ಆತಿನಂಚಿನ ಸದಸ್ಯೆರ್ $1",
+       "rcshowhideliu-show": "ತೋಜಾಲೆ",
        "rcshowhideliu-hide": "ಅಡೆಂಗಾವು",
        "rcshowhideanons": "ಪುದರ್ ಇದ್ಯಾಂದಿನ ಸದಸ್ಯೆರ್ $1",
        "rcshowhideanons-show": "ತೋಜಾಲೆ",
        "rcshowhideanons-hide": "ಅಡೆಂಗಾವು",
        "rcshowhidepatr": "$1 ಪರೀಕ್ಷಿಸಾದಿನ ಸಂಪಾದನೆಲು",
+       "rcshowhidepatr-show": "ತೋಜಾಲೆ",
+       "rcshowhidepatr-hide": "ಅಡೆಂಗಾವು",
        "rcshowhidemine": "ಎನ್ನ ಸಂಪಾದನೆಲೆನ್ $1",
        "rcshowhidemine-show": "ತೋಜಾಲೆ",
        "rcshowhidemine-hide": "ಅಡೆಂಗಾವು",
+       "rcshowhidecategorization-show": "ತೋಜಾಲೆ",
+       "rcshowhidecategorization-hide": "ಅಡೆಂಗಾವು",
        "rclinks": "ದುಂಬುದ $2 ದಿನೊಲೆಡ್ ಮಲ್ತಿನ $1 ಪಿರವುದ ಬದಲಾವಣೆಲೆನ್ ತೂಲೆ <br />$3",
        "diff": "ವ್ಯತ್ಯಾಸೊ",
        "hist": "ಇತಿಹಾಸೊ",
        "uploadlogpage": "ಅಪ್ಲೋಡ್ ದಾಖಲೆ",
        "filename": "ಕಡತದ ಪುದರ್",
        "filedesc": "ಸಾರಾಂಸೊ",
+       "fileuploadsummary": "ಸಾರಾಂಸೊ:",
        "filesource": "ಮೂಲ",
        "savefile": "ಕಡತನ್ ಒರಿಪಾಲೆ",
        "upload-source": "ಮೂಲ ಕಡತ",
+       "upload-file-error": "ಆ೦ತರಿಕ ದೋಷ",
+       "upload-dialog-button-cancel": "ವಜಾ ಮಲ್ಪುಲೆ",
+       "upload-dialog-button-done": "ಆಂಡ್",
+       "upload-dialog-button-save": "ಒರಿಪಾಲೆ",
+       "upload-dialog-button-upload": "ಅಪ್ಲೊಡ್",
+       "upload-form-label-infoform-title": "ವಿವರೊ",
+       "upload-form-label-infoform-name": "ಪುದರ್",
+       "upload-form-label-infoform-description": "ವಿವರಣೆ",
+       "upload-form-label-usage-filename": "ಕಡತದ ಪುದರ್",
+       "upload-form-label-infoform-categories": "ವರ್ಗೊಲು",
+       "upload-form-label-infoform-date": "ದಿನೊ",
+       "license": "ಪರವಾನಗಿ:",
        "license-header": "ಪರವಾನಿಗೆ",
+       "listfiles-delete": "ಮಾಜಾಲೆ",
        "imgfile": "ಫೈಲ್",
+       "listfiles_thumb": "ಎಲ್ಯಚಿತ್ರೊ",
+       "listfiles_date": "ದಿನೊ",
+       "listfiles_name": "ಪುದರ್",
+       "listfiles_user": "ಬಳಕೆದಾರೆರ್",
+       "listfiles_size": "ಗಾತ್ರೊ",
+       "listfiles_description": "ವಿವರಣೆ",
+       "listfiles_count": "ಆವೃತ್ತಿಲು",
+       "listfiles-latestversion-yes": "ಅಂದ್",
+       "listfiles-latestversion-no": "ಅತ್ತ್",
        "file-anchor-link": "ಫೈಲ್",
        "filehist": "ಫೈಲ್‍ದ ಇತಿಹಾಸೊ",
        "filehist-help": "ದಿನೊ/ಪೊರ್ತುದ ಮಿತ್ತ್ ಒತ್ತ್‌ಂಡ ಈ ಫೈಲ್‍ದ ನಿಜೊಸ್ತಿತಿ ತೋಜುಂಡು.",
        "filehist-deleteall": "ಮಾತಾ ಮಾಜಾಲೆ",
        "filehist-deleteone": "ಮಾಜಾಲೆ",
+       "filehist-revert": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
        "filehist-current": "ಇತ್ತೆದ",
        "filehist-datetime": "ದಿನೊ/ಪೊರ್ತು",
        "filehist-thumb": "ಎಲ್ಯಚಿತ್ರೊ",
        "sharedupload": "ಈ ಫೈಲ್’ನ್ ಮಸ್ತ್ ಜನ ಪಟ್ಟ್’ದುಲ್ಲೆರ್ ಅಂಚೆನೆ ಉಂದು ಮಸ್ತ್ ಪ್ರೊಜೆಕ್ಟ್’ಲೆಡ್ ಉಪಯೋಗಡುಪ್ಪು.",
        "sharedupload-desc-here": "ಈ ಪುಟೊ $1ಡ್ದ್ ಬೊಕ್ಕ ಬೇತೆ ಯೋಜನೆಡ್ದ್ ಗಳಸೊಲಿ.\nಈ ಪುಟೊತ ವಿವರೊ [$2 ಪುಟೊತ ವಿವರೊ] ತಿರ್ತ ಸಾಲ್‍ಡ್ ತೋಜಾದ್ಂಡ್",
        "upload-disallowed-here": "ಈರ್ ಈ ಫೈಲ್‍ನ್ ಕುಡೊರೊ ಬರೆವರೆ ಸಾದ್ಯೊ ಇದ್ದಿ.",
+       "filerevert-comment": "ಕಾರಣ:",
+       "filerevert-submit": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
        "filedelete-comment": "ಕಾರಣ",
        "filedelete-submit": "ಮಾಜಾಲೆ",
+       "filedelete-reason-otherlist": "ಬೇತೆ ಕಾರಣ",
+       "download": "ಡೌನ್‍ಲೋಡ್",
        "randompage": "ಯಾದೃಚ್ಛಿಕ ಪುಟೊ",
+       "randomincategory-submit": "ಪೋಲೆ",
        "statistics": "ಅಂಕಿ ಅಂಶೊಲು",
        "statistics-header-pages": "ಪುಟೊತ ಅಂಕಿ ಅಂಶಲು",
+       "statistics-pages": "ಪುಟಕುಲು",
+       "pageswithprop-submit": "ಪೋಲೆ",
+       "brokenredirects-edit": "ಸಂಪೊಲಿಪುಲೆ",
+       "brokenredirects-delete": "ಮಾಜಾಲೆ",
+       "withoutinterwiki-submit": "ತೋಜಾಲೆ",
        "nbytes": "$1 {{PLURAL:$1|ಬೈಟ್|ಬೈಟ್‍ಲು}}",
        "nmembers": "$1 {{PLURAL:$1|ಸದಸ್ಯೆ|ಸದಸ್ಯೆರ್}}",
        "wantedfiles": "ಬೋಡಾಯಿನ ಕಡತೊಲು",
        "prefixindex": "ಪೂರ್ವನಾಮೊಲ್ದ ಸೂಚಿಕೆ",
+       "prefixindex-submit": "ತೋಜಾಲೆ",
+       "protectedpages-page": "ಪುಟೊ",
+       "protectedpages-reason": "ಕಾರಣೊ",
+       "protectedpages-unknown-timestamp": "ಗೊತ್ತಿಜ್ಜಾಂದಿನ",
        "listusers": "ಬಳಕೆದಾರರೆನ ತಖ್ತೆ",
        "newpages": "ಪೊಸ ಪುಟೊಲು",
+       "newpages-submit": "ತೋಜಾಲೆ",
        "newpages-username": "ಸದಸ್ಯೆರ್ನ ಪುದರ್:",
        "move": "ಮೂವ್(ಸ್ಥಳಾಂತರ) ಮಲ್ಪುಲೆ",
        "movethispage": "ಈ ಪುಟೊನು ಮೂವ್ ಮಲ್ಪುಲೆ",
        "pager-newer-n": "{{PLURAL:$1|ಪೊಸ ೧|ಪೊಸ $1}}",
        "pager-older-n": "{{PLURAL:$1|ಪರತ್ತ್ ೧|ಪರತ್ತ್ $1}}",
+       "apisandbox-reset": "ಮಾಜಲೇ",
+       "apisandbox-retry": "ನನೊರ ಪ್ರಯತ್ನ ಮಾನ್ಪುಲೇ",
+       "apisandbox-examples": "ಉದಾಹರಣೆಲು",
+       "apisandbox-results": "ಪಲಿತಾಂಸೊ",
        "booksources": "ಬೂಕುದ ಮೂಲೊ",
        "booksources-search-legend": "ಬೂಕುದ ಮೂಲೊನು ನಾಡ್‍ಲೆ",
        "booksources-search": "ನಾಡ್‍ಲೆ",
        "log": "ದಾಕಲೆಲು",
+       "logeventslist-submit": "ತೋಜಾಲೆ",
+       "checkbox-all": "ಮಾತಾ",
+       "checkbox-none": "ಒವ್ವುಲಾ ಇಜ್ಜಿ",
        "allpages": "ಪೂರಾ ಪೂಟೊಲು",
        "allpagesfrom": "ಇಂದೆರ್ದ್ ಶುರುವಾಪುನ ಪುಟೊಲೆನ್ ತೊಜ್ಪಾವು:",
        "allpagesto": "ಇಂದೆರ್ದ್ ಅಂತ್ಯ ಆಪುನ ಪುಟೊಲೆನ್ ತೊಜ್ಪಾವು:",
        "allarticles": "ಮಾತ ಪುಟೊಲು",
        "allpagessubmit": "ಪೋಲೆ",
        "categories": "ವರ್ಗೊಲು",
+       "categories-submit": "ತೋಜಾಲೆ",
+       "sp-deletedcontributions-contribs": "ಕಾನಿಕೆಲು",
+       "linksearch-ok": "ನಾಡ್‍ಲೆ",
+       "listusers-submit": "ತೋಜಾಲೆ",
+       "listgrouprights-group": "ಗುಂಪು",
        "listgrouprights-members": "(ಸದಸ್ಯೆರ್ನ ಪಟ್ಟಿ)",
+       "listgrants-rights": "ಹಕ್ಕುಗಳು",
        "emailuser": "ಈ ಸದಸ್ಯೆರೆಗ್ ಇ-ಮೈಲ್ ಕಡಪುಡ್ಲೆ",
+       "emailusername": "ಸದಸ್ಯೆರ್ನ ಪುದರ್:",
+       "emailusernamesubmit": "ಒಪ್ಪಿಸಾಲೆ",
+       "emailsubject": "ವಿಷಯ:",
+       "emailmessage": "ಸಂದೇಶಲು:",
+       "emailsend": "ಕಡಪುಡುಲೆ",
        "watchlist": "ವೀಕ್ಷಣಾ ಪಟ್ಟಿ",
        "mywatchlist": "ಎನ್ನ ವೀಕ್ಷಣಾಪಟ್ಟಿ",
        "watch": "ತೂಲೆ",
        "watchthispage": "ಈ ಪುಟೊನು ತೂಲೆ",
        "unwatch": "ವೀಕ್ಷಣಾಪಟ್ಟಿರ್ದ್ ದೆಪ್ಪು",
+       "watchlist-hide": "ಅಡೆಂಗಾವು",
+       "watchlist-submit": "ತೋಜಾವು",
+       "wlshowhideminor": "ಎಲ್ಯೆಲ್ಯ ಬದಲಾವಣೆಲು",
        "watchlist-options": "ವೀಕ್ಷಣಾಪಟ್ಟಿ ಆಯ್ಕೆಲು",
        "watching": "ವೀಕ್ಷಣಾಪಟ್ಟಿಗ್ ಸೇರ್ಪಾವೊಂದುಂಡು...",
        "unwatching": "ವೀಕ್ಷಣಾಪಟ್ಟಿರ್ದ್ ದೆತ್ತೊಂದುಂಡು...",
+       "confirm": "ಗಟ್ಟಿಮಲ್ಪುಲೆ",
+       "delete-legend": "ಮಾಜಾಲೆ",
+       "historyaction-submit": "ತೋಜಾಲೆ",
        "actioncomplete": "ಕಾರ್ಯ ಸಂಪೂರ್ಣ",
        "dellogpage": "ಡಿಲೀಟ್ ಮಲ್ತಿನ ಫೈಲ್‍ದ ದಾಕಲೆ",
+       "deletecomment": "ಕಾರಣ:",
+       "deletereasonotherlist": "ಬೇತೆ ಕಾರಣ",
        "rollbacklink": "ಪುಡತ್ತ್ ಪಾಡ್",
        "rollbacklinkcount": "ಪಿರ ದೆತೊನ್ಲೆ $1 {{PLURAL:$1|edit|ಸಂಪದನೆಲು}}",
+       "changecontentmodel-reason-label": "ಕಾರಣ:",
+       "changecontentmodel-submit": "ಬದಲಾವಣೆ",
+       "logentry-contentmodel-change-revertlink": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
+       "logentry-contentmodel-change-revert": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
        "protectlogpage": "ಸೇರಾಯಿನ ದಾಕಲೆ",
        "protectedarticle": "\"[[$1]]\" ಸಂರಕ್ಷಿತವಾದುಂಡು.",
        "modifiedarticleprotection": "\"[[$1]]\" ಪುಟೊತ ಸಂರಕ್ಷಣೆ ಮಟ್ಟ ಬದಲಾಂಡ್",
+       "protectcomment": "ಕಾರಣೊ:",
+       "protect-otherreason-op": "ಬೇತೆ ಕಾರಣ",
+       "restriction-type": "ಒಪ್ಪುಗೆ:",
+       "restriction-edit": "ಸಂಪಾದನೆ ಮಲ್ಪುಲೆ",
+       "restriction-move": "ಸ್ಥಳಾಂತರ ಮಲ್ಪುಲೆ",
+       "restriction-create": "ಸೃಷ್ಟಿಸಾಲೆ",
+       "restriction-upload": "ಅಪ್ಲೊಡ್",
        "undeletelink": "ದುಂಬುದ ಆವೃತ್ತಿಗ್ ಪೋಲೆ",
        "undeleteviewlink": "ತೂಲೆ",
+       "undeletecomment": "ಕಾರಣೊ:",
+       "undelete-search-submit": "ನಾಡ್‍ಲೆ",
+       "undelete-show-file-submit": "ಅಂದ್",
        "namespace": "ಪುದರ್‍ದ ಬಗೆ:",
        "invert": "ಆಯ್ಕೆನ್ ತಿರ್ಗಾಲೆ",
        "tooltip-invert": "ಈ ಚೌಕೊದುಲಯಿಡ್ ಅಡೆಂಗಿನ ಪುದರ್‍ನ್ ಈ ಚೌಕೊಡೆ ಪರೀಕ್ಷಿಸಲೆಲೆ(ಬೊಕ್ಕೊ ಒಟ್ಟುಗಿತ್ತಿನ ಪುದರ್‍ನ್ಲಾ ಪರೀಕ್ಷಿಸವೊಲಿ)",
        "whatlinkshere-hidetrans": "$1 ಸೇರಾವುನವು",
        "whatlinkshere-hidelinks": "$1 ಕೊಂಡಿಕುಲು",
        "whatlinkshere-filters": "ಅರಿಪೆಲು",
+       "whatlinkshere-submit": "ಪೋಲೆ",
        "blockip": "ಈ ಸದಸ್ಯೆರೆನ್ ಬ್ಲಾಕ್ ಮಲ್ಪುಲೆ",
+       "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",
        "ipblocklist": "ತಡೆಪತ್ತ್’ದಿನ ಐ.ಪಿ ವಿಳಾಸೊಲು ಅಂಚೆನೆ ಬಳಕೆದ ಪುದರ್’ಲು",
        "blocklink": "ಅಡ್ಡ ಪತ್ತ್‌ಲೆ",
index 86290ea..1ecf70c 100644 (file)
@@ -62,7 +62,7 @@
        "tog-ccmeonemails": "నేను ఇతర వాడుకరులకు పంపించే ఈ-మెయిళ్ల కాపీలను నాకు కూడా పంపు",
        "tog-diffonly": "తేడాల కింద, పేజీలోని సమాచారాన్ని చూపించొద్దు",
        "tog-showhiddencats": "దాచిన వర్గాలను చూపించు",
-       "tog-norollbackdiff": "à°°à°¦à±\8dà°¦à±\81 చేసాక తేడాలు చూపించవద్దు",
+       "tog-norollbackdiff": "à°°à±\8bà°²à±\8dâ\80\8cà°¬à±\8dయాà°\95à±\8d చేసాక తేడాలు చూపించవద్దు",
        "tog-useeditwarning": "ఏదైనా పేజీని నేను వదిలివెళ్తున్నప్పుడు దానిలో భద్రపరచని మార్పులు ఉంటే నన్ను హెచ్చరించు",
        "tog-prefershttps": "లాగిన్ అయి ఉన్నప్పుడెల్లా భద్ర కనెక్షనునే వాడు",
        "underline-always": "ఎల్లప్పుడూ",
        "october-date": "అక్టోబరు $1",
        "november-date": "నవంబరు $1",
        "december-date": "డిసెంబరు $1",
+       "period-am": "ఉద",
+       "period-pm": "సాయం",
        "pagecategories": "{{PLURAL:$1|వర్గం|వర్గాలు}}",
        "category_header": "\"$1\" వర్గంలోని పుటలు",
        "subcategories": "ఉపవర్గాలు",
        "tagline": "{{SITENAME}} నుండి",
        "help": "సహాయం",
        "search": "వెతుకు",
+       "search-ignored-headings": " #<!-- ఈ లైనును ఉన్నది ఉన్నట్లుగా వదిలేయండి --> <pre>\n# వెతుకులాటలో పరిగణింపబడని శీర్షికలు.\n# శీర్షికతో సహా పేజీ ఇండెక్స్ కాగానే మార్పులు వర్తిస్తాయి.\n# ఉత్తుత్తి సవరణ చేయడం ద్వారా బలవంతంగా రీయిండెక్సింగ్ చేయించవచ్చు.\n# వ్యాకరణం ఇలా ఉంటుంది:\n#   * \"#\" కారెక్టరు నుండి లైను చివరి వరకూ ఉన్నదంతా వ్యాఖ్య అవుతుంది\n#   * ఖాళీగా లేని ప్రతీ లైను వెతుకులాటలో పట్టించుకోనక్కర్లేని శీర్షికగా పరిగణింపబడుతుంది.\nమూలాలు\nబయటి లింకులు\nఇవి కూడా చూడండి\n #</pre> <!-- ఈ లైనును ఉన్నది ఉన్నట్లుగా వదిలేయండి -->",
        "searchbutton": "వెతుకు",
        "go": "వెళ్లు",
        "searcharticle": "వెళ్లు",
        "laggedslavemode": "<strong>హెచ్చరిక:</strong> పేజీలో ఇటీవల జరిగిన మార్పులు ఉండకపోవచ్చు.",
        "readonly": "డేటాబేసు లాక్‌చెయ్యబడింది",
        "enterlockreason": "డేటాబేసుకు వేయబోతున్న లాకుకు కారణం తెలుపండి, దానితోపాటే ఎంతసమయం తరువాత ఆ లాకు తీసేస్తారో కూడా తెలుపండి",
-       "readonlytext": "à°¡à±\87à°\9fాబà±\87à°¸à±\81 à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤à°\82 à°²à°¾à°\95à±\81 à°\9aà±\87యబడిà°\82ది. à°®à°¾à°°à±\8dà°ªà±\81à°²à±\81, à°\9aà±\87à°°à±\8dà°ªà±\81à°²à±\81 à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤à°\82 à°\9aà±\86à°¯à±\8dయలà±\87à°°à±\81. à°®à°¾à°®à±\82à°²à±\81à°\97à°¾ à°\9cà°°à°¿à°\97à±\87 à°¨à°¿à°°à±\8dవహణ à°\95à±\8aà°°à°\95à±\81 à°\87ది à°\9cà°°à°¿à°\97à°¿ à°\89à°\82à°¡à°µà°\9aà±\8dà°\9aà±\81; అది పూర్తి కాగానే తిరిగి మామూలుగా పనిచేస్తుంది.\n\nదీనిని లాకు చేసిన నిర్వాహకుడు ఇలా తెలియజేస్తున్నాడు: $1",
+       "readonlytext": "à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤à°\82 à°\95à±\8aà°¤à±\8dà°¤ à°\8eà°\82à°\9fà±\8dà°°à±\80à°²à±\81, à°®à°¾à°°à±\8dà°ªà±\81à°\9aà±\87à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\86à°¯à±\8dà°¯à°\95à±\81à°\82à°¡à°¾ à°¡à±\87à°\9fాబà±\87à°¸à±\81 à°²à°¾à°\95à±\81 à°\9aà±\87యబడిà°\82ది. à°®à°¾à°®à±\82à°²à±\81à°\97à°¾ à°\9cà°°à°¿à°\97à±\87 à°¨à°¿à°°à±\8dవహణ à°\95à±\8aà°°à°\95à±\81 à°\87ది à°\9cà°°à°¿à°\97à°¿ à°\89à°\82à°¡à°µà°\9aà±\8dà°\9aà±\81. అది పూర్తి కాగానే తిరిగి మామూలుగా పనిచేస్తుంది.\n\nదీనిని లాకు చేసిన నిర్వాహకుడు ఇలా తెలియజేస్తున్నాడు: $1",
        "missing-article": "\"$1\" $2 అనే పేజీ యొక్క పాఠ్యం డేటాబేసులో దొరకలేదు.\n\nకాలం చెల్లిన తేడా కోసం చూసినపుడుగానీ, తొలగించిన పేజీ చరితం కోసం చూసినపుడుగానీ ఇది సాధారణంగా జరుగుతుంది.\n\nఒకవేళ అలా కాకపోతే, మీరో బగ్‌ను కనుక్కున్నట్టే.\nఈ URLను సూచిస్తూ, దీన్ని ఓ [[Special:ListUsers/sysop|నిర్వాహకునికి]] తెలియజేయండి.",
        "missingarticle-rev": "(కూర్పు#: $1)",
        "missingarticle-diff": "(తేడా: $1, $2)",
        "badtitletext": "మీరు కోరిన పేజీ యొక్క పేరు చెల్లనిది, ఖాళీగా ఉంది, లేదా తప్పు లింకుతో కూడిన అంతర్వికీ లేదా అంతర-భాషా శీర్షిక అయివుండాలి.\nశీర్షికలలో ఉపయోగించకూడని అక్షరాలు దానిలో ఉండివుండొచ్చు.",
        "title-invalid-empty": "కోరబడిన పేజీ శీర్షిక ఖాళీగా ఉంది లేదా కేవలం పేరుబరి పేరు కలిగి ఉంది.",
        "title-invalid-utf8": "కోరబడిన పేజీ శీర్షికలో చెల్లని UTF-8 అక్షరాలున్నాయి.",
-       "title-invalid-interwiki": "à°¶à±\80à°°à±\8dà°·à°¿à°\95 à°ªà°¾à° à±\8dà°¯à°\82à°²à±\8b à°\85à°\82తరవిà°\95à±\80 à°²à°\82à°\95à±\86 à°\89à°\82ది",
+       "title-invalid-interwiki": "à°®à±\80à°°à°¡à°¿à°\97à°¿à°¨ à°ªà±\87à°\9cà±\80 à°¶à±\80à°°à±\8dà°·à°¿à°\95à°²à±\8b à°\85à°\82తర à°µà°¿à°\95à±\80 à°²à°\82à°\95à±\86 à°\89à°\82ది, à°\95ానà±\80 à°\85ది à°¨à°¿à°·à°¿à°¦à±\8dà°§à°\82.",
        "title-invalid-talk-namespace": "మీరడిగిన పేజీ శీర్షిక అసలు సృష్టించే వీలే లేని చర్చా పేజీకి చెందినది.",
        "title-invalid-characters": "కోరబడిన పేజీ శీర్షికలో చెల్లని అక్షరాలున్నాయి : \"$1\".",
        "title-invalid-relative": "శీర్షికలో లంకె పాఠ్యం సాపేక్షంగా ఉంది - పూర్తిగా లేదు. సాపేక్ష పేజీ చిరునామాలు (./, ../) గల పేజీ శీర్షికలు ఎక్కువశాతం అందుబాటులో ఉండవు కనుక అవి చెల్లవు.",
        "title-invalid-magic-tilde": "కోరబడిన పేజీ శీర్షిక పాఠ్యం లో చెల్లని మ్యాజిక్ టిల్డా పదాలున్నాయి (<nowiki>~~~</nowiki>).",
-       "title-invalid-too-long": "à°\95à±\8bరబడిన à°ªà±\87à°\9cà±\80 à°¶à±\80à°°à±\8dà°·à°¿à°\95 à°ªà°¾à° à±\8dà°¯à°\82 à°®à°°à±\80 à°ªà±\8aà°¡à°µà±\81à°\97à°¾ à°\89à°\82ది. à°\87ది UTF-8 à°ªà°¦à±\8dధతిలà±\8b $1 à°¬à±\88à°\9fà±\8dà°²కు మించి ఉండరాదు.",
+       "title-invalid-too-long": "à°®à±\80à°°à°¡à°¿à°\97à°¿à°¨ à°ªà±\87à°\9cà±\80 à°¶à±\80à°°à±\8dà°·à°¿à°\95 à°®à°°à±\80 à°ªà±\8aà°¡à°µà±\81à°\97à°¾ à°\89à°\82ది. à°\87ది UTF-8 à°ªà°¦à±\8dధతిలà±\8b $1 {{PLURAL:$1|à°¬à±\88à°\9fà±\8dâ\80\8c|à°¬à±\88à°\9fà±\8dà°²}}కు మించి ఉండరాదు.",
        "title-invalid-leading-colon": "కోరబడిన పేజీ శీర్షిక పాఠ్యం మొదట్లో చెల్లని కొలొన్ చిహ్నం (:) ఉంది.",
        "perfcached": "కింది డేటా ముందే సేకరించి పెట్టుకున్నది. కాబట్టి తాజా డేటాతో పోలిస్తే తేడాలుండవచ్చు. ఈ కాషెలో గరిష్టంగా {{PLURAL:$1|ఒక్క ఫలితం ఉంది|$1 ఫలితాలు ఉన్నాయి}}.",
        "perfcachedts": "కింది సమాచారం ముందే సేకరించి పెట్టుకున్నది. దీన్ని $1న చివరిసారిగా తాజాకరించారు. ఈ కాషెలో గరిష్టంగా {{PLURAL:$4|ఒక్క ఫలితం ఉంది|$4 ఫలితాలు ఉన్నాయి}}.",
        "viewsource": "మూలాన్ని చూపించు",
        "viewsource-title": "$1 యొక్క సోర్సు చూడండి",
        "actionthrottled": "కార్యాన్ని ఆపేసారు",
-       "actionthrottledtext": "à°¸à±\8dపామà±\81à°¨à±\81 à°¨à°¿à°°à±\8bధిà°\82à°\9aà±\87à°\82à°¦à±\81à°\95à±\81 à°\97ానà±\81, à°¤à°\95à±\8dà°\95à±\81à°µ à°¸à°®à°¯à°\82à°²à±\8b à°®à°°à±\80 à°\8eà°\95à±\8dà°\95à±\81à°µ à°¸à°¾à°°à±\8dà°²à±\81 à°\88 à°ªà°¨à°¿ à°\9aà±\87à°¯à°\95à±\81à°\82à°¡à°¾ à°ªà°°à°¿à°®à°¿à°¤à°¿ à°µà°¿à°§à°¿à°\82à°\9aà°¾à°\82. à°®à±\80à°°à±\81 à°¦à°¾à°¨à±\8dని à°\85ధిà°\97మిà°\82à°\9aారà±\81. à°\95à±\8aà°¨à±\8dà°¨ి నిమిషాలు ఆగి మరలా ప్రయత్నించండి.",
+       "actionthrottledtext": "à°¦à±\81à°¶à±\8dà°\9aà°°à±\8dయనà±\81 à°¨à°¿à°°à±\8bధిà°\82à°\9aà±\87à°\82à°¦à±\81à°\95à±\81 à°\97ానà±\81, à°¤à°\95à±\8dà°\95à±\81à°µ à°¸à°®à°¯à°\82à°²à±\8b à°®à°°à±\80 à°\8eà°\95à±\8dà°\95à±\81à°µ à°¸à°¾à°°à±\8dà°²à±\81 à°\88 à°ªà°¨à°¿ à°\9aà±\87à°¯à°\95à±\81à°\82à°¡à°¾ à°ªà°°à°¿à°®à°¿à°¤à°¿ à°µà°¿à°§à°¿à°\82à°\9aà°¾à°\82. à°®à±\80à°°à±\81 à°¦à°¾à°¨à±\8dని à°\85ధిà°\97మిà°\82à°\9aారà±\81. à°\95à±\8aà°¦à±\8dà°¦ి నిమిషాలు ఆగి మరలా ప్రయత్నించండి.",
        "protectedpagetext": "ఈ పేజీలో మార్పులు వగైరాలు చెయ్యకుండా ఉండేందుకు గాను, సంరక్షించబడింది.",
-       "viewsourcetext": "మీరీ పేజీ సోర్సును చూడవచ్చు, కాపీ చేసుకోవచ్చు:",
-       "viewyourtext": "ఈ పేజీలోని <strong>మీ మార్పుల</strong> యొక్క మూలాన్ని చూడవచ్చు, కాపీచేసుకోవచ్చు:",
+       "viewsourcetext": "మీరీ పేజీ సోర్సును చూడవచ్చు, కాపీ చేసుకోవచ్చు.",
+       "viewyourtext": "ఈ పేజీలో <strong>మీరు చేసిన మార్పుల</strong> యొక్క మూలాన్ని చూడవచ్చు, కాపీచేసుకోవచ్చు.",
        "protectedinterface": "ఈ పేజీ, ఈ వికీ యొక్క సాఫ్టువేరు ఇంటరుఫేసుకు చెందిన టెక్స్టును అందిస్తుంది. దుశ్చర్యల నివారణ కోసమై దీన్ని సంరక్షించాం. వికీలన్నిటిలోను అనువాదాలను చేర్చాలన్నా, మార్చాలన్నా మీడియావికీ స్థానికీకరణ ప్రాజెక్టైన [https://translatewiki.net/ translatewiki.net] ను వాడండి.",
        "editinginterface": "<strong>హెచ్చరిక:</strong> సాఫ్టువేరుకు ఇంటరుఫేసు టెక్స్టును అందించేందుకు పనికొచ్చే పేజీని మీరు సరిదిద్దుతున్నారు.\nఈ పేజీలో చేసే మార్పుల వల్ల ఇతర వాడుకరులకు ఇంటరుఫేసు కనబడే విధానంలో తేడావస్తుంది.",
        "translateinterface": "అన్ని వికీలలో కనిపించేలా అనువాదాలు చేర్చాలన్నా, మార్చాలన్నా, దయచేసి [https://translatewiki.net/ translatewiki.net] ను వాడండి. ఇది మీడియావికీ స్థానికీకరణ ప్రాజెక్టు.",
        "special-characters-title-emdash": "ఎమ్ డాష్",
        "special-characters-title-minus": "మైనస్ గుర్తు",
        "mw-widgets-dateinput-no-date": "ఏ తేదీనీ ఎంచుకోలేదు",
-       "mw-widgets-titleinput-description-new-page": "పేజీ ఇంకా లేదు",
-       "api-error-blacklisted": "వేరే వివరమైన శీర్షకను ఎంచుకోండి"
+       "mw-widgets-titleinput-description-new-page": "పేజీ ఇంకా లేదు"
 }
index 23c10a3..70141c2 100644 (file)
@@ -24,7 +24,8 @@
                        "Pphongpan355",
                        "Macofe",
                        "Pilarbini",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "B20180"
                ]
        },
        "tog-underline": "การขีดเส้นใต้ลิงก์:",
        "laggedslavemode": "<strong>คำเตือน:</strong> หน้านี้อาจไม่มีการปรับล่าสุด",
        "readonly": "ฐานข้อมูลถูกล็อก",
        "enterlockreason": "ใส่เหตุแห่งการล็อก ทั้งเวลาที่คาดว่าจะปลดล็อก",
-       "readonlytext": "à¸\82à¸\93ะà¸\99ีà¹\89à¸\90าà¸\99à¸\82à¹\89อมูลà¸\96ูà¸\81ลà¹\87อà¸\81มิà¹\83หà¹\89รัà¸\9aà¸\82à¹\89อมูลใหม่และการแก้ไขเพิ่มเติมอื่น อาจเป็นเพราะการบำรุงรักษาฐานข้อมูลรูทีน หลังแล้วเสร็จจะกลับมาใช้งานได้ตามปกติ\n\nผู้ดูแลระบบที่ล็อกได้ให้คำอธิบายดังนี้: $1",
+       "readonlytext": "à¸\82à¸\93ะà¸\99ีà¹\89à¸\90าà¸\99à¸\82à¹\89อมูลà¸\96ูà¸\81ลà¹\87อà¸\81รายà¸\81ารใหม่และการแก้ไขเพิ่มเติมอื่น อาจเป็นเพราะการบำรุงรักษาฐานข้อมูลรูทีน หลังแล้วเสร็จจะกลับมาใช้งานได้ตามปกติ\n\nผู้ดูแลระบบที่ล็อกได้ให้คำอธิบายดังนี้: $1",
        "missing-article": "ฐานข้อมูลไม่พบข้อความของหน้าที่ควรมี ชื่อ \"$1\" $2\n\nสาเหตุมักเกิดจากผลต่างที่ล้าสมัย หรือการเชื่อมโยงประวัติไปยังหน้านั้นถูกลบแล้ว\n\nหากไม่ใช่กรณีดังกล่าว คุณอาจพบจุดบกพร่องในซอฟต์แวร์ กรุณารายงานต่อ[[Special:ListUsers/sysop|ผู้ดูแลระบบ]] พร้อมระบุยูอาร์แอล",
        "missingarticle-rev": "(รุ่นปรับปรุง#: $1)",
        "missingarticle-diff": "(ต่าง: $1, $2)",
        "protectedinterface": "หน้านี้เป็นข้อความส่วนต่อประสานสำหรับซอฟต์แวร์บนวิกินี้ และถูกล็อกเพื่อป้องกันการกระทำผิด\nในการเพิ่มหรือเปลี่ยนแปลงการแปลสำหรับทุกวิกิ โปรดใช้ [https://translatewiki.net/ translatewiki.net] โครงการแปลมีเดียวิกิเป็นภาษาถิ่น",
        "editinginterface": "<strong>คำเตือน:</strong> คุณกำลังแก้ไขหน้าที่ใช้จัดหาข้อความอินเตอร์เฟซให้ซอฟต์แวร์\nการเปลี่ยนแปลงหน้านี้จะมีผลต่อสภาพปรากฏของส่วนต่อประสานผู้ใช้แก่ผู้ใช้อื่นบนวิกินี้",
        "translateinterface": "ในการเพิ่มหรือเปลี่ยนแปลงคำแปลสำหรับทุกวิกิ โปรดใช้ [https://translatewiki.net/ translatewiki.net] โครงการแปลเป็นภาษาถิ่นของมีเดียวิกิ",
-       "cascadeprotected": "หน้านี้ถูกป้องกันมิให้แก้ไข เพราะถูกรวมอยู่ในหน้าต่อไปนี้ซึ่งถูกล็อกโดยเปิดตัวเลือก \"ต่อเรียง\":\n$2",
+       "cascadeprotected": "หน้านี้ถูกป้องกันมิให้แก้ไข เพราะถูกรวมอยู่ใน{{PLURAL:$1|page, which is|หน้าต่อไปนี้}} ซึ่งถูกล็อกโดยเปิดตัวเลือก \"ต่อเรียง\":\n$2",
        "namespaceprotected": "คุณไม่มีสิทธิแก้ไขหน้าในเนมสเปซ <strong>$1</strong>",
        "customcssprotected": "คุณไม่มีสิทธิแก้ไขหน้า CSS นี้ เพราะมีการตั้งค่าส่วนบุคคลของผู้ใช้อื่น",
        "customjsprotected": "คุณไม่มีสิทธิแก้ไขหน้าจาวาสคริปต์นี้ เพราะหน้านี้มีการตั้งค่าส่วนบุคคลของผู้ใช้อื่น",
        "special-characters-group-bangla": "บังคลา",
        "special-characters-group-telugu": "เตลูกู",
        "special-characters-group-sinhala": "สิงหล",
-       "special-characters-group-gujarati": "คุชราต",
-       "api-error-blacklisted": "โปรดใช้ชื่ออื่นที่สื่อความหมาย"
+       "special-characters-group-gujarati": "คุชราต"
 }
index a4a02e3..8c0ed14 100644 (file)
        "tagline": "{{SITENAME}} sitesinden",
        "help": "Yardım",
        "search": "Ara",
+       "search-ignored-headings": " #<!-- bu satırı olduğu gibi bırakın --> <pre>\n# Başlıklar aramada göz ardı edilecektir.\n# Bu değişiklikler başlık ve sayfa endeksli şekilde en kısa sürede yürürlüğe girecektir.\n# Boş bir düzenleme yaparak, yeniden dizin oluşturulmasını zorlayabilirsiniz.\n# Sözdizimi aşağıdaki gibidir:\n#   * \"#\" karakteri ile başlayan her satır, satır sonuna kadar bir yorumdur.\n#   * Boş olmayan her türlü satırın tam başlığı her durumda görmezden gelinir.\nKaynaklar\nDış bağlantılar\nAyrıca bakınız\n #</pre> <!-- bu satırları olduğu gibi bırakın-->",
        "searchbutton": "Ara",
        "go": "Git",
        "searcharticle": "Git",
index f0128f9..128db0e 100644 (file)
        "prefs-namespaces": "Исемнәр мәйданы",
        "default": "килешү буенча",
        "prefs-files": "Файллар",
-       "prefs-custom-css": "Үземнең CSS",
-       "prefs-custom-js": "Үземнең JS",
+       "prefs-custom-css": "Шәхси CSS",
+       "prefs-custom-js": "Шәхси JS",
        "prefs-common-css-js": "Барлык бизәлешләр өчен гомуми CSS/JS:",
        "prefs-reset-intro": "Бу бит сезнең көйләнмәләрегезне бетерү өчен кулланыла. Бу эшне башкару нәтиҗәсендә сез яңадан үз көйләнмәләрне яңадан кайтара алмыйсыз.",
        "prefs-emailconfirm-label": "E-mail раслау",
index 757e97e..d2a098f 100644 (file)
        "databaseerror": "Медээ шыгжамыры алдаг",
        "laggedslavemode": "'''Оваарымчалыг:''' Бо арында чаартыышкыннар чок болуп болур.",
        "readonly": "шоочалаарынга медээ шыгжамыры",
-       "missing-article": "Данныйлар базазында тывар ужурлуг «$1» $2 деп арынның негеттинип турар сөзүглели тывылбаан.\n\nНургулайында ындыг байдал эрги шөлүг-биле казыттынган арынның өскерилге төөгүзүнче дамчып оралдажырга тыптыр.\n\nА шынында ындыг эвес болза, Силер программа хандырылгазының алдаанга душканыңар хөңнү.\n\nОоң дугайында кайы-бир [[Special:ListUsers/sysop|удуртукчуларга]], мүн URL-ин айытпышаан, дамчыдыңарам.",
+       "missing-article": "«$1» $2 деп арында дилеп турганың сөстер медээ үндезининден тывылбады.\n\nБаладып каапкан арынның төөгүзүн, эрги айтыг таварыштыр киргеш көөр болзуңза ындыг чүвеге таваржып болур сен.\n\nБир эвес хамыктың ужуру ындыг эвес боор болза, сен программаның шын эвес ажылдааныга душканыңар ол болур. \nОоң дугайында бээр [[Special:ListUsers/sysop|удуртукчуларга]] бижипкеш, шын эвес ажылдаан арынның URL адрезин база албан айып каар сен.",
        "missingarticle-rev": "(үндүрериниң саны: $1)",
        "missingarticle-diff": "(Ылгал: $1, $2)",
        "internalerror": "Иштики алдаг",
        "createaccountreason": "Чылдагаан:",
        "badretype": "Силерниң парлаан чажыт сөзүңер таарышпас.",
        "userexists": "Силерниң парлаан адыңар амгы үеде ажыглаттынып турар.\nӨске аттан шилип алыңар.",
-       "loginerror": "Ð\9aиÑ\80им Ð°Ð»Ð´Ð°Ð° (ЧазÑ\8bглÑ\8bг ÐºÐ¸Ñ\80им)",
+       "loginerror": "Ð\9aиÑ\80ип Ñ\88Ñ\8bдавадÑ\8bÒ£, Ñ\81ени Ñ\82анÑ\8bваан Ð±Ð¾Ð¾Ñ\80",
        "loginsuccesstitle": "Чедимчелиг кирери",
        "login-userblocked": "Бо ажыглакчы blocked.  Кирери хоржок.",
        "password-login-forbidden": "Бо ажыглакчының ады болгаш чажыт сөс хоржок.",
        "searchmenu-new": "Бо вики-төлевилелге «[[:$1]]» деп арынны кылыр.{{PLURAL:$2|0=|Ол ышкаш дилээшкиниңерниң түңнелинде тывылган арынны база көрүңер.|Ол ышкаш дилээшкиниңерниң түңнелдерин база көрүңер.}}",
        "searchprofile-articles": "үндезин арыннар",
        "searchprofile-images": "Мультимедиа",
-       "searchprofile-everything": "каяа-даа",
+       "searchprofile-everything": "Ð\9aаяа-даа",
        "searchprofile-advanced": "Делгереңгей",
        "searchprofile-articles-tooltip": "$1 иштинден дилээри",
        "searchprofile-images-tooltip": "Файлдар дилээри",
        "allmessages-language": "Дыл:",
        "allmessages-filter-submit": "Күүcедири",
        "thumbnail-more": "Улгаттыр",
-       "thumbnail_error": "Биче чурумал (миниатюра) чаяарының алдаа: $1",
+       "thumbnail_error": "Бичежек чурук болдунмады: $1",
        "import-comment": "Тайылбыр:",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|үндүрери}}",
        "tooltip-pt-userpage": "Силерниң ажыглакчы арыныңнар",
        "specialpages-group-pages": "Арыннарның даңзызы",
        "specialpages-group-pagetools": "Арын херекселдери",
        "blankpage": "Куруг арын",
-       "external_image_whitelist": " #Ð\91о Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83 Ð¾Ð»-ла Ñ\85евÑ\8dÑ\8dÑ\80 Ð°Ñ\80Ñ\82Ñ\82Ñ\8bÑ\80Ñ\8bңаÑ\80<pre>\n#ТÑ\83Ñ\80Ñ\83м Ð¸Ð»ÐµÑ\80едиглеÑ\80 (Ñ\80егÑ\83лÑ\8fÑ\80нÑ\8bе Ð²Ñ\8bÑ\80ажениÑ\8f) Ñ\84Ñ\80агменÑ\82илеÑ\80ин Ð¼Ð°Ò£Ð°Ð° Ñ\81алÑ\8bңаÑ\80 (// Ð°Ñ\80азÑ\8bнга Ñ\82Ñ\83Ñ\80аÑ\80 ÐºÐµÐ·Ñ\8dÑ\8dн)\n#Ð\94аÑ\88Ñ\82Ñ\8bкÑ\8b Ñ\87Ñ\83Ñ\80Ñ\83малдаÑ\80 URL-биле Ð¾Ð»Ð°Ñ\80 Ñ\85олбааÑ\88кан Ð±Ð¾Ð»Ñ\83Ñ\80.\n#Ð\94Ñ\83жа Ð±ÐµÑ\80геннеÑ\80и Ñ\87Ñ\83Ñ\80Ñ\83малдаÑ\80 ÐºÑ\8bлдÑ\8bÑ\80 ÐºÓ©Ñ\81Ñ\82үп ÐºÐµÐ»Ð¸Ñ\80, Ð°Ñ\80Ñ\82каннаÑ\80Ñ\8b Ñ\87Ñ\83Ñ\80Ñ\83малдаÑ\80же Ñ\88өлүг ÐºÑ\8bлдÑ\8bÑ\80 ÐºÓ©Ñ\81Ñ\82Ò¯Ñ\80.\n# \"#\" Ð´ÐµÐ¿ Ð´ÐµÐ¼Ð´ÐµÐºÑ\82ен Ñ\8dгелÑ\8dÑ\8dн Ð¾Ð´Ñ\83Ñ\80Ñ\83глаÑ\80нÑ\8b Ñ\81аналдаÑ\80 ÐºÑ\8bлдÑ\8bÑ\80 Ð±Ð¸Ð»Ð´Ð¸Ð½ÐµÑ\80.\n#Ð\9eдÑ\83Ñ\80Ñ\83глаÑ\80 Ñ\80егиÑ\81Ñ\82Ñ\80ге ÐºÑ\83нÑ\83к Ñ\8dвеÑ\81 (билинмеÑ\81)\n\n#ТÑ\83Ñ\80Ñ\83м Ð¸Ð»ÐµÑ\80едиглеÑ\80 Ñ\84Ñ\80агменÑ\82илеÑ\80ин Ð±Ð¾ Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83Ò£ ÐºÑ\8bÑ\80Ñ\8bнга Ñ\81алÑ\8bңаÑ\80. Ð\90 Ð±Ð¾ Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83 Ð¾Ð»Ñ\87аан Ñ\85евÑ\8dÑ\8dÑ\80 Ð°Ñ\80Ñ\82тырыңар</pre>",
+       "external_image_whitelist": " #Ð\91о Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83 Ð¾Ð»-ла Ñ\85евÑ\8dÑ\8dÑ\80 Ð°Ñ\80Ñ\82Ñ\8bÑ\80Ñ\8bңаÑ\80<pre>\n#ТÑ\83Ñ\80Ñ\83м Ð¸Ð»ÐµÑ\80едигниң (Ñ\80егÑ\83лÑ\8fÑ\80нÑ\8bе Ð²Ñ\8bÑ\80ажениÑ\8f) Ò¯Ð·Ò¯ÐºÑ\82еÑ\80ин Ð¼Ð°Ò£Ð°Ð° Ð±Ð¸Ð¶Ð¸Ð¿Ñ\82иңеÑ\80 (// Ð´ÐµÐ¿ Ð´ÐµÐ¼Ð´ÐµÐº Ð°Ñ\80азÑ\8bнда Ñ\82Ñ\83Ñ\80аÑ\80 ÐºÐµÐ·Ñ\8dÑ\8d) Ð´Ð°Ñ\80аазÑ\8bнда Ð±Ð¾Ð»Ð·Ð°\n#олаÑ\80 Ó©Ñ\81ке URL Ð°Ð´Ñ\80еÑ\81Ñ\82е Ñ\82Ñ\83Ñ\80аÑ\80 Ñ\87Ñ\83Ñ\80Ñ\83кÑ\82аÑ\80-биле Ñ\85аÑ\80Ñ\8bлзаа Ñ\82Ñ\83дÑ\83п Ñ\82Ñ\83Ñ\80аÑ\80.\n#ТааÑ\80Ñ\8bÑ\88кан Ñ\87Ñ\83Ñ\80Ñ\83кÑ\82аÑ\80, Ñ\87Ñ\83Ñ\80Ñ\83к Ð±Ð¾Ð¾Ð¿ Ð¾Ð»-ла Ñ\85евÑ\8dÑ\8dÑ\80 ÐºÓ©Ñ\81Ñ\82үп ÐºÐµÐ»Ð¸Ñ\80, Ð°Ñ\80Ñ\82аннаÑ\80Ñ\8b Ñ\87Ñ\83Ñ\80Ñ\83кÑ\82аÑ\80же Ð°Ð¹Ñ\8bÑ\82кан Ð°Ð¹Ñ\82Ñ\8bг Ð±Ð¾Ð¾Ð¿ Ð°Ñ\80Ñ\82Ñ\8bп ÐºÐ°Ð°Ñ\80.\n# \"#\" Ð´ÐµÐ¿ Ð´ÐµÐ¼Ð´ÐµÐºÑ\82ен Ñ\8dгелÑ\8dÑ\8dн Ð¾Ð´Ñ\83Ñ\80Ñ\83глаÑ\80 Ð±Ð¾Ð»Ð·Ð°, Ð±Ð¸Ð¶Ð¸ÐºÑ\82иң Ñ\82Ñ\83Ñ\81кай Ñ\82айÑ\8bлбÑ\8bÑ\80 Ñ\82Ñ\83Ñ\80аÑ\80 ÐºÐµÐ·Ñ\8dÑ\8d-диÑ\80.\n#Ð\9eдÑ\83Ñ\80Ñ\83гга Ñ\83лÑ\83г-даа, Ð±Ð¸Ñ\87ии-даа Ò¯Ð¶Ò¯ÐºÑ\82еÑ\80 Ð±Ð¸Ð¶Ð¸Ð¿ Ð±Ð¾Ð»Ñ\83Ñ\80.\n\n#ТÑ\83Ñ\80Ñ\83м Ð¸Ð»ÐµÑ\80едигниң ÐºÐµÐ·ÐµÐºÑ\82еÑ\80ин Ð±Ð¾ Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83Ò£ ÐºÑ\8bÑ\80Ñ\8bнга Ð±Ð¸Ð¶Ð¸Ð¿ Ñ\81алÑ\8bÑ\80 Ñ\81илеÑ\80. Ð\91о Ð¾Ð´Ñ\83Ñ\80Ñ\83гнÑ\83 Ð¾Ð»Ñ\87аан, Ñ\85евÑ\8dÑ\8dÑ\80 Ð°Ñ\80тырыңар</pre>",
        "tag-filter": "[[Special:Tags|демдек]] шүүрү:",
        "tag-filter-submit": "Шүүрү",
        "tags-title": "Демдеглелдер",
index c529978..45a58d2 100644 (file)
        "tagline": "Матеріал з {{grammar:genitive|{{SITENAME}}}}",
        "help": "Довідка",
        "search": "Пошук",
+       "search-ignored-headings": " #<!-- залиште цей рядок точно таким, яким він є --> <pre>\n# Заголовки, які будуть ігноруватися при пошуці.\n# Зміни, які набирають сили при індексуванні сторінки з заголовком.\n# Ви можете примусити переіндексувати сторінку з нульовим редагуванням.\n# Синтаксис наступний:\n#   * Усе, що починається з символу \"#\" до кінця рядка, є коментарем\n#   * Кожний непорожній рядок є точним заголовком для ігнорування\nПосилання\nЗовнішні посилання\nДив. також\n #</pre> <!-- залиште цей рядок точно таким, яким він є -->",
        "searchbutton": "Пошук",
        "go": "Перейти",
        "searcharticle": "Перейти",
        "action-applychangetags": "додавання міток разом зі змінами",
        "action-changetags": "додавання або вилучення будь-яких міток для певних версій сторінок або записів журналів",
        "action-deletechangetags": "вилучення міток з бази даних",
+       "action-purge": "очищення кешу цієї сторінки",
        "nchanges": "$1 {{PLURAL:$1|зміна|зміни|змін}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|зміна з останнього візиту|зміни з останнього візиту|змін з останнього візиту}}",
        "enhancedrc-history": "історія",
        "watchnologin": "Ви не увійшли до системи",
        "addwatch": "Додати до списку спостереження",
        "addedwatchtext": "«[[:$1]]» та її сторінка обговорення додані до вашого [[Special:Watchlist|списку спостереження]].",
+       "addedwatchtext-talk": "«[[:$1]]» та пов'язану з нею сторінку додано до Вашого [[Special:Watchlist|списку спостереження]].",
        "addedwatchtext-short": "Сторінка \" $1 \" була додана до вашого списку спостереження.",
        "removewatch": "Видалити зі списку спостереження",
        "removedwatchtext": "«[[:$1]]» та її сторінка обговорення вилучені з Вашого [[Special:Watchlist|списку спостереження]].",
+       "removedwatchtext-talk": "«[[:$1]]» та пов'язану з нею сторінку вилучено з Вашого [[Special:Watchlist|списку спостереження]].",
        "removedwatchtext-short": "Сторінка \"$1\" була видалена із вашого списку спостереження.",
        "watch": "Спостерігати",
        "watchthispage": "Спостерігати за цією сторінкою",
        "unblockip": "Розблокувати IP-адресу",
        "unblockiptext": "Використовуйте подану нижче форму, щоб відновити можливість збереження з раніше заблокованої IP-адреси.",
        "ipusubmit": "Зняти це блокування",
-       "unblocked": "[[User:$1|$1]] {{GENDER:$1|розблокований|розблокована}}",
-       "unblocked-range": "$1 розблоковано",
-       "unblocked-id": "Блокування $1 було зняте",
-       "unblocked-ip": "[[Special:Contributions/$1|$1]] вже розлоковано.",
+       "unblocked": "[[User:$1|$1]] {{GENDER:$1|розблокований|розблокована}}.",
+       "unblocked-range": "$1 розблоковано.",
+       "unblocked-id": "Блокування $1 було зняте.",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] розблоковано.",
        "blocklist": "Заблоковані користувачі",
        "ipblocklist": "Список заблокованих адрес та користувачів",
        "ipblocklist-legend": "Пошук заблокованого користувача",
        "logentry-delete-delete": "$1 {{GENDER:$2|вилучив|вилучила}} сторінку $3",
        "logentry-delete-restore": "$1 {{GENDER:$2|відновив|відновила}} сторінку $3",
        "logentry-delete-event": "$1 {{GENDER:$2|змінив|змінила}} видимість {{PLURAL:$5 запису журналу|$5 записів журналу}} на $3: $4",
-       "logentry-delete-revision": "$1 {{GENDER:$2|змінив|змінила}} видимість {{PLURAL:$5 версії|$5 версій}} на сторінці $3: $4",
+       "logentry-delete-revision": "$1 {{GENDER:$2|змінив|змінила}} видимість {{PLURAL:$5|$5 версії|$5 версій}} на сторінці $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|змінив|змінила}} видимість записів журналу подій $3",
        "logentry-delete-revision-legacy": "$1 {{GENDER:$2|змінив|змінила}} видимість версій на сторінці $3",
        "logentry-suppress-delete": "$1 {{GENDER:$2|подавив|подавила}} сторінку $3",
index 1897e60..b00ef27 100644 (file)
        "specialpages": "خصوصی صفحات",
        "specialpages-group-pages": "فہارست صفحات",
        "tag-filter": "[[Special:Tags|لوحہ]] فلٹر:",
-       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگز}}]]: $2)",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگ}}]]: $2)",
        "tags-source-header": "ماخذ",
        "tags-active-header": "فعال؟",
        "tags-active-yes": "ہاں",
index 3715253..7551378 100644 (file)
        "tagline": "Từ {{SITENAME}}",
        "help": "Trợ giúp",
        "search": "Tìm kiếm",
+       "search-ignored-headings": " #<!-- để yên dòng này --> <pre>\n# Công cụ tìm kiếm sẽ bỏ qua các đề mục này.\n# Các thay đổi trên danh sách này sẽ có hiệu lực một khi trang có đề mục được đưa vào chỉ mục.\n# Để bắt trang phải được đưa lại vào chỉ mục, thực hiện một sửa đổi vô hiệu quả.\n# Cú pháp:\n#   * Tất cả mọi thứ từ ký hiệu “#” để cuối dòng là chú thích.\n#   * Mỗi dòng có nội dung là đúng tên đề mục để bỏ qua, phân biệt chữ hoa/thường.\nTham khảo\nChú thích\nLiên kết ngoài\nXem thêm\nĐọc thêm\n #</pre> <!-- để yên dòng này -->",
        "searchbutton": "Tìm kiếm",
        "go": "Xem",
        "searcharticle": "Xem",
        "watchthis": "Theo dõi trang này",
        "savearticle": "Lưu trang",
        "savechanges": "Lưu các thay đổi",
-       "publishpage": "Xuất bản trang",
-       "publishchanges": "Xuất bản các thay đổi",
+       "publishpage": "Đăng trang",
+       "publishchanges": "Đăng thay đổi",
        "preview": "Xem trước",
        "showpreview": "Xem trước",
        "showdiff": "Xem thay đổi",
        "content-json-empty-object": "Đối tượng trống",
        "content-json-empty-array": "Mảng trống",
        "deprecated-self-close-category": "Trang có thẻ HTML tự đóng không hợp lệ",
+       "deprecated-self-close-category-desc": "Trang này chứa thẻ HTML tự đóng không hợp lệ, ví dụ <code>&lt;b/></code> hoặc <code>&lt;span/></code>. Tí nữa cách trình bày các thẻ này sẽ thay đổi để tuân theo tiêu chuẩn HTML5, nên sự sử dụng chúng trong mã wiki bị phản đối.",
        "duplicate-args-warning": "<strong>Cảnh báo:</strong> [[:$1]] đang gọi  [[:$2]] với nhiều hơn một giá trị cho thông số “$3”. Chỉ giá trị cuối cùng mới được sử dụng.",
        "duplicate-args-category": "Trang đưa đối số thừa vào bản mẫu",
        "duplicate-args-category-desc": "Trang đưa một đối số nhiều lần vào một bản mẫu được nhúng, thí dụ <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> hoặc <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "action-applychangetags": "áp dụng các thẻ cùng với những thay đổi của bạn",
        "action-changetags": "thêm và loại bỏ các thẻ tùy ý trên các phiên bản riêng và các mục nhật trình",
        "action-deletechangetags": "xóa thẻ khỏi cơ sở dữ liệu",
+       "action-purge": "làm mới trang này",
        "nchanges": "$1 thay đổi",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sau lần truy cập vừa rồi}}",
        "enhancedrc-history": "lịch sử",
        "log-action-filter-patrol": "Kiểu tuần tra:",
        "log-action-filter-protect": "Loại bảo vệ:",
        "log-action-filter-rights": "Kiểu thay đổi quyền:",
-       "log-action-filter-suppress": "Kiểu ẩn giấu",
+       "log-action-filter-suppress": "Kiểu ẩn giấu:",
        "log-action-filter-upload": "Loại tải lên:",
        "log-action-filter-all": "Tất cả",
        "log-action-filter-block-block": "Khối",
index d34e2df..036c3e3 100644 (file)
        "minoredit": "דאס איז א מינערדיגע ענדערונג",
        "watchthis": "טוט אױפֿפּאַסן דעם בלאט",
        "savearticle": "אויפהיטן בלאַט",
-       "publishpage": "פובליצירן בלאט",
+       "publishpage": "פובליקירן בלאַט",
+       "publishchanges": "פובליקירן ענדערונגען",
        "preview": "פֿאראויסקוק",
        "showpreview": "ווייזן פאָרױסקוק",
        "showdiff": "ווײַז די ענדערונגען",
        "content-json-empty-object": "ליידיגער אביעקט",
        "content-json-empty-array": "ליידיגער אריי",
        "duplicate-args-warning": "<strong>ווארענונג:</strong> [[:$1]] רופט [[:$2]] מיט מער ווי איין ווערט פארן פאראמעטער \"$3\". נאר דעם לעצטן ווערט וועט מען ניצן.",
-       "duplicate-args-category": "×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f ×\92×¢×\98×\90פ×\9c×\98×¢ ×\90ר×\92×\95×\9e×¢× ×\98×\9f ×\90×\99×\9f ×\9e×\95ס×\98ער ×¨×\95פ×\9f",
+       "duplicate-args-category": "×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f ×\92×¢×\98×\90פ×\9c×\98×¢ ×\90ר×\92×\95×\9e×¢× ×\98×\9f ×\90×\99×\9f ×\90 ×\9e×\95ס×\98ער־ר×\95×£",
        "duplicate-args-category-desc": "דער בלאט אנטהאלט מוסטער־אויפרופן וואס ניצן דופליקאטן פון ארגומענטן, ווי למשל <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> or <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "'''אזהרה:''' דער בלאט אנטהאלט צופיל טייערע פארזירער רופן.\n\nער דארף האבן ווינציגער פון  $2 {{PLURAL:$2|רוף|רופן}}, אבער אצינד {{PLURAL:$1|איז דא $1 רוף|זענען דא $1 רופן}}.",
        "expensive-parserfunction-category": "בלעטער מיט צופֿיל טייערע פאַרזער פֿונקציאן רופֿן",
        "tooltip-ca-nstab-category": "באקוקט דעם קאטעגאריע בלאט",
        "tooltip-minoredit": "באצייכענען דאס אלס מינערדיגע ענדערונג",
        "tooltip-save": "אויפֿהיטן אייערע ענדערונגען",
+       "tooltip-publish": "פובליקירן אייערע ענדערונגען",
        "tooltip-preview": "פֿארויסדיגע ווײַזונג, זײַט אזוי גוט באניצט די געלעגנהייט פֿארן אויפֿהיטן!",
        "tooltip-diff": "ווײַזן אייערע ענדערונגען צום טעקסט",
        "tooltip-compareselectedversions": "פארגלײַכם די צוויי ווערסיעס פון דעם בלאט",
        "log-action-filter-upload": "טיפ ארויפֿלאד:",
        "log-action-filter-all": "אַלע",
        "log-action-filter-delete-delete": "אויסמעקן בלאט",
+       "log-action-filter-import-interwiki": "אריבערוויקי אימפארט",
        "log-action-filter-protect-unprotect": "אראפנעמען שיץ"
 }
index d65b7c8..ba97b7c 100644 (file)
@@ -7,7 +7,8 @@
                        "Urhixidur",
                        "아라",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Wikicology"
                ]
        },
        "tog-underline": "Ìfàlàsábẹ́ àwọn àjápọ̀:",
        "otherlanguages": "Àwọn èdè míràn",
        "redirectedfrom": "(Àtúnjúwe láti $1)",
        "redirectpagesub": "Ojúewé àtúnjúwe",
+       "redirectto": "àtúnjúwe sí",
        "lastmodifiedat": "Àtunṣe ojúewé yi gbẹ̀yìn wáyé ni ago $2, ọjọ́ọdún $1.",
        "viewcount": "A ti wo ojúewé yi ni {{PLURAL:$1|ẹ̀kan péré|iye ìgbà $1}}.",
        "protectedpage": "Ojúewé oníàbò",
        "gotaccountlink": "Ẹ w'ọlé",
        "userlogin-resetlink": "À bí ẹ gbàgbé ìwọlé yín?",
        "userlogin-resetpassword-link": "Ṣé ẹ ti gbàgbé ọ̀rọ̀ìpamọ́ yín?",
+       "userlogin-helplink2": "Ìrànlọ́wọ́ láti wọlé",
        "userlogin-loggedin": "Ẹ pilẹ̀ ti jáwọlé bíi {{GENDER:$1|$1}}.\nẸ lo fọ́ọ̀mù ìsàlẹ̀ látí jáwọlé gẹ́gẹ́ bíi oníṣe míràn.",
        "userlogin-createanother": "Ìdá àkópamọ́ míràn",
        "createacct-emailrequired": "Àdírẹ̀sì email",
        "rcnotefrom": "Àwọn àtúnṣe láti ''''$2''' (títí dé '''$1''' hàn) lábẹ́.",
        "rclistfrom": "Àfihàn àwọn àtúnṣe tuntun nípa bíbẹ̀rẹ̀ láti $3 $2",
        "rcshowhideminor": "$1 àwọn àtúnṣe kékéèké",
+       "rcshowhideminor-show": "Fi hàn",
        "rcshowhideminor-hide": "Ìbòmọ́lẹ̀",
        "rcshowhidebots": "$1 àwọn bot",
        "rcshowhidebots-show": "Ìfihàn",
+       "rcshowhidebots-hide": "Fi pamọ́",
        "rcshowhideliu": "$1 àwọn oníṣe aforúkọsílẹ̀",
        "rcshowhideliu-hide": "Ìbòmọ́lẹ̀",
        "rcshowhideanons": "$1 àwọn oníṣe aláìlórúkọ",
+       "rcshowhideanons-show": "Fi hàn",
        "rcshowhideanons-hide": "Ìbòmọ́lẹ̀",
        "rcshowhidepatr": "$1 àwọn àtúnṣe ọlùṣọ́",
        "rcshowhidemine": "$1 àwọn àtúnṣe mi",
+       "rcshowhidemine-show": "Fi hàn",
        "rcshowhidemine-hide": "Ìbòmọ́lẹ̀",
        "rclinks": "Ṣ'àfihàn àtúnṣe $1 tó kẹ̀yìn ní ọjọ́ $2 sẹ́yìn<br />$3",
        "diff": "ìyàtọ̀",
        "querypage-disabled": "Ojúewé pàtàkì yìí jẹ́ ìdálẹ́kun nítorí ìsiṣẹ́.",
        "booksources": "Àwọn orísun ìwé",
        "booksources-search-legend": "Àwáàrí fún áwọn ìwé ìtọ́ka",
+       "booksources-search": "Ṣàwárí",
        "booksources-text": "Nísàlẹ̀ ni àtòjọ àwọn àjápọ̀ mọ́ àwọn ibiìtakùn míràn tí wọ́n únta ìwé tuntun àti ìwé àtijọ́, wọ́n sì le ní ọ̀rọ̀ ẹ̀kúnrẹ́rẹ́ nípa àwọn ìwé tí ẹ únwá:",
        "booksources-invalid-isbn": "ISBN náà kò dà bíi pé ó jẹ́ oníìbámu; ẹ yẹ̀ ẹ́ wò bóyá àsìṣe wà láti ibi tó jẹ́ kíkọ wá.",
        "specialloguserlabel": "Olùṣe:",
        "contributions": "Àwọn àfikún {{GENDER:$1|oníṣe}}",
        "contributions-title": "Àwọn àfikún oníṣe fún $1",
        "mycontris": "Àwọn àfikún",
+       "anoncontribs": "Àwọn àfikún",
        "contribsub2": "Fún {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Kò sí àtúnṣe tuntun tó bá àwárí mu.",
        "uctop": "(lówọ́)",
        "whatlinkshere-links": "← àwọn ìjápọ̀",
        "whatlinkshere-hideredirs": "$1 àtúnjúwe",
        "whatlinkshere-hidetrans": "$1 ìkómọ́ra",
-       "whatlinkshere-hidelinks": "$1 ìjápọ̀",
+       "whatlinkshere-hidelinks": "$1 Ã\80wá»\8dn Ã¬jápá»\8dÌ\80",
        "whatlinkshere-hideimages": "$1 àwọn ìjápọ̀ fáìlì",
        "whatlinkshere-filters": "Ajọ̀",
        "autoblockid": "Ìdínàaláraẹni #$1",
        "import-logentry-interwiki-detail": "{{PLURAL:$1|Àtúnyẹ̀wò|Àwọn àtúnyẹ̀wò}} $1 láti $2",
        "javascripttest": "Ìdánwò JavaScript",
        "javascripttest-qunit-intro": "Ẹ wo [$1 ìwé aṣàlàyé ìdánwò] ní mediawiki.org.",
-       "tooltip-pt-userpage": "Ojúewé oníṣe yín",
+       "tooltip-pt-userpage": "Ojúewé oníṣe rẹ",
        "tooltip-pt-anonuserpage": "Ojúewé oníṣe fún àdírẹ́ẹ̀sì IP tí ẹ únlò láti ṣàtúnṣe",
-       "tooltip-pt-mytalk": "Ojúewé ọ̀rọ̀ yín",
+       "tooltip-pt-mytalk": "Ojúewé ọ̀rọ̀ rẹ",
        "tooltip-pt-anontalk": "Ọ̀rọ̀ nípa àtúnṣe láti àdírẹ́ẹ̀sì IP yìí",
-       "tooltip-pt-preferences": "Àwọn ìfẹ́ràn mi",
+       "tooltip-pt-preferences": "Àwọn ìfẹ́ràn rẹ",
        "tooltip-pt-watchlist": "Àkójọ àwọn ojúewé tí ẹ̀ ún mójútó bóyá wọ́nyí padà",
-       "tooltip-pt-mycontris": "Àkójọ àwọn àfikún yín",
+       "tooltip-pt-mycontris": "Àkójọ àwọn àfikún rẹ",
        "tooltip-pt-login": "A gbà yín níyànjú kí ẹwọlé, bótilẹ̀jẹ́pẹ́ kò pọndandan.",
        "tooltip-pt-logout": "Ìjáde",
        "tooltip-pt-createaccount": "Ó dára kí ẹ dá àkópamọ́ kí ẹ sì ṣe ìtẹ̀jáwọlé, ṣùgbọ́n kò pọn dandan",
        "logentry-rights-rights": "$1 yí ìjọ́mọ ẹgbẹ́ padà fún $3 láti $4 sí $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|yí}} ọmọ ẹgbẹ́ padà fún $3",
        "logentry-rights-autopromote": "$1 jẹ́ {{GENDER:$2|gbígbénípòga}} nífúnraẹni láti $4 sí $5",
+       "logentry-upload-upload": "Ó dàfikún",
        "rightsnone": "(kòsí)",
        "revdelete-summary": "àkótán àtúnṣe",
        "feedback-adding": "Ìfikún ìdáhùn sí ojúewé...",
index 61bf918..050a780 100644 (file)
@@ -26,7 +26,8 @@
                        "Yueman",
                        "CRCHF",
                        "Shinjiman",
-                       "Macofe"
+                       "Macofe",
+                       "Jdforrester"
                ]
        },
        "tog-underline": "連結加底線:",
        "minoredit": "呢個係小修改",
        "watchthis": "睇實呢一頁",
        "savearticle": "儲存呢頁",
+       "publishpage": "發佈呢頁",
+       "publishchanges": "發佈修改",
        "preview": "預覽",
        "showpreview": "顯示預覽",
        "showdiff": "顯示差異",
index d1cba1f..0beedc7 100644 (file)
        "tagline": "来自{{SITENAME}}",
        "help": "帮助",
        "search": "搜索",
+       "search-ignored-headings": " #<!-- 请将此行保持原样 --> <pre>\n# 将被搜索忽略的标题。\n# 对此页面的更改会在带标题的页面被索引时产生影响。\n# 您可以通过进行空编辑来强制页面重新索引。\n# 语法如下:\n#  * 所有以“#”开头的行都是注释。\n#  * 所有非空白行都是要忽略的标题。\n参考文献\n外部链接\n参见\n #</pre> <!-- 请将此行保持原样 -->",
        "searchbutton": "搜索",
        "go": "前往",
        "searcharticle": "前往",
        "action-applychangetags": "连同您的更改应用标签",
        "action-changetags": "在个别修订和日志记录中添加和移除任意标签",
        "action-deletechangetags": "从数据库删除标签",
+       "action-purge": "刷新此页面",
        "nchanges": "$1次更改",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|上次访问后}}$1个",
        "enhancedrc-history": "历史",
        "watchnologin": "未登录",
        "addwatch": "添加至监视列表",
        "addedwatchtext": "“[[:$1]]”及其讨论页已加入至您的[[Special:Watchlist|监视列表]]中。",
+       "addedwatchtext-talk": "“[[:$1]]”及其相关联页面已加入至您的[[Special:Watchlist|监视列表]]中。",
        "addedwatchtext-short": "页面“$1”已加入您的监视列表。",
        "removewatch": "从监视列表中删除",
        "removedwatchtext": "“[[:$1]]”及其讨论页已从您的[[Special:Watchlist|监视列表]]中移除。",
+       "removedwatchtext-talk": "“[[:$1]]”及其相关联页面已从您的[[Special:Watchlist|监视列表]]中移除。",
        "removedwatchtext-short": "页面“$1”已从您的监视列表移除。",
        "watch": "监视",
        "watchthispage": "监视本页",
index 892ce4d..99518b6 100644 (file)
@@ -73,7 +73,8 @@
                        "Zerng07",
                        "Reke",
                        "Kly",
-                       "Cosine02"
+                       "Cosine02",
+                       "一個正常人"
                ]
        },
        "tog-underline": "底線標示連結:",
        "tagline": "出自 {{SITENAME}}",
        "help": "說明",
        "search": "搜尋",
+       "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# 在搜尋中要忽略的標題。\n# 更該此檔案以快速對己列入索引的頁面標題生效。\n# 您可以編輯時不變更內容以強制頁面重新索引。\n# 語法如下:\n#   * 任何以 \"#\" 字元開頭的行至結尾會做為註解。\n#   * 任何非空白行代表要忽略的標題。\n參考文獻\n外部連結\n參見\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "搜尋",
        "go": "前往",
        "searcharticle": "執行",
        "action-applychangetags": "連同您的變更一起套用標籤",
        "action-changetags": "加入與移除任何於各別修訂與日誌項目的標籤",
        "action-deletechangetags": "從資料庫刪除標籤",
+       "action-purge": "刷新此頁面",
        "nchanges": "$1 次變更",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|自上次拜訪}}已有 $1",
        "enhancedrc-history": "歷史",
index 2c577ed..7d79818 100644 (file)
@@ -87,7 +87,7 @@ $specialPageAliases = [
        'Listbots'                  => [ 'Seznam_botů', 'Seznam_botu' ],
        'ListDuplicatedFiles'       => [ 'Seznam_duplicitních_souborů' ],
        'Listfiles'                 => [ 'Seznam_souborů', 'Seznam_souboru' ],
-       'Listgrants'                => [ 'Seznam_grantů' ],
+       'Listgrants'                => [ 'Seznam_skupin_oprávnění', 'Seznam_skupin_opravneni', 'Seznam_grantů' ],
        'Listgrouprights'           => [ 'Práva_uživatelských_skupin', 'Seznam_uživatelských_práv', 'Seznam_uzivatelskych_prav' ],
        'Listredirects'             => [ 'Seznam_přesměrování', 'Seznam_presmerovani' ],
        'Listusers'                 => [ 'Uživatelé', 'Uzivatele', 'Seznam_uživatelů', 'Seznam_uzivatelu' ],
index 1cf80ce..d7a7cc8 100644 (file)
@@ -38,5 +38,5 @@ $namespaceAliases = [
        'श्रेणी_चर्चा' => NS_CATEGORY_TALK,
        'मिडिया' => NS_MEDIA,
        'उपेगकर्तो' => NS_USER,
-       'उपेगकर्तो चर्चा' => NS_USER_TALK
+       'उपेगकर्तो_चर्चा' => NS_USER_TALK
 ];
index 4ff8d2d..4383ab4 100644 (file)
 
 $fallback = 'kn';
 
+$namespaceNames = [
+       NS_MEDIA            => 'ಮಾದ್ಯಮೊ',
+       NS_SPECIAL          => 'ವಿಸೇಸೊ',
+       NS_TALK             => 'ಪಾತೆರ',
+       NS_USER             => 'ಬಳಕೆದಾರೆ',
+       NS_USER_TALK        => 'ಬಳಕೆದಾರೆ_ಪಾತೆರ',
+       NS_PROJECT_TALK     => '$1_ಪಾತೆರ',
+       NS_FILE             => 'ಫೈಲ್',
+       NS_FILE_TALK        => 'ಫೈಲ್_ಪಾತೆರ',
+       NS_MEDIAWIKI        => 'ಮಾದ್ಯಮೊ_ವಿಕಿ',
+       NS_MEDIAWIKI_TALK   => 'ಮಾದ್ಯಮೊ_ವಿಕಿ_ಪಾತೆರ',
+       NS_TEMPLATE         => 'ಟೆಂಪ್ಲೇಟ್',
+       NS_TEMPLATE_TALK    => 'ಟೆಂಪ್ಲೇಟ್_ಪಾತೆರ',
+       NS_HELP             => 'ಸಕಾಯೊ',
+       NS_HELP_TALK        => 'ಸಕಾಯೊ_ಪಾತೆರ',
+       NS_CATEGORY         => 'ವರ್ಗೊ',
+       NS_CATEGORY_TALK    => 'ವರ್ಗೊ_ಪಾತೆರ',
+];
+
index 27d8161..8368aab 100644 (file)
@@ -123,6 +123,12 @@ abstract class Maintenance {
         */
        private $config;
 
+       /**
+        * @see Maintenance::requireExtension
+        * @var array
+        */
+       private $requiredExtensions = [];
+
        /**
         * Used to read the options in the order they were passed.
         * Useful for option chaining (Ex. dumpBackup.php). It will
@@ -506,6 +512,42 @@ abstract class Maintenance {
                $this->config = $config;
        }
 
+       /**
+        * Indicate that the specified extension must be
+        * loaded before the script can run.
+        *
+        * This *must* be called in the constructor.
+        *
+        * @since 1.28
+        * @param string $name
+        */
+       protected function requireExtension( $name ) {
+               $this->requiredExtensions[] = $name;
+       }
+
+       /**
+        * Verify that the required extensions are installed
+        *
+        * @since 1.28
+        */
+       public function checkRequiredExtensions() {
+               $registry = ExtensionRegistry::getInstance();
+               $missing = [];
+               foreach ( $this->requiredExtensions as $name ) {
+                       if ( !$registry->isLoaded( $name ) ) {
+                               $missing[] = $name;
+                       }
+               }
+
+               if ( $missing ) {
+                       $joined = implode( ', ', $missing );
+                       $msg = "The following extensions are required to be installed "
+                               . "for this script to run: $joined. Please enable them and then try again.";
+                       $this->error( $msg, 1 );
+               }
+
+       }
+
        /**
         * Run a child maintenance script. Pass all of the current arguments
         * to it.
index a550d12..9fa6632 100644 (file)
@@ -41,8 +41,6 @@ class ChangePassword extends Maintenance {
        }
 
        public function execute() {
-               global $wgDisableAuthManager;
-
                if ( $this->hasOption( "user" ) ) {
                        $user = User::newFromName( $this->getOption( 'user' ) );
                } elseif ( $this->hasOption( "userid" ) ) {
@@ -55,17 +53,13 @@ class ChangePassword extends Maintenance {
                }
                $password = $this->getOption( 'password' );
                try {
-                       if ( $wgDisableAuthManager ) {
-                               $user->setPassword( $password );
-                       } else {
-                               $status = $user->changeAuthenticationData( [
-                                       'username' => $user->getName(),
-                                       'password' => $password,
-                                       'retype' => $password,
-                               ] );
-                               if ( !$status->isGood() ) {
-                                       throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
-                               }
+                       $status = $user->changeAuthenticationData( [
+                               'username' => $user->getName(),
+                               'password' => $password,
+                               'retype' => $password,
+                       ] );
+                       if ( !$status->isGood() ) {
+                               throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
                        }
                        $user->saveSettings();
                        $this->output( "Password set for " . $user->getName() . "\n" );
index 6d2a0e9..e83d7c6 100644 (file)
@@ -230,6 +230,13 @@ class ConvertExtensionToRegistration extends Maintenance {
 
        public function handleHooks( $realName, $value ) {
                foreach ( $value as $hookName => &$handlers ) {
+                       if ( $hookName === 'UnitTestsList' ) {
+                               $this->output( "Note: the UnitTestsList hook is no longer necessary as " .
+                                       "long as your tests are located in the \"tests/phpunit/\" directory. " .
+                                       "Please see <https://www.mediawiki.org/wiki/Manual:PHP_unit_testing/" .
+                                       "Writing_unit_tests_for_extensions#Register_your_tests> for more details.\n"
+                               );
+                       }
                        foreach ( $handlers as $func ) {
                                if ( $func instanceof Closure ) {
                                        $this->error( "Error: Closures cannot be converted to JSON. " .
index 3591b9c..1872716 100644 (file)
@@ -56,8 +56,6 @@ class CreateAndPromote extends Maintenance {
        }
 
        public function execute() {
-               global $wgDisableAuthManager;
-
                $username = $this->getArg( 0 );
                $password = $this->getArg( 1 );
                $force = $this->hasOption( 'force' );
@@ -122,17 +120,13 @@ class CreateAndPromote extends Maintenance {
                if ( $password ) {
                        # Try to set the password
                        try {
-                               if ( $wgDisableAuthManager ) {
-                                       $user->setPassword( $password );
-                               } else {
-                                       $status = $user->changeAuthenticationData( [
-                                               'username' => $user->getName(),
-                                               'password' => $password,
-                                               'retype' => $password,
-                                       ] );
-                                       if ( !$status->isGood() ) {
-                                               throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
-                                       }
+                               $status = $user->changeAuthenticationData( [
+                                       'username' => $user->getName(),
+                                       'password' => $password,
+                                       'retype' => $password,
+                               ] );
+                               if ( !$status->isGood() ) {
+                                       throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
                                }
                                if ( $exists ) {
                                        $this->output( "Password set.\n" );
index 000e5f9..1272ca2 100644 (file)
@@ -99,6 +99,9 @@ require_once "$IP/includes/Setup.php";
 // Initialize main config instance
 $maintenance->setConfig( ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
 
+// Sanity-check required extensions are installed
+$maintenance->checkRequiredExtensions();
+
 // Do the work
 $maintenance->execute();
 
index 8b1d86d..0c278bc 100644 (file)
@@ -10,12 +10,11 @@ require_once __DIR__ . '/../includes/utils/AutoloadGenerator.php';
 $base = dirname( __DIR__ );
 
 $generator = new AutoloadGenerator( $base, 'local' );
-foreach ( [ 'includes', 'languages', 'maintenance', 'mw-config' ] as $dir ) {
-       $generator->readDir( $base . '/' . $dir );
-}
-foreach ( glob( $base . '/*.php' ) as $file ) {
-       $generator->readFile( $file );
-}
+$generator->initMediaWikiDefault();
 
 // Write out the autoload
-$generator->generateAutoload( 'maintenance/generateLocalAutoload.php' );
+$fileinfo = $generator->getTargetFileinfo();
+file_put_contents(
+       $fileinfo['filename'],
+       $generator->getAutoload( 'maintenance/generateLocalAutoload.php' )
+);
index 780e049..3b75c3a 100644 (file)
     "grunt-jscs": "2.8.0",
     "grunt-jsonlint": "1.0.7",
     "grunt-karma": "2.0.0",
-    "grunt-stylelint": "0.4.0",
+    "grunt-stylelint": "0.6.0",
     "karma": "1.1.0",
     "karma-chrome-launcher": "1.0.1",
     "karma-firefox-launcher": "1.0.0",
     "karma-qunit": "1.0.0",
     "qunitjs": "1.22.0",
-    "stylelint-config-wikimedia": "0.2.2"
+    "stylelint-config-wikimedia": "0.3.0"
   }
 }
index 746cbd1..053c3f3 100644 (file)
@@ -52,6 +52,7 @@ return [
 
        // Scripts managed by the current user (stored in their user space)
        'user' => [ 'class' => 'ResourceLoaderUserModule' ],
+       'user.styles' => [ 'class' => 'ResourceLoaderUserStylesModule' ],
 
        // Scripts generated based on the current user's preferences
        'user.cssprefs' => [ 'class' => 'ResourceLoaderUserCSSPrefsModule' ],
@@ -164,6 +165,7 @@ return [
        'jquery.arrowSteps' => [
                'scripts' => 'resources/src/jquery/jquery.arrowSteps.js',
                'styles' => 'resources/src/jquery/jquery.arrowSteps.css',
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'jquery.async' => [
                'scripts' => 'resources/lib/jquery/jquery.async.js',
@@ -328,6 +330,7 @@ return [
        'jquery.spinner' => [
                'scripts' => 'resources/src/jquery/jquery.spinner.js',
                'styles' => 'resources/src/jquery/jquery.spinner.css',
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'jquery.jStorage' => [
                'scripts' => 'resources/lib/jquery/jquery.jStorage.js',
@@ -920,6 +923,7 @@ return [
                        'mediawiki.api.edit',
                        'json',
                ],
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.api.user' => [
                'scripts' => 'resources/src/mediawiki/api/user.js',
@@ -939,6 +943,7 @@ return [
                'dependencies' => [
                        'mediawiki.api',
                ],
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.api.rollback' => [
                'scripts' => 'resources/src/mediawiki/api/rollback.js',
@@ -1010,6 +1015,7 @@ return [
                        'feedback-thanks-title',
                        'feedback-useragent'
                ],
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.feedlink' => [
                'position' => 'top',
@@ -1077,6 +1083,7 @@ return [
        ],
        'mediawiki.icon' => [
                'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.inspect' => [
                'scripts' => 'resources/src/mediawiki/mediawiki.inspect.js',
@@ -1406,6 +1413,7 @@ return [
                'class' => 'ResourceLoaderEditToolbarModule',
                'scripts' => 'resources/src/mediawiki.toolbar/toolbar.js',
                'styles' => 'resources/src/mediawiki.toolbar/toolbar.less',
+               'dependencies' => 'jquery.textSelection',
                'position' => 'top',
        ],
        'mediawiki.experiments' => [
@@ -1650,6 +1658,7 @@ return [
 
        'mediawiki.libs.jpegmeta' => [
                'scripts' => 'resources/src/mediawiki.libs/mediawiki.libs.jpegmeta.js',
+               'targets' => [ 'desktop', 'mobile' ],
        ],
 
        /* MediaWiki Page */
@@ -1698,6 +1707,14 @@ return [
                'position' => 'top',
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'mediawiki.page.patrol' => [
+               'position' => 'top',
+               'styles' => [
+                       'resources/src/mediawiki/page/mediawiki.page.patrol.css',
+                       'resources/src/mediawiki/page/mediawiki.page.patrol.print.css'
+                               => [ 'media' => 'print' ],
+               ]
+       ],
        'mediawiki.page.patrol.ajax' => [
                'scripts' => 'resources/src/mediawiki/page/patrol.ajax.js',
                'dependencies' => [
index b74cd06..f3c7e3c 100644 (file)
@@ -4,11 +4,24 @@
                        "Lloffiwr",
                        "Robin Owain",
                        "ОйЛ",
-                       "DChan (WMF)"
+                       "DChan (WMF)",
+                       "Jdforrester"
                ]
        },
        "ooui-outline-control-move-down": "Symud yr eitem i lawr",
        "ooui-outline-control-move-up": "Symud yr eitem i fyny",
        "ooui-outline-control-remove": "Tynnu'r eitem",
-       "ooui-toolbar-more": "Rhagor"
+       "ooui-toolbar-more": "Rhagor",
+       "ooui-toolgroup-expand": "Mwy",
+       "ooui-toolgroup-collapse": "Llai",
+       "ooui-dialog-message-accept": "Iawn",
+       "ooui-dialog-message-reject": "Canslo",
+       "ooui-dialog-process-error": "Aeth rhywbeth o’i le",
+       "ooui-dialog-process-dismiss": "Gadael",
+       "ooui-dialog-process-retry": "Ailgeisio",
+       "ooui-dialog-process-continue": "Parhau",
+       "ooui-selectfile-button-select": "Dewis ffeil",
+       "ooui-selectfile-not-supported": "Nid oes modd dewis ffeil",
+       "ooui-selectfile-placeholder": "Dim ffeil wedi'i dewis",
+       "ooui-selectfile-dragdrop-placeholder": "Gollwng ffeil yma"
 }
index 59b7ccd..326baaf 100644 (file)
@@ -15,7 +15,7 @@
        "ooui-dialog-message-accept": "Sobib",
        "ooui-dialog-message-reject": "Loobu",
        "ooui-dialog-process-error": "Midagi läks valesti",
-       "ooui-dialog-process-dismiss": "Hülga",
+       "ooui-dialog-process-dismiss": "Sule",
        "ooui-dialog-process-retry": "Proovi uuesti",
        "ooui-dialog-process-continue": "Jätka",
        "ooui-selectfile-button-select": "Vali fail",
index 3894417..0c84bd1 100644 (file)
@@ -13,8 +13,8 @@
                        "Hwangjy9"
                ]
        },
-       "ooui-outline-control-move-down": "í\95­ëª©ì\9d\84 ì\95\84ë\9e\98ë¡\9c ì\98®ê¸°ê¸°",
-       "ooui-outline-control-move-up": "í\95­ëª©ì\9d\84 ì\9c\84ë¡\9c ì\98®ê¸°ê¸°",
+       "ooui-outline-control-move-down": "í\95­ëª©ì\9d\84 ì\95\84ë\9e\98ë¡\9c ì\9d´ë\8f\99",
+       "ooui-outline-control-move-up": "í\95­ëª©ì\9d\84 ì\9c\84ë¡\9c ì\9d´ë\8f\99",
        "ooui-outline-control-remove": "항목 제거",
        "ooui-toolbar-more": "더 보기",
        "ooui-toolgroup-expand": "더 보기",
index 4bf5dac..679f1a6 100644 (file)
@@ -6,7 +6,8 @@
                        "Elioqoshi",
                        "GretaDoci",
                        "Gertakapllani",
-                       "Techlik"
+                       "Techlik",
+                       "Liridon"
                ]
        },
        "ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
@@ -21,6 +22,8 @@
        "ooui-dialog-process-dismiss": "Largoje",
        "ooui-dialog-process-retry": "Provo përsëri",
        "ooui-dialog-process-continue": "Vazhdo",
+       "ooui-selectfile-button-select": "Përzgjidhni një skedë",
        "ooui-selectfile-not-supported": "Skedari i përzgjedhur nuk përkrahet",
-       "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar"
+       "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar",
+       "ooui-selectfile-dragdrop-placeholder": "Vendose skedën këtu"
 }
index a34432f..6a38d0d 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
index 152d444..72591cc 100644 (file)
@@ -1,15 +1,16 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-element-hidden {
        display: none !important;
+       /* stylelint-disable-line declaration-no-important */
 }
 .oo-ui-buttonElement > .oo-ui-buttonElement-button {
        cursor: pointer;
        overflow: auto;
        resize: none;
 }
+.oo-ui-textInputWidget [type="number"] {
+       -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
+.oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
+       -webkit-appearance: none;
+       margin: 0;
+}
 .oo-ui-textInputWidget [type="search"] {
        -webkit-appearance: textfield;
 }
 .oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
        cursor: pointer;
 }
-.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
-       opacity: 0 !important;
+.oo-ui-comboBoxInputWidget-php ::-webkit-calendar-picker-indicator {
+       opacity: 0;
        position: absolute;
        right: 0;
        top: 0;
index a191804..23ecccd 100644 (file)
@@ -1,15 +1,16 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-element-hidden {
        display: none !important;
+       /* stylelint-disable-line declaration-no-important */
 }
 .oo-ui-buttonElement > .oo-ui-buttonElement-button {
        cursor: pointer;
        margin-bottom: 1.25em;
 }
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
-       padding: 0.25em 0.25em 0.25em 1em;
+       padding: 0.25em 0.25em 0.25em 0.5em;
 }
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding-top: 0.25em;
        margin-top: 2em;
 }
 .oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
-       font-size: 1.1em;
        margin-bottom: 0.5em;
-       padding: 0.25em 0;
+       font-size: 1.1em;
        font-weight: bold;
 }
 .oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
        background-color: transparent;
 }
 .oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
-       padding: 0.25em 0.25em 0.25em 1em;
+       padding: 0.25em 0.25em 0.25em 0.5em;
 }
 .oo-ui-radioOptionWidget .oo-ui-radioInputWidget {
        margin-right: 0;
        background-position: center center;
        background-origin: border-box;
        background-size: 0 0;
-       border: 1px solid #777777;
+       border: 1px solid #767676;
        border-radius: 2px;
 }
 .oo-ui-checkboxInputWidget [type="checkbox"]:checked + span {
        background-size: 100% 100%;
 }
 .oo-ui-checkboxInputWidget [type="checkbox"]:active + span {
-       background-color: #cccccc;
-       border-color: #cccccc;
+       background-color: #767676;
+       border-color: #767676;
 }
 .oo-ui-checkboxInputWidget [type="checkbox"]:focus + span {
        border-width: 2px;
        background-position: center center;
        background-origin: border-box;
        background-size: 0 0;
-       border: 1px solid #777777;
+       border: 1px solid #767676;
        border-radius: 100%;
 }
 .oo-ui-radioInputWidget [type="radio"]:checked + span {
        background-size: 100% 100%;
 }
 .oo-ui-radioInputWidget [type="radio"]:active + span {
-       background-color: #cccccc;
-       border-color: #cccccc;
+       background-color: #767676;
+       border-color: #767676;
 }
 .oo-ui-radioInputWidget [type="radio"]:focus + span {
        border-width: 2px;
        overflow: auto;
        resize: none;
 }
+.oo-ui-textInputWidget [type="number"] {
+       -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
+.oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
+       -webkit-appearance: none;
+       margin: 0;
+}
 .oo-ui-textInputWidget [type="search"] {
        -webkit-appearance: textfield;
 }
           -moz-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
                transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
 }
+.oo-ui-textInputWidget.oo-ui-widget-enabled input:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:hover {
+       border-color: #aaaaaa;
+}
 .oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
 .oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
        outline: 0;
        color: #777777;
        text-shadow: 0 1px 1px #ffffff;
 }
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:hover {
+       border-color: #cccccc;
+}
 .oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:focus,
 .oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:focus {
        border-color: #cccccc;
 .oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea {
        border-color: #ff0000;
 }
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:hover {
+       border-color: #ff0000;
+}
 .oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:focus,
 .oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:focus {
        border-color: #ff0000;
 .oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
        cursor: pointer;
 }
-.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
-       opacity: 0 !important;
+.oo-ui-comboBoxInputWidget-php ::-webkit-calendar-picker-indicator {
+       opacity: 0;
        position: absolute;
        right: 0;
        top: 0;
        vertical-align: middle;
 }
 .oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
-       padding: 0.25em 0.25em 0.25em 1em;
+       padding: 0.25em 0.25em 0.25em 0.5em;
 }
 .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
        margin-right: 0;
index 2a1427b..4d32961 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
@@ -6994,7 +6994,7 @@ OO.ui.CheckboxMultiselectWidget.prototype.getRelativeFocusableItem = function (
  * @param {jQuery.Event} e
  */
 OO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {
-       var $options, checked,
+       var $options, lastClickedIndex, nowClickedIndex, i, direction, wasSelected, items,
                $lastClicked = this.$lastClicked,
                $nowClicked = $( e.target ).closest( '.oo-ui-checkboxMultioptionWidget' )
                        .not( '.oo-ui-widget-disabled' );
@@ -7002,19 +7002,32 @@ OO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {
        // Allow selecting multiple options at once by Shift-clicking them
        if ( $lastClicked && $nowClicked.length && e.shiftKey ) {
                $options = this.$group.find( '.oo-ui-checkboxMultioptionWidget' );
-               checked = $nowClicked.find( 'input' ).prop( 'checked' );
-
-               $options
-                       .slice(
-                               Math.min( $options.index( $lastClicked ), $options.index( $nowClicked ) ),
-                               Math.max( $options.index( $lastClicked ), $options.index( $nowClicked ) ) + 1
-                       )
-                       .find( 'input' )
-                       .filter( function () {
-                               return !this.disabled;
-                       } )
-                       .prop( 'checked', checked )
-                       .trigger( 'change' );
+               lastClickedIndex = $options.index( $lastClicked );
+               nowClickedIndex = $options.index( $nowClicked );
+               // If it's the same item, either the user is being silly, or it's a fake event generated by the
+               // browser. In either case we don't need custom handling.
+               if ( nowClickedIndex !== lastClickedIndex ) {
+                       items = this.items;
+                       wasSelected = items[ nowClickedIndex ].isSelected();
+                       direction = nowClickedIndex > lastClickedIndex ? 1 : -1;
+
+                       // This depends on the DOM order of the items and the order of the .items array being the same.
+                       for ( i = lastClickedIndex; i !== nowClickedIndex; i += direction ) {
+                               if ( !items[ i ].isDisabled() ) {
+                                       items[ i ].setSelected( !wasSelected );
+                               }
+                       }
+                       // For the now-clicked element, use immediate timeout to allow the browser to do its own
+                       // handling first, then set our value. The order in which events happen is different for
+                       // clicks on the <input> and on the <label> and there are additional fake clicks fired for
+                       // non-click actions that change the checkboxes.
+                       e.preventDefault();
+                       setTimeout( function () {
+                               if ( !items[ nowClickedIndex ].isDisabled() ) {
+                                       items[ nowClickedIndex ].setSelected( !wasSelected );
+                               }
+                       } );
+               }
        }
 
        if ( $nowClicked.length ) {
index d0de9df..ff18605 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
index e758f82..d69ebfa 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
 .oo-ui-popupTool .oo-ui-popupWidget-anchor {
index 0c007bb..5b60528 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
 .oo-ui-popupTool .oo-ui-popupWidget-anchor {
@@ -38,8 +38,8 @@
 .oo-ui-toolGroup {
        display: inline-block;
        vertical-align: middle;
+       border-right: 1px solid #cccccc;
        border-radius: 0;
-       border-right: 1px solid #dddddd;
 }
 .oo-ui-toolGroup-empty {
        display: none;
@@ -56,9 +56,6 @@
 .oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
        margin-left: 0;
 }
-.oo-ui-toolGroup .oo-ui-toolGroup .oo-ui-widget-enabled {
-       border-right: 0 !important;
-}
 .oo-ui-barToolGroup > .oo-ui-iconElement-icon,
 .oo-ui-barToolGroup > .oo-ui-labelElement-label {
        display: none;
        padding: 0 0.4em;
 }
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
-       border-color: rgba(0, 0, 0, 0.2);
        background-color: #eeeeee;
 }
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
        color: #555555;
 }
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled {
-       border-color: rgba(0, 0, 0, 0.2);
        box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
        background-color: #e5e5e5;
 }
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
-       border-left-color: rgba(0, 0, 0, 0.1);
-}
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
 }
 }
 .oo-ui-popupToolGroup .oo-ui-tool-link {
        padding: 0.4em 0.625em;
-       box-sizing: border-box;
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
 }
 .oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
        height: 2.5em;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
-.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
-       border-color: rgba(0, 0, 0, 0.2);
-}
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
-       border-color: rgba(0, 0, 0, 0.2);
        background-color: #eeeeee;
 }
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
        opacity: 0.9;
 }
 .oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
-       border-color: rgba(0, 0, 0, 0.1);
        box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
        background-color: #e5e5e5;
 }
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
-       border-top-color: rgba(0, 0, 0, 0.1);
-}
 .oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
-       border-color: rgba(0, 0, 0, 0.2);
        background-color: #eeeeee;
 }
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
index 66473ff..5254c76 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
index e83cce5..a267b7f 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
@@ -89,6 +89,8 @@
        left: 0;
        right: 0;
        bottom: 0;
+       /* stylelint-disable declaration-no-important */
+       /* stylelint-enable declaration-no-important */
 }
 .oo-ui-menuLayout-menu,
 .oo-ui-menuLayout-content {
 .oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
        z-index: 2;
 }
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
        cursor: default;
        height: 5.5em;
        padding: 0;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: none;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
        height: 5.5em;
        width: 5.5em;
        position: absolute;
        background-size: cover;
        background-position: center center;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
        background-size: auto;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
        opacity: 0.4;
        background-color: #cccccc;
        height: 5.5em;
        width: 5.5em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        border: 0;
        background: none;
        display: block;
        width: auto;
        margin-left: 5.5em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
        position: relative;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
        display: block;
        padding-right: 2.375em;
        overflow: hidden;
        text-overflow: ellipsis;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
        display: block;
        float: none;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
        position: absolute;
        right: 0.5em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        display: none;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: block;
        margin: 0.7em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        text-align: center;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        margin: 0;
 }
 .oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
 .oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
        display: block;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        -webkit-touch-callout: none;
        -webkit-user-select: none;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
        cursor: no-drop;
 }
 .oo-ui-selectFileWidget:last-child {
 .oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
        right: 2em;
 }
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
        background-color: #e1f3ff;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        color: #cccccc;
        text-shadow: 0 1px 1px #ffffff;
        border-color: #dddddd;
        background-color: #f3f3f3;
 }
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
        background-color: #ffffff;
        border: 1px solid #aaaaaa;
        margin-bottom: 0.5em;
        vertical-align: middle;
        border-radius: 0.25em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
        border-radius: 0.25em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
        border-style: dashed;
 }
 .oo-ui-outlineOptionWidget {
 .oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
        width: 100%;
 }
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
-       -webkit-appearance: none;
-       margin: 0;
-}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"] {
-       -moz-appearance: textfield;
-}
 .oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
        white-space: nowrap;
 }
index 375a478..8145ef9 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
@@ -95,6 +95,8 @@
        left: 0;
        right: 0;
        bottom: 0;
+       /* stylelint-disable declaration-no-important */
+       /* stylelint-enable declaration-no-important */
 }
 .oo-ui-menuLayout-menu,
 .oo-ui-menuLayout-content {
                transform: translateZ(0);
        height: 2em;
        width: 3.5em;
-       border: 1px solid #777777;
+       border: 1px solid #767676;
        border-radius: 1em;
        background-color: #ffffff;
        margin-right: 0.5em;
        min-height: 16px;
        height: 1.2em;
        border-radius: 1.2em;
-       background-color: #555555;
        -webkit-transition: left 100ms, margin-left 100ms;
           -moz-transition: left 100ms, margin-left 100ms;
                transition: left 100ms, margin-left 100ms;
        left: 1.9em;
        margin-left: -2px;
 }
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on {
-       background-color: #347bff;
-       border-color: #347bff;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
-       background-color: #ffffff;
-       box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled .oo-ui-toggleSwitchWidget-grip {
+       border: 1px solid #767676;
 }
 .oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover {
        border-color: #2962cc;
 }
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover.oo-ui-toggleWidget-on {
-       background-color: #2962cc;
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover .oo-ui-toggleSwitchWidget-grip {
        border-color: #2962cc;
 }
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover {
+       background-color: #767676;
+       border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active .oo-ui-toggleSwitchWidget-grip,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover .oo-ui-toggleSwitchWidget-grip {
+       background-color: #ffffff;
+       border-color: #ffffff;
+       box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+}
 .oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus {
        border-color: #347bff;
        box-shadow: inset 0 0 0 1px #347bff;
        outline: 0;
 }
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus .oo-ui-toggleSwitchWidget-grip {
        border-color: #347bff;
 }
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on:before {
-       border-color: #ffffff;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on {
        background-color: #347bff;
        border-color: #347bff;
 }
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active .oo-ui-toggleSwitchWidget-grip,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover .oo-ui-toggleSwitchWidget-grip {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
        background-color: #ffffff;
+       border-color: #ffffff;
        box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
 }
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:hover {
+       background-color: #2962cc;
+       border-color: #2962cc;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:active,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:active:hover {
+       background-color: #1f4999;
+       border-color: #1f4999;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:focus {
+       border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:focus:before {
+       border-color: #ffffff;
+}
 .oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
        background-color: #dddddd;
        border-color: #dddddd;
 .oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
        z-index: 2;
 }
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
        cursor: default;
        height: 5.5em;
        padding: 0;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: none;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
        height: 5.5em;
        width: 5.5em;
        position: absolute;
        background-size: cover;
        background-position: center center;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
        background-size: auto;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
        opacity: 0.4;
        background-color: #cccccc;
        height: 5.5em;
        width: 5.5em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        border: 0;
        background: none;
        display: block;
        width: auto;
        margin-left: 5.5em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
        position: relative;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
        display: block;
        padding-right: 2.375em;
        overflow: hidden;
        text-overflow: ellipsis;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
        display: block;
        float: none;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
        position: absolute;
        right: 0.5em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        display: none;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: block;
        margin: 0.7em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        text-align: center;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        margin: 0;
 }
 .oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
 .oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
        display: block;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        -webkit-touch-callout: none;
        -webkit-user-select: none;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
        cursor: no-drop;
 }
 .oo-ui-selectFileWidget:last-child {
        right: 2em;
        padding-left: 0;
 }
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
        background-color: #ebf2ff;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
        border-color: #dddddd;
        background-color: #f3f3f3;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
        color: #cccccc;
        text-shadow: 0 1px 1px #ffffff;
 }
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
        background-color: #ffffff;
        border: 1px solid #cccccc;
        margin-bottom: 0.5em;
        overflow: hidden;
        border-radius: 2px;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
        border-radius: 2px;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
        background-color: #eeeeee;
        border-style: dashed;
 }
 .oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
        width: 100%;
 }
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
-       -webkit-appearance: none;
-       margin: 0;
-}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"] {
-       -moz-appearance: textfield;
-}
 .oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
        white-space: nowrap;
 }
index 8d93b80..cd62339 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
@@ -4365,8 +4365,8 @@ OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
                this.selectButton.setIcon( 'upload' );
                this.$thumbnail = $( '<div>' ).addClass( 'oo-ui-selectFileWidget-thumbnail' );
                this.setPendingElement( this.$thumbnail );
-               this.$dropTarget = $( '<div>' )
-                       .addClass( 'oo-ui-selectFileWidget-dropTarget' )
+               this.$element
+                       .addClass( 'oo-ui-selectFileWidget-dropTarget oo-ui-selectFileWidget' )
                        .on( {
                                click: this.onDropTargetClick.bind( this )
                        } )
@@ -4378,7 +4378,6 @@ OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
                                        .addClass( 'oo-ui-selectFileWidget-dropLabel' )
                                        .text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )
                        );
-               this.$element.append( this.$dropTarget );
        } else {
                this.$element
                        .addClass( 'oo-ui-selectFileWidget' )
@@ -4504,12 +4503,12 @@ OO.ui.SelectFileWidget.prototype.updateUI = function () {
                                }.bind( this ) ).always( function () {
                                        this.popPending();
                                }.bind( this ) );
-                               this.$dropTarget.off( 'click' );
+                               this.$element.off( 'click' );
                        }
                } else {
                        if ( this.showDropTarget ) {
-                               this.$dropTarget.off( 'click' );
-                               this.$dropTarget.on( {
+                               this.$element.off( 'click' );
+                               this.$element.on( {
                                        click: this.onDropTargetClick.bind( this )
                                } );
                                this.$thumbnail
@@ -5053,24 +5052,20 @@ OO.ui.NumberInputWidget = function OoUiNumberInputWidget( config ) {
                this.minusButton = new OO.ui.ButtonWidget( $.extend(
                        {
                                disabled: this.isDisabled(),
-                               tabIndex: -1
-                       },
-                       config.minusButton,
-                       {
+                               tabIndex: -1,
                                classes: [ 'oo-ui-numberInputWidget-minusButton' ],
                                label: '−'
-                       }
+                       },
+                       config.minusButton
                ) );
                this.plusButton = new OO.ui.ButtonWidget( $.extend(
                        {
                                disabled: this.isDisabled(),
-                               tabIndex: -1
-                       },
-                       config.plusButton,
-                       {
+                               tabIndex: -1,
                                classes: [ 'oo-ui-numberInputWidget-plusButton' ],
                                label: '+'
-                       }
+                       },
+                       config.plusButton
                ) );
        }
 
index 66cd523..55f891a 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-actionWidget.oo-ui-pendingElement-pending {
        background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
index 30bf1c4..0d3976f 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
  */
 .oo-ui-window {
        background: transparent;
        text-align: left;
 }
 .oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
-       border-right: 1px solid #e5e5e5;
+       border-right: 1px solid #cccccc;
        margin: 0;
 }
 .oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
        border-right-width: 0;
 }
 .oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
-       border-bottom: 1px solid #e5e5e5;
+       border-bottom: 1px solid #cccccc;
        margin: 0;
 }
 .oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
index 6446302..0e9dbf1 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
  */
 ( function ( OO ) {
 
diff --git a/resources/lib/oojs-ui/themes/apex/icons-alerts.json b/resources/lib/oojs-ui/themes/apex/icons-alerts.json
new file mode 100644 (file)
index 0000000..892b8db
--- /dev/null
@@ -0,0 +1,34 @@
+{
+       "prefix": "oo-ui-icon",
+       "intro": "@import '../../../../src/styles/common';",
+       "images": {
+               "bell": { "file": "images/icons/bell.svg" },
+               "bellOn": { "file": {
+                       "ltr": "images/icons/bellOn-ltr.svg",
+                       "rtl": "images/icons/bellOn-rtl.svg"
+               } },
+               "eye": { "file": "images/icons/eye.svg" },
+               "eyeClosed": { "file": "images/icons/eyeClosed.svg" },
+               "message": { "file": {
+                       "ltr": "images/icons/message-ltr.svg",
+                       "rtl": "images/icons/message-rtl.svg"
+               } },
+               "signature": { "file": {
+                       "ltr": "images/icons/signature-ltr.svg",
+                       "rtl": "images/icons/signature-rtl.svg"
+               } },
+               "speechBubble": { "file": {
+                       "ltr": "images/icons/speechBubble-ltr.svg",
+                       "rtl": "images/icons/speechBubble-rtl.svg"
+               } },
+               "speechBubbleAdd": { "file": {
+                       "ltr": "images/icons/speechBubbleAdd-ltr.svg",
+                       "rtl": "images/icons/speechBubbleAdd-rtl.svg"
+               } },
+               "speechBubbles": { "file": {
+                       "ltr": "images/icons/speechBubbles-ltr.svg",
+                       "rtl": "images/icons/speechBubbles-rtl.svg"
+               } },
+               "tray": { "file": "images/icons/tray.svg" }
+       }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bell.png b/resources/lib/oojs-ui/themes/apex/images/icons/bell.png
new file mode 100644 (file)
index 0000000..91e8397
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/bell.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bell.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bell.svg
new file mode 100644 (file)
index 0000000..09b65f2
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.png
new file mode 100644 (file)
index 0000000..fb13de1
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-ltr.svg
new file mode 100644 (file)
index 0000000..855581b
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.png
new file mode 100644 (file)
index 0000000..b05fd4c
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bellOn-rtl.svg
new file mode 100644 (file)
index 0000000..e1f2961
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/eye.png b/resources/lib/oojs-ui/themes/apex/images/icons/eye.png
new file mode 100644 (file)
index 0000000..62c82c0
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/eye.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/eye.svg b/resources/lib/oojs-ui/themes/apex/images/icons/eye.svg
new file mode 100644 (file)
index 0000000..343e9cf
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
+    <circle cx="12" cy="14" r="2"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.png b/resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.png
new file mode 100644 (file)
index 0000000..1ac37d6
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.svg b/resources/lib/oojs-ui/themes/apex/images/icons/eyeClosed.svg
new file mode 100644 (file)
index 0000000..d17f2c8
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M19.4 12.7c.7-.8 1.2-1.7 1.4-2.7h-1.6c-.9 2.5-3.9 4.4-7.7 4.6h-.1c-3.7-.2-6.8-2.1-7.7-4.6H2.2c.2 1 .8 1.9 1.4 2.7l-2 2 .7.7 2-2c.8.6 1.7 1.2 2.7 1.7l-1 2.8.9.3 1-2.8c1 .3 2 .6 3.1.6v3h1v-3c1.1-.1 2.2-.3 3.1-.6l1 2.8.9-.3-1-2.8c1-.4 1.9-1 2.6-1.7l2 2 .7-.7-1.9-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.png
new file mode 100644 (file)
index 0000000..2171c1f
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/message-ltr.svg
new file mode 100644 (file)
index 0000000..842d312
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M21 9c0-1.7-1.3-3-3-3H3v3l9 4 9-4zM3 11v6c0 1.7 1.3 3 3 3h15v-9l-9 4-9-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.png
new file mode 100644 (file)
index 0000000..fba7920
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/message-rtl.svg
new file mode 100644 (file)
index 0000000..0a22c75
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3H3v-9l9 4 9-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.png
new file mode 100644 (file)
index 0000000..f68a7bf
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/signature-ltr.svg
new file mode 100644 (file)
index 0000000..03b34cf
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M0 20h24v1H0v-1zm6-8l-1-1-2 2-2-2-1 1 2 2-2 2 1 1 2-2 2 2 1-1-2-2zm15.6 3.7c-.9-.5-1.9-.5-2.7 0-1.5.9-3.1.4-3.1.4-.4-.2-.8-.4-1.1-.6 2.2-.6 4.4-1.8 6-3.9 1.1-1.2 2.5-3.9.4-6-.7-.7-1.6-1.1-2.7-1-1.4.1-2.8.9-3.9 2.1-.9 1.1-3.1 4.5-2.3 7.5 0 .1 0 .2.1.3-2.3.3-4.2.2-4.4.1v1.5c.7.1 2.7.2 5.1-.2.5.7 1.3 1.2 2.3 1.6.1 0 2.4.8 4.5-.6.5-.3.9-.1 1.1 0 .4.2.7.6.7 1H23c0-.8-.6-1.7-1.4-2.2zm-8-1.7c-.5-2.2 1.1-5.1 2-6.2.8-.9 1.8-1.5 2.8-1.6h.1c.6 0 1.1.2 1.5.6 1.6 1.6-.4 3.9-.5 4-1.5 2-3.7 3-5.8 3.5l-.1-.3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.png
new file mode 100644 (file)
index 0000000..9166e8d
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/signature-rtl.svg
new file mode 100644 (file)
index 0000000..326281a
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M24 20H0v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zM2.4 15.7c.9-.5 1.9-.5 2.7 0 1.5.9 3.1.4 3.1.4.4-.2.8-.4 1.1-.6-2.2-.6-4.4-1.8-6-3.9-1.1-1.2-2.5-3.9-.4-6 .7-.7 1.6-1.1 2.7-1 1.4.1 2.8.9 3.9 2.1.9 1.1 3.1 4.5 2.3 7.5 0 .1 0 .2-.1.3 2.3.3 4.2.2 4.4.1v1.5c-.7.1-2.7.2-5.1-.2-.5.7-1.3 1.2-2.3 1.6-.1 0-2.4.8-4.5-.6-.5-.3-.9-.1-1.1 0-.4.2-.7.6-.7 1H1c0-.8.6-1.7 1.4-2.2zm8-1.7c.5-2.2-1.1-5.1-2-6.2-.8-.9-1.8-1.5-2.8-1.6h-.1c-.6 0-1.1.2-1.5.6-1.6 1.6.4 3.9.5 4 1.5 2 3.7 3 5.8 3.5l.1-.3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.png
new file mode 100644 (file)
index 0000000..2eedf9f
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-ltr.svg
new file mode 100644 (file)
index 0000000..83d47c1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M19 20H2l3-3V6h17v11c0 1.7-1.3 3-3 3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.png
new file mode 100644 (file)
index 0000000..0d14443
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubble-rtl.svg
new file mode 100644 (file)
index 0000000..e7dd668
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.png
new file mode 100644 (file)
index 0000000..aafac18
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-ltr.svg
new file mode 100644 (file)
index 0000000..c7134c3
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3V6H5zm8 3h1v3h3v1h-3v3h-1v-3h-3v-1h3V9z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.png
new file mode 100644 (file)
index 0000000..9254844
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbleAdd-rtl.svg
new file mode 100644 (file)
index 0000000..08462e0
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M2 6v11c0 1.7 1.3 3 3 3h17l-3-3V6H2zm8 3h1v3h3v1h-3v3h-1v-3H7v-1h3V9z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.png
new file mode 100644 (file)
index 0000000..f2e0564
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-ltr.svg
new file mode 100644 (file)
index 0000000..d683218
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M20 9v9l2 2H8V9h12zM3 4h12v4H7v7H1l2-2V4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.png
new file mode 100644 (file)
index 0000000..9c67f3f
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/speechBubbles-rtl.svg
new file mode 100644 (file)
index 0000000..db548a4
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M3 9v9l-2 2h14V9H3zm17-5H8v4h8v7h6l-2-2V4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/tray.png b/resources/lib/oojs-ui/themes/apex/images/icons/tray.png
new file mode 100644 (file)
index 0000000..e5c5e8f
Binary files /dev/null and b/resources/lib/oojs-ui/themes/apex/images/icons/tray.png differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/tray.svg b/resources/lib/oojs-ui/themes/apex/images/icons/tray.svg
new file mode 100644 (file)
index 0000000..d7ab69b
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
index 79f644e..6894d6e 100644 (file)
@@ -35,6 +35,7 @@
                "speechBubbles": { "file": {
                        "ltr": "images/icons/speechBubbles-ltr.svg",
                        "rtl": "images/icons/speechBubbles-rtl.svg"
-               } }
+               } },
+               "tray": { "file": "images/icons/tray.svg" }
        }
 }
index 2f0c960..05911d3 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png differ
index 7ed3635..645c9cc 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
-    <path d="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+    <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
 </svg>
index b86d5f7..91e8397 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png differ
index 787ed14..09b65f2 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-    <path d="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+    <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
 </svg>
index 1c0de72..fb21370 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png differ
index c032294..07de130 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
-    <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 19.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+    <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
 </svg>
index 1f9ae71..fb13de1 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png differ
index f68a8e0..855581b 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-    <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 19.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+    <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
 </svg>
index c21e1c0..d0ebae5 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.png differ
index 34ec94b..30617cb 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
-    <path d="M6.21 14.7L4.51 10c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+    <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
 </svg>
index 81d9a0a..b05fd4c 100644 (file)
Binary files a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png differ
index 92bcef5..e1f2961 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-    <path d="M6.21 14.7L4.51 10c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+    <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
 </svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.png
new file mode 100644 (file)
index 0000000..6196d39
Binary files /dev/null and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.png differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray-invert.svg
new file mode 100644 (file)
index 0000000..9cd3854
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
+    <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.png
new file mode 100644 (file)
index 0000000..e5c5e8f
Binary files /dev/null and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.png differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tray.svg
new file mode 100644 (file)
index 0000000..d7ab69b
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
index 6ff2e01..e52d6a7 100644 (file)
@@ -197,7 +197,7 @@ $.fn.updateTooltipAccessKeys.getAccessKeyLabel = getAccessKeyLabel;
  * getAccessKeyPrefix
  *
  * @method updateTooltipAccessKeys_getAccessKeyPrefix
- * @deprecated 1.27 Use #getAccessKeyModifiers
+ * @deprecated since 1.27 Use #getAccessKeyModifiers
  */
 $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
        return getAccessKeyModifiers( ua ).join( '-' ) + '-';
index 50bfa87..62be0d8 100644 (file)
                        for ( key in ts.collationTable ) {
                                // Check hasOwn to be safe
                                if ( ts.collationTable.hasOwnProperty( key ) ) {
-                                       keys.push( key );
+                                       keys.push( mw.RegExp.escape( key ) );
                                }
                        }
                        if ( keys.length ) {
-                               ts.collationRegex = new RegExp( '[' + keys.join( '' ) + ']', 'ig' );
+                               ts.collationRegex = new RegExp( keys.join( '|' ), 'ig' );
                        }
                }
        }
index 4209aa1..0ee4058 100644 (file)
 .editButtons input:first-child {
        margin-left: .1em;
 }
+
+/*
+ * Add a bit of margin space between the preview and the toolbar.
+ * This replaces the ugly <p><br /></p> we used to insert into the page source
+ */
+#wikiPreview.ontop {
+       margin-bottom: 1em;
+}
index d387a2d..6a7c76a 100644 (file)
@@ -19,7 +19,6 @@ div#column-one,
 #footer-places,
 .mw-hidden-catlinks,
 .usermessage,
-.patrollink,
 .ns-0 .mw-redirectedfrom,
 div.magnify,
 #mw-navigation,
index 7ccf59e..786f53d 100644 (file)
@@ -289,11 +289,6 @@ table.small {
        font-style: italic;
 }
 
-span.unpatrolled {
-       font-weight: bold;
-       color: #f00;
-}
-
 div.gallerybox {
        width: 150px;
 }
index fc16377..38d2a27 100644 (file)
@@ -98,14 +98,6 @@ span.comment {
        unicode-bidi: isolate;
 }
 
-/**
- * Add a bit of margin space between the preview and the toolbar.
- * This replaces the ugly <p><br /></p> we used to insert into the page source
- */
-#wikiPreview.ontop {
-       margin-bottom: 1em;
-}
-
 /* Stop floats from intruding into edit area in previews */
 #editform,
 #toolbar,
@@ -123,23 +115,6 @@ span.history-deleted {
        font-style: italic;
 }
 
-/**
- * Patrol stuff
- */
-.not-patrolled {
-       background-color: #ffa;
-}
-
-.unpatrolled {
-       font-weight: bold;
-       color: #f00;
-}
-
-div.patrollink {
-       font-size: 75%;
-       text-align: right;
-}
-
 /**
  * Forms
  */
@@ -704,7 +679,6 @@ ol:lang(or) li {
 #mw-revision-info-current,
 #mw-revision-nav {
        direction: ltr;
-       display: inline;
 }
 
 /* Images */
index f2019e7..4b8eced 100644 (file)
@@ -115,9 +115,3 @@ table.mw-userrights-groups * td,
 table.mw-userrights-groups * th {
        padding-right: 1.5em;
 }
-
-/* Special:Upload */
-p.mw-upload-editlicenses {
-       font-size: 90%;
-       text-align: right;
-}
index b916248..283df85 100644 (file)
@@ -8,3 +8,8 @@
        color: #705000;
        background-color: #fdf1d1;
 }
+
+p.mw-upload-editlicenses {
+       font-size: 90%;
+       text-align: right;
+}
index ff4d1c2..4c57faa 100644 (file)
                },
                // slash, colon (not supported by file systems like NTFS/Windows, Mac OS 9 [:], ext4 [/])
                {
-                       pattern: /[:\/#]/g,
+                       pattern: new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']', 'g' ),
                        replace: '-',
                        fileRule: true
                },
index 5b9d88c..a9e75d7 100644 (file)
@@ -19,6 +19,9 @@
        width: 39%;
 }
 
+/* Flatlist styling for PHP widgets... */
+.mw-htmlform-flatlist .oo-ui-fieldLayout-align-inline,
+/* ...and for JS widgets */
 .mw-htmlform-flatlist .oo-ui-optionWidget,
 .mw-htmlform-flatlist .oo-ui-multioptionWidget {
        display: inline-block;
index 3600000..ef4f6df 100644 (file)
                         * 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.
                         *
+                        * @private
                         * @param {string} [cssText=cssBuffer] If called without cssText,
                         *  the internal buffer will be inserted instead.
                         * @param {Function} [callback]
                        }
 
                        /**
-                        * @since 1.26
+                        * @private
                         * @param {Array} modules List of module names
                         * @return {string} Hash of concatenated version hashes.
                         */
                         * size of the startup module. This function changes those dependency lists back to
                         * arrays of strings.
                         *
+                        * @private
                         * @param {Array} modules Modules array
                         */
                        function resolveIndexedDependencies( modules ) {
 
                                /**
                                 * Batch-request queued dependencies from the server.
+                                *
+                                * @protected
                                 */
                                work: function () {
                                        var     reqBase, splits, maxQueryLength, q, b, bSource, bGroup, bSourceGroup,
                                /**
                                 * Get the exported value of a module.
                                 *
-                                * Module provide this value via their local `module.exports`.
+                                * Modules may provide this via their local `module.exports`.
                                 *
+                                * @protected
                                 * @since 1.27
                                 * @return {Array}
                                 */
diff --git a/resources/src/mediawiki/page/mediawiki.page.patrol.css b/resources/src/mediawiki/page/mediawiki.page.patrol.css
new file mode 100644 (file)
index 0000000..f237dbd
--- /dev/null
@@ -0,0 +1,13 @@
+.not-patrolled {
+       background-color: #ffa;
+}
+
+.unpatrolled {
+       font-weight: bold;
+       color: #f00;
+}
+
+.patrollink {
+       font-size: 75%;
+       text-align: right;
+}
diff --git a/resources/src/mediawiki/page/mediawiki.page.patrol.print.css b/resources/src/mediawiki/page/mediawiki.page.patrol.print.css
new file mode 100644 (file)
index 0000000..497bceb
--- /dev/null
@@ -0,0 +1,3 @@
+.patrollink {
+       display: none;
+}
index 2bb1d2e..ef540a8 100644 (file)
@@ -134,6 +134,7 @@ $wgAutoloadClasses += [
        'MockSvgHandler' => "$testDir/phpunit/mocks/media/MockSvgHandler.php",
        'MockDjVuHandler' => "$testDir/phpunit/mocks/media/MockDjVuHandler.php",
        'MockOggHandler' => "$testDir/phpunit/mocks/media/MockOggHandler.php",
+       'MockMediaHandlerFactory' => "$testDir/phpunit/mocks/media/MockMediaHandlerFactory.php",
        'MockWebRequest' => "$testDir/phpunit/mocks/MockWebRequest.php",
        'MediaWiki\\Session\\DummySessionBackend'
                => "$testDir/phpunit/mocks/session/DummySessionBackend.php",
index 8dfe628..27f1454 100644 (file)
@@ -341,7 +341,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
                // TODO: move global state into MediaWikiServices
                RequestContext::resetMain();
-               MediaHandler::resetCache();
                if ( session_id() !== '' ) {
                        session_write_close();
                        session_id( '' );
@@ -530,7 +529,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
                // TODO: move global state into MediaWikiServices
                RequestContext::resetMain();
-               MediaHandler::resetCache();
                if ( session_id() !== '' ) {
                        session_write_close();
                        session_id( '' );
@@ -1775,4 +1773,15 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                return $buffer;
        }
 
+       /**
+        * Create a temporary hook handler which will be reset by tearDown.
+        * This replaces other handlers for the same hook.
+        * @param string $hookName Hook name
+        * @param mixed $handler Value suitable for a hook handler
+        * @since 1.28
+        */
+       protected function setTemporaryHook( $hookName, $handler ) {
+               $this->mergeMwGlobalArrayValue( 'wgHooks', [ $hookName => [ $handler ] ] );
+       }
+
 }
diff --git a/tests/phpunit/data/templates/conds.mustache b/tests/phpunit/data/templates/conds.mustache
deleted file mode 100644 (file)
index 5ebd2ea..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{{#list}}oh no{{/list}}{{#foo}}none of this should render{{/foo}}
\ No newline at end of file
index a61b328..9d9815b 100644 (file)
@@ -18,9 +18,6 @@ class WfThumbIsStandardTest extends MediaWikiTestCase {
                                [ 300, 225 ],
                                [ 800, 600 ],
                        ],
-                       'wgMediaHandlers' => [
-                               'unknown/unknown' => 'MockBitmapHandler',
-                       ],
                ] );
        }
 
@@ -95,6 +92,7 @@ class WfThumbIsStandardTest extends MediaWikiTestCase {
         * @dataProvider provideThumbParams
         */
        public function testIsStandard( $message, $expected, $params ) {
+               $this->setService( 'MediaHandlerFactory', new MockMediaHandlerFactory() );
                $this->assertSame(
                        $expected,
                        wfThumbIsStandard( new FakeDimensionFile( [ 2000, 1800 ] ), $params ),
index d20344d..ac8c43b 100644 (file)
@@ -316,6 +316,7 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        'DBLoadBalancer' => [ 'DBLoadBalancer', 'LoadBalancer' ],
                        'WatchedItemStore' => [ 'WatchedItemStore', WatchedItemStore::class ],
                        'WatchedItemQueryService' => [ 'WatchedItemQueryService', WatchedItemQueryService::class ],
+                       'MediaHandlerFactory' => [ 'MediaHandlerFactory', MediaHandlerFactory::class ],
                        'GenderCache' => [ 'GenderCache', GenderCache::class ],
                        'LinkCache' => [ 'LinkCache', LinkCache::class ],
                        'LinkRenderer' => [ 'LinkRenderer', LinkRenderer::class ],
index 917a6ad..487ab84 100644 (file)
@@ -13,8 +13,6 @@ class ApiLoginTest extends ApiTestCase {
         * Test result of attempted login with an empty username
         */
        public function testApiLoginNoName() {
-               global $wgDisableAuthManager;
-
                $session = [
                        'wsTokenSecrets' => [ 'login' => 'foobar' ],
                ];
@@ -22,11 +20,11 @@ class ApiLoginTest extends ApiTestCase {
                        'lgname' => '', 'lgpassword' => self::$users['sysop']->getPassword(),
                        'lgtoken' => (string)( new MediaWiki\Session\Token( 'foobar', '' ) )
                ], $session );
-               $this->assertEquals( $wgDisableAuthManager ? 'NoName' : 'Failed', $data[0]['login']['result'] );
+               $this->assertEquals( 'Failed', $data[0]['login']['result'] );
        }
 
        public function testApiLoginBadPass() {
-               global $wgServer, $wgDisableAuthManager;
+               global $wgServer;
 
                $user = self::$users['sysop'];
                $userName = $user->getUser()->getName();
@@ -64,7 +62,7 @@ class ApiLoginTest extends ApiTestCase {
                $this->assertNotInternalType( "bool", $result );
                $a = $result["login"]["result"];
 
-               $this->assertEquals( $wgDisableAuthManager ? 'WrongPass' : 'Failed', $a );
+               $this->assertEquals( 'Failed', $a );
        }
 
        public function testApiLoginGoodPass() {
@@ -190,6 +188,7 @@ class ApiLoginTest extends ApiTestCase {
                $this->assertArrayHasKey( "login", $data[0] );
                $this->assertArrayHasKey( "result", $data[0]['login'] );
                $this->assertEquals( "Success", $data[0]['login']['result'] );
+               $this->assertArrayHasKey( 'lgtoken', $data[0]['login'] );
        }
 
        public function testBotPassword() {
index ac4d2c9..7e1f9d8 100644 (file)
@@ -9,7 +9,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
        protected $apiContext;
 
        protected function setUp() {
-               global $wgServer, $wgDisableAuthManager;
+               global $wgServer;
 
                parent::setUp();
                self::$apiUrl = $wgServer . wfScript( 'api' );
@@ -22,7 +22,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
                ];
 
                $this->setMwGlobals( [
-                       'wgAuth' => $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin,
+                       'wgAuth' => new MediaWiki\Auth\AuthManagerAuthPlugin,
                        'wgRequest' => new FauxRequest( [] ),
                        'wgUser' => self::$users['sysop']->getUser(),
                ] );
index 1ded0df..89e48f7 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractAuthenticationProvider
  */
 class AbstractAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractAuthenticationProvider() {
                $provider = $this->getMockForAbstractClass( AbstractAuthenticationProvider::class );
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index ecce932..a1cdf7e 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
  */
 class AbstractPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = $this->getMockForAbstractClass(
                        AbstractPasswordPrimaryAuthenticationProvider::class
index c35430e..9638451 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPreAuthenticationProvider
  */
 class AbstractPreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractPreAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 420a330..d8588d5 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPrimaryAuthenticationProvider
  */
 class AbstractPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractPrimaryAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 9cdc051..bb90dd9 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractSecondaryAuthenticationProvider
  */
 class AbstractSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractSecondaryAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 82608b0..99b9029 100644 (file)
@@ -30,12 +30,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
        protected $managerPriv;
 
        protected function setUp() {
-               global $wgDisableAuthManager;
-
                parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
 
                $this->setMwGlobals( [ 'wgAuth' => null ] );
                $this->stashMwGlobals( [ 'wgHooks' ] );
@@ -200,14 +195,6 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        \RequestContext::getMain()->getConfig(),
                        \TestingAccessWrapper::newFromObject( $singleton )->config
                );
-
-               $this->setMwGlobals( [ 'wgDisableAuthManager' => true ] );
-               try {
-                       AuthManager::singleton();
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( \BadMethodCallException $ex ) {
-                       $this->assertSame( '$wgDisableAuthManager is set', $ex->getMessage() );
-               }
        }
 
        public function testCanAuthenticateNow() {
index 44f2743..96e50e0 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider
  */
 class AuthPluginPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstruction() {
                $plugin = new AuthManagerAuthPlugin();
                try {
index cac031c..a7df221 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthenticationRequest
  */
 class AuthenticationRequestTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testBasics() {
                $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
 
index aafcd09..aa0e3c7 100644 (file)
@@ -6,15 +6,6 @@ namespace MediaWiki\Auth;
  * @group AuthManager
  */
 abstract class AuthenticationRequestTestCase extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        abstract protected function getInstance( array $args = [] );
 
        /**
index 58ff8b6..477b161 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthenticationResponse
  */
 class AuthenticationResponseTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideConstructors
         * @param string $constructor
index f2341bc..e6d3ecf 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider
  */
 class CheckBlocksSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = new CheckBlocksSecondaryAuthenticationProvider();
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index 580ef6c..3fc45a4 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
  */
 class ConfirmLinkSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideGetAuthenticationRequests
         * @param string $action
index 3548002..d482453 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\LegacyHookPreAuthenticationProvider
  */
 class LegacyHookPreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         * @return LegacyHookPreAuthenticationProvider
index 713c27e..088dd00 100644 (file)
@@ -13,15 +13,6 @@ class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase
        private $config = null;
        private $validity = null;
 
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         *
index 79c138b..90ed542 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
  */
 class ResetPasswordSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideGetAuthenticationRequests
         * @param string $action
index 8d0bf96..515a5b3 100644 (file)
@@ -13,15 +13,6 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
        private $config = null;
        private $validity = null;
 
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         *
index 8b273b5..aa6f0e8 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ThrottlePreAuthenticationProvider
  */
 class ThrottlePreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = new ThrottlePreAuthenticationProvider();
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index dba748b..5806003 100644 (file)
@@ -14,15 +14,6 @@ use Psr\Log\NullLogger;
  * @covers MediaWiki\Auth\Throttler
  */
 class ThrottlerTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $cache = new \HashBagOStuff();
                $logger = $this->getMockBuilder( AbstractLogger::class )
index 545b964..bb9050f 100644 (file)
@@ -3,6 +3,7 @@ use MediaWiki\MediaWikiServices;
 
 /**
  * @group ContentHandler
+ * @group Database
  */
 class ContentHandlerTest extends MediaWikiTestCase {
 
@@ -52,6 +53,11 @@ class ContentHandlerTest extends MediaWikiTestCase {
                parent::tearDown();
        }
 
+       public function addDBDataOnce() {
+               $this->insertPage( 'Not_Main_Page', 'This is not a main page' );
+               $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]' );
+       }
+
        public static function dataGetDefaultModelFor() {
                return [
                        [ 'Help:Foo', CONTENT_MODEL_WIKITEXT ],
@@ -409,4 +415,39 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $this->assertInstanceOf( $handlerClass, $handler );
        }
 
+       /**
+        * @covers ContentHandler::getDataForSearchIndex
+        */
+       public function testDataIndexFields() {
+               $mockEngine = $this->getMock( 'SearchEngine' );
+               $title = Title::newFromText( 'Not_Main_Page', NS_MAIN );
+               $page = new WikiPage( $title );
+
+               $this->setTemporaryHook( 'SearchDataForIndex',
+                       function ( &$fields, ContentHandler $handler, WikiPage $page, ParserOutput $output,
+                                  SearchEngine $engine ) {
+                               $fields['testDataField'] = 'test content';
+                       } );
+
+               $output = $page->getContent()->getParserOutput( $title );
+               $data = $page->getContentHandler()->getDataForSearchIndex( $page, $output, $mockEngine );
+               $this->assertArrayHasKey( 'text', $data );
+               $this->assertArrayHasKey( 'text_bytes', $data );
+               $this->assertArrayHasKey( 'language', $data );
+               $this->assertArrayHasKey( 'testDataField', $data );
+               $this->assertEquals( 'test content', $data['testDataField'] );
+       }
+
+       /**
+        * @covers ContentHandler::getParserOutputForIndexing
+        */
+       public function testParserOutputForIndexing() {
+               $title = Title::newFromText( 'Smithee', NS_MAIN );
+               $page = new WikiPage( $title );
+
+               $out = $page->getContentHandler()->getParserOutputForIndexing( $page );
+               $this->assertInstanceOf( ParserOutput::class, $out );
+               $this->assertContains( 'one who smiths', $out->getRawText() );
+       }
+
 }
index e8681c7..918815c 100644 (file)
@@ -49,5 +49,4 @@ class TextContentHandlerTest extends MediaWikiLangTestCase {
                $this->assertEquals( 'test', $mappedFields['language']['testData'] );
                $this->assertEquals( 'language', $mappedFields['language']['name'] );
        }
-
 }
index f632882..9d4abe8 100644 (file)
@@ -243,4 +243,20 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
        ) {
        }
        */
+
+       public function testDataIndexFieldsFile() {
+               $mockEngine = $this->getMock( 'SearchEngine' );
+               $title = Title::newFromText( 'Somefile.jpg', NS_FILE );
+               $page = new WikiPage( $title );
+
+               $handler = $this->getMockBuilder( WikitextContentHandler::class )
+                       ->disableOriginalConstructor()
+                       ->setMethods( [ 'getFileText' ] )
+                       ->getMock();
+               $handler->method( 'getFileText' )->will( $this->returnValue( 'This is file content' ) );
+
+               $data = $handler->getDataForSearchIndex( $page, new ParserOutput(), $mockEngine );
+               $this->assertArrayHasKey( 'file_text', $data );
+               $this->assertEquals( 'This is file content', $data['file_text'] );
+       }
 }
diff --git a/tests/phpunit/includes/content/WikitextStructureTest.php b/tests/phpunit/includes/content/WikitextStructureTest.php
new file mode 100644 (file)
index 0000000..6d83057
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+class WikitextStructureTest extends MediaWikiLangTestCase {
+
+       private function getMockTitle() {
+               return Title::newFromText( "TestTitle" );
+       }
+
+       /**
+        * Get parser output for Wiki text
+        * @param $text
+        * @return ParserOutput
+        */
+       private function getParserOutput( $text ) {
+               $content = new WikitextContent( $text );
+               return $content->getParserOutput( $this->getMockTitle() );
+       }
+
+       /**
+        * Get WikitextStructure for given text
+        * @param $text
+        * @return WikiTextStructure
+        */
+       private function getStructure( $text ) {
+               return new WikiTextStructure( $this->getParserOutput( $text ) );
+       }
+
+       public function testCategories() {
+               $text = <<<END
+We also have a {{Template}} and an {{Another template}} in addition. 
+This text also has [[Category:Some Category| ]] and then [[Category:Yet another category]].
+And [[Category:Some Category| this category]] is repeated.
+END;
+               $struct = $this->getStructure( $text );
+               $cats = $struct->categories();
+               $this->assertCount( 2, $cats );
+               $this->assertContains( "Some Category", $cats );
+               $this->assertContains( "Yet another category", $cats );
+       }
+
+       public function testOutgoingLinks() {
+               $text = <<<END
+Here I add link to [[Some Page]]. And [[Some Page|This same page]] gets linked twice. 
+We also have [[File:Image.jpg|image]].
+We also have a {{Template}} and an {{Another template}} in addition. 
+Some templates are {{lowercase}}.
+And [[Some_Page]] is linked again. 
+It also has [[Category:Some Category| ]] and then [[Category:Yet another category]].
+Also link to a [[Talk:TestTitle|talk page]] is here. 
+END;
+               $struct = $this->getStructure( $text );
+               $links = $struct->outgoingLinks();
+               $this->assertContains( "Some_Page", $links );
+               $this->assertContains( "Template:Template", $links );
+               $this->assertContains( "Template:Another_template", $links );
+               $this->assertContains( "Template:Lowercase", $links );
+               $this->assertContains( "Talk:TestTitle", $links );
+               $this->assertCount( 5, $links );
+       }
+
+       public function testTemplates() {
+               $text = <<<END
+We have a {{Template}} and an {{Another template}} in addition. 
+Some templates are {{lowercase}}. And this {{Template}} is repeated. 
+Here is {{another_template|with=argument}}.
+This is a template that {{Xdoes not exist}}.
+END;
+               $this->setTemporaryHook( 'TitleExists', function ( Title $title, &$exists ) {
+                       $txt = $title->getBaseText();
+                       if ( $txt[0] != 'X' ) {
+                               $exists = true;
+                       }
+                       return true;
+               } );
+               $struct = $this->getStructure( $text );
+               $templates = $struct->templates();
+               $this->assertCount( 3, $templates );
+               $this->assertContains( "Template:Template", $templates );
+               $this->assertContains( "Template:Another template", $templates );
+               $this->assertContains( "Template:Lowercase", $templates );
+       }
+
+       public function testHeadings() {
+               $text = <<<END
+Some text here
+== Heading one ==
+Some text
+==== heading two ====
+More text
+=== Applicability of the strict mass-energy equivalence formula, ''E'' = ''mc''<sup>2</sup> ===
+and more text
+== Wikitext '''in''' [[Heading]] and also <b>html</b> ==
+more text
+==== See also ====
+* Also things to see!
+END;
+               $struct = $this->getStructure( $text );
+               $headings = $struct->headings();
+               $this->assertCount( 4, $headings );
+               $this->assertContains( "Heading one", $headings );
+               $this->assertContains( "heading two", $headings );
+               $this->assertContains( "Applicability of the strict mass-energy equivalence formula, E = mc2",
+                       $headings );
+               $this->assertContains( "Wikitext in Heading and also html", $headings );
+       }
+
+       public function testHeadingsFirst() {
+               $text = <<<END
+== Heading one ==
+Some text
+==== heading two ====
+END;
+               $struct = $this->getStructure( $text );
+               $headings = $struct->headings();
+               $this->assertCount( 2, $headings );
+               $this->assertContains( "Heading one", $headings );
+               $this->assertContains( "heading two", $headings );
+       }
+
+       public function testHeadingsNone() {
+               $text = "This text is completely devoid of headings.";
+               $struct = $this->getStructure( $text );
+               $headings = $struct->headings();
+               $this->assertArrayEquals( [], $headings );
+       }
+
+       public function testTexts() {
+               $text = <<<END
+Opening text is opening.
+== Then comes header ==
+Then we got more<br>text
+=== And more headers ===
+{| class="wikitable"
+|-
+! Header table
+|-
+| row in table
+|-
+| another row in table
+|}
+END;
+               $struct = $this->getStructure( $text );
+               $this->assertEquals( "Opening text is opening.", $struct->getOpeningText() );
+               $this->assertEquals( "Opening text is opening.   Then we got more text",
+                       $struct->getMainText() );
+               $this->assertEquals( [ "Header table  row in table  another row in table" ],
+                       $struct->getAuxiliaryText() );
+       }
+}
index c56626f..e7abd15 100644 (file)
@@ -1,4 +1,7 @@
 <?php
+
+use MediaWiki\MediaWikiServices;
+
 /**
  * Although marked as a stub, can work independently.
  *
@@ -127,22 +130,6 @@ class NewParserTest extends MediaWikiTestCase {
                        $tmpGlobals['wgStyleDirectory'] = "$IP/skins";
                }
 
-               # Replace all media handlers with a mock. We do not need to generate
-               # actual thumbnails to do parser testing, we only care about receiving
-               # a ThumbnailImage properly initialized.
-               global $wgMediaHandlers;
-               foreach ( $wgMediaHandlers as $type => $handler ) {
-                       $tmpGlobals['wgMediaHandlers'][$type] = 'MockBitmapHandler';
-               }
-               // Vector images have to be handled slightly differently
-               $tmpGlobals['wgMediaHandlers']['image/svg+xml'] = 'MockSvgHandler';
-
-               // DjVu images have to be handled slightly differently
-               $tmpGlobals['wgMediaHandlers']['image/vnd.djvu'] = 'MockDjVuHandler';
-
-               // Ogg video/audio increasingly more differently
-               $tmpGlobals['wgMediaHandlers']['application/ogg'] = 'MockOggHandler';
-
                $tmpHooks = $wgHooks;
                $tmpHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
                $tmpHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
@@ -177,6 +164,13 @@ class NewParserTest extends MediaWikiTestCase {
                MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
                $wgContLang->resetNamespaces(); # reset namespace cache
                ParserTest::resetTitleServices();
+               MediaWikiServices::getInstance()->disableService( 'MediaHandlerFactory' );
+               MediaWikiServices::getInstance()->redefineService(
+                       'MediaHandlerFactory',
+                       function() {
+                               return new MockMediaHandlerFactory();
+                       }
+               );
        }
 
        protected function tearDown() {
@@ -196,6 +190,7 @@ class NewParserTest extends MediaWikiTestCase {
 
                // Restore message cache (temporary pages and $wgUseDatabaseMessages)
                MessageCache::destroyInstance();
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'MediaHandlerFactory' );
 
                parent::tearDown();
 
index 2dec02b..2114e0a 100644 (file)
@@ -27,6 +27,15 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
                return [
                        'noTemplateModule' => [],
 
+                       'deprecatedModule' => $base + [
+                               'deprecated' => true,
+                       ],
+                       'deprecatedTomorrow' => $base + [
+                               'deprecated' => [
+                                       'message' => 'Will be removed tomorrow.'
+                               ],
+                       ],
+
                        'htmlTemplateModule' => $base + [
                                'templates' => [
                                        'templates/template.html',
@@ -96,6 +105,34 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
                $this->assertEquals( $rl->getDependencies(), $expected );
        }
 
+       public static function providerDeprecatedModules() {
+               return [
+                       [
+                               'deprecatedModule',
+                               'mw.log.warn("This page is using the deprecated ResourceLoader module \"deprecatedModule\".");',
+                       ],
+                       [
+                               'deprecatedTomorrow',
+                               'mw.log.warn(' .
+                                       '"This page is using the deprecated ResourceLoader module \"deprecatedTomorrow\".\\n' .
+                                       "Will be removed tomorrow." .
+                                       '");'
+                       ]
+               ];
+       }
+
+       /**
+        * @dataProvider providerDeprecatedModules
+        * @covers ResourceLoaderFileModule::getScript
+        */
+       public function testDeprecatedModules( $name, $expected ) {
+               $modules = self::getModules();
+               $rl = new ResourceLoaderFileModule( $modules[$name] );
+               $rl->setName( $name );
+               $ctx = $this->getResourceLoaderContext( 'en', 'ltr' );
+               $this->assertEquals( $rl->getScript( $ctx ), $expected );
+       }
+
        /**
         * @covers ResourceLoaderFileModule::getAllStyleFiles
         * @covers ResourceLoaderFileModule::getAllSkinStyleFiles
index f084c64..081cb38 100644 (file)
@@ -185,8 +185,12 @@ class SearchEngineTest extends MediaWikiLangTestCase {
                        ->willReturnCallback( $mockFieldBuilder );
 
                // Not using mock since PHPUnit mocks do not work properly with references in params
-               $this->mergeMwGlobalArrayValue( 'wgHooks',
-                       [ 'SearchIndexFields' => [ [ $this, 'hookSearchIndexFields', $mockFieldBuilder ] ] ] );
+               $this->setTemporaryHook( 'SearchIndexFields',
+                       function ( &$fields, SearchEngine $engine ) use ( $mockFieldBuilder ) {
+                               $fields['testField'] =
+                                       $mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
+                               return true;
+                       } );
 
                $fields = $mockEngine->getSearchIndexFields();
                $this->assertArrayHasKey( 'language', $fields );
@@ -197,9 +201,4 @@ class SearchEngineTest extends MediaWikiLangTestCase {
                $this->assertArrayHasKey( 'testData', $mapping );
                $this->assertEquals( 'test', $mapping['testData'] );
        }
-
-       public function hookSearchIndexFields( $mockFieldBuilder, &$fields, SearchEngine $engine ) {
-               $fields['testField'] = $mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
-               return true;
-       }
 }
index e725fee..1ebb07c 100644 (file)
@@ -867,303 +867,6 @@ class SessionManagerTest extends MediaWikiTestCase {
                $this->assertTrue( SessionManager::validateSessionId( $id ), "Generated ID: $id" );
        }
 
-       public function testAutoCreateUser() {
-               global $wgGroupPermissions, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       $this->markTestSkipped( 'AuthManager is not disabled' );
-               }
-
-               \ObjectCache::$instances[__METHOD__] = new TestBagOStuff();
-               $this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
-               $this->setMwGlobals( [
-                       'wgAuth' => new AuthPlugin,
-               ] );
-
-               $this->stashMwGlobals( [ 'wgGroupPermissions' ] );
-               $wgGroupPermissions['*']['createaccount'] = true;
-               $wgGroupPermissions['*']['autocreateaccount'] = false;
-
-               // Replace the global singleton with one configured for testing
-               $manager = $this->getManager();
-               $reset = TestUtils::setSessionManagerSingleton( $manager );
-
-               $logger = new \TestLogger( true, function ( $m ) {
-                       if ( substr( $m, 0, 15 ) === 'SessionBackend ' ) {
-                               // Don't care.
-                               return null;
-                       }
-                       $m = str_replace( 'MediaWiki\Session\SessionManager::autoCreateUser: ', '', $m );
-                       return $m;
-               } );
-               $manager->setLogger( $logger );
-
-               $session = SessionManager::getGlobalSession();
-
-               // Can't create an already-existing user
-               $user = User::newFromName( 'UTSysop' );
-               $id = $user->getId();
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( $id, $user->getId() );
-               $this->assertSame( 'UTSysop', $user->getName() );
-               $this->assertSame( [], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation works at all
-               $user = User::newFromName( 'UTSessionAutoCreate1' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate1', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate1', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Check lack of permissions
-               $wgGroupPermissions['*']['createaccount'] = false;
-               $wgGroupPermissions['*']['autocreateaccount'] = false;
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [
-                               LogLevel::DEBUG,
-                               'user is blocked from this wiki, blacklisting',
-                       ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Check other permission
-               $wgGroupPermissions['*']['createaccount'] = false;
-               $wgGroupPermissions['*']['autocreateaccount'] = true;
-               $user = User::newFromName( 'UTSessionAutoCreate2' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate2', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate2', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test account-creation block
-               $anon = new User;
-               $block = new \Block( [
-                       'address' => $anon->getName(),
-                       'user' => $id,
-                       'reason' => __METHOD__,
-                       'expiry' => time() + 100500,
-                       'createAccount' => true,
-               ] );
-               $block->insert();
-               $this->assertInstanceOf( 'Block', $anon->isBlockedFromCreateAccount(), 'sanity check' );
-               $reset2 = new \ScopedCallback( [ $block, 'delete' ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               \ScopedCallback::consume( $reset2 );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'user is blocked from this wiki, blacklisting' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation still works
-               $user = User::newFromName( 'UTSessionAutoCreate3' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate3', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate3', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by AuthPlugin
-               global $wgAuth;
-               $oldWgAuth = $wgAuth;
-               $mockWgAuth = $this->getMock( 'AuthPlugin', [ 'autoCreate' ] );
-               $mockWgAuth->expects( $this->once() )->method( 'autoCreate' )
-                       ->will( $this->returnValue( false ) );
-               $this->setMwGlobals( [
-                       'wgAuth' => $mockWgAuth,
-               ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->setMwGlobals( [
-                       'wgAuth' => $oldWgAuth,
-               ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by AuthPlugin' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by wfReadOnly()
-               $this->setMwGlobals( [
-                       'wgReadOnly' => 'Because',
-               ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->setMwGlobals( [
-                       'wgReadOnly' => false,
-               ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by wfReadOnly()' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by a previous session
-               $session->set( 'MWSession::AutoCreateBlacklist', 'test' );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'blacklisted in session (test)' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test uncreatable name
-               $user = User::newFromName( 'UTDoesNotExist@' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist@', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'Invalid username, blacklisting' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test AbortAutoAccount hook
-               $mock = $this->getMock( __CLASS__, [ 'onAbortAutoAccount' ] );
-               $mock->expects( $this->once() )->method( 'onAbortAutoAccount' )
-                       ->will( $this->returnCallback( function ( User $user, &$msg ) {
-                               $msg = 'No way!';
-                               return false;
-                       } ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [ $mock ] ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [] ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by hook: No way!' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test AbortAutoAccount hook screwing up the name
-               $mock = $this->getMock( 'stdClass', [ 'onAbortAutoAccount' ] );
-               $mock->expects( $this->once() )->method( 'onAbortAutoAccount' )
-                       ->will( $this->returnCallback( function ( User $user ) {
-                               $user->setName( 'UTDoesNotExistEither' );
-                       } ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [ $mock ] ] );
-               try {
-                       $user = User::newFromName( 'UTDoesNotExist' );
-                       $manager->autoCreateUser( $user );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( \UnexpectedValueException $ex ) {
-                       $this->assertSame(
-                               'AbortAutoAccount hook tried to change the user name',
-                               $ex->getMessage()
-                       );
-               }
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertNotSame( 'UTDoesNotExistEither', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExistEither', User::READ_LATEST ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [] ] );
-               $session->clear();
-               $this->assertSame( [], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test for "exception backoff"
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'MWSession', 'autocreate-failed', md5( $user->getName() ) );
-               $cache->set( $backoffKey, 1, 60 * 10 );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $cache->delete( $backoffKey );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by prior creation attempt failures' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation still works, and test completion hook
-               $cb = $this->callback( function ( User $user ) {
-                       $this->assertNotEquals( 0, $user->getId() );
-                       $this->assertSame( 'UTSessionAutoCreate4', $user->getName() );
-                       $this->assertEquals(
-                               $user->getId(), User::idFromName( 'UTSessionAutoCreate4', User::READ_LATEST )
-                       );
-                       return true;
-               } );
-               $mock = $this->getMock( 'stdClass',
-                       [ 'onAuthPluginAutoCreate', 'onLocalUserCreated' ] );
-               $mock->expects( $this->once() )->method( 'onAuthPluginAutoCreate' )
-                       ->with( $cb );
-               $mock->expects( $this->once() )->method( 'onLocalUserCreated' )
-                       ->with( $cb, $this->identicalTo( true ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [
-                       'AuthPluginAutoCreate' => [ $mock ],
-                       'LocalUserCreated' => [ $mock ],
-               ] );
-               $user = User::newFromName( 'UTSessionAutoCreate4' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate4', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(),
-                       User::idFromName( 'UTSessionAutoCreate4', User::READ_LATEST )
-               );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [
-                       'AuthPluginAutoCreate' => [],
-                       'LocalUserCreated' => [],
-               ] );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-       }
-
-       public function onAbortAutoAccount( User $user, &$msg ) {
-       }
-
        public function testPreventSessionsForUser() {
                $manager = $this->getManager();
 
index de6c412..3debe6e 100644 (file)
@@ -396,6 +396,23 @@ class UploadBaseTest extends MediaWikiTestCase {
                ];
                // @codingStandardsIgnoreEnd
        }
+
+       /**
+        * @dataProvider provideCheckXMLEncodingMissmatch
+        */
+       public function testCheckXMLEncodingMissmatch( $fileContents, $evil ) {
+               $filename = $this->getNewTempFile();
+               file_put_contents( $filename, $fileContents );
+               $this->assertSame( UploadBase::checkXMLEncodingMissmatch( $filename ), $evil );
+       }
+
+       public function provideCheckXMLEncodingMissmatch() {
+               return [
+                       [ '<?xml version="1.0" encoding="utf-7"?><svg></svg>', true ],
+                       [ '<?xml version="1.0" encoding="utf-8"?><svg></svg>', false ],
+                       [ '<?xml version="1.0" encoding="WINDOWS-1252"?><svg></svg>', false ],
+               ];
+       }
 }
 
 class UploadTestHandler extends UploadBase {
index beb5e78..bd076ba 100644 (file)
@@ -212,7 +212,7 @@ class UserTest extends MediaWikiTestCase {
         * @group medium
         * @covers User::getEditCount
         */
-       public function testEditCount() {
+       public function testGetEditCount() {
                $user = $this->getMutableTestUser()->getUser();
 
                // let the user have a few (3) edits
@@ -221,17 +221,15 @@ class UserTest extends MediaWikiTestCase {
                        $page->doEdit( (string)$i, 'test', 0, false, $user );
                }
 
-               $user->clearInstanceCache();
                $this->assertEquals(
                        3,
                        $user->getEditCount(),
                        'After three edits, the user edit count should be 3'
                );
 
-               // increase the edit count and clear the cache
+               // increase the edit count
                $user->incEditCount();
 
-               $user->clearInstanceCache();
                $this->assertEquals(
                        4,
                        $user->getEditCount(),
@@ -239,6 +237,46 @@ class UserTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * Test User::editCount
+        * @group medium
+        * @covers User::getEditCount
+        */
+       public function testGetEditCountForAnons() {
+               $user = User::newFromName( 'Anonymous' );
+
+               $this->assertNull(
+                       $user->getEditCount(),
+                       'Edit count starts null for anonymous users.'
+               );
+
+               $user->incEditCount();
+
+               $this->assertNull(
+                       $user->getEditCount(),
+                       'Edit count remains null for anonymous users despite calls to increase it.'
+               );
+       }
+
+       /**
+        * Test User::editCount
+        * @group medium
+        * @covers User::incEditCount
+        */
+       public function testIncEditCount() {
+               $user = $this->getMutableTestUser()->getUser();
+               $user->incEditCount();
+
+               $reloadedUser = User::newFromId( $user->getId() );
+               $reloadedUser->incEditCount();
+
+               $this->assertEquals(
+                       2,
+                       $reloadedUser->getEditCount(),
+                       'Increasing the edit count after a fresh load leaves the object up to date.'
+               );
+       }
+
        /**
         * Test changing user options.
         * @covers User::setOption
diff --git a/tests/phpunit/mocks/media/MockMediaHandlerFactory.php b/tests/phpunit/mocks/media/MockMediaHandlerFactory.php
new file mode 100644 (file)
index 0000000..54d46b0
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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
+ * @ingroup Media
+ */
+
+/**
+ * Replace all media handlers with a mock. We do not need to generate
+ * actual thumbnails to do parser testing, we only care about receiving
+ * a ThumbnailImage properly initialized.
+ *
+ * @since 1.28
+ */
+class MockMediaHandlerFactory extends MediaHandlerFactory {
+
+       private static $overrides = [
+               'image/svg+xml' => MockSvgHandler::class,
+               'image/vnd.djvu' => MockDjVuHandler::class,
+               'application/ogg' => MockOggHandler::class,
+       ];
+
+       public function __construct() {
+               // override parent
+       }
+
+       protected function getHandlerClass( $type ) {
+               if ( isset( self::$overrides[$type] ) ) {
+                       return self::$overrides[$type];
+               }
+
+               return MockBitmapHandler::class;
+       }
+
+}
index baaa66b..a70946a 100755 (executable)
@@ -77,7 +77,7 @@ class PHPUnitMaintClass extends Maintenance {
                global $wgDevelopmentWarnings;
                global $wgSessionProviders, $wgSessionPbkdf2Iterations;
                global $wgJobTypeConf;
-               global $wgAuthManagerConfig, $wgAuth, $wgDisableAuthManager;
+               global $wgAuthManagerConfig, $wgAuth;
 
                // Inject test autoloader
                require_once __DIR__ . '/../TestsAutoLoader.php';
@@ -147,7 +147,7 @@ class PHPUnitMaintClass extends Maintenance {
                        ],
                        'secondaryauth' => [],
                ];
-               $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin();
+               $wgAuth = new MediaWiki\Auth\AuthManagerAuthPlugin();
 
                // Bug 44192 Do not attempt to send a real e-mail
                Hooks::clear( 'AlternateUserMailer' );
index 58de8e8..f36b51a 100644 (file)
@@ -143,4 +143,15 @@ class AutoLoaderTest extends MediaWikiTestCase {
                $this->assertFalse( $uncerealized instanceof __PHP_Incomplete_Class,
                        "unserialize() can load classes case-insensitively." );
        }
+
+       function testAutoloadOrder() {
+               $path = realpath( __DIR__ . '/../../..' );
+               $oldAutoload = file_get_contents( $path . '/autoload.php' );
+               $generator = new AutoloadGenerator( $path, 'local' );
+               $generator->initMediaWikiDefault();
+               $newAutoload = $generator->getAutoload( 'maintenance/generateLocalAutoload.php' );
+
+               $this->assertEquals( $oldAutoload, $newAutoload, 'autoload.php does not match' .
+                       ' output of generateLocalAutoload.php script.' );
+       }
 }
index 0e23fdd..02934fa 100644 (file)
@@ -8,10 +8,16 @@
 class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite {
        public function __construct() {
                parent::__construct();
+
                $paths = [];
+               // Autodiscover extension unit tests
+               $registry = ExtensionRegistry::getInstance();
+               foreach ( $registry->getAllThings() as $info ) {
+                       $paths[] = dirname( $info['path'] ) . '/tests/phpunit';
+               }
                // Extensions can return a list of files or directories
                Hooks::run( 'UnitTestsList', [ &$paths ] );
-               foreach ( $paths as $path ) {
+               foreach ( array_unique( $paths ) as $path ) {
                        if ( is_dir( $path ) ) {
                                // If the path is a directory, search for test cases.
                                // @since 1.24
@@ -19,7 +25,7 @@ class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite {
                                $fileIterator = new File_Iterator_Facade();
                                $matchingFiles = $fileIterator->getFilesAsArray( $path, $suffixes );
                                $this->addTestFiles( $matchingFiles );
-                       } else {
+                       } elseif ( file_exists( $path ) ) {
                                // Add a single test case or suite class
                                $this->addTestFile( $path );
                        }
index b09bb28..ca26aaf 100644 (file)
                        [ 'Strasse' ]
                ],
 
+               // Data set "digraph"
+               digraphWords = [
+                       [ 'London' ],
+                       [ 'Ljubljana' ],
+                       [ 'Luxembourg' ],
+                       [ 'Njivice' ],
+                       [ 'Norwich' ],
+                       [ 'New York' ]
+               ],
+               digraphWordsSorted = [
+                       [ 'London' ],
+                       [ 'Luxembourg' ],
+                       [ 'Ljubljana' ],
+                       [ 'New York' ],
+                       [ 'Norwich' ],
+                       [ 'Njivice' ]
+               ],
+
                complexMDYDates = [
                        [ 'January, 19 2010' ],
                        [ 'April 21 1991' ],
                }
        );
 
+       tableTest(
+               'Digraphs with custom collation',
+               [ 'City' ],
+               digraphWords,
+               digraphWordsSorted,
+               function ( $table ) {
+                       mw.config.set( 'tableSorterCollation', {
+                               lj: 'lzzzz',
+                               nj: 'nzzzz'
+                       } );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+
        QUnit.test( 'Rowspan not exploded on init', 1, function ( assert ) {
                var $table = tableCreate( header, planets );