Merge "build: Bump various devDependencies to latest"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 28 Sep 2015 23:38:36 +0000 (23:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 28 Sep 2015 23:38:36 +0000 (23:38 +0000)
478 files changed:
CREDITS
HISTORY
RELEASE-NOTES-1.26
RELEASE-NOTES-1.27 [new file with mode: 0644]
UPGRADE
autoload.php
composer.json
docs/hooks.txt
includes/DefaultSettings.php
includes/Defines.php
includes/EditPage.php
includes/FeedUtils.php
includes/FileContentsHasher.php [deleted file]
includes/GlobalFunctions.php
includes/Html.php
includes/HtmlFormatter.php
includes/HttpFunctions.php
includes/Import.php
includes/LinkFilter.php
includes/Linker.php
includes/MWTimestamp.php
includes/MimeMagic.php
includes/OutputPage.php
includes/PHPVersionCheck.php
includes/Preferences.php
includes/Revision.php
includes/Sanitizer.php
includes/TemplateParser.php
includes/Title.php
includes/User.php
includes/UserRightsProxy.php
includes/WebRequest.php
includes/WebStart.php
includes/WikiMap.php
includes/Xml.php
includes/actions/InfoAction.php
includes/actions/ProtectAction.php
includes/actions/RollbackAction.php
includes/api/ApiBase.php
includes/api/ApiCreateAccount.php
includes/api/ApiFeedContributions.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatJson.php
includes/api/ApiFormatPhp.php
includes/api/ApiHelp.php
includes/api/ApiMain.php
includes/api/ApiModuleManager.php
includes/api/ApiMove.php
includes/api/ApiOptions.php
includes/api/ApiPageSet.php
includes/api/ApiParse.php
includes/api/ApiQueryAllDeletedRevisions.php
includes/api/ApiQueryAllImages.php
includes/api/ApiQueryAllPages.php
includes/api/ApiQueryBacklinksprop.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryDeletedRevisions.php
includes/api/ApiQueryDuplicateFiles.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryLangLinks.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryRandom.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQueryUserInfo.php
includes/api/ApiUpload.php
includes/api/i18n/de.json
includes/api/i18n/en.json
includes/api/i18n/es.json
includes/api/i18n/fr.json
includes/api/i18n/he.json
includes/api/i18n/it.json
includes/api/i18n/ja.json
includes/api/i18n/ko.json
includes/api/i18n/ksh.json
includes/api/i18n/lb.json
includes/api/i18n/lt.json [new file with mode: 0644]
includes/api/i18n/pl.json
includes/api/i18n/pt-br.json
includes/api/i18n/pt.json
includes/api/i18n/ru.json
includes/api/i18n/sq.json
includes/api/i18n/zh-hans.json
includes/cache/LinkCache.php
includes/cache/LocalisationCache.php
includes/cache/MessageCache.php
includes/changes/EnhancedChangesList.php
includes/changes/RecentChange.php
includes/clientpool/RedisConnectionPool.php
includes/compat/normal/UtfNormalDefines.php
includes/content/AbstractContent.php
includes/content/ContentHandler.php
includes/content/MessageContent.php
includes/context/RequestContext.php
includes/db/CloneDatabase.php
includes/db/DBConnRef.php
includes/db/Database.php
includes/db/DatabaseMssql.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabaseOracle.php
includes/db/DatabasePostgres.php
includes/db/DatabaseSqlite.php
includes/db/IDatabase.php
includes/db/LBFactory.php [deleted file]
includes/db/LBFactoryMulti.php [deleted file]
includes/db/LBFactorySingle.php [deleted file]
includes/db/LoadBalancer.php [deleted file]
includes/db/LoadMonitor.php [deleted file]
includes/db/LoadMonitorMySQL.php [deleted file]
includes/db/loadbalancer/LBFactory.php [new file with mode: 0644]
includes/db/loadbalancer/LBFactoryFake.php [new file with mode: 0644]
includes/db/loadbalancer/LBFactoryMulti.php [new file with mode: 0644]
includes/db/loadbalancer/LBFactorySimple.php [new file with mode: 0644]
includes/db/loadbalancer/LBFactorySingle.php [new file with mode: 0644]
includes/db/loadbalancer/LoadBalancer.php [new file with mode: 0644]
includes/db/loadbalancer/LoadMonitor.php [new file with mode: 0644]
includes/db/loadbalancer/LoadMonitorMySQL.php [new file with mode: 0644]
includes/debug/logger/LegacyLogger.php
includes/debug/logger/monolog/BufferHandler.php
includes/debug/logger/monolog/KafkaHandler.php
includes/deferred/DataUpdate.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/SearchUpdate.php
includes/deferred/SqlDataUpdate.php
includes/deferred/SquidUpdate.php
includes/diff/TableDiffFormatter.php
includes/exception/MWExceptionHandler.php
includes/filerepo/FileRepo.php
includes/filerepo/LocalRepo.php
includes/filerepo/RepoGroup.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php
includes/gallery/TraditionalImageGallery.php
includes/htmlform/HTMLButtonField.php
includes/htmlform/HTMLCheckField.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/HTMLHiddenField.php
includes/htmlform/HTMLTitleTextField.php
includes/htmlform/OOUIHTMLForm.php
includes/htmlform/VFormHTMLForm.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/PostgresInstaller.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteUpdater.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerOutput.php
includes/installer/i18n/ko.json
includes/installer/i18n/lt.json
includes/installer/i18n/nap.json
includes/installer/i18n/pa.json
includes/installer/i18n/ru.json
includes/installer/i18n/sq.json
includes/jobqueue/jobs/HTMLCacheUpdateJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/jobqueue/jobs/ThumbnailRenderJob.php
includes/libs/BufferingStatsdDataFactory.php
includes/libs/CSSMin.php
includes/libs/HttpStatus.php
includes/libs/ReplacementArray.php
includes/libs/SamplingStatsdClient.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/replacers/HashtableReplacer.php
includes/logging/BlockLogFormatter.php
includes/logging/LogFormatter.php
includes/logging/LogPage.php
includes/logging/LogPager.php
includes/logging/NewUsersLogFormatter.php
includes/logging/ProtectLogFormatter.php
includes/mail/EmailNotification.php
includes/mail/UserMailer.php
includes/media/Bitmap.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/ExifBitmap.php
includes/media/FormatMetadata.php
includes/media/GIFMetadataExtractor.php
includes/media/IPTC.php
includes/media/ImageHandler.php
includes/media/MediaHandler.php
includes/media/WebP.php
includes/media/XCF.php
includes/media/XMP.php
includes/media/XMPInfo.php
includes/media/XMPValidate.php
includes/objectcache/MultiWriteBagOStuff.php
includes/page/Article.php
includes/page/ImagePage.php
includes/page/WikiPage.php
includes/parser/CacheTime.php
includes/parser/CoreParserFunctions.php
includes/parser/LinkHolderArray.php
includes/parser/MWTidy.php
includes/parser/Parser.php
includes/parser/ParserCache.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/registration/ExtensionProcessor.php
includes/registration/ExtensionRegistry.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderEditToolbarModule.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImage.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/search/SearchHighlighter.php
includes/search/SearchMySQL.php
includes/search/SearchPostgres.php
includes/site/MediaWikiSite.php
includes/site/SiteExporter.php
includes/site/SiteImporter.php
includes/site/SiteList.php
includes/skins/SkinTemplate.php
includes/specialpage/QueryPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialBooksources.php
includes/specials/SpecialCategories.php
includes/specials/SpecialChangeContentModel.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialEmailuser.php
includes/specials/SpecialExport.php
includes/specials/SpecialListfiles.php
includes/specials/SpecialListgrouprights.php
includes/specials/SpecialListusers.php
includes/specials/SpecialMergeHistory.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialPrefixindex.php
includes/specials/SpecialSearch.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUploadStash.php
includes/specials/SpecialUserlogin.php
includes/specials/SpecialWantedpages.php
includes/tidy/Html5Depurate.php
includes/tidy/RaggettExternal.php
includes/tidy/TidyDriverBase.php
includes/title/MalformedTitleException.php
includes/title/MediaWikiPageLinkRenderer.php
includes/title/MediaWikiTitleCodec.php
includes/title/NaiveForeignTitleFactory.php
includes/upload/UploadBase.php
includes/upload/UploadFromStash.php
includes/upload/UploadStash.php
includes/utils/AvroValidator.php
includes/utils/BatchRowIterator.php
includes/utils/BatchRowUpdate.php
includes/utils/FileContentsHasher.php [new file with mode: 0644]
includes/widget/ComplexNamespaceInputWidget.php
includes/widget/ComplexTitleInputWidget.php
includes/widget/TitleInputWidget.php
languages/Language.php
languages/LanguageConverter.php
languages/classes/LanguageFi.php
languages/classes/LanguageRu.php
languages/classes/LanguageTyv.php
languages/classes/LanguageUk.php
languages/classes/data/grammar.ru.json [new file with mode: 0644]
languages/i18n/ady-cyrl.json
languages/i18n/af.json
languages/i18n/aln.json
languages/i18n/ar.json
languages/i18n/as.json
languages/i18n/ast.json
languages/i18n/azb.json
languages/i18n/be-tarask.json
languages/i18n/bho.json
languages/i18n/bn.json
languages/i18n/ca.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/dty.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/eu.json
languages/i18n/ext.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gl.json
languages/i18n/gsw.json
languages/i18n/gu.json
languages/i18n/he.json
languages/i18n/ia.json
languages/i18n/ilo.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/jut.json
languages/i18n/ka.json
languages/i18n/kk-cyrl.json
languages/i18n/km.json
languages/i18n/ko.json
languages/i18n/ksh.json
languages/i18n/lb.json
languages/i18n/lt.json
languages/i18n/lv.json
languages/i18n/mg.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/nah.json
languages/i18n/nap.json
languages/i18n/nl.json
languages/i18n/olo.json
languages/i18n/or.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/ps.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/sah.json
languages/i18n/scn.json
languages/i18n/sl.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/th.json
languages/i18n/tr.json
languages/i18n/uk.json
languages/i18n/vec.json
languages/i18n/vi.json
languages/i18n/wo.json
languages/i18n/xal.json
languages/i18n/xmf.json
languages/i18n/yi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesAn.php
languages/messages/MessagesCa.php
languages/messages/MessagesDty.php
languages/messages/MessagesEs.php
languages/messages/MessagesExt.php
languages/utils/CLDRPluralRuleConverter.php [deleted file]
languages/utils/CLDRPluralRuleConverterExpression.php [deleted file]
languages/utils/CLDRPluralRuleConverterFragment.php [deleted file]
languages/utils/CLDRPluralRuleConverterOperator.php [deleted file]
languages/utils/CLDRPluralRuleError.php [deleted file]
languages/utils/CLDRPluralRuleEvaluator.php [deleted file]
languages/utils/CLDRPluralRuleEvaluatorRange.php [deleted file]
maintenance/Maintenance.php
maintenance/archives/patch-archive_ar_revid.sql
maintenance/archives/patch-backlinkindexes.sql
maintenance/archives/patch-categorylinksindex.sql
maintenance/backupPrefetch.inc
maintenance/backupTextPass.inc
maintenance/checkComposerLockUpToDate.php
maintenance/cleanupPreferences.php
maintenance/convertLinks.php
maintenance/fetchText.php
maintenance/findHooks.php
maintenance/populateContentModel.php
maintenance/preprocessorFuzzTest.php
maintenance/rebuildImages.php
maintenance/storage/compressOld.php
mw-config/config.js
package.json
phpcs.xml
profileinfo.php
resources/Resources.php
resources/src/jquery/jquery.tablesorter.js
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less
resources/src/mediawiki.language/languages/ru.js
resources/src/mediawiki.language/languages/uk.js
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.special/mediawiki.special.css
resources/src/mediawiki.special/mediawiki.special.upload.js
resources/src/mediawiki.toolbar/toolbar.less
resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less
resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css [deleted file]
resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less [new file with mode: 0644]
tests/TestsAutoLoader.php
tests/parser/parserTest.inc
tests/phpunit/LessFileCompilationTest.php
tests/phpunit/MediaWikiPHPUnitTestListener.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/data/filecontentshasher/hash.svg [new file with mode: 0644]
tests/phpunit/data/filecontentshasher/primes.txt [new file with mode: 0644]
tests/phpunit/includes/ConsecutiveParametersMatcher.php [deleted file]
tests/phpunit/includes/EditPageTest.php
tests/phpunit/includes/FallbackTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
tests/phpunit/includes/HtmlFormatterTest.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/HttpTest.php
tests/phpunit/includes/LinkFilterTest.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/MWNamespaceTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/RevisionStorageTest.php
tests/phpunit/includes/RevisionTest.php
tests/phpunit/includes/StatusTest.php
tests/phpunit/includes/TitleArrayFromResultTest.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/UserArrayFromResultTest.php
tests/phpunit/includes/UserTest.php
tests/phpunit/includes/WikiMapTest.php
tests/phpunit/includes/WikiReferenceTest.php
tests/phpunit/includes/actions/ActionTest.php
tests/phpunit/includes/api/ApiBlockTest.php
tests/phpunit/includes/api/ApiEditPageTest.php
tests/phpunit/includes/api/ApiUploadTest.php
tests/phpunit/includes/api/ApiWatchTest.php
tests/phpunit/includes/api/format/ApiFormatPhpTest.php
tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
tests/phpunit/includes/cache/GenderCacheTest.php
tests/phpunit/includes/changes/RecentChangeTest.php
tests/phpunit/includes/content/CssContentTest.php
tests/phpunit/includes/content/JavaScriptContentTest.php
tests/phpunit/includes/content/TextContentTest.php
tests/phpunit/includes/content/WikitextContentTest.php
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
tests/phpunit/includes/deferred/LinksUpdateTest.php
tests/phpunit/includes/filebackend/FileBackendTest.php
tests/phpunit/includes/filebackend/SwiftFileBackendTest.php
tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
tests/phpunit/includes/libs/RunningStatTest.php
tests/phpunit/includes/logging/LogFormatterTest.php
tests/phpunit/includes/logging/LogFormatterTestCase.php
tests/phpunit/includes/logging/ProtectLogFormatterTest.php
tests/phpunit/includes/media/DjVuTest.php
tests/phpunit/includes/media/PNGTest.php
tests/phpunit/includes/media/WebPTest.php
tests/phpunit/includes/page/WikiPageTest.php
tests/phpunit/includes/parser/MagicVariableTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/parser/PreprocessorTest.php
tests/phpunit/includes/password/UserPasswordPolicyTest.php
tests/phpunit/includes/phpunit/ConsecutiveParametersMatcher.php [new file with mode: 0644]
tests/phpunit/includes/phpunit/LICENSE [new file with mode: 0644]
tests/phpunit/includes/phpunit/README [new file with mode: 0644]
tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
tests/phpunit/includes/site/MediaWikiSiteTest.php
tests/phpunit/includes/site/SiteTest.php
tests/phpunit/includes/site/TestSites.php
tests/phpunit/includes/specials/SpecialRecentchangesTest.php
tests/phpunit/includes/specials/SpecialSearchTest.php
tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
tests/phpunit/includes/utils/AvroValidatorTest.php
tests/phpunit/includes/utils/BatchRowUpdateTest.php
tests/phpunit/includes/utils/FileContentsHasherTest.php [new file with mode: 0644]
tests/phpunit/languages/classes/LanguageRuTest.php
tests/phpunit/languages/classes/LanguageSrTest.php
tests/phpunit/languages/classes/LanguageUkTest.php
tests/phpunit/languages/classes/LanguageUzTest.php
tests/phpunit/languages/utils/CLDRPluralRuleEvaluatorTest.php [deleted file]
tests/phpunit/maintenance/MaintenanceTest.php
tests/phpunit/phpunit.php
tests/phpunit/structure/ResourcesTest.php
tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js
tests/testHelpers.inc
thumb.php

diff --git a/CREDITS b/CREDITS
index 44adc4f..76d2107 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1,6 +1,6 @@
 {{int:version-credits-summary}}
 <!--
-MediaWiki 1.26 is a collaborative project released under the
+MediaWiki 1.27 is a collaborative project released under the
 GNU General Public License v2. We would like to recognize the
 following names for their contribution to the product.
 -->
diff --git a/HISTORY b/HISTORY
index 07f0fac..0c2b8ac 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -1,4 +1,4 @@
-Change notes from older releases. For current info see RELEASE-NOTES-1.26.
+Change notes from older releases. For current info see RELEASE-NOTES-1.27.
 
 == MediaWiki 1.25 ==
 
index d4150eb..efca318 100644 (file)
@@ -44,6 +44,7 @@ production.
 * $wgBlockAllowsUTEdit is now set to true by default. This allows
   blocked users to edit their talk pages unless explicitly disabled
   when they are being blocked.
+* CLDRPluralRule* classes have been replaced with wikimedia/cldr-plural-rule-parser.
 
 === New features in 1.26 ===
 * (T51506) Now action=info gives estimates of actual watchers for a page.
@@ -90,14 +91,33 @@ production.
   page. During the deprecation period, the styles will only be loaded on pages
   which contain 'mw-ui-button' in their HTML. Starting in 1.28, the styles will
   only be loaded if explicitly required.
-
-==== External libraries ====
-* Update es5-shim from v4.0.0 to v4.1.5.
-* Update json2 from revision 2014-02-04 to 2015-05-03.
-* Update Sinon.JS from 1.10.3 to 1.15.4.
-* Upgrade jQuery Client from v1.0.0 to v2.0.0.
-* Added mediawiki/at-ease 1.0.0.
-* Update QUnit from v1.17.1 to v1.18.0.
+* If search returns zero results and current search engine has a "did you mean"
+  suggestion, results for suggestion will be shown. Can be disabled by setting
+  $wgSearchRunSuggestedQuery to false.
+
+== External libraries ==
+=== Upgraded external libraries ===
+* Updated es5-shim from v4.0.0 to v4.1.5.
+* Updated json2 from revision 2014-02-04 to 2015-05-03.
+* Updated Sinon.JS from 1.10.3 to 1.15.4.
+* Updated jQuery Client from v1.0.0 to v2.0.0.
+* Updated QUnit from v1.17.1 to v1.18.0.
+* Updated liuggio/statsd-php-client from v1.0.12 to v1.0.16
+* Updated oojs/oojs-ui from v0.9.8 to v0.12.9.
+* Updated wikimedia/utfnormal from v1.0.2 to v1.0.3
+* Updated wikimedia/composer-merge-plugin from v1.0.0 to v1.2.1.
+* Updated zordius/lightncandy from v0.18 to v0.21.
+
+=== New external libraries ===
+* Added composer/semver v0.1.0.
+* Added mediawiki/at-ease v1.1.0.
+* Added wikimedia/assert v0.2.2.
+* Added wikimedia/cldr-plural-rule-parser v1.0.0
+* Added wikimedia/ip-set v1.0.1.
+* Added wikimedia/wrappedstring v2.0.0.
+
+=== Removed and replaced external libraries ===
+* Replaced leafo/lessphp v0.5.0 with oyejorge/less.php: v1.7.0.8
 
 === Bug fixes in 1.26 ===
 * (T53283) load.php sometimes sends 304 response without full headers
@@ -131,6 +151,7 @@ production.
 * API responses to GET requests may now include ETag and Last-Modified headers,
   and will honor corresponding If-None-Match and If-Modified-Since on such
   requests.
+* (T47988) The protect log event details now use new-style formatting.
 
 === Action API internal changes in 1.26 ===
 * New metadata item ApiResult::META_KVP_MERGE to allow for merging the KVP key
@@ -215,6 +236,12 @@ changes to languages because of Phabricator reports.
   'Project:Oversight' to 'Project:Suppress'.
 * (T84937) Free external links ("autolinked" urls) will now be terminated
   by &nbsp; and HTML entity encodings of &nbsp, <, and >.
+* DatabaseBase::resultObject() is now protected (use outside Database classes
+  not necessary since 1.11).
+* Calling ResourceLoaderFileModule::readStyleFiles() without a
+  ResourceLoaderContext instance is deprecated.
+* ResourceLoader::getLessCompiler() now takes an optional parameter of
+  additional LESS variables to set for the compiler.
 
 == Compatibility ==
 
diff --git a/RELEASE-NOTES-1.27 b/RELEASE-NOTES-1.27
new file mode 100644 (file)
index 0000000..71c3dcd
--- /dev/null
@@ -0,0 +1,97 @@
+Security reminder: If you have PHP's register_globals option set, you must
+turn it off. MediaWiki will not work with it enabled.
+
+== MediaWiki 1.27 ==
+
+THIS IS NOT A RELEASE YET
+
+MediaWiki 1.27 is an alpha-quality branch and is not recommended for use in
+production.
+
+=== Configuration changes in 1.27 ===
+
+=== New features in 1.27 ===
+
+==== External libraries ====
+
+=== Bug fixes in 1.27 ===
+
+=== Action API changes in 1.27 ===
+
+=== Action API internal changes in 1.27 ===
+
+=== Languages updated in 1.27 ===
+
+MediaWiki supports over 350 languages. Many localisations are updated
+regularly. Below only new and removed languages are listed, as well as
+changes to languages because of Bugzilla reports.
+
+
+=== Other changes in 1.27 ===
+
+
+== Compatibility ==
+
+MediaWiki 1.27 requires PHP 5.3.3 or later. There is experimental support for
+HHVM 3.3.0.
+
+MySQL is the recommended DBMS. PostgreSQL or SQLite can also be used, but
+support for them is somewhat less mature. There is experimental support for
+Oracle and Microsoft SQL Server.
+
+The supported versions are:
+
+* MySQL 5.0.3 or later
+* PostgreSQL 8.3 or later
+* SQLite 3.3.7 or later
+* Oracle 9.0.1 or later
+* Microsoft SQL Server 2005 (9.00.1399)
+
+== Upgrading ==
+
+1.27 has several database changes since 1.26, and will not work without schema
+updates. Note that due to changes to some very large tables like the revision
+table, the schema update may take quite long (minutes on a medium sized site,
+many hours on a large site).
+
+If upgrading from before 1.11, and you are using a wiki as a commons
+repository, make sure that it is updated as well. Otherwise, errors may arise
+due to database schema changes.
+
+If upgrading from before 1.7, you may want to run refreshLinks.php to ensure
+new database fields are filled with data.
+
+If you are upgrading from MediaWiki 1.4.x or earlier, you should upgrade to
+1.5 first. The upgrade script maintenance/upgrade1_5.php has been removed
+with MediaWiki 1.21.
+
+Don't forget to always back up your database before upgrading!
+
+See the file UPGRADE for more detailed upgrade instructions.
+
+For notes on 1.26.x and older releases, see HISTORY.
+
+== Online documentation ==
+
+Documentation for both end-users and site administrators is available on
+MediaWiki.org, and is covered under the GNU Free Documentation License (except
+for pages that explicitly state that their contents are in the public domain):
+
+       https://www.mediawiki.org/wiki/Documentation
+
+== Mailing list ==
+
+A mailing list is available for MediaWiki user support and discussion:
+
+       https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
+
+A low-traffic announcements-only list is also available:
+
+       https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce
+
+It's highly recommended that you sign up for one of these lists if you're
+going to run a public MediaWiki, so you can be notified of security fixes.
+
+== IRC help ==
+
+There's usually someone online in #mediawiki on irc.freenode.net.
diff --git a/UPGRADE b/UPGRADE
index 1ff98cd..088701a 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -5,7 +5,7 @@ specific problems, check
 * the documentation at https://www.mediawiki.org
 * the mediawiki-l mailing list archive at
   http://lists.wikimedia.org/pipermail/mediawiki-l/
-* the bug tracker at https://bugzilla.wikimedia.org
+* the bug tracker at https://phabricator.wikimedia.org
 
 for information and workarounds to common issues.
 
index e5e7cda..f1b0a6c 100644 (file)
@@ -184,13 +184,6 @@ $wgAutoloadLocalClasses = array(
        'BmpHandler' => __DIR__ . '/includes/media/BMP.php',
        'BrokenRedirectsPage' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
        'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/BufferingStatsdDataFactory.php',
-       'CLDRPluralRuleConverter' => __DIR__ . '/languages/utils/CLDRPluralRuleConverter.php',
-       'CLDRPluralRuleConverterExpression' => __DIR__ . '/languages/utils/CLDRPluralRuleConverterExpression.php',
-       'CLDRPluralRuleConverterFragment' => __DIR__ . '/languages/utils/CLDRPluralRuleConverterFragment.php',
-       'CLDRPluralRuleConverterOperator' => __DIR__ . '/languages/utils/CLDRPluralRuleConverterOperator.php',
-       'CLDRPluralRuleError' => __DIR__ . '/languages/utils/CLDRPluralRuleError.php',
-       'CLDRPluralRuleEvaluator' => __DIR__ . '/languages/utils/CLDRPluralRuleEvaluator.php',
-       'CLDRPluralRuleEvaluatorRange' => __DIR__ . '/languages/utils/CLDRPluralRuleEvaluatorRange.php',
        'CLIParser' => __DIR__ . '/maintenance/parse.php',
        'CSSMin' => __DIR__ . '/includes/libs/CSSMin.php',
        'CacheDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
@@ -283,7 +276,7 @@ $wgAutoloadLocalClasses = array(
        'CsvStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
        'CurlHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
        'DBAccessBase' => __DIR__ . '/includes/dao/DBAccessBase.php',
-       'DBAccessError' => __DIR__ . '/includes/db/LBFactory.php',
+       'DBAccessError' => __DIR__ . '/includes/db/loadbalancer/LBFactory.php',
        'DBAccessObjectUtils' => __DIR__ . '/includes/dao/DBAccessObjectUtils.php',
        'DBConnRef' => __DIR__ . '/includes/db/DBConnRef.php',
        'DBConnectionError' => __DIR__ . '/includes/db/DatabaseError.php',
@@ -437,7 +430,7 @@ $wgAutoloadLocalClasses = array(
        'FileBackendStoreShardListIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
        'FileBasedSiteLookup' => __DIR__ . '/includes/site/FileBasedSiteLookup.php',
        'FileCacheBase' => __DIR__ . '/includes/cache/FileCacheBase.php',
-       'FileContentsHasher' => __DIR__ . '/includes/FileContentsHasher.php',
+       'FileContentsHasher' => __DIR__ . '/includes/utils/FileContentsHasher.php',
        'FileDeleteForm' => __DIR__ . '/includes/FileDeleteForm.php',
        'FileDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'FileDuplicateSearchPage' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
@@ -611,11 +604,11 @@ $wgAutoloadLocalClasses = array(
        'JsonContentHandler' => __DIR__ . '/includes/content/JsonContentHandler.php',
        'KkConverter' => __DIR__ . '/languages/classes/LanguageKk.php',
        'KuConverter' => __DIR__ . '/languages/classes/LanguageKu.php',
-       'LBFactory' => __DIR__ . '/includes/db/LBFactory.php',
-       'LBFactoryFake' => __DIR__ . '/includes/db/LBFactory.php',
-       'LBFactoryMulti' => __DIR__ . '/includes/db/LBFactoryMulti.php',
-       'LBFactorySimple' => __DIR__ . '/includes/db/LBFactory.php',
-       'LBFactorySingle' => __DIR__ . '/includes/db/LBFactorySingle.php',
+       'LBFactory' => __DIR__ . '/includes/db/loadbalancer/LBFactory.php',
+       'LBFactoryFake' => __DIR__ . '/includes/db/loadbalancer/LBFactoryFake.php',
+       'LBFactoryMulti' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMulti.php',
+       'LBFactorySimple' => __DIR__ . '/includes/db/loadbalancer/LBFactorySimple.php',
+       'LBFactorySingle' => __DIR__ . '/includes/db/loadbalancer/LBFactorySingle.php',
        'LCStore' => __DIR__ . '/includes/cache/LocalisationCache.php',
        'LCStoreCDB' => __DIR__ . '/includes/cache/LocalisationCache.php',
        'LCStoreDB' => __DIR__ . '/includes/cache/LocalisationCache.php',
@@ -686,11 +679,11 @@ $wgAutoloadLocalClasses = array(
        'ListDuplicatedFilesPage' => __DIR__ . '/includes/specials/SpecialListDuplicatedFiles.php',
        'ListVariants' => __DIR__ . '/maintenance/language/listVariants.php',
        'ListredirectsPage' => __DIR__ . '/includes/specials/SpecialListredirects.php',
-       'LoadBalancer' => __DIR__ . '/includes/db/LoadBalancer.php',
-       'LoadBalancerSingle' => __DIR__ . '/includes/db/LBFactorySingle.php',
-       'LoadMonitor' => __DIR__ . '/includes/db/LoadMonitor.php',
-       'LoadMonitorMySQL' => __DIR__ . '/includes/db/LoadMonitorMySQL.php',
-       'LoadMonitorNull' => __DIR__ . '/includes/db/LoadMonitor.php',
+       'LoadBalancer' => __DIR__ . '/includes/db/loadbalancer/LoadBalancer.php',
+       'LoadBalancerSingle' => __DIR__ . '/includes/db/loadbalancer/LBFactorySingle.php',
+       'LoadMonitor' => __DIR__ . '/includes/db/loadbalancer/LoadMonitor.php',
+       'LoadMonitorMySQL' => __DIR__ . '/includes/db/loadbalancer/LoadMonitorMySQL.php',
+       'LoadMonitorNull' => __DIR__ . '/includes/db/loadbalancer/LoadMonitor.php',
        'LocalFile' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
        'LocalFileDeleteBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
        'LocalFileMoveBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
index e41b6c7..3809499 100644 (file)
                "cssjanus/cssjanus": "1.1.1",
                "ext-iconv": "*",
                "liuggio/statsd-php-client": "1.0.16",
-               "oyejorge/less.php": "1.7.0.5",
                "mediawiki/at-ease": "1.1.0",
                "oojs/oojs-ui": "0.12.9",
+               "oyejorge/less.php": "1.7.0.8",
                "php": ">=5.3.3",
                "psr/log": "1.0.0",
                "wikimedia/assert": "0.2.2",
                "wikimedia/cdb": "1.3.0",
+               "wikimedia/cldr-plural-rule-parser": "1.0.0",
                "wikimedia/composer-merge-plugin": "1.2.1",
                "wikimedia/ip-set": "1.0.1",
                "wikimedia/utfnormal": "1.0.3",
        "require-dev": {
                "jakub-onderka/php-parallel-lint": "0.9",
                "justinrainbow/json-schema": "~1.3",
-               "phpunit/phpunit": "3.7.37",
-               "mediawiki/mediawiki-codesniffer": "0.3.0",
-               "wikimedia/avro": "1.7.7",
+               "mediawiki/mediawiki-codesniffer": "0.4.0",
+               "monolog/monolog": "1.14.0",
                "nmred/kafka-php": "0.1.4",
-               "monolog/monolog": "1.14.0"
+               "phpunit/phpunit": "3.7.37",
+               "wikimedia/avro": "1.7.7"
        },
        "suggest": {
+               "ext-apc": "Local data and opcode cache",
                "ext-fileinfo": "Improved mime magic detection",
                "ext-intl": "ICU integration",
                "ext-mbstring": "Multibyte string support",
                "ext-wikidiff2": "Diff accelerator",
-               "ext-apc": "Local data and opcode cache",
                "monolog/monolog": "Flexible debug logging system",
                "nmred/kafka-php": "Send debug log events to kafka",
                "pear/mail": "Mail sending support",
        "scripts": {
                "lint": "parallel-lint --exclude vendor",
                "phpcs": "phpcs -p $PHPCS_ARGS",
+               "pre-install-cmd": "ComposerHookHandler::onPreInstall",
+               "pre-update-cmd": "ComposerHookHandler::onPreUpdate",
                "test": [
                        "composer lint",
                        "composer phpcs"
-               ],
-               "pre-update-cmd": "ComposerHookHandler::onPreUpdate",
-               "pre-install-cmd": "ComposerHookHandler::onPreInstall"
+               ]
        },
        "config": {
-               "prepend-autoloader": false,
-               "optimize-autoloader": true
+               "optimize-autoloader": true,
+               "prepend-autoloader": false
        },
        "extra": {
                "merge-plugin": {
index 9aa2964..2d268b8 100644 (file)
@@ -641,16 +641,14 @@ $popts: parser options to be used for pre-save transformation
 'ArticleProtect': Before an article is protected.
 $wikiPage: the WikiPage being protected
 $user: the user doing the protection
-$protect: boolean whether this is a protect or an unprotect
+$protect: Set of restriction keys
 $reason: Reason for protect
-$moveonly: boolean whether this is for move only or not
 
 'ArticleProtectComplete': After an article is protected.
 $wikiPage: the WikiPage that was protected
 $user: the user who did the protection
-$protect: boolean whether it was a protect or an unprotect
+$protect: Set of restriction keys
 $reason: Reason for protect
-$moveonly: boolean whether it was for move only or not
 
 'ArticlePurge': Before executing "&action=purge".
 $wikiPage: WikiPage (object) to purge
@@ -1581,9 +1579,10 @@ $imagePage: ImagePage object ($this)
 &$html: HTML for the hook to add
 
 'ImagePageFileHistoryLine': Called when a file history line is constructed.
+$imagePage: ImagePage object ($this)
 $file: the file
-$line: the HTML of the history line
-$css: the line CSS class
+&$line: the HTML of the history line
+&$css: the line CSS class
 
 'ImagePageFindFile': Called when fetching the file associated with an image
 page.
@@ -2169,9 +2168,10 @@ $article: the article that the history is loading for
 $context: RequestContext object
 
 'PageHistoryLineEnding': Right before the end <li> is added to a history line.
-$row: the revision row for this line
-$s: the string representing this parsed line
-$classes: array containing the <li> element classes
+$historyAction: the action object
+&$row: the revision row for this line
+&$s: the string representing this parsed line
+&$classes: array containing the <li> element classes
 
 'PageHistoryPager::doBatchLookups': Called after the pager query was run, before
 any output is generated, to allow batch lookups for prefetching information
@@ -2675,8 +2675,10 @@ $out: OutputPage object
 
 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink': After creating the "permanent
 link" tab.
-$sktemplate: SkinTemplate object
-$nav_urls: array of tabs
+&$sktemplate: SkinTemplate object
+&$nav_urls: array of tabs
+&$revid: The revision id of the permanent link
+&$revid2: The revision id of the permanent link, second time
 
 'SkinTemplateGetLanguageLink': After building the data for a language link from
 which the actual html is constructed.
index 3895318..5fd8574 100644 (file)
@@ -75,7 +75,7 @@ $wgConfigRegistry = array(
  * MediaWiki version number
  * @since 1.2
  */
-$wgVersion = '1.26alpha';
+$wgVersion = '1.27alpha';
 
 /**
  * Name of the site. It must be changed in LocalSettings.php
@@ -867,12 +867,12 @@ $wgUploadSizeWarning = false;
  * [[media:...]] links for non-trusted formats.
  */
 $wgTrustedMediaFormats = array(
-       MEDIATYPE_BITMAP, //all bitmap formats
-       MEDIATYPE_AUDIO, //all audio formats
-       MEDIATYPE_VIDEO, //all plain video formats
-       "image/svg+xml", //svg (only needed if inline rendering of svg is not supported)
-       "application/pdf", //PDF files
-       #"application/x-shockwave-flash", //flash/shockwave movie
+       MEDIATYPE_BITMAP, // all bitmap formats
+       MEDIATYPE_AUDIO, // all audio formats
+       MEDIATYPE_VIDEO, // all plain video formats
+       "image/svg+xml", // svg (only needed if inline rendering of svg is not supported)
+       "application/pdf", // PDF files
+       # "application/x-shockwave-flash", //flash/shockwave movie
 );
 
 /**
@@ -1173,7 +1173,7 @@ $wgAntivirus = null;
  */
 $wgAntivirusSetup = array(
 
-       #setup for clamav
+       # setup for clamav
        'clamav' => array(
                'command' => 'clamscan --no-summary ',
                'codemap' => array(
@@ -4003,7 +4003,7 @@ $wgInvalidRedirectTargets = array( 'Filepath', 'Mypage', 'Mytalk', 'Redirect' );
  */
 $wgParserConf = array(
        'class' => 'Parser',
-       #'preprocessorClass' => 'Preprocessor_Hash',
+       # 'preprocessorClass' => 'Preprocessor_Hash',
 );
 
 /**
@@ -4702,7 +4702,7 @@ $wgGroupPermissions['*']['editmywatchlist'] = true;
 $wgGroupPermissions['*']['viewmyprivateinfo'] = true;
 $wgGroupPermissions['*']['editmyprivateinfo'] = true;
 $wgGroupPermissions['*']['editmyoptions'] = true;
-#$wgGroupPermissions['*']['patrolmarks'] = false; // let anons see what was patrolled
+# $wgGroupPermissions['*']['patrolmarks'] = false; // let anons see what was patrolled
 
 // Implicit group for all logged-in accounts
 $wgGroupPermissions['user']['move'] = true;
@@ -4780,8 +4780,8 @@ $wgGroupPermissions['sysop']['noratelimit'] = true;
 $wgGroupPermissions['sysop']['movefile'] = true;
 $wgGroupPermissions['sysop']['unblockself'] = true;
 $wgGroupPermissions['sysop']['suppressredirect'] = true;
-#$wgGroupPermissions['sysop']['pagelang'] = true;
-#$wgGroupPermissions['sysop']['upload_by_url'] = true;
+# $wgGroupPermissions['sysop']['pagelang'] = true;
+# $wgGroupPermissions['sysop']['upload_by_url'] = true;
 $wgGroupPermissions['sysop']['mergehistory'] = true;
 $wgGroupPermissions['sysop']['managechangetags'] = true;
 
@@ -4789,20 +4789,20 @@ $wgGroupPermissions['sysop']['managechangetags'] = true;
 $wgGroupPermissions['bureaucrat']['userrights'] = true;
 $wgGroupPermissions['bureaucrat']['noratelimit'] = true;
 // Permission to change users' groups assignments across wikis
-#$wgGroupPermissions['bureaucrat']['userrights-interwiki'] = true;
+# $wgGroupPermissions['bureaucrat']['userrights-interwiki'] = true;
 // Permission to export pages including linked pages regardless of $wgExportMaxLinkDepth
-#$wgGroupPermissions['bureaucrat']['override-export-depth'] = true;
+# $wgGroupPermissions['bureaucrat']['override-export-depth'] = true;
 
-#$wgGroupPermissions['sysop']['deletelogentry'] = true;
-#$wgGroupPermissions['sysop']['deleterevision'] = true;
+# $wgGroupPermissions['sysop']['deletelogentry'] = true;
+# $wgGroupPermissions['sysop']['deleterevision'] = true;
 // To hide usernames from users and Sysops
-#$wgGroupPermissions['suppress']['hideuser'] = true;
+# $wgGroupPermissions['suppress']['hideuser'] = true;
 // To hide revisions/log items from users and Sysops
-#$wgGroupPermissions['suppress']['suppressrevision'] = true;
+# $wgGroupPermissions['suppress']['suppressrevision'] = true;
 // To view revisions/log items hidden from users and Sysops
-#$wgGroupPermissions['suppress']['viewsuppressed'] = true;
+# $wgGroupPermissions['suppress']['viewsuppressed'] = true;
 // For private suppression log access
-#$wgGroupPermissions['suppress']['suppressionlog'] = true;
+# $wgGroupPermissions['suppress']['suppressionlog'] = true;
 
 /**
  * The developer group is deprecated, but can be activated if need be
@@ -6934,11 +6934,7 @@ $wgLogHeaders = array(
  *
  * Extensions with custom log types may add to this array.
  */
-$wgLogActions = array(
-       'protect/modify' => 'modifiedarticleprotection',
-       'protect/protect' => 'protectedarticle',
-       'protect/unprotect' => 'unprotectedarticle',
-);
+$wgLogActions = array();
 
 /**
  * The same as above, but here values are names of classes,
@@ -6965,7 +6961,10 @@ $wgLogActionsHandlers = array(
        'move/move' => 'MoveLogFormatter',
        'move/move_redir' => 'MoveLogFormatter',
        'patrol/patrol' => 'PatrolLogFormatter',
+       'protect/modify' => 'ProtectLogFormatter',
        'protect/move_prot' => 'ProtectLogFormatter',
+       'protect/protect' => 'ProtectLogFormatter',
+       'protect/unprotect' => 'ProtectLogFormatter',
        'rights/autopromote' => 'RightsLogFormatter',
        'rights/rights' => 'RightsLogFormatter',
        'suppress/block' => 'BlockLogFormatter',
@@ -7473,7 +7472,7 @@ $wgRunJobsAsync = true;
 /**
  * Number of rows to update per job
  */
-$wgUpdateRowsPerJob = 500;
+$wgUpdateRowsPerJob = 300;
 
 /**
  * Number of rows to update per query
@@ -7707,14 +7706,13 @@ $wgVirtualRestConfig = array(
 );
 
 /**
- * Controls the percentage of zero-result search queries with suggestions that
- * run the suggestion automatically. Must be a number between 0 and 1.  This
- * can be lowered to reduce query volume at the expense of result quality.
+ * Controls whether zero-result search queries with suggestions should display results for
+ * these suggestions.
  *
- * @var float
+ * @var bool
  * @since 1.26
  */
-$wgSearchRunSuggestedQueryPercent = 1;
+$wgSearchRunSuggestedQuery = true;
 
 /**
  * For really cool vim folding this needs to be at the end:
index d55bbcf..1c06ad0 100644 (file)
@@ -33,7 +33,7 @@ define( 'DBO_IGNORE', 4 );
 define( 'DBO_TRX', 8 ); // automatically start transaction on first query
 define( 'DBO_DEFAULT', 16 );
 define( 'DBO_PERSISTENT', 32 );
-define( 'DBO_SYSDBA', 64 ); //for oracle maintenance
+define( 'DBO_SYSDBA', 64 ); // for oracle maintenance
 define( 'DBO_DDLMODE', 128 ); // when using schema files: mostly for Oracle
 define( 'DBO_SSL', 256 );
 define( 'DBO_COMPRESS', 512 );
@@ -135,10 +135,10 @@ define( 'MEDIATYPE_ARCHIVE', 'ARCHIVE' );
 /**@{
  * Antivirus result codes, for use in $wgAntivirusSetup.
  */
-define( 'AV_NO_VIRUS', 0 );  #scan ok, no virus found
-define( 'AV_VIRUS_FOUND', 1 );  #virus found!
-define( 'AV_SCAN_ABORTED', -1 );  #scan aborted, the file is probably immune
-define( 'AV_SCAN_FAILED', false );  #scan failed (scanner not found or error in scanner)
+define( 'AV_NO_VIRUS', 0 );  # scan ok, no virus found
+define( 'AV_VIRUS_FOUND', 1 );  # virus found!
+define( 'AV_SCAN_ABORTED', -1 );  # scan aborted, the file is probably immune
+define( 'AV_SCAN_FAILED', false );  # scan failed (scanner not found or error in scanner)
 /**@}*/
 
 /**@{
index 05e0ac0..9059987 100644 (file)
@@ -980,7 +980,7 @@ class EditPage {
                global $wgUser;
                $this->edittime = $this->mArticle->getTimestamp();
 
-               $content = $this->getContentObject( false ); #TODO: track content object?!
+               $content = $this->getContentObject( false ); # TODO: track content object?!
                if ( $content === false ) {
                        return false;
                }
@@ -1228,7 +1228,7 @@ class EditPage {
                $title = Title::newFromText( $preload );
                # Check for existence to avoid getting MediaWiki:Noarticletext
                if ( $title === null || !$title->exists() || !$title->userCan( 'read', $wgUser ) ) {
-                       //TODO: somehow show a warning to the user!
+                       // TODO: somehow show a warning to the user!
                        return $handler->makeEmptyContent();
                }
 
@@ -1237,7 +1237,7 @@ class EditPage {
                        $title = $page->getRedirectTarget();
                        # Same as before
                        if ( $title === null || !$title->exists() || !$title->userCan( 'read', $wgUser ) ) {
-                               //TODO: somehow show a warning to the user!
+                               // TODO: somehow show a warning to the user!
                                return $handler->makeEmptyContent();
                        }
                        $page = WikiPage::factory( $title );
@@ -1247,7 +1247,7 @@ class EditPage {
                $content = $page->getContent( Revision::RAW );
 
                if ( !$content ) {
-                       //TODO: somehow show a warning to the user!
+                       // TODO: somehow show a warning to the user!
                        return $handler->makeEmptyContent();
                }
 
@@ -1255,7 +1255,7 @@ class EditPage {
                        $converted = $content->convert( $handler->getModelID() );
 
                        if ( !$converted ) {
-                               //TODO: somehow show a warning to the user!
+                               // TODO: somehow show a warning to the user!
                                wfDebug( "Attempt to preload incompatible content: " .
                                        "can't convert " . $content->getModel() .
                                        " to " . $handler->getModelID() );
@@ -2514,7 +2514,7 @@ class EditPage {
                # user preference is active, pass a hidden tag as wpIgnoreBlankSummary. This will stop the
                # user being bounced back more than once in the event that a summary
                # is not required.
-               #####
+               # ####
                # For a bit more sophisticated detection of blank summaries, hash the
                # automatic one and pass that in the hidden field wpAutoSummary.
                if ( $this->missingSummary || ( $this->section == 'new' && $this->nosummary ) ) {
@@ -2681,7 +2681,7 @@ class EditPage {
 
                        if ( $this->section != '' && $this->section != 'new' ) {
                                if ( !$this->summary && !$this->preview && !$this->diff ) {
-                                       $sectionTitle = self::extractSectionTitle( $this->textbox1 ); //FIXME: use Content object
+                                       $sectionTitle = self::extractSectionTitle( $this->textbox1 ); // FIXME: use Content object
                                        if ( $sectionTitle !== false ) {
                                                $this->summary = "/* $sectionTitle */ ";
                                        }
@@ -3705,7 +3705,7 @@ HTML
                $imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
                $showSignature = true;
                if ( $title ) {
-                        $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
+                       $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
                }
 
                /**
index a01d642..57ba4b3 100644 (file)
@@ -128,11 +128,11 @@ class FeedUtils {
 
                if ( $oldid ) {
 
-                       #$diffText = $de->getDiff( wfMessage( 'revisionasof',
-                       #       $wgLang->timeanddate( $timestamp ),
-                       #       $wgLang->date( $timestamp ),
-                       #       $wgLang->time( $timestamp ) )->text(),
-                       #       wfMessage( 'currentrev' )->text() );
+                       # $diffText = $de->getDiff( wfMessage( 'revisionasof',
+                       #       $wgLang->timeanddate( $timestamp ),
+                       #       $wgLang->date( $timestamp ),
+                       #       $wgLang->time( $timestamp ) )->text(),
+                       #       wfMessage( 'currentrev' )->text() );
 
                        $diffText = '';
                        // Don't bother generating the diff if we won't be able to show it
@@ -185,10 +185,10 @@ class FeedUtils {
                                        $html = nl2br( htmlspecialchars( $text ) );
                                }
                        } else {
-                               //XXX: we could get an HTML representation of the content via getParserOutput, but that may
+                               // XXX: we could get an HTML representation of the content via getParserOutput, but that may
                                //     contain JS magic and generally may not be suitable for inclusion in a feed.
                                //     Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
-                               //Compare also ApiFeedContributions::feedItemDesc
+                               // Compare also ApiFeedContributions::feedItemDesc
                                $html = null;
                        }
 
diff --git a/includes/FileContentsHasher.php b/includes/FileContentsHasher.php
deleted file mode 100644 (file)
index 67eb9d2..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * Generate hash digests of file contents to help with cache invalidation.
- *
- * 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
- */
-class FileContentsHasher {
-
-       /** @var BagOStuff */
-       protected $cache;
-
-       /** @var FileContentsHasher */
-       private static $instance;
-
-       /**
-        * Constructor.
-        */
-       public function __construct() {
-               $this->cache = ObjectCache::newAccelerator( 'hash' );
-       }
-
-       /**
-        * Get the singleton instance of this class.
-        *
-        * @return FileContentsHasher
-        */
-       public static function singleton() {
-               if ( !self::$instance ) {
-                       self::$instance = new self;
-               }
-
-               return self::$instance;
-       }
-
-       /**
-        * Get a hash of a file's contents, either by retrieving a previously-
-        * computed hash from the cache, or by computing a hash from the file.
-        *
-        * @private
-        * @param string $filePath Full path to the file.
-        * @param string $algo Name of selected hashing algorithm.
-        * @return string|bool Hash of file contents, or false if the file could not be read.
-        */
-       public function getFileContentsHashInternal( $filePath, $algo = 'md4' ) {
-               $mtime = MediaWiki\quietCall( 'filemtime', $filePath );
-               if ( $mtime === false ) {
-                       return false;
-               }
-
-               $cacheKey = wfGlobalCacheKey( __CLASS__, $filePath, $mtime, $algo );
-               $hash = $this->cache->get( $cacheKey );
-
-               if ( $hash ) {
-                       return $hash;
-               }
-
-               $contents = MediaWiki\quietCall( 'file_get_contents', $filePath );
-               if ( $contents === false ) {
-                       return false;
-               }
-
-               $hash = hash( $algo, $contents );
-               $this->cache->set( $cacheKey, $hash, 60 * 60 * 24 );  // 24h
-
-               return $hash;
-       }
-
-       /**
-        * Get a hash of the combined contents of one or more files, either by
-        * retrieving a previously-computed hash from the cache, or by computing
-        * a hash from the files.
-        *
-        * @param string|string[] $filePaths One or more file paths.
-        * @param string $algo Name of selected hashing algorithm.
-        * @return string|bool Hash of files' contents, or false if no file could not be read.
-        */
-       public static function getFileContentsHash( $filePaths, $algo = 'md4' ) {
-               $instance = self::singleton();
-
-               if ( !is_array( $filePaths ) ) {
-                       $filePaths = (array) $filePaths;
-               }
-
-               if ( count( $filePaths ) === 1 ) {
-                       return $instance->getFileContentsHashInternal( $filePaths[0], $algo );
-               }
-
-               sort( $filePaths );
-               $hashes = array_map( function ( $filePath ) use ( $instance, $algo ) {
-                       return $instance->getFileContentsHashInternal( $filePath, $algo ) ?: '';
-               }, $filePaths );
-
-               $hashes = implode( '', $hashes );
-               return $hashes ? hash( $algo, $hashes ) : false;
-       }
-}
index 486926f..6fbc11d 100644 (file)
@@ -635,7 +635,7 @@ function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
        $bits = wfParseUrl( $url );
 
        // ensure proper port for HTTPS arrives in URL
-       // https://bugzilla.wikimedia.org/show_bug.cgi?id=65184
+       // https://phabricator.wikimedia.org/T67184
        if ( $defaultProto === PROTO_HTTPS && $wgHttpsPort != 443 ) {
                $bits['port'] = $wgHttpsPort;
        }
@@ -2542,7 +2542,7 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
        MediaWiki\restoreWarnings();
 
        if ( !$ok ) {
-               //directory may have been created on another request since we last checked
+               // directory may have been created on another request since we last checked
                if ( is_dir( $dir ) ) {
                        return true;
                }
@@ -4072,13 +4072,10 @@ function wfUnpack( $format, $data, $length = false ) {
  * @return bool
  */
 function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
-       static $badImageCache = null; // based on bad_image_list msg
-
-       # Handle redirects
-       $redirectTitle = RepoGroup::singleton()->checkRedirect( Title::makeTitle( NS_FILE, $name ) );
-       if ( $redirectTitle ) {
-               $name = $redirectTitle->getDBkey();
-       }
+       # Handle redirects; callers almost always hit wfFindFile() anyway,
+       # so just use that method because it has a fast process cache.
+       $file = wfFindFile( $name ); // get the final name
+       $name = $file ? $file->getTitle()->getDBkey() : $name;
 
        # Run the extension hook
        $bad = false;
@@ -4086,10 +4083,11 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
                return $bad;
        }
 
-       $cacheable = ( $blacklist === null );
-       if ( $cacheable && $badImageCache !== null ) {
-               $badImages = $badImageCache;
-       } else { // cache miss
+       $cache = ObjectCache::newAccelerator( 'hash' );
+       $key = wfMemcKey( 'bad-image-list', ( $blacklist === null ) ? 'default' : md5( $blacklist ) );
+       $badImages = $cache->get( $key );
+
+       if ( $badImages === false ) { // cache miss
                if ( $blacklist === null ) {
                        $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list
                }
@@ -4125,13 +4123,12 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
                                $badImages[$imageDBkey] = $exceptions;
                        }
                }
-               if ( $cacheable ) {
-                       $badImageCache = $badImages;
-               }
+               $cache->set( $key, $badImages, 60 );
        }
 
        $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
        $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
+
        return $bad;
 }
 
index 62ae0b8..c61dca8 100644 (file)
@@ -857,7 +857,7 @@ class Html {
                        } elseif ( is_int( $nsId ) ) {
                                $nsName = $wgContLang->convertNamespace( $nsId );
                        }
-                       $optionsOut[ $nsId ] = $nsName;
+                       $optionsOut[$nsId] = $nsName;
                }
 
                return $optionsOut;
index 221cefb..83db268 100644 (file)
@@ -75,7 +75,7 @@ class HtmlFormatter {
 
                        // Workaround for bug that caused spaces before references
                        // to disappear during processing:
-                       // https://bugzilla.wikimedia.org/show_bug.cgi?id=53086
+                       // https://phabricator.wikimedia.org/T55086
                        //
                        // Please replace with a better fix if one can be found.
                        $html = str_replace( ' <', '&#32;<', $html );
index bc5a957..578b535 100644 (file)
@@ -678,7 +678,7 @@ class MWHttpRequest {
        public function getFinalUrl() {
                $headers = $this->getResponseHeaders();
 
-               //return full url (fix for incorrect but handled relative location)
+               // return full url (fix for incorrect but handled relative location)
                if ( isset( $headers['location'] ) ) {
                        $locations = $headers['location'];
                        $domain = '';
@@ -690,7 +690,7 @@ class MWHttpRequest {
 
                                if ( isset( $url['host'] ) ) {
                                        $domain = $url['scheme'] . '://' . $url['host'];
-                                       break; //found correct URI (with host)
+                                       break; // found correct URI (with host)
                                } else {
                                        $foundRelativeURI = true;
                                }
@@ -838,17 +838,19 @@ class CurlHttpRequest extends MWHttpRequest {
         * @return bool
         */
        public function canFollowRedirects() {
-               if ( strval( ini_get( 'open_basedir' ) ) !== '' || wfIniGetBool( 'safe_mode' ) ) {
-                       wfDebug( "Cannot follow redirects in safe mode\n" );
-                       return false;
-               }
-
                $curlVersionInfo = curl_version();
                if ( $curlVersionInfo['version_number'] < 0x071304 ) {
                        wfDebug( "Cannot follow redirects with libcurl < 7.19.4 due to CVE-2009-0037\n" );
                        return false;
                }
 
+               if ( version_compare( PHP_VERSION, '5.6.0', '<' ) ) {
+                       if ( strval( ini_get( 'open_basedir' ) ) !== '' || wfIniGetBool( 'safe_mode' ) ) {
+                               wfDebug( "Cannot follow redirects in safe mode\n" );
+                               return false;
+                       }
+               }
+
                return true;
        }
 }
@@ -895,7 +897,7 @@ class PhpHttpRequest extends MWHttpRequest {
                        ) );
                }
 
-               foreach( $certLocations as $key => $cert ) {
+               foreach ( $certLocations as $key => $cert ) {
                        if ( is_dir( $cert ) ) {
                                $certOptions['capath'] = $cert;
                                break;
index db4a6b2..60d4a1f 100644 (file)
@@ -265,7 +265,7 @@ class WikiImporter {
                        // No rootpage
                        $this->setImportTitleFactory( new NaiveImportTitleFactory() );
                } elseif ( $rootpage !== '' ) {
-                       $rootpage = rtrim( $rootpage, '/' ); //avoid double slashes
+                       $rootpage = rtrim( $rootpage, '/' ); // avoid double slashes
                        $title = Title::newFromText( $rootpage );
 
                        if ( !$title || $title->isExternal() ) {
@@ -1613,7 +1613,7 @@ class WikiRevision {
                        'page' => $pageId,
                        'content_model' => $this->getModel(),
                        'content_format' => $this->getFormat(),
-                       //XXX: just set 'content' => $this->getContent()?
+                       // XXX: just set 'content' => $this->getContent()?
                        'text' => $this->getContent()->serialize( $this->getFormat() ),
                        'comment' => $this->getComment(),
                        'user' => $userId,
@@ -1654,7 +1654,7 @@ class WikiRevision {
                                'log_namespace' => $this->getTitle()->getNamespace(),
                                'log_title' => $this->getTitle()->getDBkey(),
                                'log_comment' => $this->getComment(),
-                               #'log_user_text' => $this->user_text,
+                               # 'log_user_text' => $this->user_text,
                                'log_params' => $this->params ),
                        __METHOD__
                );
@@ -1672,7 +1672,7 @@ class WikiRevision {
                        'log_action' => $this->action,
                        'log_timestamp' => $dbw->timestamp( $this->timestamp ),
                        'log_user' => User::idFromName( $this->user_text ),
-                       #'log_user_text' => $this->user_text,
+                       # 'log_user_text' => $this->user_text,
                        'log_namespace' => $this->getTitle()->getNamespace(),
                        'log_title' => $this->getTitle()->getDBkey(),
                        'log_comment' => $this->getComment(),
index 99aaaa0..7215cec 100644 (file)
@@ -41,7 +41,7 @@ class LinkFilter {
         */
        static function matchEntry( Content $content, $filterEntry ) {
                if ( !( $content instanceof TextContent ) ) {
-                       //TODO: handle other types of content too.
+                       // TODO: handle other types of content too.
                        //      Maybe create ContentHandler::matchFilter( LinkFilter ).
                        //      Think about a common base class for LinkFilter and MagicWord.
                        return 0;
index 9b5ff27..2e33bd1 100644 (file)
@@ -1274,14 +1274,17 @@ class Linker {
         * temporarily to a value pass. Should be adjusted further. --brion
         *
         * @param string $comment
-        * @param Title|null $title Title object (to generate link to the section in autocomment) or null
+        * @param Title|null $title Title object (to generate link to the section in autocomment)
+        *  or null
         * @param bool $local Whether section links should refer to local page
-        * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to. For use with external changes.
+        * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
+        *  For use with external changes.
         *
         * @return mixed|string
         */
-       public static function formatComment( $comment, $title = null, $local = false, $wikiId = null ) {
-
+       public static function formatComment(
+               $comment, $title = null, $local = false, $wikiId = null
+       ) {
                # Sanitize text a bit:
                $comment = str_replace( "\n", " ", $comment );
                # Allow HTML entities (for bug 13815)
@@ -1306,11 +1309,14 @@ class Linker {
         * @param string $comment Comment text
         * @param Title|null $title An optional title object used to links to sections
         * @param bool $local Whether section links should refer to local page
-        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
+        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
+        *  as used by WikiMap.
         *
         * @return string Formatted comment (wikitext)
         */
-       private static function formatAutocomments( $comment, $title = null, $local = false, $wikiId = null ) {
+       private static function formatAutocomments(
+               $comment, $title = null, $local = false, $wikiId = null
+       ) {
                // @todo $append here is something of a hack to preserve the status
                // quo. Someone who knows more about bidi and such should decide
                // (1) what sane rendering even *is* for an LTR edit summary on an RTL
@@ -1334,7 +1340,12 @@ class Linker {
                                $auto = $match[2];
                                $post = $match[3] !== '';
                                $comment = null;
-                               Hooks::run( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local, $wikiId ) );
+
+                               Hooks::run(
+                                       'FormatAutocomments',
+                                       array( &$comment, $pre, $auto, $post, $title, $local, $wikiId )
+                               );
+
                                if ( $comment === null ) {
                                        $link = '';
                                        if ( $title ) {
@@ -1386,7 +1397,8 @@ class Linker {
         * @param string $comment Text to format links in
         * @param Title|null $title An optional title object used to links to sections
         * @param bool $local Whether section links should refer to local page
-        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
+        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
+        *  as used by WikiMap.
         *
         * @return string
         */
@@ -1489,18 +1501,25 @@ class Linker {
         *
         * @param Title $title
         * @param string $text
-        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
+        * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
+        *  as used by WikiMap.
         * @param string|string[] $options See the $options parameter in Linker::link.
         *
         * @return string HTML link
         */
-       public static function makeCommentLink( Title $title, $text, $wikiId = null, $options = array() ) {
+       public static function makeCommentLink(
+               Title $title, $text, $wikiId = null, $options = array()
+       ) {
                if ( $wikiId !== null && !$title->isExternal() ) {
                        $link = Linker::makeExternalLink(
-                                       WikiMap::getForeignURL( $wikiId, $title->getPrefixedText(), $title->getFragment() ),
-                                       $text,
-                                       /* escape = */ false // Already escaped
-                               );
+                               WikiMap::getForeignURL(
+                                       $wikiId,
+                                       $title->getPrefixedText(),
+                                       $title->getFragment()
+                               ),
+                               $text,
+                               /* escape = */ false // Already escaped
+                       );
                } else {
                        $link = Linker::link( $title, $text, array(), array(), $options );
                }
@@ -1594,11 +1613,14 @@ class Linker {
         * @param string $comment
         * @param Title|null $title Title object (to generate link to section in autocomment) or null
         * @param bool $local Whether section links should refer to local page
-        * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to. For use with external changes.
+        * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
+        *  For use with external changes.
         *
         * @return string
         */
-       public static function commentBlock( $comment, $title = null, $local = false, $wikiId = null ) {
+       public static function commentBlock(
+               $comment, $title = null, $local = false, $wikiId = null
+       ) {
                // '*' used to be the comment inserted by the software way back
                // in antiquity in case none was provided, here for backwards
                // compatibility, acc. to brion -ævar
index 6f3be73..102be80 100644 (file)
@@ -106,7 +106,7 @@ class MWTimestamp {
                        $ts,
                        $da
                ) ) {
-                       #TS_ISO_8601_BASIC
+                       # TS_ISO_8601_BASIC
                } elseif ( preg_match(
                        '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/',
                        $ts,
index 2b240c3..8ab92b4 100644 (file)
@@ -323,7 +323,7 @@ class MimeMagic {
                                continue;
                        }
 
-                       #print "processing MIME INFO line $s<br>";
+                       # print "processing MIME INFO line $s<br>";
 
                        $match = array();
                        if ( preg_match( '!\[\s*(\w+)\s*\]!', $s, $match ) ) {
@@ -957,7 +957,7 @@ class MimeMagic {
 
                if ( $m ) {
                        # normalize
-                       $m = preg_replace( '![;, ].*$!', '', $m ); #strip charset, etc
+                       $m = preg_replace( '![;, ].*$!', '', $m ); # strip charset, etc
                        $m = trim( $m );
                        $m = strtolower( $m );
 
index 552e181..f680d45 100644 (file)
@@ -2988,7 +2988,8 @@ class OutputPage extends ContextSource {
        function getExternalHeadScripts() {
                $links = array();
 
-               // Startup - this provides the client with the module manifest and loads jquery and mediawiki base modules
+               // Startup - this provides the client with the module
+               // manifest and loads jquery and mediawiki base modules
                $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS );
 
                return self::getHtmlFromLoaderLinks( $links );
@@ -3022,9 +3023,15 @@ class OutputPage extends ContextSource {
                // This needs to be TYPE_COMBINED so these modules are properly wrapped
                // in mw.loader.implement() calls and deferred until mw.user is available
                $embedScripts = array( 'user.options' );
-               $links[] = $this->makeResourceLoaderLink( $embedScripts, ResourceLoaderModule::TYPE_COMBINED );
+               $links[] = $this->makeResourceLoaderLink(
+                       $embedScripts,
+                       ResourceLoaderModule::TYPE_COMBINED
+               );
                // Separate user.tokens as otherwise caching will be allowed (T84960)
-               $links[] = $this->makeResourceLoaderLink( 'user.tokens', ResourceLoaderModule::TYPE_COMBINED );
+               $links[] = $this->makeResourceLoaderLink(
+                       'user.tokens',
+                       ResourceLoaderModule::TYPE_COMBINED
+               );
 
                // Modules requests - let the client calculate dependencies and batch requests as it likes
                // Only load modules that have marked themselves for loading at the top
@@ -3109,16 +3116,19 @@ class OutputPage extends ContextSource {
                        // FIXME: If the user is previewing, say, ./vector.js, his ./common.js will be loaded
                        // asynchronously and may arrive *after* the inline script here. So the previewed code
                        // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js.
-                       // Similarly, when previewing ./common.js and the user module does arrive first, it will
-                       // arrive without common.js and the inline script runs after. Thus running common after
-                       // the excluded subpage.
+                       // Similarly, when previewing ./common.js and the user module does arrive first,
+                       // it will arrive without common.js and the inline script runs after.
+                       // Thus running common after the excluded subpage.
                } else {
                        // Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
                        $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED );
                }
 
                // Group JS is only enabled if site JS is enabled.
-               $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED );
+               $links[] = $this->makeResourceLoaderLink(
+                       'user.groups',
+                       ResourceLoaderModule::TYPE_COMBINED
+               );
 
                return self::getHtmlFromLoaderLinks( $links );
        }
@@ -3375,7 +3385,9 @@ class OutputPage extends ContextSource {
                if ( $config->get( 'UniversalEditButton' ) && $this->isArticleRelated() ) {
                        $user = $this->getUser();
                        if ( $this->getTitle()->quickUserCan( 'edit', $user )
-                               && ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create', $user ) ) ) {
+                               && ( $this->getTitle()->exists() ||
+                                       $this->getTitle()->quickUserCan( 'create', $user ) )
+                       ) {
                                // Original UniversalEditButton
                                $msg = $this->msg( 'edit' )->text();
                                $tags['universal-edit-button'] = Html::element( 'link', array(
@@ -3427,8 +3439,9 @@ class OutputPage extends ContextSource {
                        $tags['rsd'] = Html::element( 'link', array(
                                'rel' => 'EditURI',
                                'type' => 'application/rsd+xml',
-                               // Output a protocol-relative URL here if $wgServer is protocol-relative
-                               // Whether RSD accepts relative or protocol-relative URLs is completely undocumented, though
+                               // Output a protocol-relative URL here if $wgServer is protocol-relative.
+                               // Whether RSD accepts relative or protocol-relative URLs is completely
+                               // undocumented, though.
                                'href' => wfExpandUrl( wfAppendQuery(
                                        wfScript( 'api' ),
                                        array( 'action' => 'rsd' ) ),
@@ -3446,7 +3459,9 @@ class OutputPage extends ContextSource {
                                        $tags["variant-$variant"] = Html::element( 'link', array(
                                                'rel' => 'alternate',
                                                'hreflang' => wfBCP47( $variant ),
-                                               'href' => $this->getTitle()->getLocalURL( array( 'variant' => $variant ) ) )
+                                               'href' => $this->getTitle()->getLocalURL(
+                                                       array( 'variant' => $variant ) )
+                                               )
                                        );
                                }
                                # x-default link per https://support.google.com/webmasters/answer/189077?hl=en
@@ -3494,7 +3509,9 @@ class OutputPage extends ContextSource {
                                        $format,
                                        $link,
                                        # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
-                                       $this->msg( "page-{$format}-feed", $this->getTitle()->getPrefixedText() )->text()
+                                       $this->msg(
+                                               "page-{$format}-feed", $this->getTitle()->getPrefixedText()
+                                       )->text()
                                );
                        }
 
@@ -3701,7 +3718,8 @@ class OutputPage extends ContextSource {
                                continue;
                        }
                        $group = $module->getGroup();
-                       // Modules in groups other than the ones needing special treatment (see $styles assignment)
+                       // Modules in groups other than the ones needing special treatment
+                       // (see $styles assignment)
                        // will be placed in the "other" style category.
                        $styles[isset( $styles[$group] ) ? $group : 'other'][] = $name;
                }
@@ -3711,10 +3729,14 @@ class OutputPage extends ContextSource {
                // statically added styles from other modules. So the order has to be
                // other, dynamic, site, private, user. Add statically added styles for
                // other modules
-               $links[] = $this->makeResourceLoaderLink( $styles['other'], ResourceLoaderModule::TYPE_STYLES );
+               $links[] = $this->makeResourceLoaderLink(
+                       $styles['other'],
+                       ResourceLoaderModule::TYPE_STYLES
+               );
                // Add normal styles added through addStyle()/addInlineStyle() here
                $links[] = implode( "\n", $this->buildCssLinksArray() ) . $this->mInlineStyles;
-               // Add marker tag to mark the place where the client-side loader should inject dynamic styles
+               // Add marker tag to mark the place where the client-side
+               // loader should inject dynamic styles
                // We use a <meta> tag with a made-up name for this because that's valid HTML
                $links[] = Html::element(
                        'meta',
@@ -3784,7 +3806,8 @@ class OutputPage extends ContextSource {
                        $url = $style;
                } else {
                        $config = $this->getConfig();
-                       $url = $config->get( 'StylePath' ) . '/' . $style . '?' . $config->get( 'StyleVersion' );
+                       $url = $config->get( 'StylePath' ) . '/' . $style . '?' .
+                               $config->get( 'StyleVersion' );
                }
 
                $link = Html::linkedStyle( $url, $media );
@@ -3973,7 +3996,7 @@ class OutputPage extends ContextSource {
                $themes = ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' );
                // Make keys (skin names) lowercase for case-insensitive matching.
                $themes = array_change_key_case( $themes, CASE_LOWER );
-               $theme = isset( $themes[ $skinName ] ) ? $themes[ $skinName ] : 'MediaWiki';
+               $theme = isset( $themes[$skinName] ) ? $themes[$skinName] : 'MediaWiki';
                // For example, 'OOUI\MediaWikiTheme'.
                $themeClass = "OOUI\\{$theme}Theme";
                OOUI\Theme::setSingleton( new $themeClass() );
index 9dec950..4b2ff8c 100644 (file)
@@ -30,7 +30,7 @@
  * version are hardcoded here
  */
 function wfEntryPointCheck( $entryPoint ) {
-       $mwVersion = '1.26';
+       $mwVersion = '1.27';
        $minimumVersionPHP = '5.3.3';
        $phpVersion = PHP_VERSION;
 
index d0475c1..b3ee207 100644 (file)
@@ -112,20 +112,20 @@ class Preferences {
         * @return array|null
         */
        static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
-               ## Remove preferences that wikis don't want to use
+               # # Remove preferences that wikis don't want to use
                foreach ( $context->getConfig()->get( 'HiddenPrefs' ) as $pref ) {
                        if ( isset( $defaultPreferences[$pref] ) ) {
                                unset( $defaultPreferences[$pref] );
                        }
                }
 
-               ## Make sure that form fields have their parent set. See bug 41337.
+               # # Make sure that form fields have their parent set. See bug 41337.
                $dummyForm = new HTMLForm( array(), $context );
 
                $disable = !$user->isAllowed( 'editmyoptions' );
 
                $defaultOptions = User::getDefaultOptions();
-               ## Prod in defaults from the user
+               # # Prod in defaults from the user
                foreach ( $defaultPreferences as $name => &$info ) {
                        $prefFromUser = self::getOptionFromUser( $name, $info, $user );
                        if ( $disable && !in_array( $name, self::$saveBlacklist ) ) {
@@ -211,7 +211,7 @@ class Preferences {
                // retrieving user name for GENDER and misc.
                $userName = $user->getName();
 
-               ## User info #####################################
+               # # User info #####################################
                // Information panel
                $defaultPreferences['username'] = array(
                        'type' => 'info',
@@ -427,7 +427,7 @@ class Preferences {
                        'section' => 'personal/signature'
                );
 
-               ## Email stuff
+               # # Email stuff
 
                if ( $config->get( 'EnableEmail' ) ) {
                        if ( $canViewPrivateInfo ) {
@@ -571,7 +571,7 @@ class Preferences {
         * @return void
         */
        static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               ## Skin #####################################
+               # # Skin #####################################
 
                // Skin selector, if there is at least one valid skin
                $skinOptions = self::generateSkinOptions( $user, $context );
@@ -620,7 +620,7 @@ class Preferences {
         * @param array $defaultPreferences
         */
        static function filesPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               ## Files #####################################
+               # # Files #####################################
                $defaultPreferences['imagesize'] = array(
                        'type' => 'select',
                        'options' => self::getImageSizes( $context ),
@@ -642,7 +642,7 @@ class Preferences {
         * @return void
         */
        static function datetimePreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               ## Date and time #####################################
+               # # Date and time #####################################
                $dateOptions = self::getDateOptions( $context );
                if ( $dateOptions ) {
                        $defaultPreferences['date'] = array(
@@ -715,7 +715,7 @@ class Preferences {
         * @param array $defaultPreferences
         */
        static function renderingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               ## Diffs ####################################
+               # # Diffs ####################################
                $defaultPreferences['diffonly'] = array(
                        'type' => 'toggle',
                        'section' => 'rendering/diffs',
@@ -727,7 +727,7 @@ class Preferences {
                        'label-message' => 'tog-norollbackdiff',
                );
 
-               ## Page Rendering ##############################
+               # # Page Rendering ##############################
                if ( $context->getConfig()->get( 'AllowUserCssPrefs' ) ) {
                        $defaultPreferences['underline'] = array(
                                'type' => 'select',
@@ -777,7 +777,7 @@ class Preferences {
         * @param array $defaultPreferences
         */
        static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               ## Editing #####################################
+               # # Editing #####################################
                $defaultPreferences['editsectiononrightclick'] = array(
                        'type' => 'toggle',
                        'section' => 'editing/advancedediting',
@@ -865,7 +865,7 @@ class Preferences {
        static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                $config = $context->getConfig();
                $rcMaxAge = $config->get( 'RCMaxAge' );
-               ## RecentChanges #####################################
+               # # RecentChanges #####################################
                $defaultPreferences['rcdays'] = array(
                        'type' => 'float',
                        'label-message' => 'recentchangesdays',
@@ -926,7 +926,7 @@ class Preferences {
                $config = $context->getConfig();
                $watchlistdaysMax = ceil( $config->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
 
-               ## Watchlist #####################################
+               # # Watchlist #####################################
                if ( $user->isAllowed( 'editmywatchlist' ) ) {
                        $editWatchlistLinks = array();
                        $editWatchlistModes = array(
index 32ee259..6584207 100644 (file)
@@ -773,7 +773,7 @@ class Revision implements IDBAccessObject {
                if ( $this->mTitle !== null ) {
                        return $this->mTitle;
                }
-               //rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
+               // rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
                if ( $this->mId !== null ) {
                        $dbr = wfGetDB( DB_SLAVE );
                        $row = $dbr->selectRow(
@@ -1418,8 +1418,8 @@ class Revision implements IDBAccessObject {
                );
 
                if ( $wgContentHandlerUseDB ) {
-                       //NOTE: Store null for the default model and format, to save space.
-                       //XXX: Makes the DB sensitive to changed defaults.
+                       // NOTE: Store null for the default model and format, to save space.
+                       // XXX: Makes the DB sensitive to changed defaults.
                        // Make this behavior optional? Only in miser mode?
 
                        $model = $this->getContentModel();
@@ -1459,7 +1459,7 @@ class Revision implements IDBAccessObject {
        protected function checkContentModel() {
                global $wgContentHandlerUseDB;
 
-               $title = $this->getTitle(); //note: may return null for revisions that have not yet been inserted.
+               $title = $this->getTitle(); // note: may return null for revisions that have not yet been inserted.
 
                $model = $this->getContentModel();
                $format = $this->getContentFormat();
index de63af7..f88dd05 100644 (file)
@@ -536,7 +536,7 @@ class Sanitizer {
                                                        $badtag = true;
                                                } elseif ( in_array( $t, $tagstack ) && !isset( $htmlnest[$t] ) ) {
                                                        $badtag = true;
-                                               # Is it a self closed htmlpair ? (bug 5487)
+                                               #  Is it a self closed htmlpair ? (bug 5487)
                                                } elseif ( $brace == '/>' && isset( $htmlpairs[$t] ) ) {
                                                        $badtag = true;
                                                } elseif ( isset( $htmlsingleonly[$t] ) ) {
@@ -738,7 +738,7 @@ class Sanitizer {
 
                $out = array();
                foreach ( $attribs as $attribute => $value ) {
-                       #allow XML namespace declaration if RDFa is enabled
+                       # allow XML namespace declaration if RDFa is enabled
                        if ( $wgAllowRdfaAttributes && preg_match( self::XMLNS_ATTRIBUTE_PATTERN, $attribute ) ) {
                                if ( !preg_match( self::EVIL_URI_PATTERN, $value ) ) {
                                        $out[$attribute] = $value;
@@ -784,7 +784,7 @@ class Sanitizer {
                                || $attribute === 'itemref' || $attribute === 'itemscope'
                                || $attribute === 'itemtype'
                        ) {
-                               //Paranoia. Allow "simple" values but suppress javascript
+                               // Paranoia. Allow "simple" values but suppress javascript
                                if ( preg_match( self::EVIL_URI_PATTERN, $value ) ) {
                                        continue;
                                }
@@ -794,7 +794,7 @@ class Sanitizer {
                        #       validation code that can be used by tag hook handlers, etc
                        if ( $attribute === 'href' || $attribute === 'src' ) {
                                if ( !preg_match( $hrefExp, $value ) ) {
-                                       continue; //drop any href or src attributes not using an allowed protocol.
+                                       continue; // drop any href or src attributes not using an allowed protocol.
                                        // NOTE: this also drops all relative URLs
                                }
                        }
@@ -1697,7 +1697,7 @@ class Sanitizer {
                        # rbc
                        'rb'         => $common,
                        'rp'         => $common,
-                       'rt'         => $common, #array_merge( $common, array( 'rbspan' ) ),
+                       'rt'         => $common, # array_merge( $common, array( 'rbspan' ) ),
                        'rtc'         => $common,
 
                        # MathML root element, where used for extensions
@@ -1807,7 +1807,9 @@ class Sanitizer {
                        $host = preg_replace( $strip, '', $host );
 
                        // IPv6 host names are bracketed with [].  Url-decode these.
-                       if ( substr_compare( "//%5B", $host, 0, 5 ) === 0 && preg_match( '!^//%5B([0-9A-Fa-f:.]+)%5D((:\d+)?)$!', $host, $matches ) ) {
+                       if ( substr_compare( "//%5B", $host, 0, 5 ) === 0 &&
+                               preg_match( '!^//%5B([0-9A-Fa-f:.]+)%5D((:\d+)?)$!', $host, $matches )
+                       ) {
                                $host = '//[' . $matches[1] . ']' . $matches[2];
                        }
 
index d6b101b..3c62c14 100644 (file)
@@ -79,7 +79,9 @@ class TemplateParser {
         */
        protected function getTemplate( $templateName ) {
                // If a renderer has already been defined for this template, reuse it
-               if ( isset( $this->renderers[$templateName] ) && is_callable( $this->renderers[$templateName] ) ) {
+               if ( isset( $this->renderers[$templateName] ) &&
+                       is_callable( $this->renderers[$templateName] )
+               ) {
                        return $this->renderers[$templateName];
                }
 
index b347edb..e54c35e 100644 (file)
@@ -206,7 +206,7 @@ class Title {
         * @return TitleFormatter
         */
        private static function getTitleFormatter() {
-               //NOTE: we know that getTitleParser() returns a MediaWikiTitleCodec,
+               // NOTE: we know that getTitleParser() returns a MediaWikiTitleCodec,
                //      which implements TitleFormatter.
                return self::getTitleParser();
        }
@@ -2944,7 +2944,7 @@ class Title {
                                        $this->mRestrictions['move'] = explode( ',', trim( $temp[0] ) );
                                } else {
                                        $restriction = trim( $temp[1] );
-                                       if ( $restriction != '' ) { //some old entries are empty
+                                       if ( $restriction != '' ) { // some old entries are empty
                                                $this->mRestrictions[$temp[0]] = explode( ',', $restriction );
                                        }
                                }
index 22c90cd..029f5cf 100644 (file)
@@ -129,7 +129,7 @@ class User implements IDBAccessObject {
                'editmyuserjs',
                'editmywatchlist',
                'editsemiprotected',
-               'editusercssjs', #deprecated
+               'editusercssjs', # deprecated
                'editusercss',
                'edituserjs',
                'hideuser',
@@ -184,7 +184,7 @@ class User implements IDBAccessObject {
        protected static $mAllRights = false;
 
        /** Cache variables */
-       //@{
+       // @{
        public $mId;
        /** @var string */
        public $mName;
@@ -228,19 +228,19 @@ class User implements IDBAccessObject {
        protected $mOptionOverrides;
        /** @var string */
        protected $mPasswordExpires;
-       //@}
+       // @}
 
        /**
         * Bool Whether the cache variables have been loaded.
         */
-       //@{
+       // @{
        public $mOptionsLoaded;
 
        /**
         * Array with already loaded items or true if all items have been loaded.
         */
        protected $mLoadedItems = array();
-       //@}
+       // @}
 
        /**
         * String Initialization data source if mLoadedItems!==true. May be one of:
@@ -458,11 +458,12 @@ class User implements IDBAccessObject {
                $data['mVersion'] = self::VERSION;
                $key = wfMemcKey( 'user', 'id', $this->mId );
 
-               ObjectCache::getMainWANInstance()->set( $key, $data, 3600 );
+               $opts = array( 'since' => wfGetDB( DB_SLAVE )->trxTimestamp() );
+               ObjectCache::getMainWANInstance()->set( $key, $data, 3600, $opts );
        }
 
        /** @name newFrom*() static factory methods */
-       //@{
+       // @{
 
        /**
         * Static factory method for creation from username.
@@ -573,7 +574,7 @@ class User implements IDBAccessObject {
                return $user;
        }
 
-       //@}
+       // @}
 
        /**
         * Get the username corresponding to a given user ID
@@ -799,7 +800,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function isValidPassword( $password ) {
-               //simple boolean wrapper for getPasswordValidity
+               // simple boolean wrapper for getPasswordValidity
                return $this->getPasswordValidity( $password ) === true;
        }
 
@@ -856,7 +857,7 @@ class User implements IDBAccessObject {
                );
 
                $status = Status::newGood();
-               $result = false; //init $result to false for the internal checks
+               $result = false; // init $result to false for the internal checks
 
                if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
                        $status->error( $result );
@@ -870,7 +871,7 @@ class User implements IDBAccessObject {
                        return $status;
                } else {
                        $status->error( $result );
-                       return $status; //the isValidPassword hook set a string $result and returned true
+                       return $status; // the isValidPassword hook set a string $result and returned true
                }
        }
 
@@ -1203,18 +1204,15 @@ class User implements IDBAccessObject {
                        return false;
                }
 
-               $db = ( $flags & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
+               list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
+               $db = wfGetDB( $index );
 
                $s = $db->selectRow(
                        'user',
                        self::selectFields(),
                        array( 'user_id' => $this->mId ),
                        __METHOD__,
-                       ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
-                               ? array( 'LOCK IN SHARE MODE' )
-                               : array()
+                       $options
                );
 
                $this->queryFlagsUsed = $flags;
@@ -1484,11 +1482,12 @@ class User implements IDBAccessObject {
 
                if ( $success ) {
                        $this->mTouched = $newTouched;
+                       $this->clearSharedCache();
+               } else {
+                       // Clears on failure too since that is desired if the cache is stale
+                       $this->clearSharedCache( 'refresh' );
                }
 
-               // Clears on failure too since that is desired if the cache is stale
-               $this->clearSharedCache();
-
                return $success;
        }
 
@@ -1694,6 +1693,7 @@ class User implements IDBAccessObject {
                        foreach ( (array)$bases as $base ) {
                                // Make hostname
                                // If we have an access key, use that too (ProjectHoneypot, etc.)
+                               $basename = $base;
                                if ( is_array( $base ) ) {
                                        if ( count( $base ) >= 2 ) {
                                                // Access key is 1, base URL is 0
@@ -1701,6 +1701,7 @@ class User implements IDBAccessObject {
                                        } else {
                                                $host = "$ipReversed.{$base[0]}";
                                        }
+                                       $basename = $base[0];
                                } else {
                                        $host = "$ipReversed.$base";
                                }
@@ -1709,11 +1710,11 @@ class User implements IDBAccessObject {
                                $ipList = gethostbynamel( $host );
 
                                if ( $ipList ) {
-                                       wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!" );
+                                       wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
                                        $found = true;
                                        break;
                                } else {
-                                       wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base." );
+                                       wfDebugLog( 'dnsblacklist', "Requested $host, not found in $basename." );
                                }
                        }
                }
@@ -2280,17 +2281,28 @@ class User implements IDBAccessObject {
        }
 
        /**
-        * Clear user data from memcached.
-        * Use after applying fun updates to the database; caller's
+        * Clear user data from memcached
+        *
+        * Use after applying updates to the database; caller's
         * responsibility to update user_touched if appropriate.
         *
         * Called implicitly from invalidateCache() and saveSettings().
+        *
+        * @param string $mode Use 'refresh' to clear now; otherwise before DB commit
         */
-       public function clearSharedCache() {
+       public function clearSharedCache( $mode = 'changed' ) {
                $id = $this->getId();
-               if ( $id ) {
-                       $key = wfMemcKey( 'user', 'id', $id );
-                       ObjectCache::getMainWANInstance()->delete( $key );
+               if ( !$id ) {
+                       return;
+               }
+
+               $key = wfMemcKey( 'user', 'id', $id );
+               if ( $mode === 'refresh' ) {
+                       ObjectCache::getMainWANInstance()->delete( $key, 1 );
+               } else {
+                       wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $key ) {
+                               ObjectCache::getMainWANInstance()->delete( $key );
+                       } );
                }
        }
 
@@ -3696,7 +3708,7 @@ class User implements IDBAccessObject {
 
                if ( !$dbw->affectedRows() ) {
                        // Maybe the problem was a missed cache update; clear it to be safe
-                       $this->clearSharedCache();
+                       $this->clearSharedCache( 'refresh' );
                        // User was changed in the meantime or loaded with stale data
                        $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
                        throw new MWException(
@@ -5203,7 +5215,7 @@ class User implements IDBAccessObject {
                # is b0rked anyway in some browsers, just return nothing.  When it's
                # re-enabled, fix this code to not output required for e-mail
                # registration.
-               #$ret = array( 'required' );
+               # $ret = array( 'required' );
                $ret = array();
 
                # We can't actually do this right now, because Opera 9.6 will print out
index a19f698..2c7032f 100644 (file)
@@ -278,8 +278,9 @@ class UserRightsProxy {
                        array( 'user_id' => $this->id ),
                        __METHOD__ );
 
-               $cache = ObjectCache::getMainWANInstance();
                $key = wfForeignMemcKey( $this->database, false, 'user', 'id', $this->id );
-               $cache->delete( $key );
+               $this->db->onTransactionPreCommitOrIdle( function() use ( $key ) {
+                       ObjectCache::getMainWANInstance()->delete( $key );
+               } );
        }
 }
index b4b8be9..f402f3b 100644 (file)
@@ -315,7 +315,9 @@ class WebRequest {
                        }
                } else {
                        global $wgContLang;
-                       $data = isset( $wgContLang ) ? $wgContLang->normalize( $data ) : UtfNormal\Validator::cleanUp( $data );
+                       $data = isset( $wgContLang ) ?
+                               $wgContLang->normalize( $data ) :
+                               UtfNormal\Validator::cleanUp( $data );
                }
                return $data;
        }
@@ -754,7 +756,8 @@ class WebRequest {
         * Appends or replaces value of query variables.
         *
         * @param array $array Array of values to replace/add to query
-        * @param bool $onlyquery Whether to only return the query string and not the complete URL [deprecated]
+        * @param bool $onlyquery Whether to only return the query string
+        *  and not the complete URL [deprecated]
         * @return string
         */
        public function appendQueryArray( $array, $onlyquery = true ) {
index f5a4f93..b095577 100644 (file)
 # Die if register_globals is enabled (PHP <=5.3)
 # This must be done before any globals are set by the code
 if ( ini_get( 'register_globals' ) ) {
-       die( 'MediaWiki does not support installations where register_globals is enabled. '
-               . 'Please see <a href="https://www.mediawiki.org/wiki/register_globals">mediawiki.org</a> '
+       die( 'MediaWiki does not support installations where register_globals is enabled. Please see '
+               . '<a href="https://www.mediawiki.org/wiki/register_globals">mediawiki.org</a> '
                . 'for help on how to disable it.' );
 }
 
 if ( function_exists( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc() ) {
-       die( 'MediaWiki does not function when magic quotes are enabled. '
-               . 'Please see the <a href="https://php.net/manual/security.magicquotes.disabling.php">PHP Manual</a> '
+       die( 'MediaWiki does not function when magic quotes are enabled. Please see the '
+               . '<a href="https://php.net/manual/security.magicquotes.disabling.php">PHP Manual</a> '
                . 'for help on how to disable magic quotes.' );
 }
 
index 027ff72..7eaebdf 100644 (file)
@@ -159,7 +159,8 @@ class WikiReference {
                if ( $parsed ) {
                        return $parsed['host'];
                } else {
-                       // Invalid server spec. There's no sane thing to do here, so just return the canonical server name in full
+                       // Invalid server spec.
+                       // There's no sane thing to do here, so just return the canonical server name in full.
                        return $this->mCanonicalServer;
                }
        }
@@ -169,7 +170,8 @@ class WikiReference {
         *
         * @todo FIXME: This may be generalized...
         *
-        * @param string $page Page name (must be normalised before calling this function! May contain a section part.)
+        * @param string $page Page name (must be normalised before calling this function!
+        *  May contain a section part.)
         * @param string|null $fragmentId
         *
         * @return string relative URL, without the server part.
index 37cffde..11f14db 100644 (file)
@@ -711,10 +711,10 @@ class Xml {
                xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
 
                if ( !xml_parse( $parser, $text, true ) ) {
-                       //$err = xml_error_string( xml_get_error_code( $parser ) );
-                       //$position = xml_get_current_byte_index( $parser );
-                       //$fragment = $this->extractFragment( $html, $position );
-                       //$this->mXmlError = "$err at byte $position:\n$fragment";
+                       // $err = xml_error_string( xml_get_error_code( $parser ) );
+                       // $position = xml_get_current_byte_index( $parser );
+                       // $fragment = $this->extractFragment( $html, $position );
+                       // $this->mXmlError = "$err at byte $position:\n$fragment";
                        xml_parser_free( $parser );
                        return false;
                }
index f3670a8..d9324e7 100644 (file)
@@ -555,9 +555,11 @@ class InfoAction extends FormlessAction {
                );
 
                // Total number of distinct authors
-               $pageInfo['header-edits'][] = array(
-                       $this->msg( 'pageinfo-authors' ), $lang->formatNum( $pageCounts['authors'] )
-               );
+               if ( $pageCounts['authors'] > 0 ) {
+                       $pageInfo['header-edits'][] = array(
+                               $this->msg( 'pageinfo-authors' ), $lang->formatNum( $pageCounts['authors'] )
+                       );
+               }
 
                // Recent number of edits (within past 30 days)
                $pageInfo['header-edits'][] = array(
@@ -718,20 +720,23 @@ class InfoAction extends FormlessAction {
                // Total number of edits
                $edits = (int)$dbr->selectField(
                        'revision',
-                       'COUNT(rev_page)',
+                       'COUNT(*)',
                        array( 'rev_page' => $id ),
                        __METHOD__
                );
                $result['edits'] = $edits;
 
                // Total number of distinct authors
-               $authors = (int)$dbr->selectField(
-                       'revision',
-                       'COUNT(DISTINCT rev_user_text)',
-                       array( 'rev_page' => $id ),
-                       __METHOD__
-               );
-               $result['authors'] = $authors;
+               if ( $config->get( 'MiserMode' ) ) {
+                       $result['authors'] = 0;
+               } else {
+                       $result['authors'] = (int)$dbr->selectField(
+                               'revision',
+                               'COUNT(DISTINCT rev_user_text)',
+                               array( 'rev_page' => $id ),
+                               __METHOD__
+                       );
+               }
 
                // "Recent" threshold defined by RCMaxAge setting
                $threshold = $dbr->timestamp( time() - $config->get( 'RCMaxAge' ) );
@@ -749,7 +754,7 @@ class InfoAction extends FormlessAction {
                $result['recent_edits'] = $edits;
 
                // Recent number of distinct authors
-               $authors = (int)$dbr->selectField(
+               $result['recent_authors'] = (int)$dbr->selectField(
                        'revision',
                        'COUNT(DISTINCT rev_user_text)',
                        array(
@@ -758,7 +763,6 @@ class InfoAction extends FormlessAction {
                        ),
                        __METHOD__
                );
-               $result['recent_authors'] = $authors;
 
                // Subpages (if enabled)
                if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
index a7f1ac3..48909cf 100644 (file)
@@ -52,4 +52,3 @@ class ProtectAction extends FormlessAction {
                $this->page->protect();
        }
 }
-
index 93669cf..0404856 100644 (file)
@@ -78,13 +78,13 @@ class RollbackAction extends FormlessAction {
                        return;
                }
 
-               #NOTE: Permission errors already handled by Action::checkExecute.
+               # NOTE: Permission errors already handled by Action::checkExecute.
 
                if ( $result == array( array( 'readonlytext' ) ) ) {
                        throw new ReadOnlyError;
                }
 
-               #XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
+               # XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
                #     Right now, we only show the first error
                foreach ( $result as $error ) {
                        throw new ErrorPageError( 'rollbackfailed', $error[0], array_slice( $error, 1 ) );
@@ -109,7 +109,7 @@ class RollbackAction extends FormlessAction {
                $this->getOutput()->returnToMain( false, $this->getTitle() );
 
                if ( !$request->getBool( 'hidediff', false ) &&
-                       !$this->getUser()->getBoolOption( 'norollbackdiff', false )
+                       !$this->getUser()->getBoolOption( 'norollbackdiff' )
                ) {
                        $contentHandler = $current->getContentHandler();
                        $de = $contentHandler->createDifferenceEngine(
index d53797b..5a1099e 100644 (file)
@@ -206,7 +206,8 @@ abstract class ApiBase extends ContextSource {
                                // Fix up the ugly "even numbered elements are description, odd
                                // numbered elemts are the link" format (see doc for self::getExamples)
                                $tmp = array();
-                               for ( $i = 0; $i < count( $examples ); $i += 2 ) {
+                               $examplesCount = count( $examples );
+                               for ( $i = 0; $i < $examplesCount; $i += 2 ) {
                                        $tmp[$examples[$i + 1]] = $examples[$i];
                                }
                                $examples = $tmp;
@@ -1070,7 +1071,9 @@ abstract class ApiBase extends ContextSource {
         * @param int $botMax Maximum value for sysops/bots
         * @param bool $enforceLimits Whether to enforce (die) if value is outside limits
         */
-       protected function validateLimit( $paramName, &$value, $min, $max, $botMax = null, $enforceLimits = false ) {
+       protected function validateLimit( $paramName, &$value, $min, $max, $botMax = null,
+               $enforceLimits = false
+       ) {
                if ( !is_null( $min ) && $value < $min ) {
                        $msg = $this->encodeParamName( $paramName ) . " may not be less than $min (set to $value)";
                        $this->warnOrDie( $msg, $enforceLimits );
@@ -2671,14 +2674,14 @@ abstract class ApiBase extends ContextSource {
                                        $desc = implode( $paramPrefix, $desc );
                                }
 
-                               //handle shorthand
+                               // handle shorthand
                                if ( !is_array( $paramSettings ) ) {
                                        $paramSettings = array(
                                                self::PARAM_DFLT => $paramSettings,
                                        );
                                }
 
-                               //handle missing type
+                               // handle missing type
                                if ( !isset( $paramSettings[ApiBase::PARAM_TYPE] ) ) {
                                        $dflt = isset( $paramSettings[ApiBase::PARAM_DFLT] )
                                                ? $paramSettings[ApiBase::PARAM_DFLT]
index 5443fac..00b7de9 100644 (file)
@@ -118,7 +118,9 @@ class ApiCreateAccount extends ApiBase {
                                        'createaccount-title',
                                        'createaccount-text'
                                ) );
-                       } elseif ( $this->getConfig()->get( 'EmailAuthentication' ) && Sanitizer::validateEmail( $user->getEmail() ) ) {
+                       } elseif ( $this->getConfig()->get( 'EmailAuthentication' ) &&
+                               Sanitizer::validateEmail( $user->getEmail() )
+                       ) {
                                // Send out an email authentication message if needed
                                $status->merge( $user->sendConfirmationMail() );
                        }
index edda672..9c3945e 100644 (file)
@@ -56,7 +56,8 @@ class ApiFeedContributions extends ApiBase {
                }
 
                $msg = wfMessage( 'Contributions' )->inContentLanguage()->text();
-               $feedTitle = $config->get( 'Sitename' ) . ' - ' . $msg . ' [' . $config->get( 'LanguageCode' ) . ']';
+               $feedTitle = $config->get( 'Sitename' ) . ' - ' . $msg .
+                       ' [' . $config->get( 'LanguageCode' ) . ']';
                $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL();
 
                $target = $params['user'] == 'newbies'
@@ -163,10 +164,10 @@ class ApiFeedContributions extends ApiBase {
                                // only textual content has a "source view".
                                $html = nl2br( htmlspecialchars( $content->getNativeData() ) );
                        } else {
-                               //XXX: we could get an HTML representation of the content via getParserOutput, but that may
+                               // XXX: we could get an HTML representation of the content via getParserOutput, but that may
                                //     contain JS magic and generally may not be suitable for inclusion in a feed.
                                //     Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
-                               //Compare also FeedUtils::formatDiffRow.
+                               // Compare also FeedUtils::formatDiffRow.
                                $html = '';
                        }
 
index e522d70..3c10518 100644 (file)
@@ -155,7 +155,7 @@ abstract class ApiFormatBase extends ApiBase {
 
                $this->getMain()->getRequest()->response()->header( "Content-Type: $mime; charset=utf-8" );
 
-               //Set X-Frame-Options API results (bug 39180)
+               // Set X-Frame-Options API results (bug 39180)
                $apiFrameOptions = $this->getConfig()->get( 'ApiFrameOptions' );
                if ( $apiFrameOptions ) {
                        $this->getMain()->getRequest()->response()->header( "X-Frame-Options: $apiFrameOptions" );
index be1b12c..a319be3 100644 (file)
@@ -93,7 +93,8 @@ class ApiFormatJson extends ApiFormatBase {
                                        break;
 
                                default:
-                                       $this->dieUsage( __METHOD__ . ': Unknown value for \'formatversion\'', 'unknownformatversion' );
+                                       $this->dieUsage( __METHOD__ .
+                                               ': Unknown value for \'formatversion\'', 'unknownformatversion' );
                        }
                }
                $data = $this->getResult()->getResultData( null, $transform );
index 6420a5b..df9d581 100644 (file)
@@ -69,7 +69,7 @@ class ApiFormatPhp extends ApiFormatBase {
                ) {
                        $this->dieUsage(
                                'This response cannot be represented using format=php. ' .
-                               'See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776',
+                               'See https://phabricator.wikimedia.org/T68776',
                                'internalerror'
                        );
                }
index f6d124f..abec828 100644 (file)
@@ -703,7 +703,12 @@ class ApiHelp extends ApiBase {
                                                $submodules[] = $manager->getModule( $name );
                                        }
                                }
-                               $help['submodules'] .= self::getHelpInternal( $context, $submodules, $suboptions, $haveModules );
+                               $help['submodules'] .= self::getHelpInternal(
+                                       $context,
+                                       $submodules,
+                                       $suboptions,
+                                       $haveModules
+                               );
                                $numSubmodules = count( $submodules );
                        }
 
index d943c86..8e0ba8b 100644 (file)
@@ -618,10 +618,13 @@ class ApiMain extends ApiBase {
 
                        $response->header( "Access-Control-Allow-Origin: $originHeader" );
                        $response->header( 'Access-Control-Allow-Credentials: true' );
-                       $response->header( "Timing-Allow-Origin: $originHeader" ); # http://www.w3.org/TR/resource-timing/#timing-allow-origin
+                       // http://www.w3.org/TR/resource-timing/#timing-allow-origin
+                       $response->header( "Timing-Allow-Origin: $originHeader" );
 
                        if ( !$preflight ) {
-                               $response->header( 'Access-Control-Expose-Headers: MediaWiki-API-Error, Retry-After, X-Database-Lag' );
+                               $response->header(
+                                       'Access-Control-Expose-Headers: MediaWiki-API-Error, Retry-After, X-Database-Lag'
+                               );
                        }
                }
 
@@ -977,7 +980,8 @@ class ApiMain extends ApiBase {
                                )
                        ) {
                                $this->dieUsage(
-                                       "The '{$module->encodeParamName( 'token' )}' parameter was found in the query string, but must be in the POST body",
+                                       "The '{$module->encodeParamName( 'token' )}' parameter was " .
+                                               'found in the query string, but must be in the POST body',
                                        'mustposttoken'
                                );
                        }
@@ -1236,7 +1240,7 @@ class ApiMain extends ApiBase {
                $this->reportUnusedParams();
 
                if ( !$this->mInternalMode ) {
-                       //append Debug information
+                       // append Debug information
                        MWDebug::appendDebugInfoToApiResult( $this->getContext(), $this->getResult() );
 
                        // Print result data
index a0300ab..ba6c144 100644 (file)
@@ -196,7 +196,9 @@ class ApiModuleManager extends ContextSource {
                        $instance = call_user_func( $factory, $this->mParent, $name );
 
                        if ( !$instance instanceof $class ) {
-                               throw new MWException( "The factory function for module $name did not return an instance of $class!" );
+                               throw new MWException(
+                                       "The factory function for module $name did not return an instance of $class!"
+                               );
                        }
                } else {
                        // create instance from class name
index aca4378..60fd426 100644 (file)
@@ -85,7 +85,7 @@ class ApiMove extends ApiBase {
                        'reason' => $params['reason']
                );
 
-               //NOTE: we assume that if the old title exists, it's because it was re-created as
+               // NOTE: we assume that if the old title exists, it's because it was re-created as
                // a redirect to the new title. This is not safe, but what we did before was
                // even worse: we just determined whether a redirect should have been created,
                // and reported that it was created if it should have, without any checks.
index a62bcb6..74ce053 100644 (file)
@@ -55,7 +55,7 @@ class ApiOptions extends ApiBase {
                // Load the user from the master to reduce CAS errors on double post (T95839)
                if ( wfGetLB()->getServerCount() > 1 ) {
                        $user = User::newFromId( $user->getId() );
-                       if ( !$user->loadFromId( User::READ_LATEST ) ) {
+                       if ( !$user->loadFromId( User::READ_EXCLUSIVE ) ) {
                                $this->dieUsage( 'Anonymous users cannot change preferences', 'notloggedin' );
                        }
                }
index 1415b79..ceb0905 100644 (file)
@@ -58,7 +58,8 @@ class ApiPageSet extends ApiBase {
        private $mGoodTitles = array();
        private $mMissingPages = array(); // [ns][dbkey] => fake page_id
        private $mMissingTitles = array();
-       private $mInvalidTitles = array(); // [fake_page_id] => array( 'title' => $title, 'invalidreason' => $reason )
+       /** @var array [fake_page_id] => array( 'title' => $title, 'invalidreason' => $reason ) */
+       private $mInvalidTitles = array();
        private $mMissingPageIDs = array();
        private $mRedirectTitles = array();
        private $mSpecialTitles = array();
index cce8572..fcab9be 100644 (file)
@@ -526,7 +526,7 @@ class ApiParse extends ApiBase {
         * @return Content
         */
        private function getContent( WikiPage $page, $pageId = null ) {
-               $content = $page->getContent( Revision::RAW ); //XXX: really raw?
+               $content = $page->getContent( Revision::RAW ); // XXX: really raw?
 
                if ( $this->section !== false && $content !== null ) {
                        $content = $this->getSectionContent(
index 172ee99..4f7984e 100644 (file)
@@ -54,7 +54,6 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                $params = $this->extractRequestParams( false );
 
                $result = $this->getResult();
-               $pageSet = $this->getPageSet();
 
                // This module operates in two modes:
                // 'user': List deleted revs by a certain user
index 381938b..877423e 100644 (file)
@@ -350,7 +350,8 @@ class ApiQueryAllImages extends ApiQueryGeneratorBase {
                                ApiBase::PARAM_DFLT => 'timestamp|url',
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_HELP_MSG => 'apihelp-query+imageinfo-param-prop',
-                               ApiBase::PARAM_HELP_MSG_PER_VALUE => ApiQueryImageInfo::getPropertyMessages( $this->propertyFilter ),
+                               ApiBase::PARAM_HELP_MSG_PER_VALUE =>
+                                       ApiQueryImageInfo::getPropertyMessages( $this->propertyFilter ),
                        ),
                        'prefix' => null,
                        'minsize' => array(
index e441991..78e3621 100644 (file)
@@ -200,14 +200,14 @@ class ApiQueryAllPages extends ApiQueryGeneratorBase {
                $this->addOption( 'LIMIT', $limit + 1 );
                $res = $this->select( __METHOD__ );
 
-               //Get gender information
+               // Get gender information
                if ( MWNamespace::hasGenderDistinction( $params['namespace'] ) ) {
                        $users = array();
                        foreach ( $res as $row ) {
                                $users[] = $row->page_title;
                        }
                        GenderCache::singleton()->doQuery( $users, __METHOD__ );
-                       $res->rewind(); //reset
+                       $res->rewind(); // reset
                }
 
                $count = 0;
index a50d58b..f1a2271 100644 (file)
@@ -143,8 +143,12 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                }
                $miser_ns = null;
                if ( $params['namespace'] !== null ) {
-                       if ( empty( $settings['from_namespace'] ) && $this->getConfig()->get( 'MiserMode' ) ) {
-                               $miser_ns = $params['namespace'];
+                       if ( empty( $settings['from_namespace'] ) ) {
+                               if ( $this->getConfig()->get( 'MiserMode' ) ) {
+                                       $miser_ns = $params['namespace'];
+                               } else {
+                                       $this->addWhereFld( 'page_namespace', $params['namespace'] );
+                               }
                        } else {
                                $this->addWhereFld( "{$p}_from_namespace", $params['namespace'] );
                                if ( !empty( $settings['from_namespace'] ) && count( $params['namespace'] ) > 1 ) {
index c66e21b..c4592c8 100644 (file)
@@ -421,7 +421,14 @@ abstract class ApiQueryBase extends ApiBase {
                $this->addFields( 'ipb_deleted' );
 
                if ( $showBlockInfo ) {
-                       $this->addFields( array( 'ipb_id', 'ipb_by', 'ipb_by_text', 'ipb_reason', 'ipb_expiry', 'ipb_timestamp' ) );
+                       $this->addFields( array(
+                               'ipb_id',
+                               'ipb_by',
+                               'ipb_by_text',
+                               'ipb_reason',
+                               'ipb_expiry',
+                               'ipb_timestamp'
+                       ) );
                }
 
                // Don't show hidden names
index bf48b19..fa1dfc2 100644 (file)
@@ -46,7 +46,6 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
                        );
                }
 
-               $result = $this->getResult();
                $pageSet = $this->getPageSet();
                $pageMap = $pageSet->getGoodAndMissingTitlesByNamespace();
                $pageCount = count( $pageSet->getGoodAndMissingTitles() );
index 3282c71..1038a9f 100644 (file)
@@ -107,7 +107,7 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
                // iterate over $images to handle continue param correct
                foreach ( $images as $image => $pageId ) {
                        if ( !isset( $sha1s[$image] ) ) {
-                               continue; //file does not exist
+                               continue; // file does not exist
                        }
                        $sha1 = $sha1s[$image];
                        $dupFiles = $filesBySha1s[$sha1];
@@ -118,14 +118,14 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
                        foreach ( $dupFiles as $dupFile ) {
                                $dupName = $dupFile->getName();
                                if ( $image == $dupName && $dupFile->isLocal() ) {
-                                       continue; //ignore the local file itself
+                                       continue; // ignore the local file itself
                                }
                                if ( $skipUntilThisDup !== false && $dupName < $skipUntilThisDup ) {
-                                       continue; //skip to pos after the image from continue param
+                                       continue; // skip to pos after the image from continue param
                                }
                                $skipUntilThisDup = false;
                                if ( ++$count > $params['limit'] ) {
-                                       $fit = false; //break outer loop
+                                       $fit = false; // break outer loop
                                        // We're one over limit which shows that
                                        // there are additional images to be had. Stop here...
                                        $this->setContinueEnumParameter( 'continue', $image . '|' . $dupName );
index ba36c67..736ac45 100644 (file)
@@ -339,7 +339,8 @@ class ApiQueryImageInfo extends ApiQueryBase {
                // in the actual normalised version, only if we can actually normalise them,
                // so we use the functions scope to throw away the normalisations.
                if ( !$h->normaliseParams( $image, $finalParams ) ) {
-                       $this->dieUsage( "Could not normalise image parameters for " . $image->getName(), "urlparamnormal" );
+                       $this->dieUsage( 'Could not normalise image parameters for ' .
+                               $image->getName(), 'urlparamnormal' );
                }
        }
 
@@ -480,7 +481,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
                }
 
                if ( !$canShowField( File::DELETED_FILE ) ) {
-                       //Early return, tidier than indenting all following things one level
+                       // Early return, tidier than indenting all following things one level
                        return $vals;
                }
 
index 25e534e..899a382 100644 (file)
@@ -75,7 +75,7 @@ class ApiQueryLangLinks extends ApiQueryBase {
                        );
                }
 
-               //FIXME: (follow-up) To allow extensions to add to the language links, we need
+               // FIXME: (follow-up) To allow extensions to add to the language links, we need
                //       to load them all, add the extra links, then apply paging.
                //       Should not be terrible, it's not going to be more than a few hundred links.
 
index d87ad1e..38be99a 100644 (file)
@@ -365,7 +365,10 @@ class ApiQueryLogEvents extends ApiQueryBase {
         */
        private function getAllowedLogActions() {
                $config = $this->getConfig();
-               return array_keys( array_merge( $config->get( 'LogActions' ), $config->get( 'LogActionsHandlers' ) ) );
+               return array_keys( array_merge(
+                       $config->get( 'LogActions' ),
+                       $config->get( 'LogActionsHandlers' )
+               ) );
        }
 
        public function getCacheMode( $params ) {
index 8e7031c..e553d12 100644 (file)
@@ -152,7 +152,8 @@ class ApiQueryRandom extends ApiQueryGeneratorBase {
                        $end = null;
                }
 
-               list( $left, $continue ) = $this->runQuery( $resultPageSet, $params['limit'], $start, $startId, $end );
+               list( $left, $continue ) =
+                       $this->runQuery( $resultPageSet, $params['limit'], $start, $startId, $end );
                if ( $end === null && $continue === null ) {
                        // Wrap around. We do this even if $left === 0 for continuation
                        // (saving a DB query in this rare case probably isn't worth the
index d57dc3c..f8dbf23 100644 (file)
@@ -307,7 +307,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        $text = null;
 
                        if ( $this->expandTemplates && !$this->parseContent ) {
-                               #XXX: implement template expansion for all content types in ContentHandler?
+                               # XXX: implement template expansion for all content types in ContentHandler?
                                if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
                                        $text = $content->getNativeData();
 
index 251c42b..f916537 100644 (file)
@@ -149,7 +149,9 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        $vals['ratelimits'] = $this->getRateLimits();
                }
 
-               if ( isset( $this->prop['realname'] ) && !in_array( 'realname', $this->getConfig()->get( 'HiddenPrefs' ) ) ) {
+               if ( isset( $this->prop['realname'] ) &&
+                       !in_array( 'realname', $this->getConfig()->get( 'HiddenPrefs' ) )
+               ) {
                        $vals['realname'] = $user->getRealName();
                }
 
index 398337b..b621cb0 100644 (file)
@@ -45,7 +45,8 @@ class ApiUpload extends ApiBase {
                $this->mParams = $this->extractRequestParams();
                $request = $this->getMain()->getRequest();
                // Check if async mode is actually supported (jobs done in cli mode)
-               $this->mParams['async'] = ( $this->mParams['async'] && $this->getConfig()->get( 'EnableAsyncUploads' ) );
+               $this->mParams['async'] = ( $this->mParams['async'] &&
+                       $this->getConfig()->get( 'EnableAsyncUploads' ) );
                // Add the uploaded file to the params array
                $this->mParams['file'] = $request->getFileName( 'file' );
                $this->mParams['chunk'] = $request->getFileName( 'chunk' );
@@ -605,16 +606,29 @@ class ApiUpload extends ApiBase {
 
                switch ( $exceptionType ) {
                        case 'UploadStashFileNotFoundException':
-                               $this->dieUsage( 'Could not find the file in the stash: ' . $e->getMessage(), 'stashedfilenotfound' );
+                               $this->dieUsage(
+                                       'Could not find the file in the stash: ' . $e->getMessage(),
+                                       'stashedfilenotfound'
+                               );
                                break;
                        case 'UploadStashBadPathException':
-                               $this->dieUsage( 'File key of improper format or otherwise invalid: ' . $e->getMessage(), 'stashpathinvalid' );
+                               $this->dieUsage(
+                                       'File key of improper format or otherwise invalid: ' . $e->getMessage(),
+                                       'stashpathinvalid'
+                               );
                                break;
                        case 'UploadStashFileException':
-                               $this->dieUsage( 'Could not store upload in the stash: ' . $e->getMessage(), 'stashfilestorage' );
+                               $this->dieUsage(
+                                       'Could not store upload in the stash: ' . $e->getMessage(),
+                                       'stashfilestorage'
+                               );
                                break;
                        case 'UploadStashZeroLengthFileException':
-                               $this->dieUsage( 'File is of zero length, and could not be stored in the stash: ' . $e->getMessage(), 'stashzerolength' );
+                               $this->dieUsage(
+                                       'File is of zero length, and could not be stored in the stash: ' .
+                                               $e->getMessage(),
+                                       'stashzerolength'
+                               );
                                break;
                        case 'UploadStashNotLoggedInException':
                                $this->dieUsage( 'Not logged in: ' . $e->getMessage(), 'stashnotloggedin' );
index 8737f7f..da328a6 100644 (file)
        "apihelp-parse-paramvalue-prop-externallinks": "Gibt die externen Links im geparsten Wikitext zurück.",
        "apihelp-parse-paramvalue-prop-revid": "Ergänzt die Versionskennung der geparsten Seite.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Ergänzt den Titel des geparsten Wikitextes.",
-       "apihelp-parse-param-section": "Gibt nur den Inhalt dieses Abschnittes zurück oder erstellt einen neuen Abschnitt, wenn <kbd>new</kbd> angegeben wird.\n\n<kbd>new</kbd> wird nur ausgewertet, wenn auch <var>text</var> angegeben wurde.",
+       "apihelp-parse-param-section": "Parst nur den Inhalt dieser Abschnittsnummer.\n\nFalls <kbd>new</kbd>, parst <var>$1text</var> und <var>$1sectiontitle</var>, als ob ein neuer Abschnitt der Seite hinzugefügt wird.\n\n<kbd>new</kbd> ist nur erlaubt mit der Angabe <var>text</var>.",
        "apihelp-parse-param-sectiontitle": "Überschrift des neuen Abschnittes, wenn <var>section</var> = <kbd>new</kbd> ist.\n\nAnders als beim Bearbeiten der Seite wird der Parameter nicht durch die <var>summary</var> ersetzt, wenn er weggelassen oder leer ist.",
        "apihelp-parse-param-disableeditsection": "Lässt Abschnittsbearbeitungslinks in der Parserausgabe weg.",
        "apihelp-parse-param-preview": "Im Vorschaumodus parsen.",
index 78f0568..009cc7b 100644 (file)
        "apihelp-parse-param-pst": "Do a pre-save transform on the input before parsing it. Only valid when used with text.",
        "apihelp-parse-param-onlypst": "Do a pre-save transform (PST) on the input, but don't parse it. Returns the same wikitext, after a PST has been applied. Only valid when used with <var>$1text</var>.",
        "apihelp-parse-param-effectivelanglinks": "Includes language links supplied by extensions (for use with <kbd>$1prop=langlinks</kbd>).",
-       "apihelp-parse-param-section": "Only retrieve the content of this section number or when <kbd>new</kbd> generate a new section.\n\n<kbd>new</kbd> section is only honored when specifying <var>text</var>.",
+       "apihelp-parse-param-section": "Only parse the content of this section number.\n\nWhen <kbd>new</kbd>, parse <var>$1text</var> and <var>$1sectiontitle</var> as if adding a new section to the page.\n\n<kbd>new</kbd> is allowed only when specifying <var>text</var>.",
        "apihelp-parse-param-sectiontitle": "New section title when <var>section</var> is <kbd>new</kbd>.\n\nUnlike page editing, this does not fall back to <var>summary</var> when omitted or empty.",
        "apihelp-parse-param-disablelimitreport": "Omit the limit report (\"NewPP limit report\") from the parser output.",
        "apihelp-parse-param-disablepp": "Use <var>$1disablelimitreport</var> instead.",
        "apihelp-query+alldeletedrevisions-param-namespace": "Only list pages in this namespace.",
        "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>Note:</strong> Due to [[mw:Manual:$wgMiserMode|miser mode]], using <var>$1user</var> and <var>$1namespace</var> together may result in fewer than <var>$1limit</var> results returned before continuing; in extreme cases, zero results may be returned.",
        "apihelp-query+alldeletedrevisions-param-generatetitles": "When being used as a generator, generate titles rather than revision IDs.",
-       "apihelp-query+alldeletedrevisions-example-user": "List the last 50 deleted contributions by user <kbd>Example<kbd>.",
+       "apihelp-query+alldeletedrevisions-example-user": "List the last 50 deleted contributions by user <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "List the first 50 deleted revisions in the main namespace.",
 
        "apihelp-query+allfileusages-description": "List all file usages, including non-existing.",
        "apihelp-query+backlinks-param-filterredir": "How to filter for redirects. If set to <kbd>nonredirects</kbd> when <var>$1redirect</var> is enabled, this is only applied to the second level.",
        "apihelp-query+backlinks-param-limit": "How many total pages to return. If <var>$1redirect</var> is enabled, the limit applies to each level separately (which means up to 2 * <var>$1limit</var> results may be returned).",
        "apihelp-query+backlinks-param-redirect": "If linking page is a redirect, find all pages that link to that redirect as well. Maximum limit is halved.",
-       "apihelp-query+backlinks-example-simple": "Show links to <kbd>Main page<kbd>.",
-       "apihelp-query+backlinks-example-generator": "Get information about pages linking to <kbd>Main page<kbd>.",
+       "apihelp-query+backlinks-example-simple": "Show links to <kbd>Main page</kbd>.",
+       "apihelp-query+backlinks-example-generator": "Get information about pages linking to <kbd>Main page</kbd>.",
 
        "apihelp-query+blocks-description": "List all blocked users and IP addresses.",
        "apihelp-query+blocks-param-start": "The timestamp to start enumerating from.",
        "apihelp-query+extlinks-param-protocol": "Protocol of the URL. If empty and <var>$1query</var> is set, the protocol is <kbd>http</kbd>. Leave both this and <var>$1query</var> empty to list all external links.",
        "apihelp-query+extlinks-param-query": "Search string without protocol. Useful for checking whether a certain page contains a certain external url.",
        "apihelp-query+extlinks-param-expandurl": "Expand protocol-relative URLs with the canonical protocol.",
-       "apihelp-query+extlinks-example-simple": "Get a list of external links on <kbd>Main Page<kbd>.",
+       "apihelp-query+extlinks-example-simple": "Get a list of external links on <kbd>Main Page</kbd>.",
 
        "apihelp-query+exturlusage-description": "Enumerate pages that contain a given URL.",
        "apihelp-query+exturlusage-param-prop": "Which pieces of information to include:",
index a9c04d0..1163680 100644 (file)
        "apihelp-stashedit-param-section": "Número de la sección. <kbd>0</kbd> para una sección superior, <kbd>new</kbd> para una sección nueva.",
        "apihelp-stashedit-param-sectiontitle": "El título de una sección nueva.",
        "apihelp-stashedit-param-text": "Contenido de la página.",
+       "apihelp-stashedit-param-contentmodel": "Modelo del contenido nuevo.",
        "apihelp-stashedit-param-contentformat": "Formato de serialización de contenido utilizado para el texto de entrada.",
        "apihelp-stashedit-param-baserevid": "Identificador de la revisión de base.",
        "apihelp-tag-param-logid": "Uno o más identificadores de entradas del registro a los que agregar o eliminar la etiqueta.",
index 8d4bd0c..c26705e 100644 (file)
        "apihelp-parse-param-pst": "Faire une transformation avant enregistrement de l’entrée avant de l’analyser. Valide uniquement quand utilisé avec du texte.",
        "apihelp-parse-param-onlypst": "Faire une transformation avant enregistrement (PST) de l’entrée, mais ne pas l’analyser. Renvoie le même wikitexte, après que la PST a été appliquée. Valide uniquement quand utilisé avec <var>$1text</var>.",
        "apihelp-parse-param-effectivelanglinks": "Inclut les liens de langue fournis par les extensions (à utiliser avec <kbd>$1prop=langlinks</kbd>).",
-       "apihelp-parse-param-section": "Récupérer uniquement le contenu de ce numéro de section ou quand <kbd>nouveau</kbd> génère une nouvelle section.\n\nLa <kbd>nouvelle</kbd> section est mise à l’honneur uniquement quand <var>text</var> est spécifié.",
+       "apihelp-parse-param-section": "Traiter uniquement le contenu de la section ayant ce numéro.\n\nQuand la valeur est <kbd>new</kbd>, traite <var>$1text</var> et <var>$1sectiontitle</var> comme s’ils correspondaient à une nouvelle section de la page.\n\nLa valeur <kbd>new</kbd> n’est autorisée que si <var>text</var> est défini.",
        "apihelp-parse-param-sectiontitle": "Nouveau titre de section quand <var>section</var> vaut <kbd>nouveau</kbd>.\n\nÀ la différence de la modification de page, cela ne revient pas à <var>summary</var> quand il est omis ou vide.",
        "apihelp-parse-param-disablelimitreport": "Omettre le rapport de limite (« rapport de limite du nouveau PP ») de la sortie de l’analyseur.",
        "apihelp-parse-param-disablepp": "Utiliser <var>$1disablelimitreport</var> à la place.",
        "apihelp-query+backlinks-param-filterredir": "Comment filtrer les redirections. Si positionné à <kbd>nonredirects</kbd> quand <var>$1redirect</var> est activé, cela ne s’applique qu’au second niveau.",
        "apihelp-query+backlinks-param-limit": "Combien de pages renvoyer au total. Si $1redirect est activé, la limite s’applique à chaque niveau séparément (ce qui signifie jusqu’à 2 * limite résultats peut être retourné).",
        "apihelp-query+backlinks-param-redirect": "Si le lien vers une page est une redirection, trouver toutes les pages qui ont un lien vers cette redirection aussi. La limite maximale est divisée par deux.",
-       "apihelp-query+backlinks-example-simple": "Afficher les liens vers <kbd>Main page<kbd>.",
-       "apihelp-query+backlinks-example-generator": "Obtenir des informations sur les pages ayant un lien vers <kbd>Main page<kbd>.",
+       "apihelp-query+backlinks-example-simple": "Afficher les liens vers <kbd>Main page</kbd>.",
+       "apihelp-query+backlinks-example-generator": "Obtenir des informations sur les pages ayant un lien vers <kbd>Main page</kbd>.",
        "apihelp-query+blocks-description": "Lister tous les utilisateurs et les adresses IP bloqués.",
        "apihelp-query+blocks-param-start": "L’horodatage auquel démarrer l’énumération.",
        "apihelp-query+blocks-param-end": "L’horodatage auquel arrêter l’énumération.",
        "apihelp-query+extlinks-param-protocol": "Protocole de l’URL. Si vide et <var>$1query</var> est positionné, le protocole est <kbd>http</kbd>. Laisser à la fois ceci et <var>$1query</var> vide pour lister tous les liens externes.",
        "apihelp-query+extlinks-param-query": "Rechercher une chaîne sans protocole. Utile pour vérifier si une certaine page contient une certaine URL externe.",
        "apihelp-query+extlinks-param-expandurl": "Étendre les URLs relatives au protocole avec le protocole canonique.",
-       "apihelp-query+extlinks-example-simple": "Obtenir une liste des liens externes de <kbd>Main Page<kbd>.",
+       "apihelp-query+extlinks-example-simple": "Obtenir une liste des liens externes de <kbd>Main Page</kbd>.",
        "apihelp-query+exturlusage-description": "Énumérer les pages contenant une URL donnée.",
        "apihelp-query+exturlusage-param-prop": "Quelles informations inclure :",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "Ajoute l’ID de la page.",
index cb29d8c..23ef669 100644 (file)
        "apihelp-parse-param-pst": "לעשות התמרה לפני שמירה על הקלט לפני פענוחו. תקין רק בשימוש עם טקסט.",
        "apihelp-parse-param-onlypst": "לעשות התמרה לפני שמירה (pre-save transform‏, PST) על הקלט, אבל לא לפענח אותו. מחזיר את אותו קוד הוויקי אחרי החלת PST. תקף רק בשימוש עם <var>$1text</var>.",
        "apihelp-parse-param-effectivelanglinks": "כולל קישור שפה שמספקות הרחבות (לשימוש עם <kbd>$1prop=langlinks</kbd>).",
-       "apihelp-parse-param-section": "×\9c×\90×\97×\96ר ×\90ת ×\94ת×\95×\9b×\9f ×©×\9c ×\94פסק×\94 ×¢×\9d ×\94×\9eספר ×\94×\96×\94, ×\90×\95, ×\90×\9d ×\96×\94 <kbd>new</kbd>, ×\9c×\99צ×\95ר ×¤×¡×§×\94 ×\97×\93ש×\94.\n\n<kbd>new</kbd> ×\99×\9b×\95×\91×\93 ×¨×§ ×\91עת ×¦×\99×\95×\9f <var>text</var>.",
+       "apihelp-parse-param-section": "×\9cפענ×\97 ×¨×§ ×\90ת ×\94ת×\95×\9b×\9f ×©×\9c ×\94פסק×\94 ×©×\96×\94 ×\9eספר×\94.\n\n×\9bשצ×\95×\99×\9f <kbd>new</kbd>, ×\9cפענ×\97 ×\90ת <var>$1text</var> ×\95×\90ת <var>$1sectiontitle</var> ×\9b×\90×\99×\9c×\95 × ×\95ספת ×¤×¡×§×\94 ×\97×\93ש×\94 ×\9c×\93×£.\n\n×\9e×\95תר ×\9c×\94שת×\9eש ×\91Ö¾<kbd>new</kbd> ×¨×§ ×\91עת ×©×\99×\9e×\95ש ×\91Ö¾<var>text</var>.",
        "apihelp-parse-param-sectiontitle": "כותרת פסקה חדשה כאשר <var>section</var> הוא <kbd>new</kbd>.\n\nבניגוד לעריכת דף, זה לא מתגבה ל־<var>summary</var> כשזה מושמט אם ריק.",
        "apihelp-parse-param-disablelimitreport": "להשמיט את דו\"ח הקדם־מעבד (\"NewPP limit report\") מפלט המפענח.",
        "apihelp-parse-param-disablepp": "יש להשתמש ב־<var>$1disablelimitreport</var> במקום.",
        "apihelp-query+alldeletedrevisions-param-namespace": "לרשום רק דפים במרחב השם הזה.",
        "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>לתשומת לבך:</strong> בשל [[mw:Manual:$wgMiserMode|מצב חיסכון]], שימוש ב־<var>$1user</var> וב־<var>$1namespace</var> ביחד עלול להניב החזרה של פחות מ־<var>$1limit</var> תוצאות לפני המשך; במצבים קיצוניים יכולות להיות מוחזרות אפס תוצאות.",
        "apihelp-query+alldeletedrevisions-param-generatetitles": "בעת שימוש בתור מחולל, לחולל כותרת במקום מזהי גרסה.",
-       "apihelp-query+alldeletedrevisions-example-user": "לרשום את 50 התרומות המחוקות האחרונות של משתמש <kbd>Example<kbd>.",
+       "apihelp-query+alldeletedrevisions-example-user": "לרשום את 50 התרומות המחוקות האחרונות של משתמש <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "רשימת 50 הגרסאות המחוקות הראשונות במרחב הראשי.",
        "apihelp-query+allfileusages-description": "לרשום את כל שימושי הקובץ, כולל בלתי־קיימים.",
        "apihelp-query+allfileusages-param-from": "מאיזה שם קובץ להתחיל למנות.",
        "apihelp-query+backlinks-param-limit": "כמה דפים להחזיר בסך הכול. אם <var>$1redirect</var> מופעל, ההגבלה חלה על כל רמה בנפרד (כלומר יכולות להיות מוחזרות עד <span dir=\"ltr\">2 * <var>$1limit</var></span> תוצאות).",
        "apihelp-query+backlinks-param-redirect": "אם הדף המקשר הוא הפניה, למצוא גם את כל הדפים שמקשרים לאותה ההפניה. ההגבלה המרבית מוקטנת בחצי.",
        "apihelp-query+backlinks-example-simple": "הצגת קישורים ל־<kbd>Main Page</kbd>.",
-       "apihelp-query+backlinks-example-generator": "קבל מידע על דפים שמקשרים ל־<kbd>Main page<kbd>.",
+       "apihelp-query+backlinks-example-generator": "קבל מידע על דפים שמקשרים ל־<kbd>Main page</kbd>.",
        "apihelp-query+blocks-description": "לרשום את כל המשתמשים וכתובות ה־IP שנחסמו.",
        "apihelp-query+blocks-param-start": "מאיזה חותם‏־זמן להתחיל למנות.",
        "apihelp-query+blocks-param-end": "באיזה חותם זמן להפסיק למנות.",
        "apihelp-query+extlinks-param-protocol": "הפרוטוקול של ה־URL. אם זה ריק, ו־<var>$1query</var> מוגדר, הפרוטוקול הוא <kbd>http</kbd>. יש להשאיר את זה ואת <var>$1query</var> ריק כדי לרשום את כל הקישורים החיצוניים.",
        "apihelp-query+extlinks-param-query": "מחרוזת חיפוש ללא פרוטוקול. שימושי לבדיקה האם דף מסוים מכיל url חיצוני מסוים.",
        "apihelp-query+extlinks-param-expandurl": "הרחבת URL־ים בעלי פרוטוקול יחסי בפרוטוקול קנוני.",
-       "apihelp-query+extlinks-example-simple": "קבלת רשימת קישורים חיצוניים ב־<kbd>Main Page<kbd>.",
+       "apihelp-query+extlinks-example-simple": "קבלת רשימת קישורים חיצוניים ב־<kbd>Main Page</kbd>.",
        "apihelp-query+exturlusage-description": "למנות דפים שמכילים URL נתון.",
        "apihelp-query+exturlusage-param-prop": "אילו חלקי מידע לכלול:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "הוספת מזהה הדף.",
index 90be9e2..f4c3c56 100644 (file)
        "api-help-parameters": "{{PLURAL:$1|Parametro|Parametri}}:",
        "api-help-param-deprecated": "Deprecato.",
        "api-help-param-required": "Questo parametro è obbligatorio.",
+       "api-help-param-list": "{{PLURAL:$1|1=Uno dei seguenti valori|2=Valori (separati da <kbd>{{!}}</kbd>)}}: $2",
        "api-help-param-multi-max": "Il numero massimo di valori è {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} per i bot).",
        "api-help-param-default": "Predefinito: $1",
        "api-help-param-default-empty": "Predefinito: <span class=\"apihelp-empty\">(vuoto)</span>",
index bb403c6..31bcd96 100644 (file)
        "apihelp-query+backlinks-description": "与えられたページにリンクしているすべてのページを検索します。",
        "apihelp-query+backlinks-param-title": "検索するページ名。<var>$1pageid</var> とは同時に使用できません。",
        "apihelp-query+backlinks-param-pageid": "検索するページID。<var>$1title</var>とは同時に使用できません。",
-       "apihelp-query+backlinks-example-simple": "<kbd>Main page<kbd> へのリンクを表示する。",
-       "apihelp-query+backlinks-example-generator": "<kbd>Main page<kbd> にリンクしているページの情報を取得する。",
+       "apihelp-query+backlinks-example-simple": "<kbd>Main page</kbd> へのリンクを表示する。",
+       "apihelp-query+backlinks-example-generator": "<kbd>Main page</kbd> にリンクしているページの情報を取得する。",
        "apihelp-query+blocks-description": "ブロックされた利用者とIPアドレスを一覧表示します。",
        "apihelp-query+blocks-param-start": "列挙の始点となるタイムスタンプ。",
        "apihelp-query+blocks-param-end": "列挙の終点となるタイムスタンプ。",
        "apihelp-query+extlinks-description": "与えられたページにあるすべての外部URL (インターウィキを除く) を返します。",
        "apihelp-query+extlinks-param-limit": "返すリンクの数。",
        "apihelp-query+extlinks-param-protocol": "URLのプロトコル。このパラメータが空であり、かつ<var>$1query</var> が設定されている場合, protocol は <kbd>http</kbd> となります。すべての外部リンクを一覧表示するためにはこのパラメータと <var>$1query</var> の両方を空にしてください。",
-       "apihelp-query+extlinks-example-simple": "<kbd>Main Page<kbd> の外部リンクの一覧を取得する。",
+       "apihelp-query+extlinks-example-simple": "<kbd>Main Page</kbd> の外部リンクの一覧を取得する。",
        "apihelp-query+exturlusage-description": "与えられたURLを含むページを一覧表示します。",
        "apihelp-query+exturlusage-example-simple": "<kbd>http://www.mediawiki.org</kbd> にリンクしているページを一覧表示する。",
        "apihelp-query+filearchive-example-simple": "削除されたファイルの一覧を表示する。",
        "apihelp-query+querypage-param-limit": "返す結果の数。",
        "apihelp-query+querypage-example-ancientpages": "[[Special:Ancientpages]] の結果を返す。",
        "apihelp-query+random-param-namespace": "この名前空間にあるページのみを返します。",
+       "apihelp-query+random-param-redirect": "代わりに <kbd>$1filterredir=redirects</kbd> を使用してください。",
+       "apihelp-query+random-param-filterredir": "転送ページを絞り込む方法。",
        "apihelp-query+random-example-simple": "標準名前空間から2つのページを無作為に返す。",
        "apihelp-query+random-example-generator": "標準名前空間から無作為に選ばれた2つのページのページ情報を返す。",
        "apihelp-query+recentchanges-description": "最近の更新を一覧表示します。",
        "api-help-parameters": "{{PLURAL:$1|パラメーター}}:",
        "api-help-param-deprecated": "廃止予定です。",
        "api-help-param-required": "このパラメーターは必須です。",
+       "api-help-datatypes-header": "データ型",
        "api-help-param-list": "{{PLURAL:$1|1=値 (次の値のいずれか1つ)|2=値 (<kbd>{{!}}</kbd>で区切る)}}: $2",
        "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=空欄にしてください|空欄にするか、または $2}}",
        "api-help-param-integer-min": "{{PLURAL:$1|値}}は $2 以上にしてください。",
index ab018c9..de64544 100644 (file)
@@ -8,7 +8,8 @@
                        "Ysjbserver",
                        "Alex00728",
                        "Hwangjy9",
-                       "Kurousagi"
+                       "Kurousagi",
+                       "Revi"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|설명문서]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 메일링 리스트]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API 공지 사항] * [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 버그 및 요청] </div>\n<strong>상태:</strong> 이 페이지에 표시된 모든 기능은 정상 작동할 것이지만, API는 여전히 활발하게 개발되고 있으며, 언제든지 바뀔 수 있습니다. 업데이트 정보를 받아보려면 [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce 메일링 리스트]를 구독하십시오.\n\n<strong>잘못된 요청:</strong> API에 잘못된 요청이 전송되면 HTTP 헤더에서 \"MediaWiki-API-Error\" 키를 보내고, 헤더 값과 오류 코드가 같게 설정됩니다. 자세한 정보에 대해서는 [[mw:API:Errors_and_warnings|API:오류 및 경고]]를 참조하십시오.",
@@ -16,7 +17,7 @@
        "apihelp-main-param-format": "출력값의 형식.",
        "apihelp-block-description": "사용자를 차단합니다.",
        "apihelp-block-param-user": "차단하고자 하는 계정 이름, IP 주소 또는 대역",
-       "apihelp-block-param-expiry": "기한. 상대값(예시: \"5 months\" 또는 \"2 weeks\") 또는 절대값(예시: \"2014-09-18T12:34:56Z\")이 될 수 있습니다. \"infinite\", \"indefinite\" 또는 \"never\"로 설정하면 무기한으로 설정됩니다.",
+       "apihelp-block-param-expiry": "기한. 상대값(예시: <kbd>5 months</kbd> 또는 </kbd>2 weeks</kbd>) 또는 절대값(예시: <kbd>2014-09-18T12:34:56Z</kbd>)이 될 수 있습니다. <kbd>infinite</kbd>, <kbd>indefinite</kbd> 또는 <kbd>never</kbd>로 설정하면 무기한으로 설정됩니다.",
        "apihelp-block-param-reason": "차단 이유.",
        "apihelp-block-param-anononly": "익명 사용자만 차단합니다. (즉, 이 IP의 익명 편집을 막음)",
        "apihelp-block-param-nocreate": "계정 생성을 막습니다.",
@@ -28,6 +29,7 @@
        "apihelp-block-param-watchuser": "해당 사용자 또는 IP 주소의 사용자 문서 및 토론 문서를 주시합니다.",
        "apihelp-block-example-ip-simple": "IP <kbd>192.0.2.5</kbd>에 대해 <kbd>First strike</kbd>라는 이유로 3일간 차단하기",
        "apihelp-block-example-user-complex": "사용자 <kbd>Vandal</kbd>을 <kbd>Vandalism</kbd>이라는 이유로 무기한 차단하며 계정 생성 및 이메일 발송을 막기",
+       "apihelp-checktoken-param-token": "테스트할 토큰",
        "apihelp-createaccount-description": "새 사용자 계정을 만듭니다.",
        "apihelp-createaccount-param-name": "사용자 이름",
        "apihelp-createaccount-param-email": "사용자 이메일 주소 (선택).",
@@ -49,6 +51,8 @@
        "apihelp-emailuser-param-target": "이메일을 받을 사용자.",
        "apihelp-expandtemplates-param-title": "문서 제목",
        "apihelp-expandtemplates-param-text": "변환할 위키텍스트.",
+       "apihelp-feedcontributions-param-deletedonly": "삭제된 기여만 봅니다.",
+       "apihelp-feedcontributions-param-toponly": "최신 판인 편집만 봅니다.",
        "apihelp-feedrecentchanges-param-hideminor": "사소한 편집을 숨깁니다.",
        "apihelp-feedrecentchanges-param-hidebots": "봇의 편집을 숨깁니다.",
        "apihelp-feedrecentchanges-param-hideanons": "익명 사용자의 편집을 숨깁니다.",
@@ -75,6 +79,7 @@
        "apihelp-options-param-reset": "사이트 기본으로 설정 초기화",
        "apihelp-options-example-reset": "모든 설정 초기화",
        "apihelp-protect-example-protect": "문서 보호",
+       "apihelp-query+allmessages-example-ipb": "<kbd>ipb-</kbd>로 시작하는 메시지를 보입니다.",
        "apihelp-query+pageswithprop-param-limit": "나타낼 문서의 최대 수입니다.",
        "apihelp-query+pageswithprop-param-dir": "정렬 순서",
        "apihelp-query+prefixsearch-param-search": "문자열 검색",
index 4e0c006..4e653cf 100644 (file)
        "apihelp-parse-paramvalue-prop-iwlinks": "Jitt de Engewikkilengks em jepahßde Wikkitäx uß.",
        "apihelp-parse-paramvalue-prop-wikitext": "Jitt de der ojinahl Wikkitäx us, dä jepahß woode es.",
        "apihelp-parse-paramvalue-prop-properties": "Jitt devärse Eijeschafte uß, di em jepahßde Wikkitäx faßjelaat woode sen.",
-       "apihelp-parse-param-section": "Holl blohß dann der Ennhalld vun däm Affschnett met dä Nommer, udder wann „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd>“ enjejovve es, maach ene neu Affschnett derbei.",
+       "apihelp-parse-param-section": "Donn blohß der Ennhalld vun däm Affschnett met dä Nommer paase.\n\nWann „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd>“ enjejovve es, donn dä Täx <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</var> un de Övverschreff <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sectiontitle</var> paase, wi wänn_enne neuje Affschnett en dä Sigg derbei köhm.\n\nDä Parramehter „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd>“ es blohß zohjelohße, wann och <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">text</var> aanjejovve es.",
        "apihelp-parse-param-sectiontitle": "De Övverschreff för dä neuje Afschnet, wann <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">section</var> = <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd> es.\n\nAnders wi beim Beärbeide vun dä Sigg weed dä Parramehter nit dorsch de <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">summary</var> ußjetuusch, wann hä fottjelohße udder läddesch es.",
        "apihelp-parse-param-disablelimitreport": "Jiff keine Bereesch vum Vüürbereijde zom Paase (der „<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">NewPP limit report</i>“) mem Paaser singe Dahte zosamme uß.",
        "apihelp-parse-param-disableeditsection": "Donn de Lenks för Affschnedde ze änndere en de Ußjahbe vum Paaser eruß lohße.",
index 89bed36..72ffefb 100644 (file)
@@ -67,6 +67,7 @@
        "apihelp-query+allusers-description": "All registréiert Benotzer opzielen.",
        "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Lëscht vun alle Gruppen an deenen de Benotzer automatesch dran ass.",
        "apihelp-query+allusers-param-activeusers": "Nëmme Benotzer opzielen déi an de leschten $1 {{PLURAL:$1|Dag|Deeg}} aktiv waren.",
+       "apihelp-query+backlinks-example-simple": "Linken op d'<kbd>Haaptsäit</kbd> weisen.",
        "apihelp-query+blocks-description": "Lëscht vun de gespaarte Benotzer an IP-Adressen.",
        "apihelp-query+blocks-paramvalue-prop-range": "Setzt de Beräich vun den IP-Adressen derbäi déi vun der Spär betraff sinn.",
        "apihelp-query+blocks-example-simple": "Lëscht vun de Spären",
diff --git a/includes/api/i18n/lt.json b/includes/api/i18n/lt.json
new file mode 100644 (file)
index 0000000..e5edf2a
--- /dev/null
@@ -0,0 +1,10 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Zygimantus"
+               ]
+       },
+       "apihelp-stashedit-param-title": "Puslapio pavadinimas buvo redaguotas.",
+       "apihelp-stashedit-param-sectiontitle": "Naujo skyriaus pavadinimas.",
+       "apihelp-stashedit-param-text": "Puslapio turinys."
+}
index a64e8e2..6d88ca5 100644 (file)
        "apihelp-query+alldeletedrevisions-param-user": "Pokazuj tylko zmiany dokonane przez tego użytkownika.",
        "apihelp-query+alldeletedrevisions-param-excludeuser": "Nie pokazuj zmian dokonanych przez tego użytkownika.",
        "apihelp-query+alldeletedrevisions-param-namespace": "Listuj tylko strony z tej przestrzeni nazw.",
-       "apihelp-query+allfileusages-param-limit": "Łączna ilość obiektów do zwrócenia.",
+       "apihelp-query+allfileusages-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+allfileusages-example-unique": "Lista unikatowych tytułów plików.",
        "apihelp-query+allimages-param-sort": "Sortowanie według właściwości.",
        "apihelp-query+allimages-example-recent": "Pokaż listę ostatnio przesłanych plików, podobnie do [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Pokaż listę plików z typem MIME <kbd>image/png</kbd> lub <kbd>image/gif</kbd>",
        "apihelp-query+alllinks-param-namespace": "Przestrzeń nazw do emulacji.",
-       "apihelp-query+alllinks-param-limit": "Łączna ilość obiektów do zwrócenia.",
+       "apihelp-query+alllinks-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+alllinks-example-unique": "Lista unikatowych tytułów plików.",
        "apihelp-query+allmessages-param-prop": "Właściwości do odczytu.",
        "apihelp-query+allmessages-param-prefix": "Zwróć wiadomości z tym prefixem.",
        "apihelp-query+allpages-param-prtype": "Ogranicz tylko do zabezpieczonych stron.",
-       "apihelp-query+allpages-param-limit": "Ilość stron do zwrócenia.",
+       "apihelp-query+allpages-param-limit": "Liczba stron do zwrócenia.",
        "apihelp-query+allpages-example-B": "Pokaż listę stron rozpoczynających się na literę <kbd>B</kbd>.",
        "apihelp-query+allredirects-description": "Lista wszystkich przekierowań do przestrzeni nazw.",
        "apihelp-query+allredirects-param-namespace": "Przestrzeń nazw do emulacji.",
-       "apihelp-query+allredirects-param-limit": "Łączna ilość obiektów do zwrócenia.",
+       "apihelp-query+allredirects-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+alltransclusions-param-namespace": "Przestrzeń nazw do emulacji.",
        "apihelp-query+allusers-param-witheditsonly": "Tylko użytkownicy, którzy edytowali.",
        "apihelp-query+backlinks-param-namespace": "Przestrzeń nazw do emulacji.",
        "apihelp-query+blocks-param-users": "Lista użytkowników do wyszukania (opcjonalne).",
        "apihelp-query+blocks-param-limit": "Maksymalna liczba blokad do wylistowania.",
        "apihelp-query+blocks-example-simple": "Listuj blokady.",
-       "apihelp-query+categories-param-limit": "Ilość kategorii do zwrócenia.",
+       "apihelp-query+categories-param-limit": "Liczba kategorii do zwrócenia.",
        "apihelp-query+categorymembers-description": "Wszystkie strony w danej kategorii.",
        "apihelp-query+categorymembers-param-limit": "Maksymalna liczba zwracanych wyników.",
        "apihelp-query+categorymembers-param-sort": "Sortowanie według właściwości.",
        "apihelp-query+deletedrevs-param-user": "Listuj tylko zmiany dokonane przez tego użytkownika.",
        "apihelp-query+deletedrevs-param-excludeuser": "Nie listuj zmian dokonanych przez tego użytkownika.",
        "apihelp-query+deletedrevs-param-namespace": "Listuj tylko strony z tej przestrzeni nazw.",
-       "apihelp-query+deletedrevs-param-limit": "Maksymalna ilość zmian do wylistowania.",
+       "apihelp-query+deletedrevs-param-limit": "Maksymalna liczba zmian do wylistowania.",
        "apihelp-query+duplicatefiles-example-generated": "Szukaj duplikatów wszystkich plików.",
        "apihelp-query+embeddedin-param-filterredir": "Jaki filtrować przekierowania.",
-       "apihelp-query+extlinks-param-limit": "Ilość linków do zwrócenia.",
-       "apihelp-query+exturlusage-param-limit": "Ilość stron do zwrócenia.",
+       "apihelp-query+extlinks-param-limit": "Liczba linków do zwrócenia.",
+       "apihelp-query+exturlusage-param-limit": "Liczba stron do zwrócenia.",
        "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias rozmiaru.",
        "apihelp-query+filearchive-example-simple": "Pokaż listę wszystkich usuniętych plików.",
        "apihelp-query+filerepoinfo-example-simple": "Uzyskaj informacje na temat repozytoriów plików.",
        "apihelp-query+imageinfo-paramvalue-prop-sha1": "Dodaj sumę kontrolną SHA-1 dla tego pliku.",
        "apihelp-query+imageinfo-paramvalue-prop-mime": "Dodaje typ MIME pliku.",
        "apihelp-query+imageinfo-param-urlheight": "Podobne do $1urlwidth.",
-       "apihelp-query+images-param-limit": "Ilość plików do zwrócenia.",
+       "apihelp-query+images-param-limit": "Liczba plików do zwrócenia.",
        "apihelp-query+info-description": "Pokaż podstawowe informacje o stronie.",
        "apihelp-query+info-paramvalue-prop-watchers": "Liczba obserwujących, jeśli jest to dozwolone.",
        "apihelp-query+info-paramvalue-prop-readable": "Czy użytkownik może przeczytać tę stronę.",
        "apihelp-query+iwbacklinks-param-prefix": "Prefix interwiki.",
-       "apihelp-query+iwbacklinks-param-limit": "Łączna ilość stron do zwrócenia.",
+       "apihelp-query+iwbacklinks-param-limit": "Łączna liczba stron do zwrócenia.",
        "apihelp-query+iwlinks-paramvalue-prop-url": "Dodaje pełny adres URL.",
-       "apihelp-query+links-param-limit": "Ilość linków do zwrócenia.",
+       "apihelp-query+links-param-limit": "Liczba linków do zwrócenia.",
        "apihelp-query+linkshere-paramvalue-prop-title": "Nazwa każdej strony.",
-       "apihelp-query+linkshere-param-limit": "Ilość do zwrócenia.",
+       "apihelp-query+linkshere-param-limit": "Liczba do zwrócenia.",
        "apihelp-query+logevents-description": "Pobierz eventy z logu.",
        "apihelp-query+logevents-example-simple": "Lista ostatnich zarejestrowanych zdarzeń.",
        "apihelp-query+pageswithprop-example-generator": "Pobierz dodatkowe informacje o pierwszych 10 stronach wykorzystując <code>_&#95;NOTOC_&#95;</code>.",
index 9c1c623..3d81d21 100644 (file)
@@ -3,7 +3,8 @@
                "authors": [
                        "Fasouzafreitas",
                        "Dianakc",
-                       "Cainamarques"
+                       "Cainamarques",
+                       "Rhcastilhos"
                ]
        },
        "apihelp-main-param-action": "Qual ação executar.",
@@ -48,6 +49,7 @@
        "apihelp-edit-param-sectiontitle": "O título para uma nova seção.",
        "apihelp-edit-param-text": "Conteúdo da página",
        "apihelp-edit-param-minor": "Edição menor.",
+       "apihelp-edit-param-notminor": "Edição não-menor.",
        "apihelp-edit-param-bot": "Marcar esta edição como feita por bot.",
        "apihelp-edit-param-createonly": "Não editar a página se já existir.",
        "apihelp-edit-param-nocreate": "Mostra um erro se a página não existir.",
        "apihelp-emailuser-param-subject": "Cabeçalho do assunto.",
        "apihelp-emailuser-param-text": "Corpo do email.",
        "apihelp-emailuser-param-ccme": "Envie uma cópia deste email para mim.",
+       "apihelp-emailuser-example-email": "Enviar um e-mail ao usuário <kbd>WikiSysop</kbd> com o texto <kbd>Content</kbd>.",
        "apihelp-expandtemplates-description": "Expande todas a predefinições em wikitexto.",
        "apihelp-expandtemplates-param-title": "Título da página.",
        "apihelp-expandtemplates-param-text": "Wikitexto para converter.",
+       "apihelp-expandtemplates-paramvalue-prop-wikitext": "O wikitexto expandido.",
        "apihelp-feedcontributions-description": "Retorna o feed de contribuições de um usuário.",
        "apihelp-feedcontributions-param-feedformat": "O formato do feed.",
        "apihelp-feedcontributions-param-namespace": "A partir de qual espaço nominal filtrar contribuições.",
        "apihelp-move-param-noredirect": "Não cria um redirecionamento.",
        "apihelp-move-param-watch": "Adiciona a página e o redirecionamento para a lista de vigiados do usuário atual.",
        "apihelp-move-param-unwatch": "Remove a página e o redirecionamento para a lista de vigiados do usuário atual.",
+       "apihelp-move-param-ignorewarnings": "Ignorar quaisquer avisos.",
+       "apihelp-opensearch-param-search": "Pesquisar string.",
        "apihelp-opensearch-param-limit": "O número máximo a se retornar.",
        "apihelp-opensearch-param-namespace": "Espaço nominal para pesquisar.",
+       "apihelp-opensearch-param-format": "O formato da saída.",
        "apihelp-opensearch-example-te": "Encontra páginas começando com <kbd>Te</kbd>.",
        "apihelp-options-param-reset": "Redefinir preferências para os padrões do site.",
        "apihelp-options-example-reset": "Resetar todas as preferências",
        "apihelp-protect-example-unprotect2": "Desprotege uma página ao não definir restrições.",
        "apihelp-purge-param-forcelinkupdate": "Atualiza as tabelas de links.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Atualiza a tabela de links, e atualiza as tabelas de links para qualquer página que usa essa página como um modelo.",
+       "apihelp-query-param-prop": "Quais propriedades obter para as páginas consultadas.",
        "apihelp-query-param-list": "Quais listas obter.",
        "apihelp-query-param-meta": "Quais metadados obter.",
        "apihelp-query+allcategories-description": "Enumera todas as categorias.",
        "apihelp-query+allcategories-param-min": "Retorna apenas as categorias com pelo menos esta quantidade de membros.",
        "apihelp-query+allcategories-param-max": "Retorna apenas as categorias com no máximo esta quantidade de membros.",
        "apihelp-query+allcategories-param-limit": "Quantas categorias retornar.",
+       "apihelp-query+allcategories-param-prop": "Que propriedades obter:",
        "apihelp-query+allcategories-example-size": "Lista categorias com a informação sobre o número de páginas em cada uma.",
        "apihelp-query+alldeletedrevisions-description": "Lista todas as revisões excluídas por um usuário ou em um espaço nominal.",
        "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Só pode ser usada com <var>$3user</var>.",
        "apihelp-query+allfileusages-description": "Lista todas as utilizações de arquivo, incluindo os não-existentes.",
        "apihelp-query+allfileusages-param-from": "O título do arquivo a partir do qual começar a enumerar.",
        "apihelp-query+allfileusages-param-to": "O título do arquivo onde parar de enumerar.",
+       "apihelp-query+allfileusages-paramvalue-prop-title": "Adiciona o título do arquivo.",
        "apihelp-query+allfileusages-param-limit": "Quantos itens retornar.",
        "apihelp-query+allimages-param-user": "Retorna apenas os arquivos enviados por este usuário. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1filterbots.",
        "apihelp-query+allimages-param-filterbots": "Como filtrar arquivos enviados por bots. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1user.",
index b919c44..95e776a 100644 (file)
        "apihelp-opensearch-param-limit": "Número máximo de resultados a apresentar.",
        "apihelp-options-param-reset": "Reiniciar preferências para os padrões do sítio.",
        "apihelp-options-example-reset": "Reiniciar todas as preferências",
+       "apihelp-parse-param-section": "Apenas analisar o conteúdo desta secção.\n\nQuando <kbd>nova</kbd>, analise <var>$1text</var> e <var>$1sectiontitle</var> como se fosse adicionar uma nova secção da página.\n\n<kbd>novo</kbd> só é permitido quando especifica <var>text</var>.",
        "apihelp-patrol-description": "Patrulhar uma página ou edição.",
        "apihelp-patrol-example-rcid": "Patrulhar uma mudança recente",
        "apihelp-patrol-example-revid": "Patrulhar uma edição",
        "apihelp-protect-example-protect": "Proteger uma página",
        "apihelp-query+allcategories-description": "Enumerar todas as categorias.",
+       "apihelp-query+alldeletedrevisions-example-user": "Lista das últimas 50 contribuições eliminadas pelo usuário <kbd>Exemplo</kbd>.",
        "apihelp-query+allpages-param-prefix": "Pesquisa para todos os títulos de páginas que comecem com este valor.",
        "apihelp-query+allpages-example-generator": "Mostrar informação sobre 4 páginas que comecem com a letra <kbd>T</kbd>.",
        "apihelp-query+allusers-example-Y": "Lista de utilizadores que comecem com <kbd>Y</kbd>.",
+       "apihelp-query+backlinks-example-simple": "Mostrar links para <kbd>Página Principal</kbd>.",
+       "apihelp-query+backlinks-example-generator": "Obtenha informações sobre as páginas de ligação para <kbd>Página Principal</kbd>.",
        "apihelp-query+blocks-param-limit": "O número máximo de bloqueios a listar.",
        "apihelp-query+categorymembers-description": "Lista de todas as páginas numa categoria fornecida.",
        "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Modo|Modos}}: $2",
        "apihelp-query+deletedrevs-param-excludeuser": "Não listar edições deste utilizador.",
        "apihelp-query+deletedrevs-param-namespace": "Listar apenas as páginas neste domínio.",
+       "apihelp-query+extlinks-example-simple": "Obtenha uma lista de links externos na <kbd>Página Principal</kbd>.",
        "apihelp-query+filearchive-example-simple": "Mostrar lista de todos os ficheiros eliminados",
        "apihelp-query+info-description": "Obter informação básica da página.",
        "apihelp-query+recentchanges-example-simple": "Lista de mudanças recentes",
index 56b3f5b..416a6f0 100644 (file)
@@ -9,7 +9,8 @@
                        "Дмитрий",
                        "WindEwriX",
                        "Ochilov",
-                       "Nzeemin"
+                       "Nzeemin",
+                       "INS Pirat"
                ]
        },
        "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 с ключом \"MediaWiki-API-Error\", после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:API:Errors_and_warnings|API: Ошибки и предупреждения]].",
@@ -27,6 +28,9 @@
        "apihelp-block-param-reason": "Причина блокировки.",
        "apihelp-block-param-anononly": "Блокировать только анонимных пользователей (т. е. запретить анонимные правки для этого IP-адреса).",
        "apihelp-block-param-nocreate": "Запретить создание учётных записей.",
+       "apihelp-block-param-autoblock": "Автоматически блокировать последний использованный IP-адрес и все последующие, с которых будут совершаться попытки авторизации.",
+       "apihelp-block-param-hidename": "Скрыть имя участника из журнала блокировок. (Требуется право <code>hideuser</code>).",
+       "apihelp-block-param-reblock": "Если участник уже заблокирован, перезаписать существующую блокировку.",
        "apihelp-block-param-watchuser": "Следить за страницей пользователя или IP-участника и страницей обсуждения.",
        "apihelp-checktoken-param-type": "Тип маркера проходит тестирование.",
        "apihelp-checktoken-param-token": "токен для проверки",
        "apihelp-expandtemplates-paramvalue-prop-parsetree": "Дерево разбора XML входных данных.",
        "apihelp-feedcontributions-param-year": "От года (и ранее).",
        "apihelp-feedcontributions-param-month": "От месяца (и ранее).",
+       "apihelp-feedcontributions-param-deletedonly": "Показать только удалённые правки.",
+       "apihelp-feedcontributions-param-toponly": "Показать только правки, являющиеся последними версиями.",
        "apihelp-feedcontributions-param-newonly": "Показывать только правки, являющиеся созданием страниц.",
        "apihelp-feedcontributions-param-showsizediff": "Показать размер различия между версиями.",
+       "apihelp-feedcontributions-example-simple": "Показать вклад участника <kbd>Example</kbd>.",
+       "apihelp-feedrecentchanges-param-invert": "Все пространства имён, кроме выбранного.",
        "apihelp-feedrecentchanges-param-limit": "Максимальное число возвращаемых результатов.",
        "apihelp-feedrecentchanges-param-from": "Показать изменения с тех пор.",
        "apihelp-feedrecentchanges-param-hideminor": "Скрыть малые правки.",
        "apihelp-feedrecentchanges-param-hidebots": "Скрыть правки ботов.",
        "apihelp-feedrecentchanges-param-hideanons": "Скрыть изменения, внесённые анонимными участниками.",
+       "apihelp-feedrecentchanges-param-hideliu": "Скрыть правки зарегистрированных участников.",
        "apihelp-feedrecentchanges-param-hidepatrolled": "Скрыть отпатруллированные правки.",
        "apihelp-feedrecentchanges-param-hidemyself": "Скрыть изменения, сделанные текущим участником.",
        "apihelp-feedrecentchanges-param-tagfilter": "Фильтр по тегам.",
+       "apihelp-feedrecentchanges-param-target": "Показать только правки на страницах, на которые ссылается данная.",
+       "apihelp-feedrecentchanges-param-showlinkedto": "Показать правки на страницах, ссылающихся на данную.",
        "apihelp-feedrecentchanges-example-simple": "Список последних изменений.",
        "apihelp-feedrecentchanges-example-30days": "Показать последние изменения в течение 30 дней.",
+       "apihelp-feedwatchlist-param-linktosections": "Ссылаться прямо на разделы с изменениями, если возможно.",
+       "apihelp-filerevert-param-filename": "Целевое имя файла без префикса File:.",
        "apihelp-filerevert-param-comment": "Загрузить комментарий.",
        "apihelp-help-example-main": "Помощь по главному модулю.",
        "apihelp-help-example-recursive": "Вся справка в одном разделе.",
        "apihelp-imagerotate-example-generator": "Повернуть все изображения в <kbd>Category:Flip</kbd> на <kbd>180</kbd> градусов.",
        "apihelp-import-param-summary": "Импорт итога",
        "apihelp-import-param-xml": "Загруженный XML-файл.",
+       "apihelp-import-example-import": "Импортировать [[meta:Help:ParserFunctions]] с полной историей в пространство имён 100.",
        "apihelp-login-param-name": "Имя участника.",
        "apihelp-login-param-password": "Пароль.",
        "apihelp-login-param-domain": "Домен (необязательно).",
        "apihelp-opensearch-param-search": "Строка поиска.",
        "apihelp-opensearch-param-limit": "Максимальное число возвращаемых результатов.",
        "apihelp-opensearch-param-namespace": "Пространства имён для поиска.",
+       "apihelp-opensearch-param-format": "Формат вывода.",
        "apihelp-options-example-reset": "Сбросить все настройки.",
+       "apihelp-paraminfo-description": "Получить информацию о модулях API.",
        "apihelp-paraminfo-param-helpformat": "Формат строк справки.",
+       "apihelp-parse-param-disabletoc": "Не включать в вывод таблицу содержания.",
        "apihelp-parse-example-page": "анализ страницы",
        "apihelp-parse-example-text": "Анализ wikitext.",
+       "apihelp-protect-description": "Изменить уровень защиты страницы.",
        "apihelp-protect-example-protect": "Защитить страницу.",
        "apihelp-purge-param-forcelinkupdate": "Обновление связей таблиц.",
        "apihelp-query-param-list": "Какие списки использовать",
        "apihelp-query+transcludedin-param-limit": "Сколько возвращать",
        "apihelp-query+usercontribs-description": "Получить все правки пользователя",
        "apihelp-revisiondelete-description": "удалить и восстановить редакции",
+       "apihelp-stashedit-param-sectiontitle": "Заголовок нового раздела.",
        "apihelp-unblock-description": "Разблокировать пользователя.",
        "apihelp-unblock-param-reason": "Причина разблокировки",
        "apihelp-unblock-example-id": "Разблокировать блок с идентификатором #<kbd>105</kbd>.",
        "api-help-license-unknown": "Лицензия: <span class=\"apihelp-unknown\">unknown</span>",
        "api-help-parameters": "Параметр{{PLURAL:$1||ы}}:",
        "api-help-param-deprecated": "Устаревший.",
-       "api-help-param-required": "Этот параметр является обязательным.",
+       "api-help-param-required": "Это обязательный параметр.",
        "api-help-datatypes-header": "Типы данных",
        "api-help-param-type-limit": "Тип: целое число или <kbd>max</kbd>",
        "api-help-param-type-integer": "Тип: {{PLURAL:$1|1=integer|2=list of integers}}",
index ed3d9e1..5f4d0ab 100644 (file)
@@ -7,6 +7,7 @@
        },
        "apihelp-block-param-reason": "Arsyeja për bllokim.",
        "apihelp-move-param-reason": "Arsyeja për riemërtim.",
+       "apihelp-query+siteinfo-paramvalue-prop-statistics": "Kthehet në faqen e statistikave.",
        "apihelp-tag-param-reason": "Arsyeja për ndërrimin.",
        "apihelp-unblock-description": "Zhblloko një përdorues.",
        "apihelp-userrights-description": "Ndërro anëtarësinë e grupit të një përdoruesit."
index 2a5f805..e890540 100644 (file)
@@ -86,7 +86,7 @@
        "apihelp-edit-param-title": "您希望编辑的页面标题。不能与<var>$1pageid</var>一起使用。",
        "apihelp-edit-param-pageid": "要编辑的页面的页面 ID。不能与<var>$1title</var>一起使用。",
        "apihelp-edit-param-section": "段落数。<kbd>0</kbd>用于首段,<kbd>new</kbd>用于新的段落。",
-       "apihelp-edit-param-sectiontitle": "新小节的标题。",
+       "apihelp-edit-param-sectiontitle": "新段落的标题。",
        "apihelp-edit-param-text": "页面内容。",
        "apihelp-edit-param-summary": "编辑摘要。当$1section=new且未设置$1sectiontitle时,还包括小节标题。",
        "apihelp-edit-param-tags": "更改标签以应用修订。",
        "apihelp-parse-paramvalue-prop-parsetree": "修订内容的XML解析树(需要内容模型<code>$1</code>)",
        "apihelp-parse-param-pst": "在解析输入前,对输入做一次保存前变换处理。仅当使用文本时有效。",
        "apihelp-parse-param-effectivelanglinks": "包含由扩展提供的语言链接(用于与<kbd>$1prop=langlinks</kbd>一起使用)。",
-       "apihelp-parse-param-section": "只检索此段数的内容,或只当<kbd>new</kbd>生成新的段落时检索。\n\n<kbd>new</kbd>段落只当指定<var>text</var>时受尊重。",
+       "apihelp-parse-param-section": "只解析此段数的内容。\n\n当<kbd>new</kbd>时,将<var>$1text</var>和<var>$1sectiontitle</var>解析为添加新段落至页面。\n\n<kbd>new</kbd>段落只当指定<var>text</var>时允许。",
        "apihelp-parse-param-sectiontitle": "当<var>section</var>为<kbd>new</kbd>时新段落标题。\n\n不像页面编辑,当省略或为空时将不会备选为<var>summary</var>。",
        "apihelp-parse-param-disablelimitreport": "从解析器输出中省略限制报告(“NewPP limit report”)。",
        "apihelp-parse-param-disablepp": "请改用<var>$1disablelimitreport</var>。",
        "apihelp-parse-param-disabletidy": "不要在解析器输出中运行HTML清理(例如tidy)。",
        "apihelp-parse-param-generatexml": "生成XML解析树(需要内容模型<code>$1</code>;被<kbd>$2prop=parsetree</kbd>所取代)。",
        "apihelp-parse-param-preview": "在预览模式下解析。",
-       "apihelp-parse-param-sectionpreview": "在小节预览模式下解析 (同时要启用预览模式)。",
+       "apihelp-parse-param-sectionpreview": "在段落预览模式下解析(同时要启用预览模式)。",
        "apihelp-parse-param-disabletoc": "在输出中省略目录。",
        "apihelp-parse-param-contentformat": "用于输入文本的内容序列化格式。只当与$1text一起使用时有效。",
        "apihelp-parse-example-page": "解析一个页面。",
        "apihelp-query+alldeletedrevisions-param-namespace": "只列出此名字空间的页面。",
        "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>注意:</strong>由于[[mw:Manual:$wgMiserMode|miser模式]],同时使用<var>$1user</var>和<var>$1namespace</var>将导致继续前返回少于<var>$1limit</var>个结果,在极端条件下可能不返回任何结果。",
        "apihelp-query+alldeletedrevisions-param-generatetitles": "当作为生成器使用时,生成标题而不是修订ID。",
-       "apihelp-query+alldeletedrevisions-example-user": "列出由<kbd>Example<kbd>作出的最近50次已删除贡献。",
+       "apihelp-query+alldeletedrevisions-example-user": "列出由<kbd>Example</kbd>作出的最近50次已删除贡献。",
        "apihelp-query+alldeletedrevisions-example-ns-main": "列出前50次已删除的主名字空间修订。",
        "apihelp-query+allfileusages-description": "列出所有文件用途,包括不存在的。",
        "apihelp-query+allfileusages-param-from": "要列举的起始文件标题。",
        "apihelp-query+allmessages-description": "返回来自该网站的消息。",
        "apihelp-query+allmessages-param-messages": "要输出的消息。<kbd>*</kbd>(默认)表示所有消息。",
        "apihelp-query+allmessages-param-prop": "要获取的属性。",
+       "apihelp-query+allmessages-param-nocontent": "如果设置,不要在输出中包含消息内容。",
        "apihelp-query+allmessages-param-args": "要替代进消息的参数。",
        "apihelp-query+allmessages-param-filter": "只返回名称包含此字符串的消息。",
        "apihelp-query+allmessages-param-customised": "只返回在此定制情形下的消息。",
        "apihelp-query+backlinks-param-filterredir": "如何过滤重定向。当<var>$1redirect</var>被启用时如果设置为<kbd>nonredirects</kbd>,这只会应用到第二级。",
        "apihelp-query+backlinks-param-limit": "返回总计页面数。如果<var>$1redirect</var>被启用,则限定分别适用于每一等级(这意味着将返回多达2 * <var>$1limit</var>个结果)。",
        "apihelp-query+backlinks-param-redirect": "如果链入页面是一个重定向,则寻找所有链接至此重定向的页面。最大限制减半。",
-       "apihelp-query+backlinks-example-simple": "显示至<kbd>Main page<kbd>的链接。",
-       "apihelp-query+backlinks-example-generator": "获取关于链接至<kbd>Main page<kbd>的页面的信息。",
+       "apihelp-query+backlinks-example-simple": "显示至<kbd>Main page</kbd>的链接。",
+       "apihelp-query+backlinks-example-generator": "获取关于链接至<kbd>Main page</kbd>的页面的信息。",
        "apihelp-query+blocks-description": "列出所有被封禁的用户和IP地址。",
        "apihelp-query+blocks-param-start": "枚举的起始时间戳。",
        "apihelp-query+blocks-param-end": "枚举的结束时间戳。",
        "apihelp-query+categorymembers-param-prop": "要包含的信息束:",
        "apihelp-query+categorymembers-paramvalue-prop-ids": "添加页面ID。",
        "apihelp-query+categorymembers-paramvalue-prop-title": "添加页面标题和名字空间ID。",
-       "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Adds the sortkey used for sorting in the category (hexadecimal string).",
-       "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Adds the sortkey prefix used for sorting in the category (human-readable part of the sortkey).",
-       "apihelp-query+categorymembers-paramvalue-prop-type": "Adds the type that the page has been categorised as (page, subcat or file).",
-       "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Adds the timestamp of when the page was included.",
+       "apihelp-query+categorymembers-paramvalue-prop-sortkey": "添加用于分类中排序的关键字(十六进制字符串)。",
+       "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "添加用于分类中排序的关键字前缀(关键字的人类可读部分)。",
+       "apihelp-query+categorymembers-paramvalue-prop-type": "添加页面被分类的类型(页面、子分类或文件)。",
+       "apihelp-query+categorymembers-paramvalue-prop-timestamp": "添加页面被包括时的时间戳。",
        "apihelp-query+categorymembers-param-namespace": "仅包含这些名字空间的页面。注意<kbd>$1type=subcat</kbd>或<kbd>$1type=file</kbd>可能被使用,而不是<kbd>$1namespace=14</kbd>或<kbd>6</kbd>。",
        "apihelp-query+categorymembers-param-type": "包含的分类成员类型。当<kbd>$1sort=timestamp</kbd>被设置时会忽略。",
        "apihelp-query+categorymembers-param-limit": "返回页面的最大数量。",
        "apihelp-query+categorymembers-param-start": "开始列举的时间戳。只能与<kbd>$1sort=timestamp</kbd>一起使用。",
        "apihelp-query+categorymembers-param-end": "列举的结尾时间戳。只能与<kbd>$1sort=timestamp</kbd>一起使用。",
        "apihelp-query+categorymembers-param-starthexsortkey": "开始列举的关键词,由<kbd>$1prop=sortkey</kbd>返回。不能与<kbd>$1sort=sortkey</kbd>一起使用。",
-       "apihelp-query+categorymembers-param-endhexsortkey": "结束列举的关键词,由<kbd>$1prop=sortkey</kbd>返回。不能与<kbd>$1sort=sortkey</kbd>一起使用。",
+       "apihelp-query+categorymembers-param-endhexsortkey": "结束列举的关键字,由<kbd>$1prop=sortkey</kbd>返回。只能与<kbd>$1sort=sortkey</kbd>一起使用。",
        "apihelp-query+categorymembers-param-startsortkeyprefix": "要开始列举的排序关键词前缀。只能与<kbd>$1sort=sortkey</kbd>一起使用。覆盖<var>$1starthexsortkey</var>。",
+       "apihelp-query+categorymembers-param-endsortkeyprefix": "要结束列举<strong>before</strong>的关键字前缀(而不是<strong>at</strong>;如果此值出现,它将不被包括!)只能与$1sort=sortkey一起使用。覆盖$1endhexsortkey。",
        "apihelp-query+categorymembers-param-startsortkey": "请改用$1starthexsortkey。",
        "apihelp-query+categorymembers-param-endsortkey": "请改用$1endhexsortkey。",
        "apihelp-query+categorymembers-example-simple": "获取<kbd>Category:Physics</kbd>中的前10个页面。",
        "apihelp-query+extlinks-param-protocol": "URL协议。如果为空并且<var>$1query</var>被设置,协议为<kbd>http</kbd>。将此和<var>$1query</var>都留空以列举所有外部链接。",
        "apihelp-query+extlinks-param-query": "不使用协议搜索字符串。对于检查某一页面是否包含某一外部URL很有用。",
        "apihelp-query+extlinks-param-expandurl": "扩展协议相对URL与规范协议。",
-       "apihelp-query+extlinks-example-simple": "获取<kbd>Main Page<kbd>的外部链接列表。",
+       "apihelp-query+extlinks-example-simple": "获取<kbd>Main Page</kbd>的外部链接列表。",
        "apihelp-query+exturlusage-description": "列举包含一个指定URL的页面。",
        "apihelp-query+exturlusage-param-prop": "要包含的信息束:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "添加页面ID。",
        "apihelp-setnotificationtimestamp-example-pagetimestamp": "设置<kbd>Main page</kbd>的通知时间戳,这样所有从2012年1月1日起的编辑都会是未复核的。",
        "apihelp-setnotificationtimestamp-example-allpages": "重置在<kbd>{{ns:user}}</kbd>名字空间中的页面的通知状态。",
        "apihelp-stashedit-param-title": "已开始编辑的页面标题。",
+       "apihelp-stashedit-param-section": "段落数。<kbd>0</kbd>用于首段,<kbd>new</kbd>用于新的段落。",
+       "apihelp-stashedit-param-sectiontitle": "新段落的标题。",
        "apihelp-stashedit-param-text": "页面内容。",
        "apihelp-stashedit-param-contentmodel": "新内容的内容模型。",
        "apihelp-tag-description": "从个别修订或日志记录中添加或移除更改标签。",
index 56c9256..3db84a6 100644 (file)
  * @ingroup Cache
  */
 class LinkCache {
-       // Increment $mClassVer whenever old serialized versions of this class
-       // becomes incompatible with the new version.
-       private $mClassVer = 5;
-
        /**
         * @var MapCacheLRU
         */
index 276e84a..f5b2350 100644 (file)
@@ -23,6 +23,7 @@
 use Cdb\Exception as CdbException;
 use Cdb\Reader as CdbReader;
 use Cdb\Writer as CdbWriter;
+use CLDRPluralRuleParser\Evaluator;
 
 /**
  * Class for caching the contents of localisation files, Messages*.php
@@ -576,7 +577,7 @@ class LocalisationCache {
                        return null;
                }
                try {
-                       $compiledRules = CLDRPluralRuleEvaluator::compile( $rules );
+                       $compiledRules = Evaluator::compile( $rules );
                } catch ( CLDRPluralRuleError $e ) {
                        wfDebugLog( 'l10n', $e->getMessage() );
 
index f22c860..ef70589 100644 (file)
@@ -394,21 +394,19 @@ class MessageCache {
                $saveSuccess = $this->saveToCaches( $cache, 'all', $code );
 
                if ( !$saveSuccess ) {
-                       # Cache save has failed.
-                       # There are two main scenarios where this could be a problem:
-                       #
-                       #   - The cache is more than the maximum size (typically
-                       #     1MB compressed).
-                       #
-                       #   - Memcached has no space remaining in the relevant slab
-                       #     class. This is unlikely with recent versions of
-                       #     memcached.
-                       #
-                       # Either way, if there is a local cache, nothing bad will
-                       # happen. If there is no local cache, disabling the message
-                       # cache for all requests avoids incurring a loadFromDB()
-                       # overhead on every request, and thus saves the wiki from
-                       # complete downtime under moderate traffic conditions.
+                       /**
+                        * Cache save has failed.
+                        *
+                        * There are two main scenarios where this could be a problem:
+                        * - The cache is more than the maximum size (typically 1MB compressed).
+                        * - Memcached has no space remaining in the relevant slab class. This is
+                        *   unlikely with recent versions of memcached.
+                        *
+                        * Either way, if there is a local cache, nothing bad will happen. If there
+                        * is no local cache, disabling the message cache for all requests avoids
+                        * incurring a loadFromDB() overhead on every request, and thus saves the
+                        * wiki from complete downtime under moderate traffic conditions.
+                        */
                        if ( !$wgUseLocalMessageCache ) {
                                $this->mMemc->set( $statusKey, 'error', 60 * 5 );
                                $where[] = 'could not save cache, disabled globally for 5 minutes';
index d912e3a..1dcb7ae 100644 (file)
@@ -283,6 +283,10 @@ class EnhancedChangesList extends ChangesList {
                // Further down are some assumptions that $block is a 0-indexed array
                // with (count-1) as last key. Let's make sure it is.
                $block = array_values( $block );
+               if ( empty( $block ) ) {
+                       // if we can't show anything, don't display this block altogether
+                       return '';
+               }
 
                $r .= $this->getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden );
 
@@ -453,6 +457,10 @@ class EnhancedChangesList extends ChangesList {
         * @return string
         */
        protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden ) {
+               if ( empty( $block ) ) {
+                       return '';
+               }
+
                # Changes message
                static $nchanges = array();
                static $sinceLastVisitMsg = array();
index 87871f4..5c884a5 100644 (file)
@@ -293,7 +293,7 @@ class RecentChange {
                $this->mAttribs['rc_timestamp'] = $dbw->timestamp( $this->mAttribs['rc_timestamp'] );
                $this->mAttribs['rc_id'] = $dbw->nextSequenceValue( 'recentchanges_rc_id_seq' );
 
-               ## If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL
+               # # If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL
                if ( $dbw->cascadingDeletes() && $this->mAttribs['rc_cur_id'] == 0 ) {
                        unset( $this->mAttribs['rc_cur_id'] );
                }
@@ -688,7 +688,7 @@ class RecentChange {
                $type, $action, $target, $logComment, $params, $newId = 0, $actionCommentIRC = '' ) {
                global $wgRequest;
 
-               ## Get pageStatus for email notification
+               # # Get pageStatus for email notification
                switch ( $type . '-' . $action ) {
                        case 'delete-delete':
                                $pageStatus = 'deleted';
index ec0573e..8a88fab 100644 (file)
@@ -442,7 +442,9 @@ class RedisConnRef {
         * @param Redis $conn
         * @param LoggerInterface $logger
         */
-       public function __construct( RedisConnectionPool $pool, $server, Redis $conn, LoggerInterface $logger ) {
+       public function __construct(
+               RedisConnectionPool $pool, $server, Redis $conn, LoggerInterface $logger
+       ) {
                $this->pool = $pool;
                $this->server = $server;
                $this->conn = $conn;
index b8e44c7..38ce855 100644 (file)
@@ -143,7 +143,7 @@ define( 'UTF8_MAX', "\xf4\x8f\xbf\xbf" /*codepointToUtf8( UNICODE_MAX )*/ );
  * @deprecated since 1.25, use UtfNormal\Constants instead
  */
 define( 'UTF8_REPLACEMENT', "\xef\xbf\xbd" /*codepointToUtf8( UNICODE_REPLACEMENT )*/ );
-#define( 'UTF8_REPLACEMENT', '!' );
+# define( 'UTF8_REPLACEMENT', '!' );
 
 /**
  * @deprecated since 1.25, use UtfNormal\Constants instead
index 6542d7d..c98b0ec 100644 (file)
@@ -446,7 +446,7 @@ abstract class AbstractContent implements Content {
         */
        public function convert( $toModel, $lossy = '' ) {
                if ( $this->getModel() === $toModel ) {
-                       //nothing to do, shorten out.
+                       // nothing to do, shorten out.
                        return $this;
                }
 
index bf91a4f..76f2a7b 100644 (file)
@@ -630,7 +630,7 @@ abstract class ContentHandler {
         * @return DifferenceEngine
         */
        public function createDifferenceEngine( IContextSource $context, $old = 0, $new = 0,
-               $rcid = 0, //FIXME: Deprecated, no longer used
+               $rcid = 0, // FIXME: Deprecated, no longer used
                $refreshCache = false, $unhide = false ) {
 
                // hook: get difference engine
index 5b84657..e3f9375 100644 (file)
@@ -83,7 +83,7 @@ class MessageContent extends AbstractContent {
         * @return Message The message object.
         */
        public function getNativeData() {
-               //NOTE: Message objects are mutable. Cloning here makes MessageContent immutable.
+               // NOTE: Message objects are mutable. Cloning here makes MessageContent immutable.
                return clone $this->mMessage;
        }
 
index 93adde1..42a2aee 100644 (file)
@@ -159,7 +159,10 @@ class RequestContext implements IContextSource, MutableContext {
                if ( $this->title === null ) {
                        global $wgTitle; # fallback to $wg till we can improve this
                        $this->title = $wgTitle;
-                       wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.' );
+                       wfDebugLog(
+                               'GlobalTitleFail',
+                               __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.'
+                       );
                }
 
                return $this->title;
index 9eb3e2f..bc703f3 100644 (file)
@@ -98,7 +98,7 @@ class CloneDatabase {
                                }
                                $this->db->dropTable( $tbl, __METHOD__ );
                                wfDebug( __METHOD__ . " dropping {$newTableName}\n" );
-                               //Dropping the oldTable because the prefix was changed
+                               // Dropping the oldTable because the prefix was changed
                        }
 
                        # Create new table
index b4f3f79..ffada49 100644 (file)
@@ -449,10 +449,6 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
-       public function resultObject( $result ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
-       }
-
        public function ping() {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
index 1e54f55..d442e4b 100644 (file)
@@ -1347,9 +1347,9 @@ abstract class DatabaseBase implements IDatabase {
                $preLimitTail .= $this->makeOrderBy( $options );
 
                // if (isset($options['LIMIT'])) {
-               //      $tailOpts .= $this->limitResult('', $options['LIMIT'],
-               //              isset($options['OFFSET']) ? $options['OFFSET']
-               //              : false);
+               //      $tailOpts .= $this->limitResult('', $options['LIMIT'],
+               //              isset($options['OFFSET']) ? $options['OFFSET']
+               //              : false);
                // }
 
                if ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
@@ -2437,7 +2437,7 @@ abstract class DatabaseBase implements IDatabase {
                if ( !$alias || (string)$alias === (string)$name ) {
                        return $name;
                } else {
-                       return $name . ' AS ' . $alias; //PostgreSQL needs AS
+                       return $name . ' AS ' . $alias; // PostgreSQL needs AS
                }
        }
 
@@ -3766,14 +3766,13 @@ abstract class DatabaseBase implements IDatabase {
         * Once upon a time, DatabaseBase::query() returned a bare MySQL result
         * resource, and it was necessary to call this function to convert it to
         * a wrapper. Nowadays, raw database objects are never exposed to external
-        * callers, so this is unnecessary in external code. For compatibility with
-        * old code, ResultWrapper objects are passed through unaltered.
+        * callers, so this is unnecessary in external code.
         *
-        * @param bool|ResultWrapper|resource $result
+        * @param bool|ResultWrapper|resource|object $result
         * @return bool|ResultWrapper
         */
-       public function resultObject( $result ) {
-               if ( empty( $result ) ) {
+       protected function resultObject( $result ) {
+               if ( !$result ) {
                        return false;
                } elseif ( $result instanceof ResultWrapper ) {
                        return $result;
index 85f1b96..354afc5 100644 (file)
@@ -145,8 +145,8 @@ class DatabaseMssql extends DatabaseBase {
         * @param bool|MssqlResultWrapper|resource $result
         * @return bool|MssqlResultWrapper
         */
-       public function resultObject( $result ) {
-               if ( empty( $result ) ) {
+       protected function resultObject( $result ) {
+               if ( !$result ) {
                        return false;
                } elseif ( $result instanceof MssqlResultWrapper ) {
                        return $result;
index be34242..5be96fa 100644 (file)
@@ -138,7 +138,7 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
 
                if ( $set ) {
                        // Use doQuery() to avoid opening implicit transactions (DBO_TRX)
-                       $success = $this->doQuery( 'SET ' . implode( ', ', $set ), __METHOD__ );
+                       $success = $this->doQuery( 'SET ' . implode( ', ', $set ) );
                        if ( !$success ) {
                                wfLogDBError(
                                        'Error setting MySQL variables on server {db_server} (check $wgSQLMode)',
@@ -302,7 +302,7 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
                // We are not checking for any errors here, since
                // these are no errors mysql_num_rows can cause.
                // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
-               // See https://bugzilla.wikimedia.org/42430
+               // See https://phabricator.wikimedia.org/T44430
                return $n;
        }
 
@@ -940,7 +940,8 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
                                $value = $this->mDefaultBigSelects;
                        }
                } elseif ( $this->mDefaultBigSelects === null ) {
-                       $this->mDefaultBigSelects = (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
+                       $this->mDefaultBigSelects =
+                               (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
                }
                $encValue = $value ? '1' : '0';
                $this->query( "SET sql_big_selects=$encValue", __METHOD__ );
index 87c3164..ad38c1d 100644 (file)
@@ -335,7 +335,7 @@ class DatabaseOracle extends DatabaseBase {
                MediaWiki\restoreWarnings();
 
                if ( $this->mUser != $this->mDBname ) {
-                       //change current schema in session
+                       // change current schema in session
                        $this->selectDB( $this->mDBname );
                }
 
@@ -982,7 +982,7 @@ class DatabaseOracle extends DatabaseBase {
         * @return string Version information from the database
         */
        function getServerVersion() {
-               //better version number, fallback on driver
+               // better version number, fallback on driver
                $rset = $this->doQuery(
                        'SELECT version FROM product_component_version ' .
                                'WHERE UPPER(product) LIKE \'ORACLE DATABASE%\''
index 56a5b2c..aaa1c6e 100644 (file)
@@ -1581,11 +1581,11 @@ SQL;
 
                $preLimitTail .= $this->makeOrderBy( $options );
 
-               //if ( isset( $options['LIMIT'] ) ) {
-               //      $tailOpts .= $this->limitResult( '', $options['LIMIT'],
-               //              isset( $options['OFFSET'] ) ? $options['OFFSET']
-               //              : false );
-               //}
+               // if ( isset( $options['LIMIT'] ) ) {
+               //      $tailOpts .= $this->limitResult( '', $options['LIMIT'],
+               //              isset( $options['OFFSET'] ) ? $options['OFFSET']
+               //              : false );
+               // }
 
                if ( isset( $options['FOR UPDATE'] ) ) {
                        $postLimitTail .= ' FOR UPDATE OF ' .
index 656547b..e909597 100644 (file)
@@ -799,15 +799,21 @@ class DatabaseSqlite extends DatabaseBase {
                        return (int)$s;
                } elseif ( strpos( $s, "\0" ) !== false ) {
                        // SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
-                       // This is a known limitation of SQLite's mprintf function which PDO should work around,
-                       // but doesn't. I have reported this to php.net as bug #63419:
+                       // This is a known limitation of SQLite's mprintf function which PDO
+                       // should work around, but doesn't. I have reported this to php.net as bug #63419:
                        // https://bugs.php.net/bug.php?id=63419
                        // There was already a similar report for SQLite3::escapeString, bug #62361:
                        // https://bugs.php.net/bug.php?id=62361
                        // There is an additional bug regarding sorting this data after insert
                        // on older versions of sqlite shipped with ubuntu 12.04
-                       // https://bugzilla.wikimedia.org/show_bug.cgi?id=72367
-                       wfDebugLog( __CLASS__, __FUNCTION__ . ': Quoting value containing null byte. For consistency all binary data should have been first processed with self::encodeBlob()' );
+                       // https://phabricator.wikimedia.org/T74367
+                       wfDebugLog(
+                               __CLASS__,
+                               __FUNCTION__ .
+                                       ': Quoting value containing null byte. ' .
+                                       'For consistency all binary data should have been ' .
+                                       'first processed with self::encodeBlob()'
+                       );
                        return "x'" . bin2hex( $s ) . "'";
                } else {
                        return $this->mConn->quote( $s );
@@ -985,7 +991,7 @@ class DatabaseSqlite extends DatabaseBase {
                        $indexInfo = $this->query( 'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')' );
                        $fields = array();
                        foreach ( $indexInfo as $indexInfoRow ) {
-                               $fields[ $indexInfoRow->seqno ] = $indexInfoRow->name;
+                               $fields[$indexInfoRow->seqno] = $indexInfoRow->name;
                        }
 
                        $sql .= '(' . implode( ',', $fields ) . ')';
index 49d0514..cb0b25f 100644 (file)
@@ -29,7 +29,7 @@
  * Basic database interface for live and lazy-loaded DB handles
  *
  * @todo: loosen up DB classes from MWException
- * @note: DatabaseBase and DBConnRef should be updated to reflect any changes
+ * @note: IDatabase and DBConnRef should be updated to reflect any changes
  * @ingroup Database
  */
 interface IDatabase {
@@ -137,7 +137,7 @@ interface IDatabase {
        public function implicitOrderby();
 
        /**
-        * Return the last query that went through DatabaseBase::query()
+        * Return the last query that went through IDatabase::query()
         * @return string
         */
        public function lastQuery();
@@ -259,7 +259,7 @@ interface IDatabase {
         * member variables.
         * If no more rows are available, false is returned.
         *
-        * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
+        * @param ResultWrapper|stdClass $res Object as returned from IDatabase::query(), etc.
         * @return stdClass|bool
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
@@ -270,7 +270,7 @@ interface IDatabase {
         * form. Fields are retrieved with $row['fieldname'].
         * If no more rows are available, false is returned.
         *
-        * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
+        * @param ResultWrapper $res Result object as returned from IDatabase::query(), etc.
         * @return array|bool
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
@@ -448,12 +448,12 @@ interface IDatabase {
         *
         * If no result rows are returned from the query, false is returned.
         *
-        * @param string|array $table Table name. See DatabaseBase::select() for details.
+        * @param string|array $table Table name. See IDatabase::select() for details.
         * @param string $var The field name to select. This must be a valid SQL
         *   fragment: do not use unvalidated user input.
-        * @param string|array $cond The condition array. See DatabaseBase::select() for details.
+        * @param string|array $cond The condition array. See IDatabase::select() for details.
         * @param string $fname The function name of the caller.
-        * @param string|array $options The query options. See DatabaseBase::select() for details.
+        * @param string|array $options The query options. See IDatabase::select() for details.
         *
         * @return bool|mixed The value from the field, or false on failure.
         */
@@ -469,12 +469,12 @@ interface IDatabase {
         *
         * If no result rows are returned from the query, false is returned.
         *
-        * @param string|array $table Table name. See DatabaseBase::select() for details.
+        * @param string|array $table Table name. See IDatabase::select() for details.
         * @param string $var The field name to select. This must be a valid SQL
         *   fragment: do not use unvalidated user input.
-        * @param string|array $cond The condition array. See DatabaseBase::select() for details.
+        * @param string|array $cond The condition array. See IDatabase::select() for details.
         * @param string $fname The function name of the caller.
-        * @param string|array $options The query options. See DatabaseBase::select() for details.
+        * @param string|array $options The query options. See IDatabase::select() for details.
         *
         * @return bool|array The values from the field, or false on failure
         * @since 1.25
@@ -506,7 +506,7 @@ interface IDatabase {
         * for use in field names (e.g. a.user_name).
         *
         * All of the table names given here are automatically run through
-        * DatabaseBase::tableName(), which causes the table prefix (if any) to be
+        * IDatabase::tableName(), which causes the table prefix (if any) to be
         * added, and various other table name mappings to be performed.
         *
         *
@@ -546,8 +546,8 @@ interface IDatabase {
         * Note that expressions are often DBMS-dependent in their syntax.
         * DBMS-independent wrappers are provided for constructing several types of
         * expression commonly used in condition queries. See:
-        *    - DatabaseBase::buildLike()
-        *    - DatabaseBase::conditional()
+        *    - IDatabase::buildLike()
+        *    - IDatabase::conditional()
         *
         *
         * @param string|array $options
@@ -630,7 +630,7 @@ interface IDatabase {
        );
 
        /**
-        * The equivalent of DatabaseBase::select() except that the constructed SQL
+        * The equivalent of IDatabase::select() except that the constructed SQL
         * is returned, instead of being immediately executed. This can be useful for
         * doing UNION queries, where the SQL text of each query is needed. In general,
         * however, callers outside of Database classes should just use select().
@@ -643,7 +643,7 @@ interface IDatabase {
         * @param string|array $join_conds Join conditions
         *
         * @return string SQL query string.
-        * @see DatabaseBase::select()
+        * @see IDatabase::select()
         */
        public function selectSQLText(
                $table, $vars, $conds = '', $fname = __METHOD__,
@@ -651,7 +651,7 @@ interface IDatabase {
        );
 
        /**
-        * Single row SELECT wrapper. Equivalent to DatabaseBase::select(), except
+        * Single row SELECT wrapper. Equivalent to IDatabase::select(), except
         * that a single row object is returned. If the query returns no rows,
         * false is returned.
         *
@@ -679,7 +679,7 @@ interface IDatabase {
         * For DBMSs that don't support fast result size estimation, this function
         * will actually perform the SELECT COUNT(*).
         *
-        * Takes the same arguments as DatabaseBase::select().
+        * Takes the same arguments as IDatabase::select().
         *
         * @param string $table Table name
         * @param string $vars Unused
@@ -697,7 +697,7 @@ interface IDatabase {
         *
         * This is useful when trying to do COUNT(*) but with a LIMIT for performance.
         *
-        * Takes the same arguments as DatabaseBase::select().
+        * Takes the same arguments as IDatabase::select().
         *
         * @param string $table Table name
         * @param string $vars Unused
@@ -770,15 +770,15 @@ interface IDatabase {
         *
         * $options is an array of options, with boolean options encoded as values
         * with numeric keys, in the same style as $options in
-        * DatabaseBase::select(). Supported options are:
+        * IDatabase::select(). Supported options are:
         *
         *   - IGNORE: Boolean: if present, duplicate key errors are ignored, and
         *     any rows which cause duplicate key errors are not inserted. It's
         *     possible to determine how many rows were successfully inserted using
-        *     DatabaseBase::affectedRows().
+        *     IDatabase::affectedRows().
         *
         * @param string $table Table name. This will be passed through
-        *   DatabaseBase::tableName().
+        *   IDatabase::tableName().
         * @param array $a Array of rows to insert
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
         * @param array $options Array of options
@@ -791,12 +791,12 @@ interface IDatabase {
         * UPDATE wrapper. Takes a condition array and a SET array.
         *
         * @param string $table Name of the table to UPDATE. This will be passed through
-        *   DatabaseBase::tableName().
+        *   IDatabase::tableName().
         * @param array $values An array of values to SET. For each array element,
         *   the key gives the field name, and the value gives the data to set
-        *   that field to. The data will be quoted by DatabaseBase::addQuotes().
+        *   that field to. The data will be quoted by IDatabase::addQuotes().
         * @param array $conds An array of conditions (WHERE). See
-        *   DatabaseBase::select() for the details of the format of condition
+        *   IDatabase::select() for the details of the format of condition
         *   arrays. Use '*' to update all rows.
         * @param string $fname The function name of the caller (from __METHOD__),
         *   for logging and profiling.
@@ -814,7 +814,7 @@ interface IDatabase {
         * @param int $mode Constant
         *    - LIST_COMMA: Comma separated, no field names
         *    - LIST_AND:   ANDed WHERE clause (without the WHERE). See the
-        *      documentation for $conds in DatabaseBase::select().
+        *      documentation for $conds in IDatabase::select().
         *    - LIST_OR:    ORed WHERE clause (without the WHERE)
         *    - LIST_SET:   Comma separated with field names, like a SET clause
         *    - LIST_NAMES: Comma separated field names
@@ -975,7 +975,7 @@ interface IDatabase {
         * @param array $uniqueIndexes Is an array of indexes. Each element may be either
         *    a field name or an array of field names
         * @param array $rows Can be either a single row to insert, or multiple rows,
-        *    in the same format as for DatabaseBase::insert()
+        *    in the same format as for IDatabase::insert()
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
         */
        public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ );
@@ -1004,12 +1004,12 @@ interface IDatabase {
         *
         * @since 1.22
         *
-        * @param string $table Table name. This will be passed through DatabaseBase::tableName().
+        * @param string $table Table name. This will be passed through IDatabase::tableName().
         * @param array $rows A single row or list of rows to insert
         * @param array $uniqueIndexes List of single field names or field name tuples
         * @param array $set An array of values to SET. For each array element, the
         *   key gives the field name, and the value gives the data to set that
-        *   field to. The data will be quoted by DatabaseBase::addQuotes().
+        *   field to. The data will be quoted by IDatabase::addQuotes().
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
         * @throws Exception
         * @return bool
@@ -1046,7 +1046,7 @@ interface IDatabase {
         * DELETE query wrapper.
         *
         * @param array $table Table name
-        * @param string|array $conds Array of conditions. See $conds in DatabaseBase::select()
+        * @param string|array $conds Array of conditions. See $conds in IDatabase::select()
         *   for the format. Use $conds == "*" to delete all rows
         * @param string $fname Name of the calling function
         * @throws DBUnexpectedError
@@ -1065,18 +1065,18 @@ interface IDatabase {
         * @param array $varMap Must be an associative array of the form
         *    array( 'dest1' => 'source1', ...). Source items may be literals
         *    rather than field names, but strings should be quoted with
-        *    DatabaseBase::addQuotes()
+        *    IDatabase::addQuotes()
         *
-        * @param array $conds Condition array. See $conds in DatabaseBase::select() for
+        * @param array $conds Condition array. See $conds in IDatabase::select() for
         *    the details of the format of condition arrays. May be "*" to copy the
         *    whole table.
         *
         * @param string $fname The function name of the caller, from __METHOD__
         *
         * @param array $insertOptions Options for the INSERT part of the query, see
-        *    DatabaseBase::insert() for details.
+        *    IDatabase::insert() for details.
         * @param array $selectOptions Options for the SELECT part of the query, see
-        *    DatabaseBase::select() for details.
+        *    IDatabase::select() for details.
         *
         * @return ResultWrapper
         */
@@ -1236,7 +1236,7 @@ interface IDatabase {
         * Atomic sections are more strict than transactions. With transactions,
         * attempting to begin a new transaction when one is already running results
         * in MediaWiki issuing a brief warning and doing an implicit commit. All
-        * atomic levels *must* be explicitly closed using DatabaseBase::endAtomic(),
+        * atomic levels *must* be explicitly closed using IDatabase::endAtomic(),
         * and any database transactions cannot be began or committed until all atomic
         * levels are closed. There is no such thing as implicitly opening or closing
         * an atomic section.
@@ -1254,7 +1254,7 @@ interface IDatabase {
         * if necessary.
         *
         * @since 1.23
-        * @see DatabaseBase::startAtomic
+        * @see IDatabase::startAtomic
         * @param string $fname
         * @throws DBError
         */
@@ -1347,22 +1347,6 @@ interface IDatabase {
         */
        public function timestampOrNull( $ts = null );
 
-       /**
-        * Take the result from a query, and wrap it in a ResultWrapper if
-        * necessary. Boolean values are passed through as is, to indicate success
-        * of write queries or failure.
-        *
-        * Once upon a time, DatabaseBase::query() returned a bare MySQL result
-        * resource, and it was necessary to call this function to convert it to
-        * a wrapper. Nowadays, raw database objects are never exposed to external
-        * callers, so this is unnecessary in external code. For compatibility with
-        * old code, ResultWrapper objects are passed through unaltered.
-        *
-        * @param bool|ResultWrapper|resource $result
-        * @return bool|ResultWrapper
-        */
-       public function resultObject( $result );
-
        /**
         * Ping the server and try to reconnect if it there is no connection
         *
@@ -1392,7 +1376,7 @@ interface IDatabase {
         * Some DBMSs have a special format for inserting into blob fields, they
         * don't allow simple quoted strings to be inserted. To insert into such
         * a field, pass the data through this function before passing it to
-        * DatabaseBase::insert().
+        * IDatabase::insert().
         *
         * @param string $b
         * @return string
diff --git a/includes/db/LBFactory.php b/includes/db/LBFactory.php
deleted file mode 100644 (file)
index cf522b2..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-<?php
-/**
- * Generator of database load balancing objects.
- *
- * 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 Database
- */
-
-/**
- * An interface for generating database load balancers
- * @ingroup Database
- */
-abstract class LBFactory {
-       /** @var LBFactory */
-       private static $instance;
-
-       /**
-        * Disables all access to the load balancer, will cause all database access
-        * to throw a DBAccessError
-        */
-       public static function disableBackend() {
-               global $wgLBFactoryConf;
-               self::$instance = new LBFactoryFake( $wgLBFactoryConf );
-       }
-
-       /**
-        * Get an LBFactory instance
-        *
-        * @return LBFactory
-        */
-       public static function singleton() {
-               global $wgLBFactoryConf;
-
-               if ( is_null( self::$instance ) ) {
-                       $class = self::getLBFactoryClass( $wgLBFactoryConf );
-
-                       self::$instance = new $class( $wgLBFactoryConf );
-               }
-
-               return self::$instance;
-       }
-
-       /**
-        * Returns the LBFactory class to use and the load balancer configuration.
-        *
-        * @param array $config (e.g. $wgLBFactoryConf)
-        * @return string Class name
-        */
-       public static function getLBFactoryClass( array $config ) {
-               // For configuration backward compatibility after removing
-               // underscores from class names in MediaWiki 1.23.
-               $bcClasses = array(
-                       'LBFactory_Simple' => 'LBFactorySimple',
-                       'LBFactory_Single' => 'LBFactorySingle',
-                       'LBFactory_Multi' => 'LBFactoryMulti',
-                       'LBFactory_Fake' => 'LBFactoryFake',
-               );
-
-               $class = $config['class'];
-
-               if ( isset( $bcClasses[$class] ) ) {
-                       $class = $bcClasses[$class];
-                       wfDeprecated(
-                               '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
-                               '1.23'
-                       );
-               }
-
-               return $class;
-       }
-
-       /**
-        * Shut down, close connections and destroy the cached instance.
-        */
-       public static function destroyInstance() {
-               if ( self::$instance ) {
-                       self::$instance->shutdown();
-                       self::$instance->forEachLBCallMethod( 'closeAll' );
-                       self::$instance = null;
-               }
-       }
-
-       /**
-        * Set the instance to be the given object
-        *
-        * @param LBFactory $instance
-        */
-       public static function setInstance( $instance ) {
-               self::destroyInstance();
-               self::$instance = $instance;
-       }
-
-       /**
-        * Construct a factory based on a configuration array (typically from $wgLBFactoryConf)
-        * @param array $conf
-        */
-       abstract public function __construct( array $conf );
-
-       /**
-        * Create a new load balancer object. The resulting object will be untracked,
-        * not chronology-protected, and the caller is responsible for cleaning it up.
-        *
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancer
-        */
-       abstract public function newMainLB( $wiki = false );
-
-       /**
-        * Get a cached (tracked) load balancer object.
-        *
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancer
-        */
-       abstract public function getMainLB( $wiki = false );
-
-       /**
-        * Create a new load balancer for external storage. The resulting object will be
-        * untracked, not chronology-protected, and the caller is responsible for
-        * cleaning it up.
-        *
-        * @param string $cluster External storage cluster, or false for core
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancer
-        */
-       abstract protected function newExternalLB( $cluster, $wiki = false );
-
-       /**
-        * Get a cached (tracked) load balancer for external storage
-        *
-        * @param string $cluster External storage cluster, or false for core
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancer
-        */
-       abstract public function &getExternalLB( $cluster, $wiki = false );
-
-       /**
-        * Execute a function for each tracked load balancer
-        * The callback is called with the load balancer as the first parameter,
-        * and $params passed as the subsequent parameters.
-        *
-        * @param callable $callback
-        * @param array $params
-        */
-       abstract public function forEachLB( $callback, array $params = array() );
-
-       /**
-        * Prepare all tracked load balancers for shutdown
-        * STUB
-        */
-       public function shutdown() {
-       }
-
-       /**
-        * Call a method of each tracked load balancer
-        *
-        * @param string $methodName
-        * @param array $args
-        */
-       private function forEachLBCallMethod( $methodName, array $args = array() ) {
-               $this->forEachLB( function ( LoadBalancer $loadBalancer, $methodName, array $args ) {
-                       call_user_func_array( array( $loadBalancer, $methodName ), $args );
-               }, array( $methodName, $args ) );
-       }
-
-       /**
-        * Commit on all connections. Done for two reasons:
-        * 1. To commit changes to the masters.
-        * 2. To release the snapshot on all connections, master and slave.
-        */
-       public function commitAll() {
-               $this->forEachLBCallMethod( 'commitAll' );
-       }
-
-       /**
-        * Commit changes on all master connections
-        */
-       public function commitMasterChanges() {
-               $this->forEachLBCallMethod( 'commitMasterChanges' );
-       }
-
-       /**
-        * Rollback changes on all master connections
-        * @since 1.23
-        */
-       public function rollbackMasterChanges() {
-               $this->forEachLBCallMethod( 'rollbackMasterChanges' );
-       }
-
-       /**
-        * Detemine if any master connection has pending changes.
-        * @since 1.23
-        * @return bool
-        */
-       public function hasMasterChanges() {
-               $ret = false;
-               $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) {
-                       $ret = $ret || $lb->hasMasterChanges();
-               } );
-               return $ret;
-       }
-}
-
-/**
- * A simple single-master LBFactory that gets its configuration from the b/c globals
- */
-class LBFactorySimple extends LBFactory {
-       /** @var LoadBalancer */
-       private $mainLB;
-
-       /** @var LoadBalancer[] */
-       private $extLBs = array();
-
-       /** @var ChronologyProtector */
-       private $chronProt;
-
-       public function __construct( array $conf ) {
-               $this->chronProt = new ChronologyProtector;
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancer
-        */
-       public function newMainLB( $wiki = false ) {
-               global $wgDBservers;
-               if ( $wgDBservers ) {
-                       $servers = $wgDBservers;
-               } else {
-                       global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype, $wgDebugDumpSql;
-                       global $wgDBssl, $wgDBcompress;
-
-                       $flags = DBO_DEFAULT;
-                       if ( $wgDebugDumpSql ) {
-                               $flags |= DBO_DEBUG;
-                       }
-                       if ( $wgDBssl ) {
-                               $flags |= DBO_SSL;
-                       }
-                       if ( $wgDBcompress ) {
-                               $flags |= DBO_COMPRESS;
-                       }
-
-                       $servers = array( array(
-                               'host' => $wgDBserver,
-                               'user' => $wgDBuser,
-                               'password' => $wgDBpassword,
-                               'dbname' => $wgDBname,
-                               'type' => $wgDBtype,
-                               'load' => 1,
-                               'flags' => $flags
-                       ) );
-               }
-
-               return new LoadBalancer( array(
-                       'servers' => $servers,
-               ) );
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancer
-        */
-       public function getMainLB( $wiki = false ) {
-               if ( !isset( $this->mainLB ) ) {
-                       $this->mainLB = $this->newMainLB( $wiki );
-                       $this->mainLB->parentInfo( array( 'id' => 'main' ) );
-                       $this->chronProt->initLB( $this->mainLB );
-               }
-
-               return $this->mainLB;
-       }
-
-       /**
-        * @throws MWException
-        * @param string $cluster
-        * @param bool|string $wiki
-        * @return LoadBalancer
-        */
-       protected function newExternalLB( $cluster, $wiki = false ) {
-               global $wgExternalServers;
-               if ( !isset( $wgExternalServers[$cluster] ) ) {
-                       throw new MWException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
-               }
-
-               return new LoadBalancer( array(
-                       'servers' => $wgExternalServers[$cluster]
-               ) );
-       }
-
-       /**
-        * @param string $cluster
-        * @param bool|string $wiki
-        * @return array
-        */
-       public function &getExternalLB( $cluster, $wiki = false ) {
-               if ( !isset( $this->extLBs[$cluster] ) ) {
-                       $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
-                       $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) );
-                       $this->chronProt->initLB( $this->extLBs[$cluster] );
-               }
-
-               return $this->extLBs[$cluster];
-       }
-
-       /**
-        * Execute a function for each tracked load balancer
-        * The callback is called with the load balancer as the first parameter,
-        * and $params passed as the subsequent parameters.
-        *
-        * @param callable $callback
-        * @param array $params
-        */
-       public function forEachLB( $callback, array $params = array() ) {
-               if ( isset( $this->mainLB ) ) {
-                       call_user_func_array( $callback, array_merge( array( $this->mainLB ), $params ) );
-               }
-               foreach ( $this->extLBs as $lb ) {
-                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
-               }
-       }
-
-       public function shutdown() {
-               if ( $this->mainLB ) {
-                       $this->chronProt->shutdownLB( $this->mainLB );
-               }
-               foreach ( $this->extLBs as $extLB ) {
-                       $this->chronProt->shutdownLB( $extLB );
-               }
-               $this->chronProt->shutdown();
-               $this->commitMasterChanges();
-       }
-}
-
-/**
- * LBFactory class that throws an error on any attempt to use it.
- * This will typically be done via wfGetDB().
- * Call LBFactory::disableBackend() to start using this, and
- * LBFactory::enableBackend() to return to normal behavior
- */
-class LBFactoryFake extends LBFactory {
-       public function __construct( array $conf ) {
-       }
-
-       public function newMainLB( $wiki = false ) {
-               throw new DBAccessError;
-       }
-
-       public function getMainLB( $wiki = false ) {
-               throw new DBAccessError;
-       }
-
-       protected function newExternalLB( $cluster, $wiki = false ) {
-               throw new DBAccessError;
-       }
-
-       public function &getExternalLB( $cluster, $wiki = false ) {
-               throw new DBAccessError;
-       }
-
-       public function forEachLB( $callback, array $params = array() ) {
-       }
-}
-
-/**
- * Exception class for attempted DB access
- */
-class DBAccessError extends MWException {
-       public function __construct() {
-               parent::__construct( "Mediawiki tried to access the database via wfGetDB(). " .
-                       "This is not allowed." );
-       }
-}
diff --git a/includes/db/LBFactoryMulti.php b/includes/db/LBFactoryMulti.php
deleted file mode 100644 (file)
index 92fbccd..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-<?php
-/**
- * Advanced generator of database load balancing objects for wiki farms.
- *
- * 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 Database
- */
-
-/**
- * A multi-wiki, multi-master factory for Wikimedia and similar installations.
- * Ignores the old configuration globals
- *
- * Configuration:
- *     sectionsByDB                A map of database names to section names.
- *
- *     sectionLoads                A 2-d map. For each section, gives a map of server names to
- *                                 load ratios. For example:
- *                                 array(
- *                                     'section1' => array(
- *                                         '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(
- *                                             'db1' => 100,
- *                                             'db2' => 100
- *                                         )
- *                                     )
- *                                 )
- *
- *     groupLoadsByDB              A 3-d map giving server load ratios by DB name.
- *
- *     hostsByName                 A map of hostname to IP address.
- *
- *     externalLoads               A map of external storage cluster name to server load map.
- *
- *     externalTemplateOverrides   A set of server info keys overriding serverTemplate for external
- *                                 storage.
- *
- *     templateOverridesByServer   A 2-d map overriding serverTemplate and
- *                                 externalTemplateOverrides on a server-by-server basis. Applies
- *                                 to both core and external storage.
- *
- *     templateOverridesByCluster  A 2-d map overriding the server info by external storage cluster.
- *
- *     masterTemplateOverrides     An override array for all master servers.
- *
- *     readOnlyBySection           A map of section name to read-only message.
- *                                 Missing or false for read/write.
- *
- * @ingroup Database
- */
-class LBFactoryMulti extends LBFactory {
-       // Required settings
-
-       /** @var array A map of database names to section names */
-       private $sectionsByDB;
-
-       /**
-        * @var array A 2-d map. For each section, gives a map of server names to
-        * load ratios
-        */
-       private $sectionLoads;
-
-       /**
-        * @var array A server info associative array as documented for
-        * $wgDBservers. The host, hostName and load entries will be
-        * overridden
-        */
-       private $serverTemplate;
-
-       // Optional settings
-
-       /** @var array A 3-d map giving server load ratios for each section and group */
-       private $groupLoadsBySection = array();
-
-       /** @var array A 3-d map giving server load ratios by DB name */
-       private $groupLoadsByDB = array();
-
-       /** @var array A map of hostname to IP address */
-       private $hostsByName = array();
-
-       /** @var array A map of external storage cluster name to server load map */
-       private $externalLoads = array();
-
-       /**
-        * @var array A set of server info keys overriding serverTemplate for
-        * external storage
-        */
-       private $externalTemplateOverrides;
-
-       /**
-        * @var array A 2-d map overriding serverTemplate and
-        * externalTemplateOverrides on a server-by-server basis. Applies to both
-        * core and external storage
-        */
-       private $templateOverridesByServer;
-
-       /** @var array A 2-d map overriding the server info by external storage cluster */
-       private $templateOverridesByCluster;
-
-       /** @var array An override array for all master servers */
-       private $masterTemplateOverrides;
-
-       /**
-        * @var array|bool A map of section name to read-only message. Missing or
-        * false for read/write
-        */
-       private $readOnlyBySection = array();
-
-       // Other stuff
-
-       /** @var array Load balancer factory configuration */
-       private $conf;
-
-       /** @var LoadBalancer[] */
-       private $mainLBs = array();
-
-       /** @var LoadBalancer[] */
-       private $extLBs = array();
-
-       /** @var string */
-       private $lastWiki;
-
-       /** @var string */
-       private $lastSection;
-
-       /**
-        * @param array $conf
-        * @throws MWException
-        */
-       public function __construct( array $conf ) {
-               $this->chronProt = new ChronologyProtector;
-               $this->conf = $conf;
-               $required = array( 'sectionsByDB', 'sectionLoads', 'serverTemplate' );
-               $optional = array( 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName',
-                       'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer',
-                       'templateOverridesByCluster', 'masterTemplateOverrides',
-                       'readOnlyBySection' );
-
-               foreach ( $required as $key ) {
-                       if ( !isset( $conf[$key] ) ) {
-                               throw new MWException( __CLASS__ . ": $key is required in configuration" );
-                       }
-                       $this->$key = $conf[$key];
-               }
-
-               foreach ( $optional as $key ) {
-                       if ( isset( $conf[$key] ) ) {
-                               $this->$key = $conf[$key];
-                       }
-               }
-
-               // Check for read-only mode
-               $section = $this->getSectionForWiki();
-               if ( !empty( $this->readOnlyBySection[$section] ) ) {
-                       global $wgReadOnly;
-                       $wgReadOnly = $this->readOnlyBySection[$section];
-               }
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return string
-        */
-       private function getSectionForWiki( $wiki = false ) {
-               if ( $this->lastWiki === $wiki ) {
-                       return $this->lastSection;
-               }
-               list( $dbName, ) = $this->getDBNameAndPrefix( $wiki );
-               if ( isset( $this->sectionsByDB[$dbName] ) ) {
-                       $section = $this->sectionsByDB[$dbName];
-               } else {
-                       $section = 'DEFAULT';
-               }
-               $this->lastSection = $section;
-               $this->lastWiki = $wiki;
-
-               return $section;
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancer
-        */
-       public function newMainLB( $wiki = false ) {
-               list( $dbName, ) = $this->getDBNameAndPrefix( $wiki );
-               $section = $this->getSectionForWiki( $wiki );
-               $groupLoads = array();
-               if ( isset( $this->groupLoadsByDB[$dbName] ) ) {
-                       $groupLoads = $this->groupLoadsByDB[$dbName];
-               }
-
-               if ( isset( $this->groupLoadsBySection[$section] ) ) {
-                       $groupLoads = array_merge_recursive( $groupLoads, $this->groupLoadsBySection[$section] );
-               }
-
-               return $this->newLoadBalancer(
-                       $this->serverTemplate,
-                       $this->sectionLoads[$section],
-                       $groupLoads
-               );
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancer
-        */
-       public function getMainLB( $wiki = false ) {
-               $section = $this->getSectionForWiki( $wiki );
-               if ( !isset( $this->mainLBs[$section] ) ) {
-                       $lb = $this->newMainLB( $wiki );
-                       $lb->parentInfo( array( 'id' => "main-$section" ) );
-                       $this->chronProt->initLB( $lb );
-                       $this->mainLBs[$section] = $lb;
-               }
-
-               return $this->mainLBs[$section];
-       }
-
-       /**
-        * @param string $cluster
-        * @param bool|string $wiki
-        * @throws MWException
-        * @return LoadBalancer
-        */
-       protected function newExternalLB( $cluster, $wiki = false ) {
-               if ( !isset( $this->externalLoads[$cluster] ) ) {
-                       throw new MWException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
-               }
-               $template = $this->serverTemplate;
-               if ( isset( $this->externalTemplateOverrides ) ) {
-                       $template = $this->externalTemplateOverrides + $template;
-               }
-               if ( isset( $this->templateOverridesByCluster[$cluster] ) ) {
-                       $template = $this->templateOverridesByCluster[$cluster] + $template;
-               }
-
-               return $this->newLoadBalancer( $template, $this->externalLoads[$cluster], array() );
-       }
-
-       /**
-        * @param string $cluster External storage cluster, or false for core
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancer
-        */
-       public function &getExternalLB( $cluster, $wiki = false ) {
-               if ( !isset( $this->extLBs[$cluster] ) ) {
-                       $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
-                       $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) );
-                       $this->chronProt->initLB( $this->extLBs[$cluster] );
-               }
-
-               return $this->extLBs[$cluster];
-       }
-
-       /**
-        * Make a new load balancer object based on template and load array
-        *
-        * @param array $template
-        * @param array $loads
-        * @param array $groupLoads
-        * @return LoadBalancer
-        */
-       private function newLoadBalancer( $template, $loads, $groupLoads ) {
-               $servers = $this->makeServerArray( $template, $loads, $groupLoads );
-               $lb = new LoadBalancer( array(
-                       'servers' => $servers,
-               ) );
-
-               return $lb;
-       }
-
-       /**
-        * Make a server array as expected by LoadBalancer::__construct, using a template and load array
-        *
-        * @param array $template
-        * @param array $loads
-        * @param array $groupLoads
-        * @return array
-        */
-       private function makeServerArray( $template, $loads, $groupLoads ) {
-               $servers = array();
-               $master = true;
-               $groupLoadsByServer = $this->reindexGroupLoads( $groupLoads );
-               foreach ( $groupLoadsByServer as $server => $stuff ) {
-                       if ( !isset( $loads[$server] ) ) {
-                               $loads[$server] = 0;
-                       }
-               }
-               foreach ( $loads as $serverName => $load ) {
-                       $serverInfo = $template;
-                       if ( $master ) {
-                               $serverInfo['master'] = true;
-                               if ( isset( $this->masterTemplateOverrides ) ) {
-                                       $serverInfo = $this->masterTemplateOverrides + $serverInfo;
-                               }
-                               $master = false;
-                       }
-                       if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
-                               $serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
-                       }
-                       if ( isset( $groupLoadsByServer[$serverName] ) ) {
-                               $serverInfo['groupLoads'] = $groupLoadsByServer[$serverName];
-                       }
-                       if ( isset( $this->hostsByName[$serverName] ) ) {
-                               $serverInfo['host'] = $this->hostsByName[$serverName];
-                       } else {
-                               $serverInfo['host'] = $serverName;
-                       }
-                       $serverInfo['hostName'] = $serverName;
-                       $serverInfo['load'] = $load;
-                       $servers[] = $serverInfo;
-               }
-
-               return $servers;
-       }
-
-       /**
-        * Take a group load array indexed by group then server, and reindex it by server then group
-        * @param array $groupLoads
-        * @return array
-        */
-       private function reindexGroupLoads( $groupLoads ) {
-               $reindexed = array();
-               foreach ( $groupLoads as $group => $loads ) {
-                       foreach ( $loads as $server => $load ) {
-                               $reindexed[$server][$group] = $load;
-                       }
-               }
-
-               return $reindexed;
-       }
-
-       /**
-        * Get the database name and prefix based on the wiki ID
-        * @param bool|string $wiki
-        * @return array
-        */
-       private function getDBNameAndPrefix( $wiki = false ) {
-               if ( $wiki === false ) {
-                       global $wgDBname, $wgDBprefix;
-
-                       return array( $wgDBname, $wgDBprefix );
-               } else {
-                       return wfSplitWikiID( $wiki );
-               }
-       }
-
-       /**
-        * Execute a function for each tracked load balancer
-        * The callback is called with the load balancer as the first parameter,
-        * and $params passed as the subsequent parameters.
-        * @param callable $callback
-        * @param array $params
-        */
-       public function forEachLB( $callback, array $params = array() ) {
-               foreach ( $this->mainLBs as $lb ) {
-                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
-               }
-               foreach ( $this->extLBs as $lb ) {
-                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
-               }
-       }
-
-       public function shutdown() {
-               foreach ( $this->mainLBs as $lb ) {
-                       $this->chronProt->shutdownLB( $lb );
-               }
-               foreach ( $this->extLBs as $extLB ) {
-                       $this->chronProt->shutdownLB( $extLB );
-               }
-               $this->chronProt->shutdown();
-               $this->commitMasterChanges();
-       }
-}
diff --git a/includes/db/LBFactorySingle.php b/includes/db/LBFactorySingle.php
deleted file mode 100644 (file)
index a41dadf..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
- * Simple generator of database connections that always returns the same object.
- *
- * 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 Database
- */
-
-/**
- * An LBFactory class that always returns a single database object.
- */
-class LBFactorySingle extends LBFactory {
-       /** @var LoadBalancerSingle */
-       private $lb;
-
-       /**
-        * @param array $conf An associative array with one member:
-        *  - connection: The DatabaseBase connection object
-        */
-       public function __construct( array $conf ) {
-               $this->lb = new LoadBalancerSingle( $conf );
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancerSingle
-        */
-       public function newMainLB( $wiki = false ) {
-               return $this->lb;
-       }
-
-       /**
-        * @param bool|string $wiki
-        * @return LoadBalancerSingle
-        */
-       public function getMainLB( $wiki = false ) {
-               return $this->lb;
-       }
-
-       /**
-        * @param string $cluster External storage cluster, or false for core
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancerSingle
-        */
-       protected function newExternalLB( $cluster, $wiki = false ) {
-               return $this->lb;
-       }
-
-       /**
-        * @param string $cluster External storage cluster, or false for core
-        * @param bool|string $wiki Wiki ID, or false for the current wiki
-        * @return LoadBalancerSingle
-        */
-       public function &getExternalLB( $cluster, $wiki = false ) {
-               return $this->lb;
-       }
-
-       /**
-        * @param string|callable $callback
-        * @param array $params
-        */
-       public function forEachLB( $callback, array $params = array() ) {
-               call_user_func_array( $callback, array_merge( array( $this->lb ), $params ) );
-       }
-}
-
-/**
- * Helper class for LBFactorySingle.
- */
-class LoadBalancerSingle extends LoadBalancer {
-       /** @var DatabaseBase */
-       private $db;
-
-       /**
-        * @param array $params
-        */
-       public function __construct( array $params ) {
-               $this->db = $params['connection'];
-               parent::__construct( array( 'servers' => array( array(
-                       'type' => $this->db->getType(),
-                       'host' => $this->db->getServer(),
-                       'dbname' => $this->db->getDBname(),
-                       'load' => 1,
-               ) ) ) );
-       }
-
-       /**
-        *
-        * @param string $server
-        * @param bool $dbNameOverride
-        *
-        * @return DatabaseBase
-        */
-       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
-               return $this->db;
-       }
-}
diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php
deleted file mode 100644 (file)
index 52dca08..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-<?php
-/**
- * Database load balancing.
- *
- * 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 Database
- */
-
-/**
- * Database load balancing object
- *
- * @todo document
- * @ingroup Database
- */
-class LoadBalancer {
-       /** @var array[] Map of (server index => server config array) */
-       private $mServers;
-       /** @var array[] Map of (local/foreignUsed/foreignFree => server index => DatabaseBase array) */
-       private $mConns;
-       /** @var array Map of (server index => weight) */
-       private $mLoads;
-       /** @var array[] Map of (group => server index => weight) */
-       private $mGroupLoads;
-       /** @var bool Whether to disregard slave lag as a factor in slave selection */
-       private $mAllowLagged;
-       /** @var integer Seconds to spend waiting on slave lag to resolve */
-       private $mWaitTimeout;
-
-       /** @var array LBFactory information */
-       private $mParentInfo;
-       /** @var string The LoadMonitor subclass name */
-       private $mLoadMonitorClass;
-       /** @var LoadMonitor */
-       private $mLoadMonitor;
-
-       /** @var bool|DatabaseBase Database connection that caused a problem */
-       private $mErrorConnection;
-       /** @var integer The generic (not query grouped) slave index (of $mServers) */
-       private $mReadIndex;
-       /** @var bool|DBMasterPos False if not set */
-       private $mWaitForPos;
-       /** @var bool Whether the generic reader fell back to a lagged slave */
-       private $mLaggedSlaveMode;
-       /** @var string The last DB selection or connection error */
-       private $mLastError = 'Unknown error';
-       /** @var integer Total connections opened */
-       private $connsOpened = 0;
-
-       /** @var integer Warn when this many connection are held */
-       const CONN_HELD_WARN_THRESHOLD = 10;
-
-       /**
-        * @param array $params Array with keys:
-        *   servers           Required. Array of server info structures.
-        *   loadMonitor       Name of a class used to fetch server lag and load.
-        * @throws MWException
-        */
-       public function __construct( array $params ) {
-               if ( !isset( $params['servers'] ) ) {
-                       throw new MWException( __CLASS__ . ': missing servers parameter' );
-               }
-               $this->mServers = $params['servers'];
-               $this->mWaitTimeout = 10;
-
-               $this->mReadIndex = -1;
-               $this->mWriteIndex = -1;
-               $this->mConns = array(
-                       'local' => array(),
-                       'foreignUsed' => array(),
-                       'foreignFree' => array() );
-               $this->mLoads = array();
-               $this->mWaitForPos = false;
-               $this->mLaggedSlaveMode = false;
-               $this->mErrorConnection = false;
-               $this->mAllowLagged = false;
-
-               if ( isset( $params['loadMonitor'] ) ) {
-                       $this->mLoadMonitorClass = $params['loadMonitor'];
-               } else {
-                       $master = reset( $params['servers'] );
-                       if ( isset( $master['type'] ) && $master['type'] === 'mysql' ) {
-                               $this->mLoadMonitorClass = 'LoadMonitorMySQL';
-                       } else {
-                               $this->mLoadMonitorClass = 'LoadMonitorNull';
-                       }
-               }
-
-               foreach ( $params['servers'] as $i => $server ) {
-                       $this->mLoads[$i] = $server['load'];
-                       if ( isset( $server['groupLoads'] ) ) {
-                               foreach ( $server['groupLoads'] as $group => $ratio ) {
-                                       if ( !isset( $this->mGroupLoads[$group] ) ) {
-                                               $this->mGroupLoads[$group] = array();
-                                       }
-                                       $this->mGroupLoads[$group][$i] = $ratio;
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Get a LoadMonitor instance
-        *
-        * @return LoadMonitor
-        */
-       private function getLoadMonitor() {
-               if ( !isset( $this->mLoadMonitor ) ) {
-                       $class = $this->mLoadMonitorClass;
-                       $this->mLoadMonitor = new $class( $this );
-               }
-
-               return $this->mLoadMonitor;
-       }
-
-       /**
-        * Get or set arbitrary data used by the parent object, usually an LBFactory
-        * @param mixed $x
-        * @return mixed
-        */
-       public function parentInfo( $x = null ) {
-               return wfSetVar( $this->mParentInfo, $x );
-       }
-
-       /**
-        * Given an array of non-normalised probabilities, this function will select
-        * an element and return the appropriate key
-        *
-        * @deprecated since 1.21, use ArrayUtils::pickRandom()
-        *
-        * @param array $weights
-        * @return bool|int|string
-        */
-       public function pickRandom( array $weights ) {
-               return ArrayUtils::pickRandom( $weights );
-       }
-
-       /**
-        * @param array $loads
-        * @param bool|string $wiki Wiki to get non-lagged for
-        * @param float $maxLag Restrict the maximum allowed lag to this many seconds
-        * @return bool|int|string
-        */
-       private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
-               $lags = $this->getLagTimes( $wiki );
-
-               # Unset excessively lagged servers
-               foreach ( $lags as $i => $lag ) {
-                       if ( $i != 0 ) {
-                               $maxServerLag = $maxLag;
-                               if ( isset( $this->mServers[$i]['max lag'] ) ) {
-                                       $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
-                               }
-                               if ( $lag === false ) {
-                                       wfDebugLog( 'replication', "Server #$i is not replicating" );
-                                       unset( $loads[$i] );
-                               } elseif ( $lag > $maxServerLag ) {
-                                       wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" );
-                                       unset( $loads[$i] );
-                               }
-                       }
-               }
-
-               # Find out if all the slaves with non-zero load are lagged
-               $sum = 0;
-               foreach ( $loads as $load ) {
-                       $sum += $load;
-               }
-               if ( $sum == 0 ) {
-                       # No appropriate DB servers except maybe the master and some slaves with zero load
-                       # Do NOT use the master
-                       # Instead, this function will return false, triggering read-only mode,
-                       # and a lagged slave will be used instead.
-                       return false;
-               }
-
-               if ( count( $loads ) == 0 ) {
-                       return false;
-               }
-
-               #wfDebugLog( 'connect', var_export( $loads, true ) );
-
-               # Return a random representative of the remainder
-               return ArrayUtils::pickRandom( $loads );
-       }
-
-       /**
-        * Get the index of the reader connection, which may be a slave
-        * This takes into account load ratios and lag times. It should
-        * always return a consistent index during a given invocation
-        *
-        * Side effect: opens connections to databases
-        * @param string|bool $group Query group, or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
-        * @throws MWException
-        * @return bool|int|string
-        */
-       public function getReaderIndex( $group = false, $wiki = false ) {
-               global $wgDBtype;
-
-               # @todo FIXME: For now, only go through all this for mysql databases
-               if ( $wgDBtype != 'mysql' ) {
-                       return $this->getWriterIndex();
-               }
-
-               if ( count( $this->mServers ) == 1 ) {
-                       # Skip the load balancing if there's only one server
-                       return 0;
-               } elseif ( $group === false && $this->mReadIndex >= 0 ) {
-                       # Shortcut if generic reader exists already
-                       return $this->mReadIndex;
-               }
-
-               # Find the relevant load array
-               if ( $group !== false ) {
-                       if ( isset( $this->mGroupLoads[$group] ) ) {
-                               $nonErrorLoads = $this->mGroupLoads[$group];
-                       } else {
-                               # No loads for this group, return false and the caller can use some other group
-                               wfDebug( __METHOD__ . ": no loads for group $group\n" );
-
-                               return false;
-                       }
-               } else {
-                       $nonErrorLoads = $this->mLoads;
-               }
-
-               if ( !count( $nonErrorLoads ) ) {
-                       throw new MWException( "Empty server array given to LoadBalancer" );
-               }
-
-               # Scale the configured load ratios according to the dynamic load (if the load monitor supports it)
-               $this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $group, $wiki );
-
-               $laggedSlaveMode = false;
-
-               # No server found yet
-               $i = false;
-               # First try quickly looking through the available servers for a server that
-               # meets our criteria
-               $currentLoads = $nonErrorLoads;
-               while ( count( $currentLoads ) ) {
-                       if ( $this->mAllowLagged || $laggedSlaveMode ) {
-                               $i = ArrayUtils::pickRandom( $currentLoads );
-                       } else {
-                               $i = false;
-                               if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
-                                       # ChronologyProtecter causes mWaitForPos to be set via sessions.
-                                       # This triggers doWait() after connect, so it's especially good to
-                                       # avoid lagged servers so as to avoid just blocking in that method.
-                                       $ago = microtime( true ) - $this->mWaitForPos->asOfTime();
-                                       # Aim for <= 1 second of waiting (being too picky can backfire)
-                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki, $ago + 1 );
-                               }
-                               if ( $i === false ) {
-                                       # Any server with less lag than it's 'max lag' param is preferable
-                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki );
-                               }
-                               if ( $i === false && count( $currentLoads ) != 0 ) {
-                                       # All slaves lagged. Switch to read-only mode
-                                       wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );
-                                       $i = ArrayUtils::pickRandom( $currentLoads );
-                                       $laggedSlaveMode = true;
-                               }
-                       }
-
-                       if ( $i === false ) {
-                               # pickRandom() returned false
-                               # This is permanent and means the configuration or the load monitor
-                               # wants us to return false.
-                               wfDebugLog( 'connect', __METHOD__ . ": pickRandom() returned false" );
-
-                               return false;
-                       }
-
-                       $serverName = $this->getServerName( $i );
-                       wfDebugLog( 'connect', __METHOD__ . ": Using reader #$i: $serverName..." );
-
-                       $conn = $this->openConnection( $i, $wiki );
-                       if ( !$conn ) {
-                               wfDebugLog( 'connect', __METHOD__ . ": Failed connecting to $i/$wiki" );
-                               unset( $nonErrorLoads[$i] );
-                               unset( $currentLoads[$i] );
-                               $i = false;
-                               continue;
-                       }
-
-                       // Decrement reference counter, we are finished with this connection.
-                       // It will be incremented for the caller later.
-                       if ( $wiki !== false ) {
-                               $this->reuseConnection( $conn );
-                       }
-
-                       # Return this server
-                       break;
-               }
-
-               # If all servers were down, quit now
-               if ( !count( $nonErrorLoads ) ) {
-                       wfDebugLog( 'connect', "All servers down" );
-               }
-
-               if ( $i !== false ) {
-                       # Slave connection successful
-                       # Wait for the session master pos for a short time
-                       if ( $this->mWaitForPos && $i > 0 ) {
-                               if ( !$this->doWait( $i ) ) {
-                                       $this->mServers[$i]['slave pos'] = $conn->getSlavePos();
-                               }
-                       }
-                       if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group === false ) {
-                               $this->mReadIndex = $i;
-                               # Record if the generic reader index is in "lagged slave" mode
-                               if ( $laggedSlaveMode ) {
-                                       $this->mLaggedSlaveMode = true;
-                               }
-                       }
-                       $serverName = $this->getServerName( $i );
-                       wfDebug( __METHOD__ . ": using server $serverName for group '$group'\n" );
-               }
-
-               return $i;
-       }
-
-       /**
-        * Set the master wait position
-        * If a DB_SLAVE connection has been opened already, waits
-        * Otherwise sets a variable telling it to wait if such a connection is opened
-        * @param DBMasterPos $pos
-        */
-       public function waitFor( $pos ) {
-               $this->mWaitForPos = $pos;
-               $i = $this->mReadIndex;
-
-               if ( $i > 0 ) {
-                       if ( !$this->doWait( $i ) ) {
-                               $this->mServers[$i]['slave pos'] = $this->getAnyOpenConnection( $i )->getSlavePos();
-                               $this->mLaggedSlaveMode = true;
-                       }
-               }
-       }
-
-       /**
-        * Set the master wait position and wait for a "generic" slave to catch up to it
-        *
-        * This can be used a faster proxy for waitForAll()
-        *
-        * @param DBMasterPos $pos
-        * @param int $timeout Max seconds to wait; default is mWaitTimeout
-        * @return bool Success (able to connect and no timeouts reached)
-        * @since 1.26
-        */
-       public function waitForOne( $pos, $timeout = null ) {
-               $this->mWaitForPos = $pos;
-
-               $i = $this->mReadIndex;
-               if ( $i <= 0 ) {
-                       // Pick a generic slave if there isn't one yet
-                       $readLoads = $this->mLoads;
-                       unset( $readLoads[$this->getWriterIndex()] ); // slaves only
-                       $readLoads = array_filter( $readLoads ); // with non-zero load
-                       $i = ArrayUtils::pickRandom( $readLoads );
-               }
-
-               if ( $i > 0 ) {
-                       $ok = $this->doWait( $i, true, $timeout );
-               } else {
-                       $ok = true; // no applicable loads
-               }
-
-               return $ok;
-       }
-
-       /**
-        * Set the master wait position and wait for ALL slaves to catch up to it
-        * @param DBMasterPos $pos
-        * @param int $timeout Max seconds to wait; default is mWaitTimeout
-        * @return bool Success (able to connect and no timeouts reached)
-        */
-       public function waitForAll( $pos, $timeout = null ) {
-               $this->mWaitForPos = $pos;
-               $serverCount = count( $this->mServers );
-
-               $ok = true;
-               for ( $i = 1; $i < $serverCount; $i++ ) {
-                       if ( $this->mLoads[$i] > 0 ) {
-                               $ok = $this->doWait( $i, true, $timeout ) && $ok;
-                       }
-               }
-
-               return $ok;
-       }
-
-       /**
-        * Get any open connection to a given server index, local or foreign
-        * Returns false if there is no connection open
-        *
-        * @param int $i
-        * @return DatabaseBase|bool False on failure
-        */
-       public function getAnyOpenConnection( $i ) {
-               foreach ( $this->mConns as $conns ) {
-                       if ( !empty( $conns[$i] ) ) {
-                               return reset( $conns[$i] );
-                       }
-               }
-
-               return false;
-       }
-
-       /**
-        * Wait for a given slave to catch up to the master pos stored in $this
-        * @param int $index Server index
-        * @param bool $open Check the server even if a new connection has to be made
-        * @param int $timeout Max seconds to wait; default is mWaitTimeout
-        * @return bool
-        */
-       protected function doWait( $index, $open = false, $timeout = null ) {
-               $close = false; // close the connection afterwards
-
-               # Find a connection to wait on, creating one if needed and allowed
-               $conn = $this->getAnyOpenConnection( $index );
-               if ( !$conn ) {
-                       if ( !$open ) {
-                               wfDebug( __METHOD__ . ": no connection open\n" );
-
-                               return false;
-                       } else {
-                               $conn = $this->openConnection( $index, '' );
-                               if ( !$conn ) {
-                                       wfDebug( __METHOD__ . ": failed to open connection\n" );
-
-                                       return false;
-                               }
-                               // Avoid connection spam in waitForAll() when connections
-                               // are made just for the sake of doing this lag check.
-                               $close = true;
-                       }
-               }
-
-               wfDebug( __METHOD__ . ": Waiting for slave #$index to catch up...\n" );
-               $timeout = $timeout ?: $this->mWaitTimeout;
-               $result = $conn->masterPosWait( $this->mWaitForPos, $timeout );
-
-               if ( $result == -1 || is_null( $result ) ) {
-                       # Timed out waiting for slave, use master instead
-                       $server = $server = $this->getServerName( $index );
-                       $msg = __METHOD__ . ": Timed out waiting on $server pos {$this->mWaitForPos}";
-                       wfDebug( "$msg\n" );
-                       wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
-                       $ok = false;
-               } else {
-                       wfDebug( __METHOD__ . ": Done\n" );
-                       $ok = true;
-               }
-
-               if ( $close ) {
-                       $this->closeConnection( $conn );
-               }
-
-               return $ok;
-       }
-
-       /**
-        * Get a connection by index
-        * This is the main entry point for this class.
-        *
-        * @param int $i Server index
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
-        *
-        * @throws MWException
-        * @return DatabaseBase
-        */
-       public function getConnection( $i, $groups = array(), $wiki = false ) {
-               if ( $i === null || $i === false ) {
-                       throw new MWException( 'Attempt to call ' . __METHOD__ .
-                               ' with invalid server index' );
-               }
-
-               if ( $wiki === wfWikiID() ) {
-                       $wiki = false;
-               }
-
-               $groups = ( $groups === false || $groups === array() )
-                       ? array( false ) // check one "group": the generic pool
-                       : (array)$groups;
-
-               $masterOnly = ( $i == DB_MASTER || $i == $this->getWriterIndex() );
-               $oldConnsOpened = $this->connsOpened; // connections open now
-
-               if ( $i == DB_MASTER ) {
-                       $i = $this->getWriterIndex();
-               } else {
-                       # Try to find an available server in any the query groups (in order)
-                       foreach ( $groups as $group ) {
-                               $groupIndex = $this->getReaderIndex( $group, $wiki );
-                               if ( $groupIndex !== false ) {
-                                       $i = $groupIndex;
-                                       break;
-                               }
-                       }
-               }
-
-               # Operation-based index
-               if ( $i == DB_SLAVE ) {
-                       $this->mLastError = 'Unknown error'; // reset error string
-                       # Try the general server pool if $groups are unavailable.
-                       $i = in_array( false, $groups, true )
-                               ? false // don't bother with this if that is what was tried above
-                               : $this->getReaderIndex( false, $wiki );
-                       # Couldn't find a working server in getReaderIndex()?
-                       if ( $i === false ) {
-                               $this->mLastError = 'No working slave server: ' . $this->mLastError;
-
-                               return $this->reportConnectionError();
-                       }
-               }
-
-               # Now we have an explicit index into the servers array
-               $conn = $this->openConnection( $i, $wiki );
-               if ( !$conn ) {
-                       return $this->reportConnectionError();
-               }
-
-               # Profile any new connections that happen
-               if ( $this->connsOpened > $oldConnsOpened ) {
-                       $host = $conn->getServer();
-                       $dbname = $conn->getDBname();
-                       $trxProf = Profiler::instance()->getTransactionProfiler();
-                       $trxProf->recordConnection( $host, $dbname, $masterOnly );
-               }
-
-               return $conn;
-       }
-
-       /**
-        * Mark a foreign connection as being available for reuse under a different
-        * DB name or prefix. This mechanism is reference-counted, and must be called
-        * the same number of times as getConnection() to work.
-        *
-        * @param DatabaseBase $conn
-        * @throws MWException
-        */
-       public function reuseConnection( $conn ) {
-               $serverIndex = $conn->getLBInfo( 'serverIndex' );
-               $refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
-               if ( $serverIndex === null || $refCount === null ) {
-                       wfDebug( __METHOD__ . ": this connection was not opened as a foreign connection\n" );
-
-                       /**
-                        * This can happen in code like:
-                        *   foreach ( $dbs as $db ) {
-                        *     $conn = $lb->getConnection( DB_SLAVE, array(), $db );
-                        *     ...
-                        *     $lb->reuseConnection( $conn );
-                        *   }
-                        * When a connection to the local DB is opened in this way, reuseConnection()
-                        * should be ignored
-                        */
-
-                       return;
-               }
-
-               $dbName = $conn->getDBname();
-               $prefix = $conn->tablePrefix();
-               if ( strval( $prefix ) !== '' ) {
-                       $wiki = "$dbName-$prefix";
-               } else {
-                       $wiki = $dbName;
-               }
-               if ( $this->mConns['foreignUsed'][$serverIndex][$wiki] !== $conn ) {
-                       throw new MWException( __METHOD__ . ": connection not found, has " .
-                               "the connection been freed already?" );
-               }
-               $conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
-               if ( $refCount <= 0 ) {
-                       $this->mConns['foreignFree'][$serverIndex][$wiki] = $conn;
-                       unset( $this->mConns['foreignUsed'][$serverIndex][$wiki] );
-                       wfDebug( __METHOD__ . ": freed connection $serverIndex/$wiki\n" );
-               } else {
-                       wfDebug( __METHOD__ . ": reference count for $serverIndex/$wiki reduced to $refCount\n" );
-               }
-       }
-
-       /**
-        * Get a database connection handle reference
-        *
-        * The handle's methods wrap simply wrap those of a DatabaseBase handle
-        *
-        * @see LoadBalancer::getConnection() for parameter information
-        *
-        * @param int $db
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
-        * @return DBConnRef
-        */
-       public function getConnectionRef( $db, $groups = array(), $wiki = false ) {
-               return new DBConnRef( $this, $this->getConnection( $db, $groups, $wiki ) );
-       }
-
-       /**
-        * Get a database connection handle reference without connecting yet
-        *
-        * The handle's methods wrap simply wrap those of a DatabaseBase handle
-        *
-        * @see LoadBalancer::getConnection() for parameter information
-        *
-        * @param int $db
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
-        * @return DBConnRef
-        */
-       public function getLazyConnectionRef( $db, $groups = array(), $wiki = false ) {
-               return new DBConnRef( $this, array( $db, $groups, $wiki ) );
-       }
-
-       /**
-        * Open a connection to the server given by the specified index
-        * Index must be an actual index into the array.
-        * If the server is already open, returns it.
-        *
-        * On error, returns false, and the connection which caused the
-        * error will be available via $this->mErrorConnection.
-        *
-        * @param int $i Server index
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
-        * @return DatabaseBase
-        *
-        * @access private
-        */
-       public function openConnection( $i, $wiki = false ) {
-               if ( $wiki !== false ) {
-                       $conn = $this->openForeignConnection( $i, $wiki );
-               } elseif ( isset( $this->mConns['local'][$i][0] ) ) {
-                       $conn = $this->mConns['local'][$i][0];
-               } else {
-                       $server = $this->mServers[$i];
-                       $server['serverIndex'] = $i;
-                       $conn = $this->reallyOpenConnection( $server, false );
-                       $serverName = $this->getServerName( $i );
-                       if ( $conn->isOpen() ) {
-                               wfDebug( "Connected to database $i at $serverName\n" );
-                               $this->mConns['local'][$i][0] = $conn;
-                       } else {
-                               wfDebug( "Failed to connect to database $i at $serverName\n" );
-                               $this->mErrorConnection = $conn;
-                               $conn = false;
-                       }
-               }
-
-               if ( $conn && !$conn->isOpen() ) {
-                       // Connection was made but later unrecoverably lost for some reason.
-                       // Do not return a handle that will just throw exceptions on use,
-                       // but let the calling code (e.g. getReaderIndex) try another server.
-                       // See DatabaseMyslBase::ping() for how this can happen.
-                       $this->mErrorConnection = $conn;
-                       $conn = false;
-               }
-
-               return $conn;
-       }
-
-       /**
-        * Open a connection to a foreign DB, or return one if it is already open.
-        *
-        * Increments a reference count on the returned connection which locks the
-        * connection to the requested wiki. This reference count can be
-        * decremented by calling reuseConnection().
-        *
-        * If a connection is open to the appropriate server already, but with the wrong
-        * database, it will be switched to the right database and returned, as long as
-        * it has been freed first with reuseConnection().
-        *
-        * On error, returns false, and the connection which caused the
-        * error will be available via $this->mErrorConnection.
-        *
-        * @param int $i Server index
-        * @param string $wiki Wiki ID to open
-        * @return DatabaseBase
-        */
-       private function openForeignConnection( $i, $wiki ) {
-               list( $dbName, $prefix ) = wfSplitWikiID( $wiki );
-               if ( isset( $this->mConns['foreignUsed'][$i][$wiki] ) ) {
-                       // Reuse an already-used connection
-                       $conn = $this->mConns['foreignUsed'][$i][$wiki];
-                       wfDebug( __METHOD__ . ": reusing connection $i/$wiki\n" );
-               } elseif ( isset( $this->mConns['foreignFree'][$i][$wiki] ) ) {
-                       // Reuse a free connection for the same wiki
-                       $conn = $this->mConns['foreignFree'][$i][$wiki];
-                       unset( $this->mConns['foreignFree'][$i][$wiki] );
-                       $this->mConns['foreignUsed'][$i][$wiki] = $conn;
-                       wfDebug( __METHOD__ . ": reusing free connection $i/$wiki\n" );
-               } elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) {
-                       // Reuse a connection from another wiki
-                       $conn = reset( $this->mConns['foreignFree'][$i] );
-                       $oldWiki = key( $this->mConns['foreignFree'][$i] );
-
-                       // The empty string as a DB name means "don't care".
-                       // DatabaseMysqlBase::open() already handle this on connection.
-                       if ( $dbName !== '' && !$conn->selectDB( $dbName ) ) {
-                               $this->mLastError = "Error selecting database $dbName on server " .
-                                       $conn->getServer() . " from client host " . wfHostname() . "\n";
-                               $this->mErrorConnection = $conn;
-                               $conn = false;
-                       } else {
-                               $conn->tablePrefix( $prefix );
-                               unset( $this->mConns['foreignFree'][$i][$oldWiki] );
-                               $this->mConns['foreignUsed'][$i][$wiki] = $conn;
-                               wfDebug( __METHOD__ . ": reusing free connection from $oldWiki for $wiki\n" );
-                       }
-               } else {
-                       // Open a new connection
-                       $server = $this->mServers[$i];
-                       $server['serverIndex'] = $i;
-                       $server['foreignPoolRefCount'] = 0;
-                       $server['foreign'] = true;
-                       $conn = $this->reallyOpenConnection( $server, $dbName );
-                       if ( !$conn->isOpen() ) {
-                               wfDebug( __METHOD__ . ": error opening connection for $i/$wiki\n" );
-                               $this->mErrorConnection = $conn;
-                               $conn = false;
-                       } else {
-                               $conn->tablePrefix( $prefix );
-                               $this->mConns['foreignUsed'][$i][$wiki] = $conn;
-                               wfDebug( __METHOD__ . ": opened new connection for $i/$wiki\n" );
-                       }
-               }
-
-               // Increment reference count
-               if ( $conn ) {
-                       $refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
-                       $conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
-               }
-
-               return $conn;
-       }
-
-       /**
-        * Test if the specified index represents an open connection
-        *
-        * @param int $index Server index
-        * @access private
-        * @return bool
-        */
-       private function isOpen( $index ) {
-               if ( !is_integer( $index ) ) {
-                       return false;
-               }
-
-               return (bool)$this->getAnyOpenConnection( $index );
-       }
-
-       /**
-        * Really opens a connection. Uncached.
-        * Returns a Database object whether or not the connection was successful.
-        * @access private
-        *
-        * @param array $server
-        * @param bool $dbNameOverride
-        * @throws MWException
-        * @return DatabaseBase
-        */
-       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
-               if ( !is_array( $server ) ) {
-                       throw new MWException( 'You must update your load-balancing configuration. ' .
-                               'See DefaultSettings.php entry for $wgDBservers.' );
-               }
-
-               if ( $dbNameOverride !== false ) {
-                       $server['dbname'] = $dbNameOverride;
-               }
-
-               // Log when many connection are made on requests
-               if ( ++$this->connsOpened >= self::CONN_HELD_WARN_THRESHOLD ) {
-                       $masterAddr = $this->getServerName( 0 );
-                       wfDebugLog( 'DBPerformance', __METHOD__ . ": " .
-                               "{$this->connsOpened}+ connections made (master=$masterAddr)\n" .
-                               wfBacktrace( true ) );
-               }
-
-               # Create object
-               try {
-                       $db = DatabaseBase::factory( $server['type'], $server );
-               } catch ( DBConnectionError $e ) {
-                       // FIXME: This is probably the ugliest thing I have ever done to
-                       // PHP. I'm half-expecting it to segfault, just out of disgust. -- TS
-                       $db = $e->db;
-               }
-
-               $db->setLBInfo( $server );
-               if ( isset( $server['fakeSlaveLag'] ) ) {
-                       $db->setFakeSlaveLag( $server['fakeSlaveLag'] );
-               }
-               if ( isset( $server['fakeMaster'] ) ) {
-                       $db->setFakeMaster( true );
-               }
-
-               return $db;
-       }
-
-       /**
-        * @throws DBConnectionError
-        * @return bool
-        */
-       private function reportConnectionError() {
-               $conn = $this->mErrorConnection; // The connection which caused the error
-               $context = array(
-                       'method' => __METHOD__,
-                       'last_error' => $this->mLastError,
-               );
-
-               if ( !is_object( $conn ) ) {
-                       // No last connection, probably due to all servers being too busy
-                       wfLogDBError(
-                               "LB failure with no last connection. Connection error: {last_error}",
-                               $context
-                       );
-
-                       // If all servers were busy, mLastError will contain something sensible
-                       throw new DBConnectionError( null, $this->mLastError );
-               } else {
-                       $context['db_server'] = $conn->getProperty( 'mServer' );
-                       wfLogDBError(
-                               "Connection error: {last_error} ({db_server})",
-                               $context
-                       );
-                       $conn->reportConnectionError( "{$this->mLastError} ({$context['db_server']})" ); // throws DBConnectionError
-               }
-
-               return false; /* not reached */
-       }
-
-       /**
-        * @return int
-        * @since 1.26
-        */
-       public function getWriterIndex() {
-               return 0;
-       }
-
-       /**
-        * Returns true if the specified index is a valid server index
-        *
-        * @param string $i
-        * @return bool
-        */
-       public function haveIndex( $i ) {
-               return array_key_exists( $i, $this->mServers );
-       }
-
-       /**
-        * Returns true if the specified index is valid and has non-zero load
-        *
-        * @param string $i
-        * @return bool
-        */
-       public function isNonZeroLoad( $i ) {
-               return array_key_exists( $i, $this->mServers ) && $this->mLoads[$i] != 0;
-       }
-
-       /**
-        * Get the number of defined servers (not the number of open connections)
-        *
-        * @return int
-        */
-       public function getServerCount() {
-               return count( $this->mServers );
-       }
-
-       /**
-        * Get the host name or IP address of the server with the specified index
-        * Prefer a readable name if available.
-        * @param string $i
-        * @return string
-        */
-       public function getServerName( $i ) {
-               if ( isset( $this->mServers[$i]['hostName'] ) ) {
-                       $name = $this->mServers[$i]['hostName'];
-               } elseif ( isset( $this->mServers[$i]['host'] ) ) {
-                       $name = $this->mServers[$i]['host'];
-               } else {
-                       $name = '';
-               }
-
-               return ( $name != '' ) ? $name : 'localhost';
-       }
-
-       /**
-        * Return the server info structure for a given index, or false if the index is invalid.
-        * @param int $i
-        * @return array|bool
-        */
-       public function getServerInfo( $i ) {
-               if ( isset( $this->mServers[$i] ) ) {
-                       return $this->mServers[$i];
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Sets the server info structure for the given index. Entry at index $i
-        * is created if it doesn't exist
-        * @param int $i
-        * @param array $serverInfo
-        */
-       public function setServerInfo( $i, array $serverInfo ) {
-               $this->mServers[$i] = $serverInfo;
-       }
-
-       /**
-        * Get the current master position for chronology control purposes
-        * @return mixed
-        */
-       public function getMasterPos() {
-               # If this entire request was served from a slave without opening a connection to the
-               # master (however unlikely that may be), then we can fetch the position from the slave.
-               $masterConn = $this->getAnyOpenConnection( 0 );
-               if ( !$masterConn ) {
-                       $serverCount = count( $this->mServers );
-                       for ( $i = 1; $i < $serverCount; $i++ ) {
-                               $conn = $this->getAnyOpenConnection( $i );
-                               if ( $conn ) {
-                                       wfDebug( "Master pos fetched from slave\n" );
-
-                                       return $conn->getSlavePos();
-                               }
-                       }
-               } else {
-                       wfDebug( "Master pos fetched from master\n" );
-
-                       return $masterConn->getMasterPos();
-               }
-
-               return false;
-       }
-
-       /**
-        * Close all open connections
-        */
-       public function closeAll() {
-               foreach ( $this->mConns as $conns2 ) {
-                       foreach ( $conns2 as $conns3 ) {
-                               /** @var DatabaseBase $conn */
-                               foreach ( $conns3 as $conn ) {
-                                       $conn->close();
-                               }
-                       }
-               }
-               $this->mConns = array(
-                       'local' => array(),
-                       'foreignFree' => array(),
-                       'foreignUsed' => array(),
-               );
-               $this->connsOpened = 0;
-       }
-
-       /**
-        * Close a connection
-        * Using this function makes sure the LoadBalancer knows the connection is closed.
-        * If you use $conn->close() directly, the load balancer won't update its state.
-        * @param DatabaseBase $conn
-        */
-       public function closeConnection( $conn ) {
-               $done = false;
-               foreach ( $this->mConns as $i1 => $conns2 ) {
-                       foreach ( $conns2 as $i2 => $conns3 ) {
-                               foreach ( $conns3 as $i3 => $candidateConn ) {
-                                       if ( $conn === $candidateConn ) {
-                                               $conn->close();
-                                               unset( $this->mConns[$i1][$i2][$i3] );
-                                               --$this->connsOpened;
-                                               $done = true;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               if ( !$done ) {
-                       $conn->close();
-               }
-       }
-
-       /**
-        * Commit transactions on all open connections
-        */
-       public function commitAll() {
-               foreach ( $this->mConns as $conns2 ) {
-                       foreach ( $conns2 as $conns3 ) {
-                               /** @var DatabaseBase[] $conns3 */
-                               foreach ( $conns3 as $conn ) {
-                                       if ( $conn->trxLevel() ) {
-                                               $conn->commit( __METHOD__, 'flush' );
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /**
-        *  Issue COMMIT only on master, only if queries were done on connection
-        */
-       public function commitMasterChanges() {
-               $masterIndex = $this->getWriterIndex();
-               foreach ( $this->mConns as $conns2 ) {
-                       if ( empty( $conns2[$masterIndex] ) ) {
-                               continue;
-                       }
-                       /** @var DatabaseBase $conn */
-                       foreach ( $conns2[$masterIndex] as $conn ) {
-                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
-                                       $conn->commit( __METHOD__, 'flush' );
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Issue ROLLBACK only on master, only if queries were done on connection
-        * @since 1.23
-        */
-       public function rollbackMasterChanges() {
-               $failedServers = array();
-
-               $masterIndex = $this->getWriterIndex();
-               foreach ( $this->mConns as $conns2 ) {
-                       if ( empty( $conns2[$masterIndex] ) ) {
-                               continue;
-                       }
-                       /** @var DatabaseBase $conn */
-                       foreach ( $conns2[$masterIndex] as $conn ) {
-                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
-                                       try {
-                                               $conn->rollback( __METHOD__, 'flush' );
-                                       } catch ( DBError $e ) {
-                                               MWExceptionHandler::logException( $e );
-                                               $failedServers[] = $conn->getServer();
-                                       }
-                               }
-                       }
-               }
-
-               if ( $failedServers ) {
-                       throw new DBExpectedError( null, "Rollback failed on server(s) " .
-                               implode( ', ', array_unique( $failedServers ) ) );
-               }
-       }
-
-       /**
-        * @return bool Whether a master connection is already open
-        * @since 1.24
-        */
-       public function hasMasterConnection() {
-               return $this->isOpen( $this->getWriterIndex() );
-       }
-
-       /**
-        * Determine if there are pending changes in a transaction by this thread
-        * @since 1.23
-        * @return bool
-        */
-       public function hasMasterChanges() {
-               $masterIndex = $this->getWriterIndex();
-               foreach ( $this->mConns as $conns2 ) {
-                       if ( empty( $conns2[$masterIndex] ) ) {
-                               continue;
-                       }
-                       /** @var DatabaseBase $conn */
-                       foreach ( $conns2[$masterIndex] as $conn ) {
-                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
-                                       return true;
-                               }
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Get the timestamp of the latest write query done by this thread
-        * @since 1.25
-        * @return float|bool UNIX timestamp or false
-        */
-       public function lastMasterChangeTimestamp() {
-               $lastTime = false;
-               $masterIndex = $this->getWriterIndex();
-               foreach ( $this->mConns as $conns2 ) {
-                       if ( empty( $conns2[$masterIndex] ) ) {
-                               continue;
-                       }
-                       /** @var DatabaseBase $conn */
-                       foreach ( $conns2[$masterIndex] as $conn ) {
-                               $lastTime = max( $lastTime, $conn->lastDoneWrites() );
-                       }
-               }
-               return $lastTime;
-       }
-
-       /**
-        * Check if this load balancer object had any recent or still
-        * pending writes issued against it by this PHP thread
-        *
-        * @param float $age How many seconds ago is "recent" [defaults to mWaitTimeout]
-        * @return bool
-        * @since 1.25
-        */
-       public function hasOrMadeRecentMasterChanges( $age = null ) {
-               $age = ( $age === null ) ? $this->mWaitTimeout : $age;
-
-               return ( $this->hasMasterChanges()
-                       || $this->lastMasterChangeTimestamp() > microtime( true ) - $age );
-       }
-
-       /**
-        * @param mixed $value
-        * @return mixed
-        */
-       public function waitTimeout( $value = null ) {
-               return wfSetVar( $this->mWaitTimeout, $value );
-       }
-
-       /**
-        * @return bool Whether the generic connection for reads is highly "lagged"
-        */
-       public function getLaggedSlaveMode() {
-               # Get a generic reader connection
-               $this->getConnection( DB_SLAVE );
-
-               return $this->mLaggedSlaveMode;
-       }
-
-       /**
-        * Disables/enables lag checks
-        * @param null|bool $mode
-        * @return bool
-        */
-       public function allowLagged( $mode = null ) {
-               if ( $mode === null ) {
-                       return $this->mAllowLagged;
-               }
-               $this->mAllowLagged = $mode;
-
-               return $this->mAllowLagged;
-       }
-
-       /**
-        * @return bool
-        */
-       public function pingAll() {
-               $success = true;
-               foreach ( $this->mConns as $conns2 ) {
-                       foreach ( $conns2 as $conns3 ) {
-                               /** @var DatabaseBase[] $conns3 */
-                               foreach ( $conns3 as $conn ) {
-                                       if ( !$conn->ping() ) {
-                                               $success = false;
-                                       }
-                               }
-                       }
-               }
-
-               return $success;
-       }
-
-       /**
-        * Call a function with each open connection object
-        * @param callable $callback
-        * @param array $params
-        */
-       public function forEachOpenConnection( $callback, array $params = array() ) {
-               foreach ( $this->mConns as $conns2 ) {
-                       foreach ( $conns2 as $conns3 ) {
-                               foreach ( $conns3 as $conn ) {
-                                       $mergedParams = array_merge( array( $conn ), $params );
-                                       call_user_func_array( $callback, $mergedParams );
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Get the hostname and lag time of the most-lagged slave
-        *
-        * This is useful for maintenance scripts that need to throttle their updates.
-        * May attempt to open connections to slaves on the default DB. If there is
-        * no lag, the maximum lag will be reported as -1.
-        *
-        * @param bool|string $wiki Wiki ID, or false for the default database
-        * @return array ( host, max lag, index of max lagged host )
-        */
-       public function getMaxLag( $wiki = false ) {
-               $maxLag = -1;
-               $host = '';
-               $maxIndex = 0;
-
-               if ( $this->getServerCount() <= 1 ) {
-                       return array( $host, $maxLag, $maxIndex ); // no replication = no lag
-               }
-
-               $lagTimes = $this->getLagTimes( $wiki );
-               foreach ( $lagTimes as $i => $lag ) {
-                       if ( $lag > $maxLag ) {
-                               $maxLag = $lag;
-                               $host = $this->mServers[$i]['host'];
-                               $maxIndex = $i;
-                       }
-               }
-
-               return array( $host, $maxLag, $maxIndex );
-       }
-
-       /**
-        * Get lag time for each server
-        *
-        * Results are cached for a short time in memcached/process cache
-        *
-        * @param string|bool $wiki
-        * @return int[] Map of (server index => seconds)
-        */
-       public function getLagTimes( $wiki = false ) {
-               if ( $this->getServerCount() <= 1 ) {
-                       return array( 0 => 0 ); // no replication = no lag
-               }
-
-               # Send the request to the load monitor
-               return $this->getLoadMonitor()->getLagTimes( array_keys( $this->mServers ), $wiki );
-       }
-
-       /**
-        * Get the lag in seconds for a given connection, or zero if this load
-        * balancer does not have replication enabled.
-        *
-        * This should be used in preference to Database::getLag() in cases where
-        * replication may not be in use, since there is no way to determine if
-        * replication is in use at the connection level without running
-        * potentially restricted queries such as SHOW SLAVE STATUS. Using this
-        * function instead of Database::getLag() avoids a fatal error in this
-        * case on many installations.
-        *
-        * @param DatabaseBase $conn
-        * @return int
-        */
-       public function safeGetLag( $conn ) {
-               if ( $this->getServerCount() == 1 ) {
-                       return 0;
-               } else {
-                       return $conn->getLag();
-               }
-       }
-
-       /**
-        * Clear the cache for slag lag delay times
-        *
-        * This is only used for testing
-        */
-       public function clearLagTimeCache() {
-               $this->getLoadMonitor()->clearCaches();
-       }
-}
diff --git a/includes/db/LoadMonitor.php b/includes/db/LoadMonitor.php
deleted file mode 100644 (file)
index 4975ea1..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * Database load monitoring.
- *
- * 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 Database
- */
-
-/**
- * An interface for database load monitoring
- *
- * @ingroup Database
- */
-interface LoadMonitor {
-       /**
-        * Construct a new LoadMonitor with a given LoadBalancer parent
-        *
-        * @param LoadBalancer $parent
-        */
-       public function __construct( $parent );
-
-       /**
-        * Perform pre-connection load ratio adjustment.
-        * @param array $loads
-        * @param string|bool $group The selected query group. Default: false
-        * @param string|bool $wiki Default: false
-        */
-       public function scaleLoads( &$loads, $group = false, $wiki = false );
-
-       /**
-        * Return an estimate of replication lag for each server
-        *
-        * @param array $serverIndexes
-        * @param string $wiki
-        *
-        * @return array Map of (server index => seconds)
-        */
-       public function getLagTimes( $serverIndexes, $wiki );
-}
-
-class LoadMonitorNull implements LoadMonitor {
-       public function __construct( $parent ) {
-       }
-
-       public function scaleLoads( &$loads, $group = false, $wiki = false ) {
-       }
-
-       public function getLagTimes( $serverIndexes, $wiki ) {
-               return array_fill_keys( $serverIndexes, 0 );
-       }
-}
diff --git a/includes/db/LoadMonitorMySQL.php b/includes/db/LoadMonitorMySQL.php
deleted file mode 100644 (file)
index 3008419..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-<?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
- * @ingroup Database
- */
-
-/**
- * Basic MySQL load monitor with no external dependencies
- * Uses memcached to cache the replication lag for a short time
- *
- * @ingroup Database
- */
-class LoadMonitorMySQL implements LoadMonitor {
-       /** @var LoadBalancer */
-       public $parent;
-       /** @var BagOStuff */
-       protected $srvCache;
-       /** @var BagOStuff */
-       protected $mainCache;
-
-       public function __construct( $parent ) {
-               $this->parent = $parent;
-
-               $this->srvCache = ObjectCache::newAccelerator( 'hash' );
-               $this->mainCache = wfGetMainCache();
-       }
-
-       public function scaleLoads( &$loads, $group = false, $wiki = false ) {
-       }
-
-       public function getLagTimes( $serverIndexes, $wiki ) {
-               if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
-                       # Single server only, just return zero without caching
-                       return array( 0 => 0 );
-               }
-
-               $key = $this->getLagTimeCacheKey();
-               # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
-               $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
-               # Keep keys around longer as fallbacks
-               $staleTTL = 60;
-
-               # (a) Check the local APC cache
-               $value = $this->srvCache->get( $key );
-               if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
-                       wfDebugLog( 'replication',  __FUNCTION__ . ": got lag times ($key) from local cache" );
-                       return $value['lagTimes']; // cache hit
-               }
-               $staleValue = $value ?: false;
-
-               # (b) Check the shared cache and backfill APC
-               $value = $this->mainCache->get( $key );
-               if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
-                       $this->srvCache->set( $key, $value, $staleTTL );
-                       wfDebugLog( 'replication',  __FUNCTION__ . ": got lag times ($key) from main cache" );
-
-                       return $value['lagTimes']; // cache hit
-               }
-               $staleValue = $value ?: $staleValue;
-
-               # (c) Cache key missing or expired; regenerate and backfill
-               if ( $this->mainCache->lock( $key, 0, 10 ) ) {
-                       # Let this process alone update the cache value
-                       $cache = $this->mainCache;
-                       /** @noinspection PhpUnusedLocalVariableInspection */
-                       $unlocker = new ScopedCallback( function () use ( $cache, $key ) {
-                               $cache->unlock( $key );
-                       } );
-               } elseif ( $staleValue ) {
-                       # Could not acquire lock but an old cache exists, so use it
-                       return $staleValue['lagTimes'];
-               }
-
-               $lagTimes = array();
-               foreach ( $serverIndexes as $i ) {
-                       if ( $i == 0 ) { # Master
-                               $lagTimes[$i] = 0;
-                       } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
-                               $lagTimes[$i] = $conn->getLag();
-                       } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
-                               $lagTimes[$i] = $conn->getLag();
-                               # Close the connection to avoid sleeper connections piling up.
-                               # Note that the caller will pick one of these DBs and reconnect,
-                               # which is slightly inefficient, but this only matters for the lag
-                               # time cache miss cache, which is far less common that cache hits.
-                               $this->parent->closeConnection( $conn );
-                       }
-               }
-
-               # Add a timestamp key so we know when it was cached
-               $value = array( 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) );
-               $this->mainCache->set( $key, $value, $staleTTL );
-               $this->srvCache->set( $key, $value, $staleTTL );
-               wfDebugLog( 'replication',  __FUNCTION__ . ": re-calculated lag times ($key)" );
-
-               return $value['lagTimes'];
-       }
-
-       public function clearCaches() {
-               $key = $this->getLagTimeCacheKey();
-               $this->srvCache->delete( $key );
-               $this->mainCache->delete( $key );
-       }
-
-       private function getLagTimeCacheKey() {
-               # Lag is per-server, not per-DB, so key on the master DB name
-               return wfGlobalCacheKey( 'lag-times', $this->parent->getServerName( 0 ) );
-       }
-}
diff --git a/includes/db/loadbalancer/LBFactory.php b/includes/db/loadbalancer/LBFactory.php
new file mode 100644 (file)
index 0000000..da0fe44
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+/**
+ * Generator of database load balancing objects.
+ *
+ * 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 Database
+ */
+
+/**
+ * An interface for generating database load balancers
+ * @ingroup Database
+ */
+abstract class LBFactory {
+       /** @var LBFactory */
+       private static $instance;
+
+       /**
+        * Disables all access to the load balancer, will cause all database access
+        * to throw a DBAccessError
+        */
+       public static function disableBackend() {
+               global $wgLBFactoryConf;
+               self::$instance = new LBFactoryFake( $wgLBFactoryConf );
+       }
+
+       /**
+        * Get an LBFactory instance
+        *
+        * @return LBFactory
+        */
+       public static function singleton() {
+               global $wgLBFactoryConf;
+
+               if ( is_null( self::$instance ) ) {
+                       $class = self::getLBFactoryClass( $wgLBFactoryConf );
+
+                       self::$instance = new $class( $wgLBFactoryConf );
+               }
+
+               return self::$instance;
+       }
+
+       /**
+        * Returns the LBFactory class to use and the load balancer configuration.
+        *
+        * @param array $config (e.g. $wgLBFactoryConf)
+        * @return string Class name
+        */
+       public static function getLBFactoryClass( array $config ) {
+               // For configuration backward compatibility after removing
+               // underscores from class names in MediaWiki 1.23.
+               $bcClasses = array(
+                       'LBFactory_Simple' => 'LBFactorySimple',
+                       'LBFactory_Single' => 'LBFactorySingle',
+                       'LBFactory_Multi' => 'LBFactoryMulti',
+                       'LBFactory_Fake' => 'LBFactoryFake',
+               );
+
+               $class = $config['class'];
+
+               if ( isset( $bcClasses[$class] ) ) {
+                       $class = $bcClasses[$class];
+                       wfDeprecated(
+                               '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
+                               '1.23'
+                       );
+               }
+
+               return $class;
+       }
+
+       /**
+        * Shut down, close connections and destroy the cached instance.
+        */
+       public static function destroyInstance() {
+               if ( self::$instance ) {
+                       self::$instance->shutdown();
+                       self::$instance->forEachLBCallMethod( 'closeAll' );
+                       self::$instance = null;
+               }
+       }
+
+       /**
+        * Set the instance to be the given object
+        *
+        * @param LBFactory $instance
+        */
+       public static function setInstance( $instance ) {
+               self::destroyInstance();
+               self::$instance = $instance;
+       }
+
+       /**
+        * Construct a factory based on a configuration array (typically from $wgLBFactoryConf)
+        * @param array $conf
+        */
+       abstract public function __construct( array $conf );
+
+       /**
+        * Create a new load balancer object. The resulting object will be untracked,
+        * not chronology-protected, and the caller is responsible for cleaning it up.
+        *
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancer
+        */
+       abstract public function newMainLB( $wiki = false );
+
+       /**
+        * Get a cached (tracked) load balancer object.
+        *
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancer
+        */
+       abstract public function getMainLB( $wiki = false );
+
+       /**
+        * Create a new load balancer for external storage. The resulting object will be
+        * untracked, not chronology-protected, and the caller is responsible for
+        * cleaning it up.
+        *
+        * @param string $cluster External storage cluster, or false for core
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancer
+        */
+       abstract protected function newExternalLB( $cluster, $wiki = false );
+
+       /**
+        * Get a cached (tracked) load balancer for external storage
+        *
+        * @param string $cluster External storage cluster, or false for core
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancer
+        */
+       abstract public function &getExternalLB( $cluster, $wiki = false );
+
+       /**
+        * Execute a function for each tracked load balancer
+        * The callback is called with the load balancer as the first parameter,
+        * and $params passed as the subsequent parameters.
+        *
+        * @param callable $callback
+        * @param array $params
+        */
+       abstract public function forEachLB( $callback, array $params = array() );
+
+       /**
+        * Prepare all tracked load balancers for shutdown
+        * STUB
+        */
+       public function shutdown() {
+       }
+
+       /**
+        * Call a method of each tracked load balancer
+        *
+        * @param string $methodName
+        * @param array $args
+        */
+       private function forEachLBCallMethod( $methodName, array $args = array() ) {
+               $this->forEachLB( function ( LoadBalancer $loadBalancer, $methodName, array $args ) {
+                       call_user_func_array( array( $loadBalancer, $methodName ), $args );
+               }, array( $methodName, $args ) );
+       }
+
+       /**
+        * Commit on all connections. Done for two reasons:
+        * 1. To commit changes to the masters.
+        * 2. To release the snapshot on all connections, master and slave.
+        */
+       public function commitAll() {
+               $this->forEachLBCallMethod( 'commitAll' );
+       }
+
+       /**
+        * Commit changes on all master connections
+        */
+       public function commitMasterChanges() {
+               $this->forEachLBCallMethod( 'commitMasterChanges' );
+       }
+
+       /**
+        * Rollback changes on all master connections
+        * @since 1.23
+        */
+       public function rollbackMasterChanges() {
+               $this->forEachLBCallMethod( 'rollbackMasterChanges' );
+       }
+
+       /**
+        * Detemine if any master connection has pending changes.
+        * @since 1.23
+        * @return bool
+        */
+       public function hasMasterChanges() {
+               $ret = false;
+               $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) {
+                       $ret = $ret || $lb->hasMasterChanges();
+               } );
+               return $ret;
+       }
+}
+
+/**
+ * Exception class for attempted DB access
+ */
+class DBAccessError extends MWException {
+       public function __construct() {
+               parent::__construct( "Mediawiki tried to access the database via wfGetDB(). " .
+                       "This is not allowed." );
+       }
+}
diff --git a/includes/db/loadbalancer/LBFactoryFake.php b/includes/db/loadbalancer/LBFactoryFake.php
new file mode 100644 (file)
index 0000000..d8becf5
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Generator of database load balancing objects.
+ *
+ * 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 Database
+ */
+
+/**
+ * LBFactory class that throws an error on any attempt to use it.
+ * This will typically be done via wfGetDB().
+ * Call LBFactory::disableBackend() to start using this, and
+ * LBFactory::enableBackend() to return to normal behavior
+ */
+class LBFactoryFake extends LBFactory {
+       public function __construct( array $conf ) {
+       }
+
+       public function newMainLB( $wiki = false ) {
+               throw new DBAccessError;
+       }
+
+       public function getMainLB( $wiki = false ) {
+               throw new DBAccessError;
+       }
+
+       protected function newExternalLB( $cluster, $wiki = false ) {
+               throw new DBAccessError;
+       }
+
+       public function &getExternalLB( $cluster, $wiki = false ) {
+               throw new DBAccessError;
+       }
+
+       public function forEachLB( $callback, array $params = array() ) {
+       }
+}
diff --git a/includes/db/loadbalancer/LBFactoryMulti.php b/includes/db/loadbalancer/LBFactoryMulti.php
new file mode 100644 (file)
index 0000000..92fbccd
--- /dev/null
@@ -0,0 +1,399 @@
+<?php
+/**
+ * Advanced generator of database load balancing objects for wiki farms.
+ *
+ * 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 Database
+ */
+
+/**
+ * A multi-wiki, multi-master factory for Wikimedia and similar installations.
+ * Ignores the old configuration globals
+ *
+ * Configuration:
+ *     sectionsByDB                A map of database names to section names.
+ *
+ *     sectionLoads                A 2-d map. For each section, gives a map of server names to
+ *                                 load ratios. For example:
+ *                                 array(
+ *                                     'section1' => array(
+ *                                         '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(
+ *                                             'db1' => 100,
+ *                                             'db2' => 100
+ *                                         )
+ *                                     )
+ *                                 )
+ *
+ *     groupLoadsByDB              A 3-d map giving server load ratios by DB name.
+ *
+ *     hostsByName                 A map of hostname to IP address.
+ *
+ *     externalLoads               A map of external storage cluster name to server load map.
+ *
+ *     externalTemplateOverrides   A set of server info keys overriding serverTemplate for external
+ *                                 storage.
+ *
+ *     templateOverridesByServer   A 2-d map overriding serverTemplate and
+ *                                 externalTemplateOverrides on a server-by-server basis. Applies
+ *                                 to both core and external storage.
+ *
+ *     templateOverridesByCluster  A 2-d map overriding the server info by external storage cluster.
+ *
+ *     masterTemplateOverrides     An override array for all master servers.
+ *
+ *     readOnlyBySection           A map of section name to read-only message.
+ *                                 Missing or false for read/write.
+ *
+ * @ingroup Database
+ */
+class LBFactoryMulti extends LBFactory {
+       // Required settings
+
+       /** @var array A map of database names to section names */
+       private $sectionsByDB;
+
+       /**
+        * @var array A 2-d map. For each section, gives a map of server names to
+        * load ratios
+        */
+       private $sectionLoads;
+
+       /**
+        * @var array A server info associative array as documented for
+        * $wgDBservers. The host, hostName and load entries will be
+        * overridden
+        */
+       private $serverTemplate;
+
+       // Optional settings
+
+       /** @var array A 3-d map giving server load ratios for each section and group */
+       private $groupLoadsBySection = array();
+
+       /** @var array A 3-d map giving server load ratios by DB name */
+       private $groupLoadsByDB = array();
+
+       /** @var array A map of hostname to IP address */
+       private $hostsByName = array();
+
+       /** @var array A map of external storage cluster name to server load map */
+       private $externalLoads = array();
+
+       /**
+        * @var array A set of server info keys overriding serverTemplate for
+        * external storage
+        */
+       private $externalTemplateOverrides;
+
+       /**
+        * @var array A 2-d map overriding serverTemplate and
+        * externalTemplateOverrides on a server-by-server basis. Applies to both
+        * core and external storage
+        */
+       private $templateOverridesByServer;
+
+       /** @var array A 2-d map overriding the server info by external storage cluster */
+       private $templateOverridesByCluster;
+
+       /** @var array An override array for all master servers */
+       private $masterTemplateOverrides;
+
+       /**
+        * @var array|bool A map of section name to read-only message. Missing or
+        * false for read/write
+        */
+       private $readOnlyBySection = array();
+
+       // Other stuff
+
+       /** @var array Load balancer factory configuration */
+       private $conf;
+
+       /** @var LoadBalancer[] */
+       private $mainLBs = array();
+
+       /** @var LoadBalancer[] */
+       private $extLBs = array();
+
+       /** @var string */
+       private $lastWiki;
+
+       /** @var string */
+       private $lastSection;
+
+       /**
+        * @param array $conf
+        * @throws MWException
+        */
+       public function __construct( array $conf ) {
+               $this->chronProt = new ChronologyProtector;
+               $this->conf = $conf;
+               $required = array( 'sectionsByDB', 'sectionLoads', 'serverTemplate' );
+               $optional = array( 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName',
+                       'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer',
+                       'templateOverridesByCluster', 'masterTemplateOverrides',
+                       'readOnlyBySection' );
+
+               foreach ( $required as $key ) {
+                       if ( !isset( $conf[$key] ) ) {
+                               throw new MWException( __CLASS__ . ": $key is required in configuration" );
+                       }
+                       $this->$key = $conf[$key];
+               }
+
+               foreach ( $optional as $key ) {
+                       if ( isset( $conf[$key] ) ) {
+                               $this->$key = $conf[$key];
+                       }
+               }
+
+               // Check for read-only mode
+               $section = $this->getSectionForWiki();
+               if ( !empty( $this->readOnlyBySection[$section] ) ) {
+                       global $wgReadOnly;
+                       $wgReadOnly = $this->readOnlyBySection[$section];
+               }
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return string
+        */
+       private function getSectionForWiki( $wiki = false ) {
+               if ( $this->lastWiki === $wiki ) {
+                       return $this->lastSection;
+               }
+               list( $dbName, ) = $this->getDBNameAndPrefix( $wiki );
+               if ( isset( $this->sectionsByDB[$dbName] ) ) {
+                       $section = $this->sectionsByDB[$dbName];
+               } else {
+                       $section = 'DEFAULT';
+               }
+               $this->lastSection = $section;
+               $this->lastWiki = $wiki;
+
+               return $section;
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancer
+        */
+       public function newMainLB( $wiki = false ) {
+               list( $dbName, ) = $this->getDBNameAndPrefix( $wiki );
+               $section = $this->getSectionForWiki( $wiki );
+               $groupLoads = array();
+               if ( isset( $this->groupLoadsByDB[$dbName] ) ) {
+                       $groupLoads = $this->groupLoadsByDB[$dbName];
+               }
+
+               if ( isset( $this->groupLoadsBySection[$section] ) ) {
+                       $groupLoads = array_merge_recursive( $groupLoads, $this->groupLoadsBySection[$section] );
+               }
+
+               return $this->newLoadBalancer(
+                       $this->serverTemplate,
+                       $this->sectionLoads[$section],
+                       $groupLoads
+               );
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancer
+        */
+       public function getMainLB( $wiki = false ) {
+               $section = $this->getSectionForWiki( $wiki );
+               if ( !isset( $this->mainLBs[$section] ) ) {
+                       $lb = $this->newMainLB( $wiki );
+                       $lb->parentInfo( array( 'id' => "main-$section" ) );
+                       $this->chronProt->initLB( $lb );
+                       $this->mainLBs[$section] = $lb;
+               }
+
+               return $this->mainLBs[$section];
+       }
+
+       /**
+        * @param string $cluster
+        * @param bool|string $wiki
+        * @throws MWException
+        * @return LoadBalancer
+        */
+       protected function newExternalLB( $cluster, $wiki = false ) {
+               if ( !isset( $this->externalLoads[$cluster] ) ) {
+                       throw new MWException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
+               }
+               $template = $this->serverTemplate;
+               if ( isset( $this->externalTemplateOverrides ) ) {
+                       $template = $this->externalTemplateOverrides + $template;
+               }
+               if ( isset( $this->templateOverridesByCluster[$cluster] ) ) {
+                       $template = $this->templateOverridesByCluster[$cluster] + $template;
+               }
+
+               return $this->newLoadBalancer( $template, $this->externalLoads[$cluster], array() );
+       }
+
+       /**
+        * @param string $cluster External storage cluster, or false for core
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancer
+        */
+       public function &getExternalLB( $cluster, $wiki = false ) {
+               if ( !isset( $this->extLBs[$cluster] ) ) {
+                       $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
+                       $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) );
+                       $this->chronProt->initLB( $this->extLBs[$cluster] );
+               }
+
+               return $this->extLBs[$cluster];
+       }
+
+       /**
+        * Make a new load balancer object based on template and load array
+        *
+        * @param array $template
+        * @param array $loads
+        * @param array $groupLoads
+        * @return LoadBalancer
+        */
+       private function newLoadBalancer( $template, $loads, $groupLoads ) {
+               $servers = $this->makeServerArray( $template, $loads, $groupLoads );
+               $lb = new LoadBalancer( array(
+                       'servers' => $servers,
+               ) );
+
+               return $lb;
+       }
+
+       /**
+        * Make a server array as expected by LoadBalancer::__construct, using a template and load array
+        *
+        * @param array $template
+        * @param array $loads
+        * @param array $groupLoads
+        * @return array
+        */
+       private function makeServerArray( $template, $loads, $groupLoads ) {
+               $servers = array();
+               $master = true;
+               $groupLoadsByServer = $this->reindexGroupLoads( $groupLoads );
+               foreach ( $groupLoadsByServer as $server => $stuff ) {
+                       if ( !isset( $loads[$server] ) ) {
+                               $loads[$server] = 0;
+                       }
+               }
+               foreach ( $loads as $serverName => $load ) {
+                       $serverInfo = $template;
+                       if ( $master ) {
+                               $serverInfo['master'] = true;
+                               if ( isset( $this->masterTemplateOverrides ) ) {
+                                       $serverInfo = $this->masterTemplateOverrides + $serverInfo;
+                               }
+                               $master = false;
+                       }
+                       if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
+                               $serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
+                       }
+                       if ( isset( $groupLoadsByServer[$serverName] ) ) {
+                               $serverInfo['groupLoads'] = $groupLoadsByServer[$serverName];
+                       }
+                       if ( isset( $this->hostsByName[$serverName] ) ) {
+                               $serverInfo['host'] = $this->hostsByName[$serverName];
+                       } else {
+                               $serverInfo['host'] = $serverName;
+                       }
+                       $serverInfo['hostName'] = $serverName;
+                       $serverInfo['load'] = $load;
+                       $servers[] = $serverInfo;
+               }
+
+               return $servers;
+       }
+
+       /**
+        * Take a group load array indexed by group then server, and reindex it by server then group
+        * @param array $groupLoads
+        * @return array
+        */
+       private function reindexGroupLoads( $groupLoads ) {
+               $reindexed = array();
+               foreach ( $groupLoads as $group => $loads ) {
+                       foreach ( $loads as $server => $load ) {
+                               $reindexed[$server][$group] = $load;
+                       }
+               }
+
+               return $reindexed;
+       }
+
+       /**
+        * Get the database name and prefix based on the wiki ID
+        * @param bool|string $wiki
+        * @return array
+        */
+       private function getDBNameAndPrefix( $wiki = false ) {
+               if ( $wiki === false ) {
+                       global $wgDBname, $wgDBprefix;
+
+                       return array( $wgDBname, $wgDBprefix );
+               } else {
+                       return wfSplitWikiID( $wiki );
+               }
+       }
+
+       /**
+        * Execute a function for each tracked load balancer
+        * The callback is called with the load balancer as the first parameter,
+        * and $params passed as the subsequent parameters.
+        * @param callable $callback
+        * @param array $params
+        */
+       public function forEachLB( $callback, array $params = array() ) {
+               foreach ( $this->mainLBs as $lb ) {
+                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
+               }
+               foreach ( $this->extLBs as $lb ) {
+                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
+               }
+       }
+
+       public function shutdown() {
+               foreach ( $this->mainLBs as $lb ) {
+                       $this->chronProt->shutdownLB( $lb );
+               }
+               foreach ( $this->extLBs as $extLB ) {
+                       $this->chronProt->shutdownLB( $extLB );
+               }
+               $this->chronProt->shutdown();
+               $this->commitMasterChanges();
+       }
+}
diff --git a/includes/db/loadbalancer/LBFactorySimple.php b/includes/db/loadbalancer/LBFactorySimple.php
new file mode 100644 (file)
index 0000000..23cdbc6
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+/**
+ * Generator of database load balancing objects.
+ *
+ * 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 Database
+ */
+
+/**
+ * A simple single-master LBFactory that gets its configuration from the b/c globals
+ */
+class LBFactorySimple extends LBFactory {
+       /** @var LoadBalancer */
+       private $mainLB;
+
+       /** @var LoadBalancer[] */
+       private $extLBs = array();
+
+       /** @var ChronologyProtector */
+       private $chronProt;
+
+       public function __construct( array $conf ) {
+               $this->chronProt = new ChronologyProtector;
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancer
+        */
+       public function newMainLB( $wiki = false ) {
+               global $wgDBservers;
+               if ( $wgDBservers ) {
+                       $servers = $wgDBservers;
+               } else {
+                       global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype, $wgDebugDumpSql;
+                       global $wgDBssl, $wgDBcompress;
+
+                       $flags = DBO_DEFAULT;
+                       if ( $wgDebugDumpSql ) {
+                               $flags |= DBO_DEBUG;
+                       }
+                       if ( $wgDBssl ) {
+                               $flags |= DBO_SSL;
+                       }
+                       if ( $wgDBcompress ) {
+                               $flags |= DBO_COMPRESS;
+                       }
+
+                       $servers = array( array(
+                               'host' => $wgDBserver,
+                               'user' => $wgDBuser,
+                               'password' => $wgDBpassword,
+                               'dbname' => $wgDBname,
+                               'type' => $wgDBtype,
+                               'load' => 1,
+                               'flags' => $flags
+                       ) );
+               }
+
+               return new LoadBalancer( array(
+                       'servers' => $servers,
+               ) );
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancer
+        */
+       public function getMainLB( $wiki = false ) {
+               if ( !isset( $this->mainLB ) ) {
+                       $this->mainLB = $this->newMainLB( $wiki );
+                       $this->mainLB->parentInfo( array( 'id' => 'main' ) );
+                       $this->chronProt->initLB( $this->mainLB );
+               }
+
+               return $this->mainLB;
+       }
+
+       /**
+        * @throws MWException
+        * @param string $cluster
+        * @param bool|string $wiki
+        * @return LoadBalancer
+        */
+       protected function newExternalLB( $cluster, $wiki = false ) {
+               global $wgExternalServers;
+               if ( !isset( $wgExternalServers[$cluster] ) ) {
+                       throw new MWException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
+               }
+
+               return new LoadBalancer( array(
+                       'servers' => $wgExternalServers[$cluster]
+               ) );
+       }
+
+       /**
+        * @param string $cluster
+        * @param bool|string $wiki
+        * @return array
+        */
+       public function &getExternalLB( $cluster, $wiki = false ) {
+               if ( !isset( $this->extLBs[$cluster] ) ) {
+                       $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
+                       $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) );
+                       $this->chronProt->initLB( $this->extLBs[$cluster] );
+               }
+
+               return $this->extLBs[$cluster];
+       }
+
+       /**
+        * Execute a function for each tracked load balancer
+        * The callback is called with the load balancer as the first parameter,
+        * and $params passed as the subsequent parameters.
+        *
+        * @param callable $callback
+        * @param array $params
+        */
+       public function forEachLB( $callback, array $params = array() ) {
+               if ( isset( $this->mainLB ) ) {
+                       call_user_func_array( $callback, array_merge( array( $this->mainLB ), $params ) );
+               }
+               foreach ( $this->extLBs as $lb ) {
+                       call_user_func_array( $callback, array_merge( array( $lb ), $params ) );
+               }
+       }
+
+       public function shutdown() {
+               if ( $this->mainLB ) {
+                       $this->chronProt->shutdownLB( $this->mainLB );
+               }
+               foreach ( $this->extLBs as $extLB ) {
+                       $this->chronProt->shutdownLB( $extLB );
+               }
+               $this->chronProt->shutdown();
+               $this->commitMasterChanges();
+       }
+}
diff --git a/includes/db/loadbalancer/LBFactorySingle.php b/includes/db/loadbalancer/LBFactorySingle.php
new file mode 100644 (file)
index 0000000..a41dadf
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Simple generator of database connections that always returns the same object.
+ *
+ * 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 Database
+ */
+
+/**
+ * An LBFactory class that always returns a single database object.
+ */
+class LBFactorySingle extends LBFactory {
+       /** @var LoadBalancerSingle */
+       private $lb;
+
+       /**
+        * @param array $conf An associative array with one member:
+        *  - connection: The DatabaseBase connection object
+        */
+       public function __construct( array $conf ) {
+               $this->lb = new LoadBalancerSingle( $conf );
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancerSingle
+        */
+       public function newMainLB( $wiki = false ) {
+               return $this->lb;
+       }
+
+       /**
+        * @param bool|string $wiki
+        * @return LoadBalancerSingle
+        */
+       public function getMainLB( $wiki = false ) {
+               return $this->lb;
+       }
+
+       /**
+        * @param string $cluster External storage cluster, or false for core
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancerSingle
+        */
+       protected function newExternalLB( $cluster, $wiki = false ) {
+               return $this->lb;
+       }
+
+       /**
+        * @param string $cluster External storage cluster, or false for core
+        * @param bool|string $wiki Wiki ID, or false for the current wiki
+        * @return LoadBalancerSingle
+        */
+       public function &getExternalLB( $cluster, $wiki = false ) {
+               return $this->lb;
+       }
+
+       /**
+        * @param string|callable $callback
+        * @param array $params
+        */
+       public function forEachLB( $callback, array $params = array() ) {
+               call_user_func_array( $callback, array_merge( array( $this->lb ), $params ) );
+       }
+}
+
+/**
+ * Helper class for LBFactorySingle.
+ */
+class LoadBalancerSingle extends LoadBalancer {
+       /** @var DatabaseBase */
+       private $db;
+
+       /**
+        * @param array $params
+        */
+       public function __construct( array $params ) {
+               $this->db = $params['connection'];
+               parent::__construct( array( 'servers' => array( array(
+                       'type' => $this->db->getType(),
+                       'host' => $this->db->getServer(),
+                       'dbname' => $this->db->getDBname(),
+                       'load' => 1,
+               ) ) ) );
+       }
+
+       /**
+        *
+        * @param string $server
+        * @param bool $dbNameOverride
+        *
+        * @return DatabaseBase
+        */
+       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
+               return $this->db;
+       }
+}
diff --git a/includes/db/loadbalancer/LoadBalancer.php b/includes/db/loadbalancer/LoadBalancer.php
new file mode 100644 (file)
index 0000000..e794fa0
--- /dev/null
@@ -0,0 +1,1275 @@
+<?php
+/**
+ * Database load balancing.
+ *
+ * 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 Database
+ */
+
+/**
+ * Database load balancing object
+ *
+ * @todo document
+ * @ingroup Database
+ */
+class LoadBalancer {
+       /** @var array[] Map of (server index => server config array) */
+       private $mServers;
+       /** @var array[] Map of (local/foreignUsed/foreignFree => server index => DatabaseBase array) */
+       private $mConns;
+       /** @var array Map of (server index => weight) */
+       private $mLoads;
+       /** @var array[] Map of (group => server index => weight) */
+       private $mGroupLoads;
+       /** @var bool Whether to disregard slave lag as a factor in slave selection */
+       private $mAllowLagged;
+       /** @var integer Seconds to spend waiting on slave lag to resolve */
+       private $mWaitTimeout;
+
+       /** @var array LBFactory information */
+       private $mParentInfo;
+       /** @var string The LoadMonitor subclass name */
+       private $mLoadMonitorClass;
+       /** @var LoadMonitor */
+       private $mLoadMonitor;
+
+       /** @var bool|DatabaseBase Database connection that caused a problem */
+       private $mErrorConnection;
+       /** @var integer The generic (not query grouped) slave index (of $mServers) */
+       private $mReadIndex;
+       /** @var bool|DBMasterPos False if not set */
+       private $mWaitForPos;
+       /** @var bool Whether the generic reader fell back to a lagged slave */
+       private $mLaggedSlaveMode;
+       /** @var string The last DB selection or connection error */
+       private $mLastError = 'Unknown error';
+       /** @var integer Total connections opened */
+       private $connsOpened = 0;
+
+       /** @var integer Warn when this many connection are held */
+       const CONN_HELD_WARN_THRESHOLD = 10;
+
+       /**
+        * @param array $params Array with keys:
+        *   servers           Required. Array of server info structures.
+        *   loadMonitor       Name of a class used to fetch server lag and load.
+        * @throws MWException
+        */
+       public function __construct( array $params ) {
+               if ( !isset( $params['servers'] ) ) {
+                       throw new MWException( __CLASS__ . ': missing servers parameter' );
+               }
+               $this->mServers = $params['servers'];
+               $this->mWaitTimeout = 10;
+
+               $this->mReadIndex = -1;
+               $this->mWriteIndex = -1;
+               $this->mConns = array(
+                       'local' => array(),
+                       'foreignUsed' => array(),
+                       'foreignFree' => array() );
+               $this->mLoads = array();
+               $this->mWaitForPos = false;
+               $this->mLaggedSlaveMode = false;
+               $this->mErrorConnection = false;
+               $this->mAllowLagged = false;
+
+               if ( isset( $params['loadMonitor'] ) ) {
+                       $this->mLoadMonitorClass = $params['loadMonitor'];
+               } else {
+                       $master = reset( $params['servers'] );
+                       if ( isset( $master['type'] ) && $master['type'] === 'mysql' ) {
+                               $this->mLoadMonitorClass = 'LoadMonitorMySQL';
+                       } else {
+                               $this->mLoadMonitorClass = 'LoadMonitorNull';
+                       }
+               }
+
+               foreach ( $params['servers'] as $i => $server ) {
+                       $this->mLoads[$i] = $server['load'];
+                       if ( isset( $server['groupLoads'] ) ) {
+                               foreach ( $server['groupLoads'] as $group => $ratio ) {
+                                       if ( !isset( $this->mGroupLoads[$group] ) ) {
+                                               $this->mGroupLoads[$group] = array();
+                                       }
+                                       $this->mGroupLoads[$group][$i] = $ratio;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Get a LoadMonitor instance
+        *
+        * @return LoadMonitor
+        */
+       private function getLoadMonitor() {
+               if ( !isset( $this->mLoadMonitor ) ) {
+                       $class = $this->mLoadMonitorClass;
+                       $this->mLoadMonitor = new $class( $this );
+               }
+
+               return $this->mLoadMonitor;
+       }
+
+       /**
+        * Get or set arbitrary data used by the parent object, usually an LBFactory
+        * @param mixed $x
+        * @return mixed
+        */
+       public function parentInfo( $x = null ) {
+               return wfSetVar( $this->mParentInfo, $x );
+       }
+
+       /**
+        * Given an array of non-normalised probabilities, this function will select
+        * an element and return the appropriate key
+        *
+        * @deprecated since 1.21, use ArrayUtils::pickRandom()
+        *
+        * @param array $weights
+        * @return bool|int|string
+        */
+       public function pickRandom( array $weights ) {
+               return ArrayUtils::pickRandom( $weights );
+       }
+
+       /**
+        * @param array $loads
+        * @param bool|string $wiki Wiki to get non-lagged for
+        * @param float $maxLag Restrict the maximum allowed lag to this many seconds
+        * @return bool|int|string
+        */
+       private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
+               $lags = $this->getLagTimes( $wiki );
+
+               # Unset excessively lagged servers
+               foreach ( $lags as $i => $lag ) {
+                       if ( $i != 0 ) {
+                               $maxServerLag = $maxLag;
+                               if ( isset( $this->mServers[$i]['max lag'] ) ) {
+                                       $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
+                               }
+                               if ( $lag === false ) {
+                                       wfDebugLog( 'replication', "Server #$i is not replicating" );
+                                       unset( $loads[$i] );
+                               } elseif ( $lag > $maxServerLag ) {
+                                       wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" );
+                                       unset( $loads[$i] );
+                               }
+                       }
+               }
+
+               # Find out if all the slaves with non-zero load are lagged
+               $sum = 0;
+               foreach ( $loads as $load ) {
+                       $sum += $load;
+               }
+               if ( $sum == 0 ) {
+                       # No appropriate DB servers except maybe the master and some slaves with zero load
+                       # Do NOT use the master
+                       # Instead, this function will return false, triggering read-only mode,
+                       # and a lagged slave will be used instead.
+                       return false;
+               }
+
+               if ( count( $loads ) == 0 ) {
+                       return false;
+               }
+
+               # wfDebugLog( 'connect', var_export( $loads, true ) );
+
+               # Return a random representative of the remainder
+               return ArrayUtils::pickRandom( $loads );
+       }
+
+       /**
+        * Get the index of the reader connection, which may be a slave
+        * This takes into account load ratios and lag times. It should
+        * always return a consistent index during a given invocation
+        *
+        * Side effect: opens connections to databases
+        * @param string|bool $group Query group, or false for the generic reader
+        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @throws MWException
+        * @return bool|int|string
+        */
+       public function getReaderIndex( $group = false, $wiki = false ) {
+               global $wgDBtype;
+
+               # @todo FIXME: For now, only go through all this for mysql databases
+               if ( $wgDBtype != 'mysql' ) {
+                       return $this->getWriterIndex();
+               }
+
+               if ( count( $this->mServers ) == 1 ) {
+                       # Skip the load balancing if there's only one server
+                       return 0;
+               } elseif ( $group === false && $this->mReadIndex >= 0 ) {
+                       # Shortcut if generic reader exists already
+                       return $this->mReadIndex;
+               }
+
+               # Find the relevant load array
+               if ( $group !== false ) {
+                       if ( isset( $this->mGroupLoads[$group] ) ) {
+                               $nonErrorLoads = $this->mGroupLoads[$group];
+                       } else {
+                               # No loads for this group, return false and the caller can use some other group
+                               wfDebug( __METHOD__ . ": no loads for group $group\n" );
+
+                               return false;
+                       }
+               } else {
+                       $nonErrorLoads = $this->mLoads;
+               }
+
+               if ( !count( $nonErrorLoads ) ) {
+                       throw new MWException( "Empty server array given to LoadBalancer" );
+               }
+
+               # Scale the configured load ratios according to the dynamic load (if the load monitor supports it)
+               $this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $group, $wiki );
+
+               $laggedSlaveMode = false;
+
+               # No server found yet
+               $i = false;
+               # First try quickly looking through the available servers for a server that
+               # meets our criteria
+               $currentLoads = $nonErrorLoads;
+               while ( count( $currentLoads ) ) {
+                       if ( $this->mAllowLagged || $laggedSlaveMode ) {
+                               $i = ArrayUtils::pickRandom( $currentLoads );
+                       } else {
+                               $i = false;
+                               if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
+                                       # ChronologyProtecter causes mWaitForPos to be set via sessions.
+                                       # This triggers doWait() after connect, so it's especially good to
+                                       # avoid lagged servers so as to avoid just blocking in that method.
+                                       $ago = microtime( true ) - $this->mWaitForPos->asOfTime();
+                                       # Aim for <= 1 second of waiting (being too picky can backfire)
+                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki, $ago + 1 );
+                               }
+                               if ( $i === false ) {
+                                       # Any server with less lag than it's 'max lag' param is preferable
+                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki );
+                               }
+                               if ( $i === false && count( $currentLoads ) != 0 ) {
+                                       # All slaves lagged. Switch to read-only mode
+                                       wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );
+                                       $i = ArrayUtils::pickRandom( $currentLoads );
+                                       $laggedSlaveMode = true;
+                               }
+                       }
+
+                       if ( $i === false ) {
+                               # pickRandom() returned false
+                               # This is permanent and means the configuration or the load monitor
+                               # wants us to return false.
+                               wfDebugLog( 'connect', __METHOD__ . ": pickRandom() returned false" );
+
+                               return false;
+                       }
+
+                       $serverName = $this->getServerName( $i );
+                       wfDebugLog( 'connect', __METHOD__ . ": Using reader #$i: $serverName..." );
+
+                       $conn = $this->openConnection( $i, $wiki );
+                       if ( !$conn ) {
+                               wfDebugLog( 'connect', __METHOD__ . ": Failed connecting to $i/$wiki" );
+                               unset( $nonErrorLoads[$i] );
+                               unset( $currentLoads[$i] );
+                               $i = false;
+                               continue;
+                       }
+
+                       // Decrement reference counter, we are finished with this connection.
+                       // It will be incremented for the caller later.
+                       if ( $wiki !== false ) {
+                               $this->reuseConnection( $conn );
+                       }
+
+                       # Return this server
+                       break;
+               }
+
+               # If all servers were down, quit now
+               if ( !count( $nonErrorLoads ) ) {
+                       wfDebugLog( 'connect', "All servers down" );
+               }
+
+               if ( $i !== false ) {
+                       # Slave connection successful
+                       # Wait for the session master pos for a short time
+                       if ( $this->mWaitForPos && $i > 0 ) {
+                               if ( !$this->doWait( $i ) ) {
+                                       $this->mServers[$i]['slave pos'] = $conn->getSlavePos();
+                               }
+                       }
+                       if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group === false ) {
+                               $this->mReadIndex = $i;
+                               # Record if the generic reader index is in "lagged slave" mode
+                               if ( $laggedSlaveMode ) {
+                                       $this->mLaggedSlaveMode = true;
+                               }
+                       }
+                       $serverName = $this->getServerName( $i );
+                       wfDebug( __METHOD__ . ": using server $serverName for group '$group'\n" );
+               }
+
+               return $i;
+       }
+
+       /**
+        * Set the master wait position
+        * If a DB_SLAVE connection has been opened already, waits
+        * Otherwise sets a variable telling it to wait if such a connection is opened
+        * @param DBMasterPos $pos
+        */
+       public function waitFor( $pos ) {
+               $this->mWaitForPos = $pos;
+               $i = $this->mReadIndex;
+
+               if ( $i > 0 ) {
+                       if ( !$this->doWait( $i ) ) {
+                               $this->mServers[$i]['slave pos'] = $this->getAnyOpenConnection( $i )->getSlavePos();
+                               $this->mLaggedSlaveMode = true;
+                       }
+               }
+       }
+
+       /**
+        * Set the master wait position and wait for a "generic" slave to catch up to it
+        *
+        * This can be used a faster proxy for waitForAll()
+        *
+        * @param DBMasterPos $pos
+        * @param int $timeout Max seconds to wait; default is mWaitTimeout
+        * @return bool Success (able to connect and no timeouts reached)
+        * @since 1.26
+        */
+       public function waitForOne( $pos, $timeout = null ) {
+               $this->mWaitForPos = $pos;
+
+               $i = $this->mReadIndex;
+               if ( $i <= 0 ) {
+                       // Pick a generic slave if there isn't one yet
+                       $readLoads = $this->mLoads;
+                       unset( $readLoads[$this->getWriterIndex()] ); // slaves only
+                       $readLoads = array_filter( $readLoads ); // with non-zero load
+                       $i = ArrayUtils::pickRandom( $readLoads );
+               }
+
+               if ( $i > 0 ) {
+                       $ok = $this->doWait( $i, true, $timeout );
+               } else {
+                       $ok = true; // no applicable loads
+               }
+
+               return $ok;
+       }
+
+       /**
+        * Set the master wait position and wait for ALL slaves to catch up to it
+        * @param DBMasterPos $pos
+        * @param int $timeout Max seconds to wait; default is mWaitTimeout
+        * @return bool Success (able to connect and no timeouts reached)
+        */
+       public function waitForAll( $pos, $timeout = null ) {
+               $this->mWaitForPos = $pos;
+               $serverCount = count( $this->mServers );
+
+               $ok = true;
+               for ( $i = 1; $i < $serverCount; $i++ ) {
+                       if ( $this->mLoads[$i] > 0 ) {
+                               $ok = $this->doWait( $i, true, $timeout ) && $ok;
+                       }
+               }
+
+               return $ok;
+       }
+
+       /**
+        * Get any open connection to a given server index, local or foreign
+        * Returns false if there is no connection open
+        *
+        * @param int $i
+        * @return DatabaseBase|bool False on failure
+        */
+       public function getAnyOpenConnection( $i ) {
+               foreach ( $this->mConns as $conns ) {
+                       if ( !empty( $conns[$i] ) ) {
+                               return reset( $conns[$i] );
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Wait for a given slave to catch up to the master pos stored in $this
+        * @param int $index Server index
+        * @param bool $open Check the server even if a new connection has to be made
+        * @param int $timeout Max seconds to wait; default is mWaitTimeout
+        * @return bool
+        */
+       protected function doWait( $index, $open = false, $timeout = null ) {
+               $close = false; // close the connection afterwards
+
+               # Find a connection to wait on, creating one if needed and allowed
+               $conn = $this->getAnyOpenConnection( $index );
+               if ( !$conn ) {
+                       if ( !$open ) {
+                               wfDebug( __METHOD__ . ": no connection open\n" );
+
+                               return false;
+                       } else {
+                               $conn = $this->openConnection( $index, '' );
+                               if ( !$conn ) {
+                                       wfDebug( __METHOD__ . ": failed to open connection\n" );
+
+                                       return false;
+                               }
+                               // Avoid connection spam in waitForAll() when connections
+                               // are made just for the sake of doing this lag check.
+                               $close = true;
+                       }
+               }
+
+               wfDebug( __METHOD__ . ": Waiting for slave #$index to catch up...\n" );
+               $timeout = $timeout ?: $this->mWaitTimeout;
+               $result = $conn->masterPosWait( $this->mWaitForPos, $timeout );
+
+               if ( $result == -1 || is_null( $result ) ) {
+                       # Timed out waiting for slave, use master instead
+                       $server = $server = $this->getServerName( $index );
+                       $msg = __METHOD__ . ": Timed out waiting on $server pos {$this->mWaitForPos}";
+                       wfDebug( "$msg\n" );
+                       wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
+                       $ok = false;
+               } else {
+                       wfDebug( __METHOD__ . ": Done\n" );
+                       $ok = true;
+               }
+
+               if ( $close ) {
+                       $this->closeConnection( $conn );
+               }
+
+               return $ok;
+       }
+
+       /**
+        * Get a connection by index
+        * This is the main entry point for this class.
+        *
+        * @param int $i Server index
+        * @param array|string|bool $groups Query group(s), or false for the generic reader
+        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        *
+        * @throws MWException
+        * @return DatabaseBase
+        */
+       public function getConnection( $i, $groups = array(), $wiki = false ) {
+               if ( $i === null || $i === false ) {
+                       throw new MWException( 'Attempt to call ' . __METHOD__ .
+                               ' with invalid server index' );
+               }
+
+               if ( $wiki === wfWikiID() ) {
+                       $wiki = false;
+               }
+
+               $groups = ( $groups === false || $groups === array() )
+                       ? array( false ) // check one "group": the generic pool
+                       : (array)$groups;
+
+               $masterOnly = ( $i == DB_MASTER || $i == $this->getWriterIndex() );
+               $oldConnsOpened = $this->connsOpened; // connections open now
+
+               if ( $i == DB_MASTER ) {
+                       $i = $this->getWriterIndex();
+               } else {
+                       # Try to find an available server in any the query groups (in order)
+                       foreach ( $groups as $group ) {
+                               $groupIndex = $this->getReaderIndex( $group, $wiki );
+                               if ( $groupIndex !== false ) {
+                                       $i = $groupIndex;
+                                       break;
+                               }
+                       }
+               }
+
+               # Operation-based index
+               if ( $i == DB_SLAVE ) {
+                       $this->mLastError = 'Unknown error'; // reset error string
+                       # Try the general server pool if $groups are unavailable.
+                       $i = in_array( false, $groups, true )
+                               ? false // don't bother with this if that is what was tried above
+                               : $this->getReaderIndex( false, $wiki );
+                       # Couldn't find a working server in getReaderIndex()?
+                       if ( $i === false ) {
+                               $this->mLastError = 'No working slave server: ' . $this->mLastError;
+
+                               return $this->reportConnectionError();
+                       }
+               }
+
+               # Now we have an explicit index into the servers array
+               $conn = $this->openConnection( $i, $wiki );
+               if ( !$conn ) {
+                       return $this->reportConnectionError();
+               }
+
+               # Profile any new connections that happen
+               if ( $this->connsOpened > $oldConnsOpened ) {
+                       $host = $conn->getServer();
+                       $dbname = $conn->getDBname();
+                       $trxProf = Profiler::instance()->getTransactionProfiler();
+                       $trxProf->recordConnection( $host, $dbname, $masterOnly );
+               }
+
+               return $conn;
+       }
+
+       /**
+        * Mark a foreign connection as being available for reuse under a different
+        * DB name or prefix. This mechanism is reference-counted, and must be called
+        * the same number of times as getConnection() to work.
+        *
+        * @param DatabaseBase $conn
+        * @throws MWException
+        */
+       public function reuseConnection( $conn ) {
+               $serverIndex = $conn->getLBInfo( 'serverIndex' );
+               $refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
+               if ( $serverIndex === null || $refCount === null ) {
+                       wfDebug( __METHOD__ . ": this connection was not opened as a foreign connection\n" );
+
+                       /**
+                        * This can happen in code like:
+                        *   foreach ( $dbs as $db ) {
+                        *     $conn = $lb->getConnection( DB_SLAVE, array(), $db );
+                        *     ...
+                        *     $lb->reuseConnection( $conn );
+                        *   }
+                        * When a connection to the local DB is opened in this way, reuseConnection()
+                        * should be ignored
+                        */
+
+                       return;
+               }
+
+               $dbName = $conn->getDBname();
+               $prefix = $conn->tablePrefix();
+               if ( strval( $prefix ) !== '' ) {
+                       $wiki = "$dbName-$prefix";
+               } else {
+                       $wiki = $dbName;
+               }
+               if ( $this->mConns['foreignUsed'][$serverIndex][$wiki] !== $conn ) {
+                       throw new MWException( __METHOD__ . ": connection not found, has " .
+                               "the connection been freed already?" );
+               }
+               $conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
+               if ( $refCount <= 0 ) {
+                       $this->mConns['foreignFree'][$serverIndex][$wiki] = $conn;
+                       unset( $this->mConns['foreignUsed'][$serverIndex][$wiki] );
+                       wfDebug( __METHOD__ . ": freed connection $serverIndex/$wiki\n" );
+               } else {
+                       wfDebug( __METHOD__ . ": reference count for $serverIndex/$wiki reduced to $refCount\n" );
+               }
+       }
+
+       /**
+        * Get a database connection handle reference
+        *
+        * The handle's methods wrap simply wrap those of a DatabaseBase handle
+        *
+        * @see LoadBalancer::getConnection() for parameter information
+        *
+        * @param int $db
+        * @param array|string|bool $groups Query group(s), or false for the generic reader
+        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @return DBConnRef
+        */
+       public function getConnectionRef( $db, $groups = array(), $wiki = false ) {
+               return new DBConnRef( $this, $this->getConnection( $db, $groups, $wiki ) );
+       }
+
+       /**
+        * Get a database connection handle reference without connecting yet
+        *
+        * The handle's methods wrap simply wrap those of a DatabaseBase handle
+        *
+        * @see LoadBalancer::getConnection() for parameter information
+        *
+        * @param int $db
+        * @param array|string|bool $groups Query group(s), or false for the generic reader
+        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @return DBConnRef
+        */
+       public function getLazyConnectionRef( $db, $groups = array(), $wiki = false ) {
+               return new DBConnRef( $this, array( $db, $groups, $wiki ) );
+       }
+
+       /**
+        * Open a connection to the server given by the specified index
+        * Index must be an actual index into the array.
+        * If the server is already open, returns it.
+        *
+        * On error, returns false, and the connection which caused the
+        * error will be available via $this->mErrorConnection.
+        *
+        * @param int $i Server index
+        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @return DatabaseBase
+        *
+        * @access private
+        */
+       public function openConnection( $i, $wiki = false ) {
+               if ( $wiki !== false ) {
+                       $conn = $this->openForeignConnection( $i, $wiki );
+               } elseif ( isset( $this->mConns['local'][$i][0] ) ) {
+                       $conn = $this->mConns['local'][$i][0];
+               } else {
+                       $server = $this->mServers[$i];
+                       $server['serverIndex'] = $i;
+                       $conn = $this->reallyOpenConnection( $server, false );
+                       $serverName = $this->getServerName( $i );
+                       if ( $conn->isOpen() ) {
+                               wfDebug( "Connected to database $i at $serverName\n" );
+                               $this->mConns['local'][$i][0] = $conn;
+                       } else {
+                               wfDebug( "Failed to connect to database $i at $serverName\n" );
+                               $this->mErrorConnection = $conn;
+                               $conn = false;
+                       }
+               }
+
+               if ( $conn && !$conn->isOpen() ) {
+                       // Connection was made but later unrecoverably lost for some reason.
+                       // Do not return a handle that will just throw exceptions on use,
+                       // but let the calling code (e.g. getReaderIndex) try another server.
+                       // See DatabaseMyslBase::ping() for how this can happen.
+                       $this->mErrorConnection = $conn;
+                       $conn = false;
+               }
+
+               return $conn;
+       }
+
+       /**
+        * Open a connection to a foreign DB, or return one if it is already open.
+        *
+        * Increments a reference count on the returned connection which locks the
+        * connection to the requested wiki. This reference count can be
+        * decremented by calling reuseConnection().
+        *
+        * If a connection is open to the appropriate server already, but with the wrong
+        * database, it will be switched to the right database and returned, as long as
+        * it has been freed first with reuseConnection().
+        *
+        * On error, returns false, and the connection which caused the
+        * error will be available via $this->mErrorConnection.
+        *
+        * @param int $i Server index
+        * @param string $wiki Wiki ID to open
+        * @return DatabaseBase
+        */
+       private function openForeignConnection( $i, $wiki ) {
+               list( $dbName, $prefix ) = wfSplitWikiID( $wiki );
+               if ( isset( $this->mConns['foreignUsed'][$i][$wiki] ) ) {
+                       // Reuse an already-used connection
+                       $conn = $this->mConns['foreignUsed'][$i][$wiki];
+                       wfDebug( __METHOD__ . ": reusing connection $i/$wiki\n" );
+               } elseif ( isset( $this->mConns['foreignFree'][$i][$wiki] ) ) {
+                       // Reuse a free connection for the same wiki
+                       $conn = $this->mConns['foreignFree'][$i][$wiki];
+                       unset( $this->mConns['foreignFree'][$i][$wiki] );
+                       $this->mConns['foreignUsed'][$i][$wiki] = $conn;
+                       wfDebug( __METHOD__ . ": reusing free connection $i/$wiki\n" );
+               } elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) {
+                       // Reuse a connection from another wiki
+                       $conn = reset( $this->mConns['foreignFree'][$i] );
+                       $oldWiki = key( $this->mConns['foreignFree'][$i] );
+
+                       // The empty string as a DB name means "don't care".
+                       // DatabaseMysqlBase::open() already handle this on connection.
+                       if ( $dbName !== '' && !$conn->selectDB( $dbName ) ) {
+                               $this->mLastError = "Error selecting database $dbName on server " .
+                                       $conn->getServer() . " from client host " . wfHostname() . "\n";
+                               $this->mErrorConnection = $conn;
+                               $conn = false;
+                       } else {
+                               $conn->tablePrefix( $prefix );
+                               unset( $this->mConns['foreignFree'][$i][$oldWiki] );
+                               $this->mConns['foreignUsed'][$i][$wiki] = $conn;
+                               wfDebug( __METHOD__ . ": reusing free connection from $oldWiki for $wiki\n" );
+                       }
+               } else {
+                       // Open a new connection
+                       $server = $this->mServers[$i];
+                       $server['serverIndex'] = $i;
+                       $server['foreignPoolRefCount'] = 0;
+                       $server['foreign'] = true;
+                       $conn = $this->reallyOpenConnection( $server, $dbName );
+                       if ( !$conn->isOpen() ) {
+                               wfDebug( __METHOD__ . ": error opening connection for $i/$wiki\n" );
+                               $this->mErrorConnection = $conn;
+                               $conn = false;
+                       } else {
+                               $conn->tablePrefix( $prefix );
+                               $this->mConns['foreignUsed'][$i][$wiki] = $conn;
+                               wfDebug( __METHOD__ . ": opened new connection for $i/$wiki\n" );
+                       }
+               }
+
+               // Increment reference count
+               if ( $conn ) {
+                       $refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
+                       $conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
+               }
+
+               return $conn;
+       }
+
+       /**
+        * Test if the specified index represents an open connection
+        *
+        * @param int $index Server index
+        * @access private
+        * @return bool
+        */
+       private function isOpen( $index ) {
+               if ( !is_integer( $index ) ) {
+                       return false;
+               }
+
+               return (bool)$this->getAnyOpenConnection( $index );
+       }
+
+       /**
+        * Really opens a connection. Uncached.
+        * Returns a Database object whether or not the connection was successful.
+        * @access private
+        *
+        * @param array $server
+        * @param bool $dbNameOverride
+        * @throws MWException
+        * @return DatabaseBase
+        */
+       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
+               if ( !is_array( $server ) ) {
+                       throw new MWException( 'You must update your load-balancing configuration. ' .
+                               'See DefaultSettings.php entry for $wgDBservers.' );
+               }
+
+               if ( $dbNameOverride !== false ) {
+                       $server['dbname'] = $dbNameOverride;
+               }
+
+               // Log when many connection are made on requests
+               if ( ++$this->connsOpened >= self::CONN_HELD_WARN_THRESHOLD ) {
+                       $masterAddr = $this->getServerName( 0 );
+                       wfDebugLog( 'DBPerformance', __METHOD__ . ": " .
+                               "{$this->connsOpened}+ connections made (master=$masterAddr)\n" .
+                               wfBacktrace( true ) );
+               }
+
+               # Create object
+               try {
+                       $db = DatabaseBase::factory( $server['type'], $server );
+               } catch ( DBConnectionError $e ) {
+                       // FIXME: This is probably the ugliest thing I have ever done to
+                       // PHP. I'm half-expecting it to segfault, just out of disgust. -- TS
+                       $db = $e->db;
+               }
+
+               $db->setLBInfo( $server );
+               if ( isset( $server['fakeSlaveLag'] ) ) {
+                       $db->setFakeSlaveLag( $server['fakeSlaveLag'] );
+               }
+               if ( isset( $server['fakeMaster'] ) ) {
+                       $db->setFakeMaster( true );
+               }
+
+               return $db;
+       }
+
+       /**
+        * @throws DBConnectionError
+        * @return bool
+        */
+       private function reportConnectionError() {
+               $conn = $this->mErrorConnection; // The connection which caused the error
+               $context = array(
+                       'method' => __METHOD__,
+                       'last_error' => $this->mLastError,
+               );
+
+               if ( !is_object( $conn ) ) {
+                       // No last connection, probably due to all servers being too busy
+                       wfLogDBError(
+                               "LB failure with no last connection. Connection error: {last_error}",
+                               $context
+                       );
+
+                       // If all servers were busy, mLastError will contain something sensible
+                       throw new DBConnectionError( null, $this->mLastError );
+               } else {
+                       $context['db_server'] = $conn->getProperty( 'mServer' );
+                       wfLogDBError(
+                               "Connection error: {last_error} ({db_server})",
+                               $context
+                       );
+
+                       // throws DBConnectionError
+                       $conn->reportConnectionError( "{$this->mLastError} ({$context['db_server']})" );
+               }
+
+               return false; /* not reached */
+       }
+
+       /**
+        * @return int
+        * @since 1.26
+        */
+       public function getWriterIndex() {
+               return 0;
+       }
+
+       /**
+        * Returns true if the specified index is a valid server index
+        *
+        * @param string $i
+        * @return bool
+        */
+       public function haveIndex( $i ) {
+               return array_key_exists( $i, $this->mServers );
+       }
+
+       /**
+        * Returns true if the specified index is valid and has non-zero load
+        *
+        * @param string $i
+        * @return bool
+        */
+       public function isNonZeroLoad( $i ) {
+               return array_key_exists( $i, $this->mServers ) && $this->mLoads[$i] != 0;
+       }
+
+       /**
+        * Get the number of defined servers (not the number of open connections)
+        *
+        * @return int
+        */
+       public function getServerCount() {
+               return count( $this->mServers );
+       }
+
+       /**
+        * Get the host name or IP address of the server with the specified index
+        * Prefer a readable name if available.
+        * @param string $i
+        * @return string
+        */
+       public function getServerName( $i ) {
+               if ( isset( $this->mServers[$i]['hostName'] ) ) {
+                       $name = $this->mServers[$i]['hostName'];
+               } elseif ( isset( $this->mServers[$i]['host'] ) ) {
+                       $name = $this->mServers[$i]['host'];
+               } else {
+                       $name = '';
+               }
+
+               return ( $name != '' ) ? $name : 'localhost';
+       }
+
+       /**
+        * Return the server info structure for a given index, or false if the index is invalid.
+        * @param int $i
+        * @return array|bool
+        */
+       public function getServerInfo( $i ) {
+               if ( isset( $this->mServers[$i] ) ) {
+                       return $this->mServers[$i];
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * Sets the server info structure for the given index. Entry at index $i
+        * is created if it doesn't exist
+        * @param int $i
+        * @param array $serverInfo
+        */
+       public function setServerInfo( $i, array $serverInfo ) {
+               $this->mServers[$i] = $serverInfo;
+       }
+
+       /**
+        * Get the current master position for chronology control purposes
+        * @return mixed
+        */
+       public function getMasterPos() {
+               # If this entire request was served from a slave without opening a connection to the
+               # master (however unlikely that may be), then we can fetch the position from the slave.
+               $masterConn = $this->getAnyOpenConnection( 0 );
+               if ( !$masterConn ) {
+                       $serverCount = count( $this->mServers );
+                       for ( $i = 1; $i < $serverCount; $i++ ) {
+                               $conn = $this->getAnyOpenConnection( $i );
+                               if ( $conn ) {
+                                       wfDebug( "Master pos fetched from slave\n" );
+
+                                       return $conn->getSlavePos();
+                               }
+                       }
+               } else {
+                       wfDebug( "Master pos fetched from master\n" );
+
+                       return $masterConn->getMasterPos();
+               }
+
+               return false;
+       }
+
+       /**
+        * Close all open connections
+        */
+       public function closeAll() {
+               foreach ( $this->mConns as $conns2 ) {
+                       foreach ( $conns2 as $conns3 ) {
+                               /** @var DatabaseBase $conn */
+                               foreach ( $conns3 as $conn ) {
+                                       $conn->close();
+                               }
+                       }
+               }
+               $this->mConns = array(
+                       'local' => array(),
+                       'foreignFree' => array(),
+                       'foreignUsed' => array(),
+               );
+               $this->connsOpened = 0;
+       }
+
+       /**
+        * Close a connection
+        * Using this function makes sure the LoadBalancer knows the connection is closed.
+        * If you use $conn->close() directly, the load balancer won't update its state.
+        * @param DatabaseBase $conn
+        */
+       public function closeConnection( $conn ) {
+               $done = false;
+               foreach ( $this->mConns as $i1 => $conns2 ) {
+                       foreach ( $conns2 as $i2 => $conns3 ) {
+                               foreach ( $conns3 as $i3 => $candidateConn ) {
+                                       if ( $conn === $candidateConn ) {
+                                               $conn->close();
+                                               unset( $this->mConns[$i1][$i2][$i3] );
+                                               --$this->connsOpened;
+                                               $done = true;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if ( !$done ) {
+                       $conn->close();
+               }
+       }
+
+       /**
+        * Commit transactions on all open connections
+        */
+       public function commitAll() {
+               foreach ( $this->mConns as $conns2 ) {
+                       foreach ( $conns2 as $conns3 ) {
+                               /** @var DatabaseBase[] $conns3 */
+                               foreach ( $conns3 as $conn ) {
+                                       if ( $conn->trxLevel() ) {
+                                               $conn->commit( __METHOD__, 'flush' );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /**
+        *  Issue COMMIT only on master, only if queries were done on connection
+        */
+       public function commitMasterChanges() {
+               $masterIndex = $this->getWriterIndex();
+               foreach ( $this->mConns as $conns2 ) {
+                       if ( empty( $conns2[$masterIndex] ) ) {
+                               continue;
+                       }
+                       /** @var DatabaseBase $conn */
+                       foreach ( $conns2[$masterIndex] as $conn ) {
+                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
+                                       $conn->commit( __METHOD__, 'flush' );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Issue ROLLBACK only on master, only if queries were done on connection
+        * @since 1.23
+        */
+       public function rollbackMasterChanges() {
+               $failedServers = array();
+
+               $masterIndex = $this->getWriterIndex();
+               foreach ( $this->mConns as $conns2 ) {
+                       if ( empty( $conns2[$masterIndex] ) ) {
+                               continue;
+                       }
+                       /** @var DatabaseBase $conn */
+                       foreach ( $conns2[$masterIndex] as $conn ) {
+                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
+                                       try {
+                                               $conn->rollback( __METHOD__, 'flush' );
+                                       } catch ( DBError $e ) {
+                                               MWExceptionHandler::logException( $e );
+                                               $failedServers[] = $conn->getServer();
+                                       }
+                               }
+                       }
+               }
+
+               if ( $failedServers ) {
+                       throw new DBExpectedError( null, "Rollback failed on server(s) " .
+                               implode( ', ', array_unique( $failedServers ) ) );
+               }
+       }
+
+       /**
+        * @return bool Whether a master connection is already open
+        * @since 1.24
+        */
+       public function hasMasterConnection() {
+               return $this->isOpen( $this->getWriterIndex() );
+       }
+
+       /**
+        * Determine if there are pending changes in a transaction by this thread
+        * @since 1.23
+        * @return bool
+        */
+       public function hasMasterChanges() {
+               $masterIndex = $this->getWriterIndex();
+               foreach ( $this->mConns as $conns2 ) {
+                       if ( empty( $conns2[$masterIndex] ) ) {
+                               continue;
+                       }
+                       /** @var DatabaseBase $conn */
+                       foreach ( $conns2[$masterIndex] as $conn ) {
+                               if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Get the timestamp of the latest write query done by this thread
+        * @since 1.25
+        * @return float|bool UNIX timestamp or false
+        */
+       public function lastMasterChangeTimestamp() {
+               $lastTime = false;
+               $masterIndex = $this->getWriterIndex();
+               foreach ( $this->mConns as $conns2 ) {
+                       if ( empty( $conns2[$masterIndex] ) ) {
+                               continue;
+                       }
+                       /** @var DatabaseBase $conn */
+                       foreach ( $conns2[$masterIndex] as $conn ) {
+                               $lastTime = max( $lastTime, $conn->lastDoneWrites() );
+                       }
+               }
+               return $lastTime;
+       }
+
+       /**
+        * Check if this load balancer object had any recent or still
+        * pending writes issued against it by this PHP thread
+        *
+        * @param float $age How many seconds ago is "recent" [defaults to mWaitTimeout]
+        * @return bool
+        * @since 1.25
+        */
+       public function hasOrMadeRecentMasterChanges( $age = null ) {
+               $age = ( $age === null ) ? $this->mWaitTimeout : $age;
+
+               return ( $this->hasMasterChanges()
+                       || $this->lastMasterChangeTimestamp() > microtime( true ) - $age );
+       }
+
+       /**
+        * @param mixed $value
+        * @return mixed
+        */
+       public function waitTimeout( $value = null ) {
+               return wfSetVar( $this->mWaitTimeout, $value );
+       }
+
+       /**
+        * @return bool Whether the generic connection for reads is highly "lagged"
+        */
+       public function getLaggedSlaveMode() {
+               # Get a generic reader connection
+               $this->getConnection( DB_SLAVE );
+
+               return $this->mLaggedSlaveMode;
+       }
+
+       /**
+        * Disables/enables lag checks
+        * @param null|bool $mode
+        * @return bool
+        */
+       public function allowLagged( $mode = null ) {
+               if ( $mode === null ) {
+                       return $this->mAllowLagged;
+               }
+               $this->mAllowLagged = $mode;
+
+               return $this->mAllowLagged;
+       }
+
+       /**
+        * @return bool
+        */
+       public function pingAll() {
+               $success = true;
+               foreach ( $this->mConns as $conns2 ) {
+                       foreach ( $conns2 as $conns3 ) {
+                               /** @var DatabaseBase[] $conns3 */
+                               foreach ( $conns3 as $conn ) {
+                                       if ( !$conn->ping() ) {
+                                               $success = false;
+                                       }
+                               }
+                       }
+               }
+
+               return $success;
+       }
+
+       /**
+        * Call a function with each open connection object
+        * @param callable $callback
+        * @param array $params
+        */
+       public function forEachOpenConnection( $callback, array $params = array() ) {
+               foreach ( $this->mConns as $conns2 ) {
+                       foreach ( $conns2 as $conns3 ) {
+                               foreach ( $conns3 as $conn ) {
+                                       $mergedParams = array_merge( array( $conn ), $params );
+                                       call_user_func_array( $callback, $mergedParams );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Get the hostname and lag time of the most-lagged slave
+        *
+        * This is useful for maintenance scripts that need to throttle their updates.
+        * May attempt to open connections to slaves on the default DB. If there is
+        * no lag, the maximum lag will be reported as -1.
+        *
+        * @param bool|string $wiki Wiki ID, or false for the default database
+        * @return array ( host, max lag, index of max lagged host )
+        */
+       public function getMaxLag( $wiki = false ) {
+               $maxLag = -1;
+               $host = '';
+               $maxIndex = 0;
+
+               if ( $this->getServerCount() <= 1 ) {
+                       return array( $host, $maxLag, $maxIndex ); // no replication = no lag
+               }
+
+               $lagTimes = $this->getLagTimes( $wiki );
+               foreach ( $lagTimes as $i => $lag ) {
+                       if ( $lag > $maxLag ) {
+                               $maxLag = $lag;
+                               $host = $this->mServers[$i]['host'];
+                               $maxIndex = $i;
+                       }
+               }
+
+               return array( $host, $maxLag, $maxIndex );
+       }
+
+       /**
+        * Get lag time for each server
+        *
+        * Results are cached for a short time in memcached/process cache
+        *
+        * @param string|bool $wiki
+        * @return int[] Map of (server index => seconds)
+        */
+       public function getLagTimes( $wiki = false ) {
+               if ( $this->getServerCount() <= 1 ) {
+                       return array( 0 => 0 ); // no replication = no lag
+               }
+
+               # Send the request to the load monitor
+               return $this->getLoadMonitor()->getLagTimes( array_keys( $this->mServers ), $wiki );
+       }
+
+       /**
+        * Get the lag in seconds for a given connection, or zero if this load
+        * balancer does not have replication enabled.
+        *
+        * This should be used in preference to Database::getLag() in cases where
+        * replication may not be in use, since there is no way to determine if
+        * replication is in use at the connection level without running
+        * potentially restricted queries such as SHOW SLAVE STATUS. Using this
+        * function instead of Database::getLag() avoids a fatal error in this
+        * case on many installations.
+        *
+        * @param DatabaseBase $conn
+        * @return int
+        */
+       public function safeGetLag( $conn ) {
+               if ( $this->getServerCount() == 1 ) {
+                       return 0;
+               } else {
+                       return $conn->getLag();
+               }
+       }
+
+       /**
+        * Clear the cache for slag lag delay times
+        *
+        * This is only used for testing
+        */
+       public function clearLagTimeCache() {
+               $this->getLoadMonitor()->clearCaches();
+       }
+}
diff --git a/includes/db/loadbalancer/LoadMonitor.php b/includes/db/loadbalancer/LoadMonitor.php
new file mode 100644 (file)
index 0000000..4975ea1
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Database load monitoring.
+ *
+ * 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 Database
+ */
+
+/**
+ * An interface for database load monitoring
+ *
+ * @ingroup Database
+ */
+interface LoadMonitor {
+       /**
+        * Construct a new LoadMonitor with a given LoadBalancer parent
+        *
+        * @param LoadBalancer $parent
+        */
+       public function __construct( $parent );
+
+       /**
+        * Perform pre-connection load ratio adjustment.
+        * @param array $loads
+        * @param string|bool $group The selected query group. Default: false
+        * @param string|bool $wiki Default: false
+        */
+       public function scaleLoads( &$loads, $group = false, $wiki = false );
+
+       /**
+        * Return an estimate of replication lag for each server
+        *
+        * @param array $serverIndexes
+        * @param string $wiki
+        *
+        * @return array Map of (server index => seconds)
+        */
+       public function getLagTimes( $serverIndexes, $wiki );
+}
+
+class LoadMonitorNull implements LoadMonitor {
+       public function __construct( $parent ) {
+       }
+
+       public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+       }
+
+       public function getLagTimes( $serverIndexes, $wiki ) {
+               return array_fill_keys( $serverIndexes, 0 );
+       }
+}
diff --git a/includes/db/loadbalancer/LoadMonitorMySQL.php b/includes/db/loadbalancer/LoadMonitorMySQL.php
new file mode 100644 (file)
index 0000000..39ced1b
--- /dev/null
@@ -0,0 +1,124 @@
+<?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
+ * @ingroup Database
+ */
+
+/**
+ * Basic MySQL load monitor with no external dependencies
+ * Uses memcached to cache the replication lag for a short time
+ *
+ * @ingroup Database
+ */
+class LoadMonitorMySQL implements LoadMonitor {
+       /** @var LoadBalancer */
+       public $parent;
+       /** @var BagOStuff */
+       protected $srvCache;
+       /** @var BagOStuff */
+       protected $mainCache;
+
+       public function __construct( $parent ) {
+               $this->parent = $parent;
+
+               $this->srvCache = ObjectCache::newAccelerator( 'hash' );
+               $this->mainCache = wfGetMainCache();
+       }
+
+       public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+       }
+
+       public function getLagTimes( $serverIndexes, $wiki ) {
+               if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
+                       # Single server only, just return zero without caching
+                       return array( 0 => 0 );
+               }
+
+               $key = $this->getLagTimeCacheKey();
+               # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
+               $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
+               # Keep keys around longer as fallbacks
+               $staleTTL = 60;
+
+               # (a) Check the local APC cache
+               $value = $this->srvCache->get( $key );
+               if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+                       wfDebugLog( 'replication', __FUNCTION__ . ": got lag times ($key) from local cache" );
+                       return $value['lagTimes']; // cache hit
+               }
+               $staleValue = $value ?: false;
+
+               # (b) Check the shared cache and backfill APC
+               $value = $this->mainCache->get( $key );
+               if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+                       $this->srvCache->set( $key, $value, $staleTTL );
+                       wfDebugLog( 'replication', __FUNCTION__ . ": got lag times ($key) from main cache" );
+
+                       return $value['lagTimes']; // cache hit
+               }
+               $staleValue = $value ?: $staleValue;
+
+               # (c) Cache key missing or expired; regenerate and backfill
+               if ( $this->mainCache->lock( $key, 0, 10 ) ) {
+                       # Let this process alone update the cache value
+                       $cache = $this->mainCache;
+                       /** @noinspection PhpUnusedLocalVariableInspection */
+                       $unlocker = new ScopedCallback( function () use ( $cache, $key ) {
+                               $cache->unlock( $key );
+                       } );
+               } elseif ( $staleValue ) {
+                       # Could not acquire lock but an old cache exists, so use it
+                       return $staleValue['lagTimes'];
+               }
+
+               $lagTimes = array();
+               foreach ( $serverIndexes as $i ) {
+                       if ( $i == 0 ) { # Master
+                               $lagTimes[$i] = 0;
+                       } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
+                               $lagTimes[$i] = $conn->getLag();
+                       } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
+                               $lagTimes[$i] = $conn->getLag();
+                               # Close the connection to avoid sleeper connections piling up.
+                               # Note that the caller will pick one of these DBs and reconnect,
+                               # which is slightly inefficient, but this only matters for the lag
+                               # time cache miss cache, which is far less common that cache hits.
+                               $this->parent->closeConnection( $conn );
+                       }
+               }
+
+               # Add a timestamp key so we know when it was cached
+               $value = array( 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) );
+               $this->mainCache->set( $key, $value, $staleTTL );
+               $this->srvCache->set( $key, $value, $staleTTL );
+               wfDebugLog( 'replication', __FUNCTION__ . ": re-calculated lag times ($key)" );
+
+               return $value['lagTimes'];
+       }
+
+       public function clearCaches() {
+               $key = $this->getLagTimeCacheKey();
+               $this->srvCache->delete( $key );
+               $this->mainCache->delete( $key );
+       }
+
+       private function getLagTimeCacheKey() {
+               # Lag is per-server, not per-DB, so key on the master DB name
+               return wfGlobalCacheKey( 'lag-times', $this->parent->getServerName( 0 ) );
+       }
+}
index 0f4c648..bb3c7e1 100644 (file)
@@ -357,7 +357,7 @@ class LegacyLogger extends AbstractLogger {
                }
 
                if ( is_scalar( $item ) ) {
-                       return (string) $item;
+                       return (string)$item;
                }
 
                if ( is_array( $item ) ) {
@@ -376,7 +376,7 @@ class LegacyLogger extends AbstractLogger {
 
                if ( is_object( $item ) ) {
                        if ( method_exists( $item, '__toString' ) ) {
-                               return (string) $item;
+                               return (string)$item;
                        }
 
                        return '[Object ' . get_class( $item ) . ']';
index 3ebd0b1..d53ccde 100644 (file)
@@ -37,11 +37,10 @@ class BufferHandler extends BaseBufferHandler {
         * {@inheritDoc}
         */
        public function handle( array $record ) {
-               if (!$this->initialized) {
+               if ( !$this->initialized ) {
                        DeferredUpdates::addCallableUpdate( array( $this, 'close' ) );
                        $this->initialized = true;
                }
                return parent::handle( $record );
        }
 }
-
index 59d7764..4e8e65b 100644 (file)
@@ -76,7 +76,9 @@ class KafkaHandler extends AbstractProcessingHandler {
         * @param int $level The minimum logging level at which this handler will be triggered
         * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
         */
-       public function __construct( Produce $produce, array $options, $level = Logger::DEBUG, $bubble = true ) {
+       public function __construct(
+               Produce $produce, array $options, $level = Logger::DEBUG, $bubble = true
+       ) {
                parent::__construct( $level, $bubble );
                $this->produce = $produce;
                $this->options = array_merge( self::$defaultOptions, $options );
@@ -92,7 +94,9 @@ class KafkaHandler extends AbstractProcessingHandler {
         * @param bool $bubble Whether the messages that are handled can bubble the stack or not
         * @return KafkaHandler
         */
-       public static function factory( $kafkaServers, array $options = array(), $level = Logger::DEBUG, $bubble = true ) {
+       public static function factory(
+               $kafkaServers, array $options = array(), $level = Logger::DEBUG, $bubble = true
+       ) {
                $metadata = new MetaDataFromKafka( $kafkaServers );
                $produce = new Produce( $metadata );
                if ( isset( $options['logExceptions'] ) && is_string( $options['logExceptions'] ) ) {
@@ -133,7 +137,7 @@ class KafkaHandler extends AbstractProcessingHandler {
                                }
                        }
                        if ( $messages ) {
-                               $this->addMessages($channel, $messages);
+                               $this->addMessages( $channel, $messages );
                        }
                }
 
index f5d6845..e07fc87 100644 (file)
@@ -31,7 +31,7 @@
  */
 abstract class DataUpdate implements DeferrableUpdate {
        public function __construct() {
-               //noop
+               // noop
        }
 
        /**
@@ -39,7 +39,7 @@ abstract class DataUpdate implements DeferrableUpdate {
         * This default implementation does nothing.
         */
        public function beginTransaction() {
-               //noop
+               // noop
        }
 
        /**
@@ -47,7 +47,7 @@ abstract class DataUpdate implements DeferrableUpdate {
         * This default implementation does nothing.
         */
        public function commitTransaction() {
-               //noop
+               // noop
        }
 
        /**
@@ -55,7 +55,7 @@ abstract class DataUpdate implements DeferrableUpdate {
         * This default implementation does nothing.
         */
        public function rollbackTransaction() {
-               //noop
+               // noop
        }
 
        /**
@@ -152,4 +152,4 @@ interface EnqueueableDataUpdate {
         * Push the update into the job queue
         */
        public function enqueueUpdate();
-}
\ No newline at end of file
+}
index bbdfcf1..b7cc70e 100644 (file)
@@ -102,4 +102,4 @@ class LinksDeletionUpdate extends SqlDataUpdate {
                        }
                }
        }
-}
\ No newline at end of file
+}
index ba14f09..6ed1d00 100644 (file)
@@ -148,21 +148,22 @@ class SearchUpdate implements DeferrableUpdate {
                # Strip all remaining non-search characters
                $text = preg_replace( "/[^{$lc}]+/", " ", $text );
 
-               # Handle 's, s'
-               #
-               #   $text = preg_replace( "/([{$lc}]+)'s /", "\\1 \\1's ", $text );
-               #   $text = preg_replace( "/([{$lc}]+)s' /", "\\1s ", $text );
-               #
-               # These tail-anchored regexps are insanely slow. The worst case comes
-               # when Japanese or Chinese text (ie, no word spacing) is written on
-               # a wiki configured for Western UTF-8 mode. The Unicode characters are
-               # expanded to hex codes and the "words" are very long paragraph-length
-               # monstrosities. On a large page the above regexps may take over 20
-               # seconds *each* on a 1GHz-level processor.
-               #
-               # Following are reversed versions which are consistently fast
-               # (about 3 milliseconds on 1GHz-level processor).
-               #
+               /**
+                * Handle 's, s'
+                *
+                *   $text = preg_replace( "/([{$lc}]+)'s /", "\\1 \\1's ", $text );
+                *   $text = preg_replace( "/([{$lc}]+)s' /", "\\1s ", $text );
+                *
+                * These tail-anchored regexps are insanely slow. The worst case comes
+                * when Japanese or Chinese text (ie, no word spacing) is written on
+                * a wiki configured for Western UTF-8 mode. The Unicode characters are
+                * expanded to hex codes and the "words" are very long paragraph-length
+                * monstrosities. On a large page the above regexps may take over 20
+                * seconds *each* on a 1GHz-level processor.
+                *
+                * Following are reversed versions which are consistently fast
+                * (about 3 milliseconds on 1GHz-level processor).
+                */
                $text = strrev( preg_replace( "/ s'([{$lc}]+)/", " s'\\1 \\1", strrev( $text ) ) );
                $text = strrev( preg_replace( "/ 's([{$lc}]+)/", " s\\1", strrev( $text ) ) );
 
index 49164e3..0455690 100644 (file)
@@ -93,7 +93,7 @@ abstract class SqlDataUpdate extends DataUpdate {
         * Abort the database transaction started via beginTransaction (if any).
         */
        public function abortTransaction() {
-               if ( $this->mHasTransaction ) { //XXX: actually... maybe always?
+               if ( $this->mHasTransaction ) { // XXX: actually... maybe always?
                        $this->mDb->rollback( get_class( $this ) . '::abortTransaction' );
                        $this->mHasTransaction = false;
                }
index 950a264..e148f56 100644 (file)
@@ -54,7 +54,7 @@ class SquidUpdate {
        /**
         * Create a SquidUpdate from an array of Title objects, or a TitleArray object
         *
-        * @param array $titles
+        * @param Traversable|array $titles
         * @param array $urlArr
         * @return SquidUpdate
         */
index 83e04a5..4737f08 100644 (file)
@@ -62,8 +62,14 @@ class TableDiffFormatter extends DiffFormatter {
        protected function blockHeader( $xbeg, $xlen, $ybeg, $ylen ) {
                // '<!--LINE \d+ -->' get replaced by a localised line number
                // in DifferenceEngine::localiseLineNumbers
-               $r = '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l' . $xbeg . '" ><!--LINE ' . $xbeg . "--></td>\n" .
-                       '<td colspan="2" class="diff-lineno"><!--LINE ' . $ybeg . "--></td></tr>\n";
+               $r = '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l' .
+                       $xbeg .
+                       '" ><!--LINE ' .
+                       $xbeg .
+                       "--></td>\n" .
+                       '<td colspan="2" class="diff-lineno"><!--LINE ' .
+                       $ybeg .
+                       "--></td></tr>\n";
 
                return $r;
        }
index d25f1a8..4e50070 100644 (file)
@@ -485,6 +485,14 @@ TXT;
                return "[$id] $url   $type from line $line of $file: $message";
        }
 
+       public static function getPublicLogMessage( Exception $e ) {
+               $logId = self::getLogId( $e );
+               $type = get_class( $e );
+               return '[' . $logId . '] '
+                       . gmdate( 'Y-m-d H:i:s' ) . ': '
+                       . 'Fatal exception of type ' . $type;
+       }
+
        /**
         * Get a PSR-3 log event context from an Exception.
         *
index 7370c5c..25e46d8 100644 (file)
@@ -753,7 +753,6 @@ class FileRepo {
                }
                if ( !is_null( $this->articleUrl ) ) {
                        # "http://example.com/wiki/$1"
-                       #
                        # We use "Image:" as the canonical namespace for
                        # compatibility across all MediaWiki versions.
                        return str_replace( '$1',
@@ -761,7 +760,6 @@ class FileRepo {
                }
                if ( !is_null( $this->scriptDirUrl ) ) {
                        # "http://example.com/w"
-                       #
                        # We use "Image:" as the canonical namespace for
                        # compatibility across all MediaWiki versions,
                        # and just sort of hope index.php is right. ;)
index 6a2c064..6e3fb51 100644 (file)
@@ -203,6 +203,7 @@ class LocalRepo extends FileRepo {
                } else {
                        $expiry = 86400; // has invalidation, 1 day
                }
+
                $cachedValue = $cache->get( $memcKey );
                if ( $cachedValue === ' ' || $cachedValue === '' ) {
                        // Does not exist
@@ -211,9 +212,11 @@ class LocalRepo extends FileRepo {
                        return Title::newFromText( $cachedValue, NS_FILE );
                } // else $cachedValue is false or null: cache miss
 
+               $opts = array( 'since' => $this->getSlaveDB()->trxTimestamp() );
+
                $id = $this->getArticleID( $title );
                if ( !$id ) {
-                       $cache->set( $memcKey, " ", $expiry );
+                       $cache->set( $memcKey, " ", $expiry, $opts );
 
                        return false;
                }
@@ -227,11 +230,11 @@ class LocalRepo extends FileRepo {
 
                if ( $row && $row->rd_namespace == NS_FILE ) {
                        $targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title );
-                       $cache->set( $memcKey, $targetTitle->getDBkey(), $expiry );
+                       $cache->set( $memcKey, $targetTitle->getDBkey(), $expiry, $opts );
 
                        return $targetTitle;
                } else {
-                       $cache->set( $memcKey, '', $expiry );
+                       $cache->set( $memcKey, '', $expiry, $opts );
 
                        return false;
                }
@@ -251,12 +254,12 @@ class LocalRepo extends FileRepo {
                $dbr = $this->getSlaveDB();
                $id = $dbr->selectField(
                        'page', // Table
-                       'page_id', //Field
-                       array( //Conditions
+                       'page_id', // Field
+                       array( // Conditions
                                'page_namespace' => $title->getNamespace(),
                                'page_title' => $title->getDBkey(),
                        ),
-                       __METHOD__ //Function name
+                       __METHOD__ // Function name
                );
 
                return $id;
@@ -424,7 +427,7 @@ class LocalRepo extends FileRepo {
         */
        function findBySha1s( array $hashes ) {
                if ( !count( $hashes ) ) {
-                       return array(); //empty parameter
+                       return array(); // empty parameter
                }
 
                $dbr = $this->getSlaveDB();
@@ -521,15 +524,11 @@ class LocalRepo extends FileRepo {
         * @return void
         */
        function invalidateImageRedirect( Title $title ) {
-               $cache = ObjectCache::getMainWANInstance();
-
-               $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
-               if ( $memcKey ) {
-                       // Set a temporary value for the cache key, to ensure
-                       // that this value stays purged long enough so that
-                       // it isn't refreshed with a stale value due to a
-                       // lagged slave.
-                       $cache->delete( $memcKey, 12 );
+               $key = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
+               if ( $key ) {
+                       $this->getMasterDB()->onTransactionPreCommitOrIdle( function() use ( $key ) {
+                               ObjectCache::getMainWANInstance()->delete( $key );
+                       } );
                }
        }
 
index 050c429..c89dca1 100644 (file)
@@ -304,7 +304,7 @@ class RepoGroup {
                foreach ( $this->foreignRepos as $repo ) {
                        $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) );
                }
-               //sort the merged (and presorted) sublist of each hash
+               // sort the merged (and presorted) sublist of each hash
                foreach ( $result as $hash => $files ) {
                        usort( $result[$hash], 'File::compare' );
                }
index f40d216..ec5af85 100644 (file)
@@ -383,7 +383,7 @@ abstract class File implements IDBAccessObject {
                                wfDebug( __METHOD__ . ': supposed to render ' . $this->getName() .
                                        ' (' . $this->getMimeType() . "), but can't!\n" );
 
-                               return $this->getURL(); #hm... return NULL?
+                               return $this->getURL(); # hm... return NULL?
                        }
                } else {
                        return $this->getURL();
@@ -806,17 +806,17 @@ abstract class File implements IDBAccessObject {
 
                $type = $this->getMediaType();
                $mime = $this->getMimeType();
-               #wfDebug( "LocalFile::isSafeFile: type= $type, mime= $mime\n" );
+               # wfDebug( "LocalFile::isSafeFile: type= $type, mime= $mime\n" );
 
                if ( !$type || $type === MEDIATYPE_UNKNOWN ) {
-                       return false; #unknown type, not trusted
+                       return false; # unknown type, not trusted
                }
                if ( in_array( $type, $wgTrustedMediaFormats ) ) {
                        return true;
                }
 
                if ( $mime === "unknown/unknown" ) {
-                       return false; #unknown type, not trusted
+                       return false; # unknown type, not trusted
                }
                if ( in_array( $mime, $wgTrustedMediaFormats ) ) {
                        return true;
@@ -839,8 +839,8 @@ abstract class File implements IDBAccessObject {
         * @return bool
         */
        function isTrustedFile() {
-               #this could be implemented to check a flag in the database,
-               #look for signatures, etc
+               # this could be implemented to check a flag in the database,
+               # look for signatures, etc
                return false;
        }
 
index d2c37e6..d146708 100644 (file)
@@ -308,8 +308,9 @@ class LocalFile extends File {
                }
 
                // Cache presence for 1 week and negatives for 1 day
-               $cache = ObjectCache::getMainWANInstance();
-               $cache->set( $key, $cacheVal, $this->fileExists ? 86400 * 7 : 86400 );
+               $ttl = $this->fileExists ? 86400 * 7 : 86400;
+               $opts = array( 'since' => wfGetDB( DB_SLAVE )->trxTimestamp() );
+               ObjectCache::getMainWANInstance()->set( $key, $cacheVal, $ttl, $opts );
        }
 
        /**
@@ -321,7 +322,9 @@ class LocalFile extends File {
                        return;
                }
 
-               ObjectCache::getMainWANInstance()->delete( $key );
+               $this->repo->getMasterDB()->onTransactionPreCommitOrIdle( function() use ( $key ) {
+                       ObjectCache::getMainWANInstance()->delete( $key );
+               } );
        }
 
        /**
@@ -456,7 +459,7 @@ class LocalFile extends File {
        }
 
        /**
-        * @param array $row Row
+        * @param array|object $row
         * @param string $prefix
         * @throws MWException
         * @return array
@@ -2212,7 +2215,6 @@ class LocalFileDeleteBatch {
 
                // Lock the filearchive rows so that the files don't get deleted by a cleanup operation
                // We acquire this lock by running the inserts now, before the file operations.
-               //
                // This potentially has poor lock contention characteristics -- an alternative
                // scheme would be to insert stub filearchive entries with no fa_name and commit
                // them in a separate transaction, then run the file ops, then update the fa_name fields.
index 0df6f84..0934f6a 100644 (file)
@@ -46,6 +46,7 @@ class TraditionalImageGallery extends ImageGalleryBase {
                        array( 'class' => 'gallery mw-gallery-' . $this->mMode ), $this->mAttribs );
 
                $modules = $this->getModules();
+               $modules[] = 'mediawiki.page.gallery.styles';
 
                if ( $this->mParser ) {
                        $this->mParser->getOutput()->addModules( $modules );
index 56a23ad..5a1006a 100644 (file)
@@ -15,8 +15,9 @@ class HTMLButtonField extends HTMLFormField {
 
        public function __construct( $info ) {
                $info['nodata'] = true;
-               if ( isset( $info['flags'] ) )
+               if ( isset( $info['flags'] ) ) {
                        $this->mFlags = $info['flags'];
+               }
                parent::__construct( $info );
        }
 
@@ -28,7 +29,7 @@ class HTMLButtonField extends HTMLFormField {
                ) {
                        $prefix = 'mw-ui-';
                        // add mw-ui-button separately, so the descriptor doesn't need to set it
-                       $flags .= ' ' . $prefix.'button';
+                       $flags .= ' ' . $prefix . 'button';
                }
                foreach ( $this->mFlags as $flag ) {
                        $flags .= ' ' . $prefix . $flag;
index 9666c4e..b226854 100644 (file)
@@ -56,7 +56,10 @@ class HTMLCheckField extends HTMLFormField {
                $attr['id'] = $this->mID;
                $attr['name'] = $this->mName;
 
-               $attr += $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) );
+               $attr += $this->getAttributes(
+                       array( 'disabled', 'tabindex' ),
+                       array( 'tabindex' => 'tabIndex' )
+               );
 
                if ( $this->mClass !== '' ) {
                        $attr['classes'] = array( $this->mClass );
index 08fa0a9..e51620f 100644 (file)
@@ -537,6 +537,12 @@ class HTMLForm extends ContextSource {
         *       params) or strings (message keys)
         */
        function trySubmit() {
+               $valid = true;
+               $hoistedErrors = array();
+               $hoistedErrors[] = isset( $this->mValidationErrorMessage )
+                       ? $this->mValidationErrorMessage
+                       : array( 'htmlform-invalid-input' );
+
                $this->mWasSubmitted = true;
 
                # Check for cancelled submission
@@ -558,15 +564,20 @@ class HTMLForm extends ContextSource {
                        if ( $field->isHidden( $this->mFieldData ) ) {
                                continue;
                        }
-                       if ( $field->validate(
-                                       $this->mFieldData[$fieldname],
-                                       $this->mFieldData )
-                               !== true
-                       ) {
-                               return isset( $this->mValidationErrorMessage )
-                                       ? $this->mValidationErrorMessage
-                                       : array( 'htmlform-invalid-input' );
+                       $res = $field->validate( $this->mFieldData[$fieldname], $this->mFieldData );
+                       if ( $res !== true ) {
+                               $valid = false;
+                               if ( $res !== false && !$field->canDisplayErrors() ) {
+                                       $hoistedErrors[] = array( 'rawmessage', $res );
+                               }
+                       }
+               }
+
+               if ( !$valid ) {
+                       if ( count( $hoistedErrors ) === 1 ) {
+                               $hoistedErrors = $hoistedErrors[0];
                        }
+                       return $hoistedErrors;
                }
 
                $callback = $this->mSubmitCallback;
@@ -948,7 +959,11 @@ class HTMLForm extends ContextSource {
                        $html = Xml::fieldset( $legend, $html );
                }
 
-               return Html::rawElement( 'form', $this->getFormAttributes() + array( 'class' => 'visualClear' ), $html );
+               return Html::rawElement(
+                       'form',
+                       $this->getFormAttributes() + array( 'class' => 'visualClear' ),
+                       $html
+               );
        }
 
        /**
index 13756e3..20d7250 100644 (file)
@@ -55,6 +55,15 @@ abstract class HTMLFormField {
                return false;
        }
 
+       /**
+        * True if this field type is able to display errors; false if validation errors need to be
+        * displayed in the main HTMLForm error area.
+        * @return bool
+        */
+       public function canDisplayErrors() {
+               return true;
+       }
+
        /**
         * Get a translated interface message
         *
@@ -916,7 +925,8 @@ abstract class HTMLFormField {
         * Returns the given attributes from the parameters
         *
         * @param array $list List of attributes to get
-        * @param array $mappings Optional - Key/value map of attribute names to use instead of the ones passed in
+        * @param array $mappings Optional - Key/value map of attribute names to use
+        *   instead of the ones passed in.
         * @return array Attributes
         */
        public function getAttributes( array $list, array $mappings = null ) {
index ffde915..e4695f7 100644 (file)
@@ -55,4 +55,8 @@ class HTMLHiddenField extends HTMLFormField {
        public function getInputHTML( $value ) {
                return '';
        }
+
+       public function canDisplayErrors() {
+               return false;
+       }
 }
index a225c67..ade4cf7 100644 (file)
@@ -55,7 +55,9 @@ class HTMLTitleTextField extends HTMLTextField {
                }
 
                $text = $title->getPrefixedText();
-               if ( $this->mParams['namespace'] !== false && !$title->inNamespace( $this->mParams['namespace'] ) ) {
+               if ( $this->mParams['namespace'] !== false &&
+                       !$title->inNamespace( $this->mParams['namespace'] )
+               ) {
                        return $this->msg( 'htmlform-title-badnamespace', $this->mParams['namespace'], $text )->parse();
                }
 
index f8aa0ac..60f02a1 100644 (file)
@@ -39,7 +39,9 @@ class OOUIHTMLForm extends HTMLForm {
         */
        protected $displayFormat = 'ooui';
 
-       public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+       public static function loadInputFromParameters( $fieldname, $descriptor,
+               HTMLForm $parent = null
+       ) {
                $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
                $field->setShowEmptyLabel( false );
                return $field;
index 3788379..124a3d5 100644 (file)
@@ -42,7 +42,9 @@ class VFormHTMLForm extends HTMLForm {
                return true;
        }
 
-       public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+       public static function loadInputFromParameters( $fieldname, $descriptor,
+               HTMLForm $parent = null
+       ) {
                $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
                $field->setShowEmptyLabel( false );
                return $field;
index 7070790..57084cb 100644 (file)
@@ -455,6 +455,7 @@ abstract class DatabaseUpdater {
                        flush();
                        if ( $ret !== false ) {
                                $updatesDone[] = $origParams;
+                               wfWaitForSlaves();
                        } else {
                                $updatesSkipped[] = array( $func, $params, $origParams );
                        }
index 662469b..064bd6d 100644 (file)
@@ -370,12 +370,14 @@ abstract class Installer {
                $GLOBALS['wgMemc'] = new EmptyBagOStuff;
                ObjectCache::clear();
                $emptyCache = array( 'class' => 'EmptyBagOStuff' );
+               // disable (problematic) object cache types explicitly, preserving all other (working) ones
+               // bug T113843
                $GLOBALS['wgObjectCaches'] = array(
                        CACHE_NONE => $emptyCache,
                        CACHE_DB => $emptyCache,
                        CACHE_ANYTHING => $emptyCache,
                        CACHE_MEMCACHED => $emptyCache,
-               );
+               ) + $GLOBALS['wgObjectCaches'];
 
                // Load the installer's i18n.
                $wgMessagesDirs['MediawikiInstaller'] = __DIR__ . '/i18n';
@@ -534,13 +536,15 @@ abstract class Installer {
                // then some poorly-formed extensions try to call their own classes
                // after immediately registering them. We really need to get extension
                // registration out of the global scope and into a real format.
-               // @see https://bugzilla.wikimedia.org/67440
+               // @see https://phabricator.wikimedia.org/T69440
                global $wgAutoloadClasses;
                $wgAutoloadClasses = array();
 
+               // @codingStandardsIgnoreStart
                // LocalSettings.php should not call functions, except wfLoadSkin/wfLoadExtensions
                // Define the required globals here, to ensure, the functions can do it work correctly.
                global $wgExtensionDirectory, $wgStyleDirectory;
+               // @codingStandardsIgnoreEnd
 
                MediaWiki\suppressWarnings();
                $_lsExists = file_exists( "$IP/LocalSettings.php" );
@@ -1477,7 +1481,7 @@ abstract class Installer {
                 * want here is $wgHooks['LoadExtensionSchemaUpdates']. This won't work
                 * if the extension has hidden hook registration in $wgExtensionFunctions,
                 * but we're not opening that can of worms
-                * @see https://bugzilla.wikimedia.org/show_bug.cgi?id=26857
+                * @see https://phabricator.wikimedia.org/T28857
                 */
                global $wgAutoloadClasses;
                $wgAutoloadClasses = array();
@@ -1746,7 +1750,7 @@ abstract class Installer {
                                User::newFromName( 'MediaWiki default' )
                        );
                } catch ( Exception $e ) {
-                       //using raw, because $wgShowExceptionDetails can not be set yet
+                       // using raw, because $wgShowExceptionDetails can not be set yet
                        $status->fatal( 'config-install-mainpage-failed', $e->getMessage() );
                }
 
index cb40f88..c10e81a 100644 (file)
@@ -83,7 +83,12 @@ class PostgresInstaller extends DatabaseInstaller {
 
        function submitConnectForm() {
                // Get variables from the request
-               $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema' ) );
+               $newValues = $this->setVarsFromRequest( array(
+                       'wgDBserver',
+                       'wgDBport',
+                       'wgDBname',
+                       'wgDBmwschema'
+               ) );
 
                // Validate them
                $status = Status::newGood();
index e1063b0..7414d92 100644 (file)
@@ -250,7 +250,8 @@ class PostgresUpdater extends DatabaseUpdater {
                        array( 'addPgIndex', 'recentchanges', 'rc_timestamp_bot', '(rc_timestamp) WHERE rc_bot = 0' ),
                        array( 'addPgIndex', 'templatelinks', 'templatelinks_from', '(tl_from)' ),
                        array( 'addPgIndex', 'watchlist', 'wl_user', '(wl_user)' ),
-                       array( 'addPgIndex', 'watchlist', 'wl_user_notificationtimestamp', '(wl_user, wl_notificationtimestamp)' ),
+                       array( 'addPgIndex', 'watchlist', 'wl_user_notificationtimestamp',
+                               '(wl_user, wl_notificationtimestamp)' ),
                        array( 'addPgIndex', 'logging', 'logging_user_type_time',
                                '(log_user, log_type, log_timestamp)' ),
                        array( 'addPgIndex', 'logging', 'logging_page_id_time', '(log_page,log_timestamp)' ),
@@ -691,8 +692,8 @@ END;
        }
 
        protected function changeFieldPurgeTable( $table, $field, $newtype, $default ) {
-               ## For a cache table, empty it if the field needs to be changed, because the old contents
-               ## may be corrupted.  If the column is already the desired type, refrain from purging.
+               # # For a cache table, empty it if the field needs to be changed, because the old contents
+               # # may be corrupted.  If the column is already the desired type, refrain from purging.
                $fi = $this->db->fieldInfo( $table, $field );
                if ( is_null( $fi ) ) {
                        $this->output( "...ERROR: expected column $table.$field to exist\n" );
@@ -955,6 +956,7 @@ END;
                        $this->output( "...bug 66650 already fixed or not applicable.\n" );
                        return true;
                };
-               $this->applyPatch( 'patch-textsearch_bug66650.sql', false, "Rebuilding text search for bug 66650" );
+               $this->applyPatch( 'patch-textsearch_bug66650.sql', false,
+                       'Rebuilding text search for bug 66650' );
        }
 }
index 2693be0..0de1fd7 100644 (file)
@@ -132,7 +132,8 @@ class SqliteUpdater extends DatabaseUpdater {
                        // 1.24
                        array( 'addField', 'page_props', 'pp_sortkey', 'patch-pp_sortkey.sql' ),
                        array( 'dropField', 'recentchanges', 'rc_cur_time', 'patch-drop-rc_cur_time.sql' ),
-                       array( 'addIndex', 'watchlist', 'wl_user_notificationtimestamp', 'patch-watchlist-user-notificationtimestamp-index.sql' ),
+                       array( 'addIndex', 'watchlist', 'wl_user_notificationtimestamp',
+                               'patch-watchlist-user-notificationtimestamp-index.sql' ),
                        array( 'addField', 'page', 'page_lang', 'patch-page-page_lang.sql' ),
                        array( 'addField', 'pagelinks', 'pl_from_namespace', 'patch-pl_from_namespace.sql' ),
                        array( 'addField', 'templatelinks', 'tl_from_namespace', 'patch-tl_from_namespace.sql' ),
index 74904f1..c2243b9 100644 (file)
@@ -960,7 +960,8 @@ class WebInstaller extends Installer {
         *      var:             The variable to be configured (required)
         *      label:           The message name for the label (required)
         *      itemLabelPrefix: The message name prefix for the item labels (required)
-        *      itemLabels:      List of message names to use for the item labels instead of itemLabelPrefix, keyed by values
+        *      itemLabels:      List of message names to use for the item labels instead
+        *                       of itemLabelPrefix, keyed by values
         *      values:          List of allowed values (required)
         *      itemAttribs:     Array of attribute arrays, outer key is the value name (optional)
         *      commonAttribs:   Attribute array applied to all items
index 0ccdb11..211bad1 100644 (file)
@@ -170,7 +170,8 @@ class WebInstallerOutput {
                        $styles = array_merge( $styles, ResourceLoader::makeCombinedStyles(
                                $module->readStyleFiles(
                                        $module->getStyleFiles( $rlContext ),
-                                       $module->getFlip( $rlContext )
+                                       $module->getFlip( $rlContext ),
+                                       $rlContext
                        ) ) );
                }
 
index 573172d..31547ad 100644 (file)
        "config-profile-no-anon": "계정 만들기 필요",
        "config-profile-fishbowl": "승인된 편집자만",
        "config-profile-private": "비공개 위키",
-       "config-profile-help": "ì\9c\84í\82¤ë\8a\94 ê°\80ë\8a¥í\95\9c ë§\8eì\9d\80 ì\82¬ë\9e\8cë\93¤ì\9d´ í\8e¸ì§\91í\95  ì\88\98 ì\9e\88ë\8f\84ë¡\9d í\95  ë\95\8c ê°\80ì\9e¥ ë\9b°ì\96´ë\82\9c ì\97­í\95 ì\9d\84 í\95©ë\8b\88ë\8b¤.\n미ë\94\94ì\96´ì\9c\84í\82¤ì\97\90ì\84\9cë\8a\94 ìµ\9cê·¼ ë°\94ë\80\9cì\9d\84 ê²\80í\86 í\95\98기 ì\89½ê³ , ë¯¸ì\88\99í\95\98ê±°ë\82\98 ì\95\85ì\9d\98ì \81ì\9d¸ ì\82¬ì\9a©ì\9e\90ì\9d\98 ì\96´ë\96 한 손실을 되돌리는 것이 쉽습니다.\n\n그러나 많은 사람이 미디어위키가 다양한 역할을 수행하는 데 유용하다는 것을 알고 있지만, 때로는 모든 사람에게 위키 방식의 장점을 설득하기 쉽지 않을 지도 모릅니다.\n그래서 선택할 수 있습니다.\n\n<strong>{{int:config-profile-wiki}}/<strong> 모델은 로그인하지 않고도 누구나 편집할 수 있습니다.\n<strong>{{int:config-profile-no-anon}}</strong>인 위키에서는 편집자에게 추가적인 책임을 부여하지만, 부담 없는 기여를 저해할 수도 있습니다.\n\n<strong>{{int:config-profile-fishbowl}}</strong> 시나리오에서는 승인된 사용자만 편집할 수 있지만, 일반 사용자도 문서(문서 역사 포함)는 볼 수 있습니다.\n<strong>{{int:config-profile-private}}</strong>는 승인된 사용자만 문서를 볼 수 있으며, 승인된 사용자 그룹이 편집할 수 있습니다.\n\n더 복잡한 사용자 권한 설정은 설치한 후 사용할 수 있으며 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights 관련 설명서 항목]을 참조하세요.",
+       "config-profile-help": "ì\9c\84í\82¤ë\8a\94 ê°\80ë\8a¥í\95\9c ë§\8eì\9d\80 ì\82¬ë\9e\8cë\93¤ì\9d´ í\8e¸ì§\91í\95  ì\88\98 ì\9e\88ë\8f\84ë¡\9d í\95  ë\95\8c ê°\80ì\9e¥ ë\9b°ì\96´ë\82\9c ì\97­í\95 ì\9d\84 í\95©ë\8b\88ë\8b¤.\n미ë\94\94ì\96´ì\9c\84í\82¤ì\97\90ì\84\9cë\8a\94 ìµ\9cê·¼ ë°\94ë\80\9cì\9d\84 ê²\80í\86 í\95\98기 ì\89½ê³ , ë¯¸ì\88\99í\95\98ê±°ë\82\98 ì\95\85ì\9d\98ì \81ì\9d¸ ì\82¬ì\9a©ì\9e\90ì\97\90 ì\9d\98한 손실을 되돌리는 것이 쉽습니다.\n\n그러나 많은 사람이 미디어위키가 다양한 역할을 수행하는 데 유용하다는 것을 알고 있지만, 때로는 모든 사람에게 위키 방식의 장점을 설득하기 쉽지 않을 지도 모릅니다.\n그래서 선택할 수 있습니다.\n\n<strong>{{int:config-profile-wiki}}/<strong> 모델은 로그인하지 않고도 누구나 편집할 수 있습니다.\n<strong>{{int:config-profile-no-anon}}</strong>인 위키에서는 편집자에게 추가적인 책임을 부여하지만, 부담 없는 기여를 저해할 수도 있습니다.\n\n<strong>{{int:config-profile-fishbowl}}</strong> 시나리오에서는 승인된 사용자만 편집할 수 있지만, 일반 사용자도 문서(문서 역사 포함)는 볼 수 있습니다.\n<strong>{{int:config-profile-private}}</strong>는 승인된 사용자만 문서를 볼 수 있으며, 승인된 사용자 그룹이 편집할 수 있습니다.\n\n더 복잡한 사용자 권한 설정은 설치한 후 사용할 수 있으며 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights 관련 설명서 항목]을 참조하세요.",
        "config-license": "저작권 및 라이선스:",
        "config-license-none": "라이선스 바닥글 없음",
        "config-license-cc-by-sa": "크리에이티브 커먼즈 저작자표시-동일조건변경허락",
index f7e4e67..dad7b4c 100644 (file)
@@ -2,14 +2,16 @@
        "@metadata": {
                "authors": [
                        "Eitvys200",
-                       "Mantak111"
+                       "Mantak111",
+                       "Zygimantus"
                ]
        },
        "config-desc": "MediaWiki diegimas",
        "config-title": "MediaWiki $1 diegimas",
        "config-information": "Informacija",
        "config-localsettings-key": "Naujinimo raktas:",
-       "config-localsettings-badkey": "Raktą, kurį pateikėte yra neteisingas.",
+       "config-localsettings-badkey": "Raktas, kurį pateikėte, yra neteisingas.",
+       "config-session-error": "Klaida pradedant seansą: $1",
        "config-your-language": "Jūsų kalba:",
        "config-wiki-language": "Viki kalba:",
        "config-back": "← Atgal",
        "config-page-install": "Įdiegti",
        "config-page-complete": "Baigta!",
        "config-page-restart": "Iš naujo paleiskite diegimą",
-       "config-page-readme": "Perskaityk manę",
+       "config-page-readme": "Skaityti daugiau",
+       "config-page-releasenotes": "Leidimo pastabos",
        "config-page-copying": "Kopijuojama",
        "config-page-upgradedoc": "Atnaujinama",
-       "config-page-existingwiki": "Esamas wiki",
+       "config-page-existingwiki": "Esamas viki",
        "config-restart": "Taip, paleiskite jį iš naujo",
        "config-env-php": "PHP $1 yra įdiegtas.",
-       "config-env-php-toolow": "PHP $1 įdiegta.\nTačiau, MediaWiki reikia PHP $2 ar naujesnės.",
        "config-db-type": "Duomenų bazės tipas:",
        "config-db-host": "Duomenų bazės serveris:",
        "config-db-name": "Duomenų bazės pavadinimas:",
        "config-mssql-windowsauth": "Windows autentifikavimas",
        "config-site-name": "Viki pavadinimas:",
        "config-site-name-blank": "Įveskite svetainės pavadinimą.",
-       "config-project-namespace": "Projekto pavadinimas:",
+       "config-project-namespace": "Projekto vardų sritis:",
        "config-ns-generic": "Projektas",
        "config-ns-site-name": "Toks pat kaip viki pavadinimas: $1",
-       "config-ns-other-default": "ManoWiki",
+       "config-ns-other-default": "ManoViki",
        "config-admin-box": "Administratoriaus paskyra",
-       "config-admin-name": "Jūsų vardas:",
+       "config-admin-name": "Jūsų naudotojo vardas:",
        "config-admin-password": "Slaptažodis:",
        "config-admin-password-confirm": "Slaptažodis dar kartą:",
        "config-admin-name-blank": "Įveskite administratoriaus vartotojo vardą.",
@@ -67,9 +69,9 @@
        "config-optional-continue": "Paklausti daugiau klausimų.",
        "config-optional-skip": "Man jau nuobodu, tiesiog įdiekite viki.",
        "config-profile": "Vartotojo teisių paskyra:",
-       "config-profile-wiki": "Tradicinė viki",
+       "config-profile-wiki": "Atidaryti viki",
        "config-profile-private": "Privati viki",
-       "config-license-pd": "Viešas Domenas",
+       "config-license-pd": "Viešas domenas",
        "config-email-settings": "El. pašto nustatymai",
        "config-upload-enable": "Įgalinti failų įkėlimus",
        "config-logo": "Logotipo URL:",
@@ -81,7 +83,7 @@
        "config-install-tables": "Kuriamos lentelės",
        "config-install-stats": "Inicijuojamos statistikos",
        "config-install-keys": "Generuojami slapti raktai",
-       "config-install-done": "'''Sveikiname!'''\nJūs sėkmingai įdiegėte MediaWiki.\n\nĮdiegimo programa sukūrė <code>LocalSettings.php</code> failą.\nJame yra visos jūsų konfigūracijos.\n\nJums reikės atsisiųsti ir įdėti jį į savo wiki įdiegimo bazę (pačiame kataloge, kaip index.php). Atsisiuntimas turėtų prasidėti automatiškai.\n\nJei atsisiuntimas nebuvo pasiūlytas, arba jį atšaukėte, galite iš naujo atsisiųsti paspaudę žemiau esančią nuorodą:\n\n$3\n\n'''Pastaba:''' Jei jūs to nepadarysite dabar, tada šis sukurtas konfigūracijos failas nebus galimas vėliau, jei išeisite iš įdiegimo be atsisiuntimo.\n\nKai baigsite, jūs galėsite '''[$2 įeiti į savo wiki]'''.",
+       "config-install-done": "'''Sveikiname!'''\nJūs sėkmingai įdiegėte MediaWiki.\n\nĮdiegimo programa sukūrė <code>LocalSettings.php</code> failą.\nJame yra visos jūsų konfigūracijos.\n\nJums reikės atsisiųsti ir įdėti jį į savo wiki įdiegimo bazę (pačiame kataloge, kaip index.php). Atsisiuntimas turėtų prasidėti automatiškai.\n\nJei atsisiuntimas nebuvo pasiūlytas, arba jį atšaukėte, galite iš naujo atsisiųsti paspaudę žemiau esančią nuorodą:\n\n$3\n\n'''Pastaba:''' Jei jūs to nepadarysite dabar, tada šis sukurtas konfigūracijos failas nebus galimas vėliau, jei išeisite iš įdiegimo be atsisiuntimo.\n\nKai baigsite, jūs galėsite '''[$2 įeiti į savo viki]'''.",
        "config-download-localsettings": "Atsisiųsti <code>LocalSettings.php</code>",
        "config-help": "pagalba",
        "mainpagetext": "'''MediaWiki sėkmingai įdiegta.'''",
index f518d15..c5bcf7d 100644 (file)
        "config-email-watchlist": "Appiccia notifica 'osservati speciale",
        "config-email-watchlist-help": "Premmettesse ll'utente 'e se piglià notifiche ncopp' 'e paggene cuntrullate lloro si tenessero appicciate chisto in'a le mpustaziune.",
        "config-email-auth": "Appiccia autenticaziona via email",
+       "config-email-auth-help": "Si st'opzione è appicciata, ll'utente avesser'a cunfermà 'o cunto e-mail ausanno nu cullegamento ca se mannasse a chiste quanno facessero 'a mpustaziona o pure quanno facessero 'o cagnamiento.\nSurtanto 'e mail autenticate putesser piglià mail 'a ll'at'utente o cagnà email 'e notifica.\nMpustà st'opzione è <strong>raccumannato</strong p' 'e wiki pubbreche pecché se putesse ausà o se fà abbuso d' 'e funziune mail.",
        "config-email-sender": "Innerizo email e ritorno:",
        "config-upload-settings": "Immaggene e upload",
        "config-upload-enable": "Premmette 'a carreca 'e file",
index 75f73d3..7f76504 100644 (file)
@@ -2,10 +2,13 @@
        "@metadata": {
                "authors": [
                        "Aalam",
-                       "Babanwalia"
+                       "Babanwalia",
+                       "ਪ੍ਰਚਾਰਕ"
                ]
        },
+       "config-desc": "ਮੀਡੀਅਾਵਿਕੀ ਲੲੀ ਸਥਾਪਿਤਕਰਤਾ",
        "config-information": "ਜਾਣਕਾਰੀ",
+       "config-localsettings-badkey": "ਤੁਹਾਡੇ ਦੁਅਾਰਾ ਦਿਤੀ ਗੲੀ ਚਾਬੀ ਗਲਤ ਹੈ",
        "config-your-language": "ਤੁਹਾਡੀ ਭਾਸ਼ਾ:",
        "config-your-language-help": "ਜੜਾਈ ਦੀ ਕਾਰਵਾਈ ਵੇਲੇ ਵਰਤਣ ਵਾਸਤੇ ਕੋਈ ਭਾਸ਼ਾ ਚੁਣੋ।",
        "config-wiki-language": "ਵਿਕੀ ਦੀ ਭਾਸ਼ਾ:",
@@ -27,6 +30,8 @@
        "config-page-upgradedoc": "ਮਿਆਰ-ਉਚਾਈ",
        "config-page-existingwiki": "ਮੌਜੂਦਾ ਵਿਕੀ",
        "config-restart": "ਹਾਂਜੀ, ਮੁੜ ਸ਼ੁਰੂ ਕਰੋ",
+       "config-env-good": "ਵਾਤਾਵਰਨ ਪਰਖਿਅਾ ਗਿਅਾ ਹੈ।\nਤੁਸੀਂ ਮੀਡੀਆਵਿਕੀ ਸਥਾਪਿਤ ਕਰ ਸਕਦੇ ਹੋ",
+       "config-env-bad": "ਵਾਤਾਵਰਨ ਪਰਖਿਅਾ ਗਿਅਾ ਹੈ।\nਤੁਸੀਂ ਮੀਡੀਆਵਿਕੀ ਸਥਾਪਿਤ ਨਹੀਂ ਕਰ ਸਕਦੇ ਹੋ",
        "config-env-php": "PHP $1 ਜੜਿਆ ਗਿਆ।",
        "config-env-hhvm": "HHVM $1 ਜੜਿਆ ਗਿਆ।",
        "config-db-wiki-settings": "ਇਸ ਵਿਕੀ ਦੀ ਪਛਾਣ ਕਰਾਉ",
index dfe4376..c4ccec6 100644 (file)
@@ -58,7 +58,7 @@
        "config-help-restart": "Вы хотите удалить все сохранённые данные, которые вы ввели, и запустить процесс установки заново?",
        "config-restart": "Да, начать заново",
        "config-welcome": "=== Проверка окружения ===\nБудут проведены базовые проверки с целью определить, подходит ли данная система для установки MediaWiki.\nНе забудьте включить эту информацию, если вам потребуется помощь для завершения установки.",
-       "config-copyright": "=== Авторские права и условия ===\n\n$1\n\nMediaWiki является свободным программным обеспечением, которое вы можете распространять и/или изменять в соответствии с условиями лицензии GNU General Public License, опубликованной фондом свободного программного обеспечения; второй версии, либо любой более поздней версии.\n\nMediaWiki распространяется в надежде, что она будет полезной, но '''без каких-либо гарантий''', даже без подразумеваемых гарантий '''коммерческой ценности''' или '''пригодности для определённой цели'''. См. лицензию GNU General Public License для более подробной информации.\n\nВы должны были получить <doclink href=Copying>копию GNU General Public License</doclink> вместе с этой программой, если нет, то напишите Free Software Foundation, Inc., по адресу: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA или [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html прочтите её онлайн].",
+       "config-copyright": "=== Авторские права и условия ===\n\n$1\n\nMediaWiki — свободное программное обеспечение, которое вы можете распространять и/или изменять в соответствии с условиями лицензии GNU General Public License, опубликованной фондом свободного программного обеспечения; второй версии, либо любой более поздней версии.\n\nMediaWiki распространяется в надежде, что она будет полезной, но <strong>без каких-либо гарантий</strong>, даже без подразумеваемых гарантий <strong>коммерческой ценности</strong> или <strong>пригодности для определённой цели</strong>. См. лицензию GNU General Public License для более подробной информации.\n\nВы должны были получить <doclink href=Copying>копию GNU General Public License</doclink> вместе с этой программой, если нет, то напишите Free Software Foundation, Inc., по адресу: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA или [http://www.gnu.org/copyleft/gpl.html прочтите её онлайн].",
        "config-sidebar": "* [//www.mediawiki.org Сайт MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents/ru Справка для пользователей]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents/ru Справка для администраторов]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/ru FAQ]\n----\n* <doclink href=Readme>Readme-файл</doclink>\n* <doclink href=ReleaseNotes>Информация о выпуске</doclink>\n* <doclink href=Copying>Лицензия</doclink>\n* <doclink href=UpgradeDoc>Обновление</doclink>",
        "config-env-good": "Проверка внешней среды была успешно проведена.\nВы можете установить MediaWiki.",
        "config-env-bad": "Была проведена проверка внешней среды.\nВы не можете установить MediaWiki.",
index 388968b..a6f0745 100644 (file)
@@ -7,7 +7,7 @@
        },
        "config-desc": "Instaluesi për MediaWiki",
        "config-title": "Instalimi MediaWiki $1",
-       "config-information": "Të dhëna",
+       "config-information": "Informacion",
        "config-your-language": "Gjuha e juaj:",
        "config-your-language-help": "Zgjidhni një gjuhë për ta përdorur gjatë procesit të instalimit.",
        "config-wiki-language": "Gjuha e wikit:",
@@ -16,7 +16,7 @@
        "config-continue": "Para →",
        "config-page-language": "Gjuha",
        "config-page-welcome": "Mirësevini në MediaWiki!",
-       "config-page-dbconnect": "Lidhuni me bazën e të dhënave",
+       "config-page-dbconnect": "Lidhu me bazën e të dhënave",
        "config-page-dbsettings": "Parametrat e bazës së të dhënave",
        "config-page-name": "Emri",
        "config-page-options": "Opcionet",
@@ -38,6 +38,7 @@
        "config-license-pd": "Domeni publik",
        "config-logo": "URL e logos:",
        "config-install-tables": "Duke krijuar tabela",
+       "config-install-stats": "Nisja e statistikave",
        "config-help": "ndihmë",
        "mainpagetext": "'''MediaWiki software u instalua me sukses.'''",
        "mainpagedocfooter": "Për më shumë informata rreth përdorimit të softwerit wiki , ju lutem shikoni [//meta.wikimedia.org/wiki/Help:Contents dokumentacionin përkatës].\n\n== Sa për fillim==\n* [//www.mediawiki.org/wiki/Help:Configuration_settings Parazgjedhjet e MediaWiki-t]\n* [//www.mediawiki.org/wiki/Help:FAQ Pyetjet e shpeshta rreth MediaWiki-t]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Njoftime rreth MediaWiki-t]"
index a9010c2..ef9fec0 100644 (file)
@@ -85,8 +85,6 @@ class HTMLCacheUpdateJob extends Job {
                        return;
                }
 
-               $dbw = wfGetDB( DB_MASTER );
-
                // The page_touched field will need to be bumped for these pages.
                // Only bump it to the present time if no "rootJobTimestamp" was known.
                // If it is known, it can be used instead, which avoids invalidating output
@@ -100,9 +98,12 @@ class HTMLCacheUpdateJob extends Job {
                        $touchTimestamp = wfTimestampNow();
                }
 
+               $dbw = wfGetDB( DB_MASTER );
                // Update page_touched (skipping pages already touched since the root job).
                // Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
                foreach ( array_chunk( $pageIds, $wgUpdateRowsPerQuery ) as $batch ) {
+                       $dbw->commit( __METHOD__, 'flush' );
+
                        $dbw->update( 'page',
                                array( 'page_touched' => $dbw->timestamp( $touchTimestamp ) ),
                                array( 'page_id' => $batch,
index 935d2fb..4ba1d4c 100644 (file)
@@ -47,13 +47,13 @@ class RefreshLinksJob extends Job {
                }
                // Base backlink update jobs and per-title update jobs can be de-duplicated.
                // If template A changes twice before any jobs run, a clean queue will have:
-               //              (A base, A base)
+               //              (A base, A base)
                // The second job is ignored by the queue on insertion.
                // Suppose, many pages use template A, and that template itself uses template B.
                // An edit to both will first create two base jobs. A clean FIFO queue will have:
-               //              (A base, B base)
+               //              (A base, B base)
                // When these jobs run, the queue will have per-title and remnant partition jobs:
-               //              (titleX,titleY,titleZ,...,A remnant,titleM,titleN,titleO,...,B remnant)
+               //              (titleX,titleY,titleZ,...,A remnant,titleM,titleN,titleO,...,B remnant)
                // Some these jobs will be the same, and will automatically be ignored by
                // the queue upon insertion. Some title jobs will run before the duplicate is
                // inserted, so the work will still be done twice in those cases. More titles
index f558c48..0abc0e3 100644 (file)
@@ -59,14 +59,16 @@ class ThumbnailRenderJob extends Job {
                                if ( $status === 200 || $status === 301 || $status === 302 || $status === 400 ) {
                                        return true;
                                } elseif ( $status ) {
-                                       $this->setLastError( __METHOD__ . ': incorrect HTTP status ' . $status . ' when hitting ' . $thumbUrl );
+                                       $this->setLastError( __METHOD__ . ': incorrect HTTP status ' .
+                                               $status . ' when hitting ' . $thumbUrl );
                                        return false;
                                } else {
                                        $this->setLastError( __METHOD__ . ': HTTP request failure' );
                                        return false;
                                }
                        } else {
-                               $this->setLastError( __METHOD__ . ': unknown thumbnail render method ' . $wgUploadThumbnailRenderMethod );
+                               $this->setLastError( __METHOD__ . ': unknown thumbnail render method ' .
+                                       $wgUploadThumbnailRenderMethod );
                                return false;
                        }
                } else {
index 100d2a4..a0020da 100644 (file)
@@ -57,7 +57,9 @@ class BufferingStatsdDataFactory extends StatsdDataFactory {
                return str_replace( array( '._', '_.' ), '.', $key );
        }
 
-       public function produceStatsdData( $key, $value = 1, $metric = StatsdDataInterface::STATSD_METRIC_COUNT ) {
+       public function produceStatsdData(
+               $key, $value = 1, $metric = StatsdDataInterface::STATSD_METRIC_COUNT
+       ) {
                $entity = $this->produceStatsdDataEntity();
                if ( $key !== null ) {
                        $key = self::normalizeMetricKey( "{$this->prefix}.{$key}" );
index 5a8c4c7..6ca0fed 100644 (file)
@@ -180,6 +180,25 @@ class CSSMin {
                return false;
        }
 
+       /**
+        * Serialize a string (escape and quote) for use as a CSS string value.
+        * http://www.w3.org/TR/2013/WD-cssom-20131205/#serialize-a-string
+        *
+        * @param string $value
+        * @return string
+        * @throws Exception
+        */
+       public static function serializeStringValue( $value ) {
+               if ( strstr( $value, "\0" ) ) {
+                       throw new Exception( "Invalid character in CSS string" );
+               }
+               $value = strtr( $value, array( '\\' => '\\\\', '"' => '\\"' ) );
+               $value = preg_replace_callback( '/[\x01-\x1f\x7f-\x9f]/', function ( $match ) {
+                       return '\\' . base_convert( ord( $match[0] ), 10, 16 ) . ' ';
+               }, $value );
+               return '"' . $value . '"';
+       }
+
        /**
         * @param $file string
         * @return bool|string
@@ -285,7 +304,17 @@ class CSSMin {
                                // Check for global @embed comment and remove it. Allow other comments to be present
                                // before @embed (they have been replaced with placeholders at this point).
                                $embedAll = false;
-                               $rule = preg_replace( '/^((?:\s+|' . CSSMin::PLACEHOLDER . '(\d+)x)*)' . CSSMin::EMBED_REGEX . '\s*/', '$1', $rule, 1, $embedAll );
+                               $rule = preg_replace(
+                                       '/^((?:\s+|' .
+                                               CSSMin::PLACEHOLDER .
+                                               '(\d+)x)*)' .
+                                               CSSMin::EMBED_REGEX .
+                                               '\s*/',
+                                       '$1',
+                                       $rule,
+                                       1,
+                                       $embedAll
+                               );
 
                                // Build two versions of current rule: with remapped URLs
                                // and with embedded data: URIs (where possible).
index 442298a..3d7dee7 100644 (file)
@@ -102,7 +102,10 @@ class HttpStatus {
                }
 
                if ( $version === null ) {
-                       $version = isset( $_SERVER['SERVER_PROTOCOL'] ) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0' ? '1.0' : '1.1';
+                       $version = isset( $_SERVER['SERVER_PROTOCOL'] ) &&
+                               $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0' ?
+                                       '1.0' :
+                                       '1.1';
                }
 
                header( "HTTP/$version $code $message" );
index b6faa37..ea50a85 100644 (file)
@@ -112,7 +112,7 @@ class ReplacementArray {
         */
        public function replace( $subject ) {
                if (
-                       function_exists( 'fss_prep_replace' )  &&
+                       function_exists( 'fss_prep_replace' ) &&
                        version_compare( PHP_VERSION, '5.5.0' ) < 0
                ) {
                        if ( $this->fss === false ) {
index f7afdb5..a8477c9 100644 (file)
@@ -80,7 +80,7 @@ class SamplingStatsdClient extends StatsdClient {
                if ( $this->getReducePacket() ) {
                        $data = $this->reduceCount( $data );
                }
-               //failures in any of this should be silently ignored if ..
+               // failures in any of this should be silently ignored if ..
                $written = 0;
                try {
                        $fp = $this->getSender()->open();
index 41dc66f..f44bd7b 100644 (file)
 /**
  * Multi-datacenter aware caching interface
  *
- * All operations go to the local cache, except the delete()
- * and touchCheckKey(), which broadcast to all clusters.
+ * All operations go to the local datacenter cache, except for delete(),
+ * touchCheckKey(), and resetCheckKey(), which broadcast to all clusters.
+ *
  * This class is intended for caching data from primary stores.
  * If the get() method does not return a value, then the caller
  * should query the new value and backfill the cache using set().
- * When the source data changes, the delete() method should be called.
- * Since delete() is expensive, it should be avoided. One can do so if:
+ * When the source data changes, a purge method should be called.
+ * Since purges are expensive, they should be avoided. One can do so if:
  *   - a) The object cached is immutable; or
  *   - b) Validity is checked against the source after get(); or
  *   - c) Using a modest TTL is reasonably correct and performant
- * Consider using getWithSetCallback() instead of the get()/set() cycle.
+ * The simplest purge method is delete().
  *
  * Instances of this class must be configured to point to a valid
  * PubSub endpoint, and there must be listeners on the cache servers
@@ -67,8 +68,15 @@ class WANObjectCache {
        /** @var int */
        protected $lastRelayError = self::ERR_NONE;
 
+       /** Max time expected to pass between delete() and DB commit finishing */
+       const MAX_COMMIT_DELAY = 1;
+       /** Max expected replication lag for a reasonable storage setup */
+       const MAX_REPLICA_LAG = 7;
+       /** Max time since snapshot transaction start to avoid no-op of set() */
+       const MAX_SNAPSHOT_LAG = 6;
        /** Seconds to tombstone keys on delete() */
-       const HOLDOFF_TTL = 10;
+       const HOLDOFF_TTL = 14; // MAX_COMMIT_DELAY + MAX_REPLICA_LAG + MAX_SNAPSHOT_LAG
+
        /** Seconds to keep dependency purge keys around */
        const CHECK_KEY_TTL = 31536000; // 1 year
        /** Seconds to keep lock keys around */
@@ -159,7 +167,8 @@ class WANObjectCache {
         *   - b) Keeping transaction duration shorter than delete() hold-off TTL
         * However, pre-snapshot values might still be seen due to delete() relay lag.
         *
-        * For keys that are hot/expensive, consider using getWithSetCallback() instead.
+        * Consider using getWithSetCallback() instead of get()/set() cycles.
+        * That method has cache slam avoiding features for hot/expensive keys.
         *
         * @param string $key Cache key
         * @param mixed $curTTL Approximate TTL left on the key if present [returned]
@@ -248,13 +257,53 @@ class WANObjectCache {
         * the changes do not replicate to the other WAN sites. In that case, delete()
         * should be used instead. This method is intended for use on cache misses.
         *
+        * If the data was read from a snapshot-isolated transactions (e.g. the default
+        * REPEATABLE-READ in innoDB), use 'since' to avoid the following race condition:
+        *   - a) T1 starts
+        *   - b) T2 updates a row, calls delete(), and commits
+        *   - c) The HOLDOFF_TTL passes, expiring the delete() tombstone
+        *   - d) T1 reads the row and calls set() due to a cache miss
+        *   - e) Stale value is stuck in cache
+        *
+        * Example usage:
+        * @code
+        *     $dbr = wfGetDB( DB_SLAVE );
+        *     // Fetch the row from the DB
+        *     $row = $dbr->selectRow( ... );
+        *     $key = wfMemcKey( 'building', $buildingId );
+        *     // Give the age of the transaction snapshot the data came from
+        *     $opts = array( 'since' => $dbr->trxTimestamp() );
+        *     $cache->set( $key, $row, 86400, $opts );
+        * @endcode
+        *
         * @param string $key Cache key
         * @param mixed $value
         * @param integer $ttl Seconds to live [0=forever]
+        * @param array $opts Options map:
+        *   - since   : UNIX timestamp of the data in $value. Typically, this is either
+        *               the current time the data was read or (if applicable) the time when
+        *               the snapshot-isolated transaction the data was read from started.
+        *               [Default: 0 seconds]
+        *   - lockTSE : if excessive possible snapshot lag is detected,
+        *               then stash the value into a temporary location
+        *               with this TTL. This is only useful if the reads
+        *               use getWithSetCallback() with "lockTSE" set.
+        *               [Default: WANObjectCache::TSE_NONE]
         * @return bool Success
         */
-       final public function set( $key, $value, $ttl = 0 ) {
-               $key = self::VALUE_KEY_PREFIX . $key;
+       final public function set( $key, $value, $ttl = 0, array $opts = array() ) {
+               $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
+               $age = isset( $opts['since'] ) ? max( 0, microtime( true ) - $opts['since'] ) : 0;
+
+               if ( $age > self::MAX_SNAPSHOT_LAG ) {
+                       if ( $lockTSE >= 0 ) {
+                               $tempTTL = max( 1, (int)$lockTSE ); // set() expects seconds
+                               $this->cache->set( self::STASH_KEY_PREFIX . $key, $value, $tempTTL );
+                       }
+
+                       return true; // no-op the write for being unsafe
+               }
+
                $wrapped = $this->wrap( $value, $ttl );
 
                $func = function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
@@ -263,7 +312,7 @@ class WANObjectCache {
                                : $wrapped;
                };
 
-               return $this->cache->merge( $key, $func, $ttl, 1 );
+               return $this->cache->merge( self::VALUE_KEY_PREFIX . $key, $func, $ttl, 1 );
        }
 
        /**
@@ -284,6 +333,31 @@ class WANObjectCache {
         *   - a) Replication lag is bounded to being less than HOLDOFF_TTL; or
         *   - b) If lag is higher, the DB will have gone into read-only mode already
         *
+        * When using potentially long-running ACID transactions, a good pattern is
+        * to use a pre-commit hook to issue the delete. This means that immediately
+        * after commit, callers will see the tombstone in cache in the local datacenter
+        * and in the others upon relay. It also avoids the following race condition:
+        *   - a) T1 begins, changes a row, and calls delete()
+        *   - b) The HOLDOFF_TTL passes, expiring the delete() tombstone
+        *   - c) T2 starts, reads the row and calls set() due to a cache miss
+        *   - d) T1 finally commits
+        *   - e) Stale value is stuck in cache
+        *
+        * Example usage:
+        * @code
+        *     $dbw->begin(); // start of request
+        *     ... <execute some stuff> ...
+        *     // Update the row in the DB
+        *     $dbw->update( ... );
+        *     $key = wfMemcKey( 'homes', $homeId );
+        *     // Purge the corresponding cache entry just before committing
+        *     $dbw->onTransactionPreCommitOrIdle( function() use ( $cache, $key ) {
+        *         $cache->delete( $key );
+        *     } );
+        *     ... <execute some stuff> ...
+        *     $dbw->commit(); // end of request
+        * @endcode
+        *
         * If called twice on the same key, then the last hold-off TTL takes
         * precedence. For idempotence, the $ttl should not vary for different
         * delete() calls on the same key. Also note that lowering $ttl reduces
@@ -378,10 +452,10 @@ class WANObjectCache {
         * This is similar to touchCheckKey() in that keys using it via
         * getWithSetCallback() will be invalidated. The differences are:
         *   - a) The timestamp will be deleted from all caches and lazily
-        *      re-initialized when accessed (rather than set everywhere)
+        *        re-initialized when accessed (rather than set everywhere)
         *   - b) Thus, dependent keys will be known to be invalid, but not
-        *      for how long (they are treated as "just" purged), which
-        *      effects any lockTSE logic in getWithSetCallback()
+        *        for how long (they are treated as "just" purged), which
+        *        effects any lockTSE logic in getWithSetCallback()
         * The advantage is that this does not place high TTL keys on every cache
         * server, making it better for code that will cache many different keys
         * and either does not use lockTSE or uses a low enough TTL anyway.
@@ -408,19 +482,21 @@ class WANObjectCache {
        /**
         * Method to fetch/regenerate cache keys
         *
-        * On cache miss, the key will be set to the callback result,
-        * unless the callback returns false. The arguments supplied are:
-        *     (current value or false, &$ttl)
+        * On cache miss, the key will be set to the callback result via set()
+        * unless the callback returns false. The arguments supplied to it are:
+        *     (current value or false, &$ttl, &$setOpts)
         * The callback function returns the new value given the current
         * value (false if not present). Preemptive re-caching and $checkKeys
         * can result in a non-false current value. The TTL of the new value
         * can be set dynamically by altering $ttl in the callback (by reference).
+        * The $setOpts array can be altered and is given to set() when called;
+        * it is recommended to set the 'since' field to avoid race conditions.
         *
         * Usually, callbacks ignore the current value, but it can be used
         * to maintain "most recent X" values that come from time or sequence
         * based source data, provided that the "as of" id/time is tracked.
         *
-        * Usage of $checkKeys is similar to get()/getMulti(). However,
+        * Usage of $checkKeys is similar to get() and getMulti(). However,
         * rather than the caller having to inspect a "current time left"
         * variable (e.g. $curTTL, $curTTLs), a cache regeneration will be
         * triggered using the callback.
@@ -437,7 +513,14 @@ class WANObjectCache {
         * @code
         *     $key = wfMemcKey( 'cat-recent-actions', $catId );
         *     // Function that derives the new key value given the old value
-        *     $callback = function( $cValue, &$ttl ) { ... };
+        *     $callback = function( $cValue, &$ttl, array &$setOpts ) {
+        *         $dbr = wfGetDB( DB_SLAVE );
+        *         // Fetch the row from the DB
+        *         $row = $dbr->selectRow( ... );
+        *         // Give the age of the transaction snapshot the data came from
+        *         $setOpts = array( 'since' => $dbr->trxTimestamp() );
+        *         return $row;
+        *     };
         *     // Get the key value from cache or from source on cache miss;
         *     // try to only let one cluster thread manage doing cache updates
         *     $opts = array( 'lockTSE' => 5, 'lowTTL' => 10 );
@@ -463,6 +546,7 @@ class WANObjectCache {
         * @endcode
         *
         * @see WANObjectCache::get()
+        * @see WANObjectCache::set()
         *
         * @param string $key Cache key
         * @param callable $callback Value generation function
@@ -538,7 +622,8 @@ class WANObjectCache {
                }
 
                // Generate the new value from the callback...
-               $value = call_user_func_array( $callback, array( $cValue, &$ttl ) );
+               $setOpts = array();
+               $value = call_user_func_array( $callback, array( $cValue, &$ttl, &$setOpts ) );
                // When delete() is called, writes are write-holed by the tombstone,
                // so use a special stash key to pass the new value around threads.
                if ( $useMutex && $value !== false && $ttl >= 0 ) {
@@ -552,7 +637,8 @@ class WANObjectCache {
 
                if ( $value !== false && $ttl >= 0 ) {
                        // Update the cache; this will fail if the key is tombstoned
-                       $this->set( $key, $value, $ttl );
+                       $setOpts['lockTSE'] = $lockTSE;
+                       $this->set( $key, $value, $ttl, $setOpts );
                }
 
                return $value;
index b3c219d..11637d0 100644 (file)
@@ -41,4 +41,3 @@ class HashtableReplacer extends Replacer {
                return $this->table[$matches[$this->index]];
        }
 }
-
index 07ef24b..72fcc3a 100644 (file)
@@ -125,7 +125,7 @@ class BlockLogFormatter extends LogFormatter {
        public static function formatBlockFlags( $flags, $lang ) {
                $flags = trim( $flags );
                if ( $flags === '' ) {
-                       return ''; //nothing to do
+                       return ''; // nothing to do
                }
                $flags = explode( ',', $flags );
                $flagsCount = count( $flags );
index f31a42a..1d31088 100644 (file)
@@ -263,7 +263,7 @@ class LogFormatter {
                                switch ( $entry->getSubtype() ) {
                                        case 'protect':
                                                $text = wfMessage( 'protectedarticle' )
-                                                       ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
+                                                       ->rawParams( $target . ' ' . $parameters['4::description'] )->inContentLanguage()->escaped();
                                                break;
                                        case 'unprotect':
                                                $text = wfMessage( 'unprotectedarticle' )
@@ -271,7 +271,7 @@ class LogFormatter {
                                                break;
                                        case 'modify':
                                                $text = wfMessage( 'modifiedarticleprotection' )
-                                                       ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
+                                                       ->rawParams( $target . ' ' . $parameters['4::description'] )->inContentLanguage()->escaped();
                                                break;
                                        case 'move_prot':
                                                $text = wfMessage( 'movedarticleprotection' )
@@ -932,32 +932,6 @@ class LegacyLogFormatter extends LogFormatter {
                $type = $this->entry->getType();
                $subtype = $this->entry->getSubtype();
 
-               if ( $type == 'protect'
-                       && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' )
-               ) {
-                       $links = array(
-                               Linker::link( $title,
-                                       $this->msg( 'hist' )->escaped(),
-                                       array(),
-                                       array(
-                                               'action' => 'history',
-                                               'offset' => $this->entry->getTimestamp()
-                                       )
-                               )
-                       );
-                       if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
-                               $links[] = Linker::linkKnown(
-                                       $title,
-                                       $this->msg( 'protect_change' )->escaped(),
-                                       array(),
-                                       array( 'action' => 'protect' )
-                               );
-                       }
-
-                       return $this->msg( 'parentheses' )->rawParams(
-                               $this->context->getLanguage()->pipeList( $links ) )->escaped();
-               }
-
                // Do nothing. The implementation is handled by the hook modifiying the
                // passed-by-ref parameters. This also changes the default value so that
                // getComment() and getActionLinks() do not call them indefinitely.
index 82e5808..2e28917 100644 (file)
@@ -285,30 +285,10 @@ class LogPage {
                                        $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink )
                                                ->inLanguage( $langObj )->escaped();
                                } else {
-                                       $details = '';
                                        array_unshift( $params, $titleLink );
 
-                                       // Page protections
-                                       if ( $type == 'protect' && count( $params ) == 3 ) {
-                                               // Restrictions and expiries
-                                               if ( $skin ) {
-                                                       $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" );
-                                               } else {
-                                                       $details .= " {$params[1]}";
-                                               }
-
-                                               // Cascading flag...
-                                               if ( $params[2] ) {
-                                                       $text = wfMessage( 'protect-summary-cascade' )
-                                                               ->inLanguage( $langObj )->text();
-                                                       $details .= ' ';
-                                                       $details .= wfMessage( 'brackets', $text )->inLanguage( $langObj )->text();
-
-                                               }
-                                       }
-
                                        $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params )
-                                                       ->inLanguage( $langObj )->escaped() . $details;
+                                                       ->inLanguage( $langObj )->escaped();
                                }
                        }
                } else {
index 598a45f..3583599 100644 (file)
@@ -218,17 +218,19 @@ class LogPager extends ReverseChronologicalPager {
                        }
                }
 
-               # Using the (log_namespace, log_title, log_timestamp) index with a
-               # range scan (LIKE) on the first two parts, instead of simple equality,
-               # makes it unusable for sorting.  Sorted retrieval using another index
-               # would be possible, but then we might have to scan arbitrarily many
-               # nodes of that index. Therefore, we need to avoid this if $wgMiserMode
-               # is on.
-               #
-               # This is not a problem with simple title matches, because then we can
-               # use the page_time index.  That should have no more than a few hundred
-               # log entries for even the busiest pages, so it can be safely scanned
-               # in full to satisfy an impossible condition on user or similar.
+               /**
+                * Using the (log_namespace, log_title, log_timestamp) index with a
+                * range scan (LIKE) on the first two parts, instead of simple equality,
+                * makes it unusable for sorting.  Sorted retrieval using another index
+                * would be possible, but then we might have to scan arbitrarily many
+                * nodes of that index. Therefore, we need to avoid this if $wgMiserMode
+                * is on.
+                *
+                * This is not a problem with simple title matches, because then we can
+                * use the page_time index.  That should have no more than a few hundred
+                * log entries for even the busiest pages, so it can be safely scanned
+                * in full to satisfy an impossible condition on user or similar.
+                */
                $this->mConds['log_namespace'] = $ns;
                if ( $doUserRightsLogLike ) {
                        $params = array( $name . $wgUserrightsInterwikiDelimiter );
index c870d51..b7068a0 100644 (file)
@@ -59,7 +59,7 @@ class NewUsersLogFormatter extends LogFormatter {
        public function getPreloadTitles() {
                $subtype = $this->entry->getSubtype();
                if ( $subtype === 'create2' || $subtype === 'byemail' ) {
-                       //add the user talk to LinkBatch for the userLink
+                       // add the user talk to LinkBatch for the userLink
                        return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) );
                }
 
index 5327e07..bd04f15 100644 (file)
@@ -37,11 +37,38 @@ class ProtectLogFormatter extends LogFormatter {
                return array();
        }
 
+       protected function getMessageKey() {
+               $key = parent::getMessageKey();
+               $params = $this->extractParameters();
+               if ( isset( $params[4] ) && $params[4] ) {
+                       // Messages: logentry-protect-protect-cascade, logentry-protect-modify-cascade
+                       $key .= '-cascade';
+               }
+
+               return $key;
+       }
+
        protected function getMessageParameters() {
                $params = parent::getMessageParameters();
 
                $subtype = $this->entry->getSubtype();
-               if ( $subtype === 'move_prot' ) {
+               if ( $subtype === 'protect' || $subtype === 'modify' ) {
+                       $rawParams = $this->entry->getParameters();
+                       if ( isset( $rawParams['details'] ) ) {
+                               $params[3] = $this->createProtectDescription( $rawParams['details'] );
+                       } elseif ( isset( $params[3] ) ) {
+                               // Old way of Restrictions and expiries
+                               $params[3] = $this->context->getLanguage()->getDirMark() . $params[3];
+                       } else {
+                               // Very old way (nothing set)
+                               $params[3] = '';
+                       }
+                       // Cascading flag
+                       if ( isset( $params[4] ) ) {
+                               // handled in getMessageKey
+                               unset( $params[4] );
+                       }
+               } elseif ( $subtype === 'move_prot' ) {
                        $oldname = $this->makePageLink( Title::newFromText( $params[3] ), array( 'redirect' => 'no' ) );
                        $params[3] = Message::rawParam( $oldname );
                }
@@ -49,15 +76,59 @@ class ProtectLogFormatter extends LogFormatter {
                return $params;
        }
 
+       public function getActionLinks() {
+               $subtype = $this->entry->getSubtype();
+               if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
+                       || $subtype === 'move_prot' // the move log entry has the right action link
+               ) {
+                       return '';
+               }
+
+               // Show history link for all changes after the protection
+               $title = $this->entry->getTarget();
+               $links = array(
+                       Linker::link( $title,
+                               $this->msg( 'hist' )->escaped(),
+                               array(),
+                               array(
+                                       'action' => 'history',
+                                       'offset' => $this->entry->getTimestamp(),
+                               )
+                       )
+               );
+
+               // Show change protection link
+               if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
+                       $links[] = Linker::linkKnown(
+                               $title,
+                               $this->msg( 'protect_change' )->escaped(),
+                               array(),
+                               array( 'action' => 'protect' )
+                       );
+               }
+
+               return $this->msg( 'parentheses' )->rawParams(
+                       $this->context->getLanguage()->pipeList( $links ) )->escaped();
+       }
+
        protected function getParametersForApi() {
                $entry = $this->entry;
+               $subtype = $this->entry->getSubtype();
                $params = $entry->getParameters();
 
-               static $map = array(
-                       // param keys for move_prot sub type
-                       '4:title:oldtitle',
-                       '4::oldtitle' => '4:title:oldtitle',
-               );
+               $map = array();
+               if ( $subtype === 'protect' || $subtype === 'modify' ) {
+                       $map = array(
+                               '4::description',
+                               '5:bool:cascade',
+                               'details' => ':array:details',
+                       );
+               } elseif ( $subtype === 'move_prot' ) {
+                       $map = array(
+                               '4:title:oldtitle',
+                               '4::oldtitle' => '4:title:oldtitle',
+                       );
+               }
                foreach ( $map as $index => $key ) {
                        if ( isset( $params[$index] ) ) {
                                $params[$key] = $params[$index];
@@ -65,6 +136,78 @@ class ProtectLogFormatter extends LogFormatter {
                        }
                }
 
+               // Change string to explicit boolean
+               if ( isset( $params['5:bool:cascade'] ) && is_string( $params['5:bool:cascade'] ) ) {
+                       $params['5:bool:cascade'] = $params['5:bool:cascade'] === 'cascade';
+               }
+
                return $params;
        }
+
+       public function formatParametersForApi() {
+               global $wgContLang;
+
+               $ret = parent::formatParametersForApi();
+               if ( isset( $ret['details'] ) && is_array( $ret['details'] ) ) {
+                       foreach ( $ret['details'] as &$detail ) {
+                               if ( isset( $detail['expiry'] ) ) {
+                                       $detail['expiry'] = $wgContLang->formatExpiry( $detail['expiry'], TS_ISO_8601, 'infinite' );
+                               }
+                       }
+               }
+
+               return $ret;
+       }
+
+       /**
+        * Create the protect description to show in the log formatter
+        *
+        * @param array $details
+        * @return string
+        */
+       public function createProtectDescription( array $details ) {
+               $protectDescription = '';
+
+               foreach ( $details as $param ) {
+                       $expiryText = $this->formatExpiry( $param['expiry'] );
+
+                       // Messages: restriction-edit, restriction-move, restriction-create,
+                       // restriction-upload
+                       $action = $this->context->msg( 'restriction-' . $param['type'] )->escaped();
+
+                       $protectionLevel = $param['level'];
+                       // Messages: protect-level-autoconfirmed, protect-level-sysop
+                       $message = $this->context->msg( 'protect-level-' . $protectionLevel );
+                       if ( $message->isDisabled() ) {
+                               // Require "$1" permission
+                               $restrictions = $this->context->msg( "protect-fallback", $protectionLevel )->parse();
+                       } else {
+                               $restrictions = $message->escaped();
+                       }
+
+                       if ( $protectDescription !== '' ) {
+                               $protectDescription .= $this->context->msg( 'word-separator' )->escaped();
+                       }
+
+                       $protectDescription .= $this->context->msg( 'protect-summary-desc' )
+                               ->params( $action, $restrictions, $expiryText )->escaped();
+               }
+
+               return $protectDescription;
+       }
+
+       private function formatExpiry( $expiry ) {
+               if ( wfIsInfinity( $expiry ) ) {
+                       return $this->context->msg( 'protect-expiry-indefinite' )->text();
+               }
+               $lang = $this->context->getLanguage();
+               $user = $this->context->getUser();
+               return $this->context->msg(
+                       'protect-expiring-local',
+                       $lang->userTimeAndDate( $expiry, $user ),
+                       $lang->userDate( $expiry, $user ),
+                       $lang->userTime( $expiry, $user )
+               )->text();
+       }
+
 }
index 01b6afa..31dd395 100644 (file)
@@ -148,11 +148,10 @@ class EmailNotification {
                $watchers = self::updateWatchlistTimestamp( $editor, $title, $timestamp );
 
                $sendEmail = true;
+               // $watchers deals with $wgEnotifWatchlist.
                // If nobody is watching the page, and there are no users notified on all changes
                // don't bother creating a job/trying to send emails, unless it's a
                // talk page with an applicable notification.
-               //
-               // $watchers deals with $wgEnotifWatchlist
                if ( !count( $watchers ) && !count( $wgUsersNotifiedOnAllChanges ) ) {
                        $sendEmail = false;
                        // Only send notification for non minor edits, unless $wgEnotifMinorEdits
index 7c5f18d..3c28c5f 100644 (file)
@@ -178,32 +178,34 @@ class UserMailer {
                        return Status::newFatal( 'user-mail-no-addy' );
                }
 
-               // Forge email headers
-               // -------------------
-               //
-               // WARNING
-               //
-               // DO NOT add To: or Subject: headers at this step. They need to be
-               // handled differently depending upon the mailer we are going to use.
-               //
-               // To:
-               //  PHP mail() first argument is the mail receiver. The argument is
-               //  used as a recipient destination and as a To header.
-               //
-               //  PEAR mailer has a recipient argument which is only used to
-               //  send the mail. If no To header is given, PEAR will set it to
-               //  to 'undisclosed-recipients:'.
-               //
-               //  NOTE: To: is for presentation, the actual recipient is specified
-               //  by the mailer using the Rcpt-To: header.
-               //
-               // Subject:
-               //  PHP mail() second argument to pass the subject, passing a Subject
-               //  as an additional header will result in a duplicate header.
-               //
-               //  PEAR mailer should be passed a Subject header.
-               //
-               // -- hashar 20120218
+               /**
+                * Forge email headers
+                * -------------------
+                *
+                * WARNING
+                *
+                * DO NOT add To: or Subject: headers at this step. They need to be
+                * handled differently depending upon the mailer we are going to use.
+                *
+                * To:
+                *  PHP mail() first argument is the mail receiver. The argument is
+                *  used as a recipient destination and as a To header.
+                *
+                *  PEAR mailer has a recipient argument which is only used to
+                *  send the mail. If no To header is given, PEAR will set it to
+                *  to 'undisclosed-recipients:'.
+                *
+                *  NOTE: To: is for presentation, the actual recipient is specified
+                *  by the mailer using the Rcpt-To: header.
+                *
+                * Subject:
+                *  PHP mail() second argument to pass the subject, passing a Subject
+                *  as an additional header will result in a duplicate header.
+                *
+                *  PEAR mailer should be passed a Subject header.
+                *
+                * -- hashar 20120218
+                */
 
                $headers['From'] = $from->toString();
                $returnPath = $from->address;
@@ -326,9 +328,7 @@ class UserMailer {
                        MediaWiki\restoreWarnings();
                        return Status::newGood();
                } else {
-                       //
                        // PHP mail()
-                       //
                        if ( count( $to ) > 1 ) {
                                $headers['To'] = 'undisclosed-recipients:;';
                        }
index 1f00650..692e5a6 100644 (file)
@@ -299,7 +299,6 @@ class BitmapHandler extends TransformationalImageHandler {
         */
        protected function transformGd( $image, $params ) {
                # Use PHP's builtin GD library functions.
-               #
                # First find out what kind of file this is, and select the correct
                # input routine for this.
 
@@ -339,7 +338,9 @@ class BitmapHandler extends TransformationalImageHandler {
 
                $src_image = call_user_func( $loader, $params['srcPath'] );
 
-               $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ? $this->getRotation( $image ) : 0;
+               $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ?
+                       $this->getRotation( $image ) :
+                       0;
                list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
                $dst_image = imagecreatetruecolor( $width, $height );
 
index dac76fa..3b9b7c9 100644 (file)
@@ -410,11 +410,11 @@ EOT;
                                $xml .= Xml::tags(
                                        'OBJECT',
                                        array(
-                                               #'data' => '',
-                                               #'type' => 'image/x.djvu',
+                                               # 'data' => '',
+                                               # 'type' => 'image/x.djvu',
                                                'height' => $m[2],
                                                'width' => $m[1],
-                                               #'usemap' => '',
+                                               # 'usemap' => '',
                                        ),
                                        "\n" .
                                                Xml::element( 'PARAM', array( 'name' => 'DPI', 'value' => $m[3] ) ) . "\n" .
index b4cc43e..052c39d 100644 (file)
@@ -390,8 +390,8 @@ class Exif {
                $this->charCodeString( 'GPSProcessingMethod' );
                $this->charCodeString( 'GPSAreaInformation' );
 
-               //ComponentsConfiguration should really be an array instead of a string...
-               //This turns a string of binary numbers into an array of numbers.
+               // ComponentsConfiguration should really be an array instead of a string...
+               // This turns a string of binary numbers into an array of numbers.
 
                if ( isset( $this->mFilteredExifData['ComponentsConfiguration'] ) ) {
                        $val = $this->mFilteredExifData['ComponentsConfiguration'];
@@ -401,16 +401,16 @@ class Exif {
                        for ( $i = 0; $i < $strLen; $i++ ) {
                                $ccVals[$i] = ord( substr( $val, $i, 1 ) );
                        }
-                       $ccVals['_type'] = 'ol'; //this is for formatting later.
+                       $ccVals['_type'] = 'ol'; // this is for formatting later.
                        $this->mFilteredExifData['ComponentsConfiguration'] = $ccVals;
                }
 
-               //GPSVersion(ID) is treated as the wrong type by php exif support.
-               //Go through each byte turning it into a version string.
-               //For example: "\x02\x02\x00\x00" -> "2.2.0.0"
+               // GPSVersion(ID) is treated as the wrong type by php exif support.
+               // Go through each byte turning it into a version string.
+               // For example: "\x02\x02\x00\x00" -> "2.2.0.0"
 
-               //Also change exif tag name from GPSVersion (what php exif thinks it is)
-               //to GPSVersionID (what the exif standard thinks it is).
+               // Also change exif tag name from GPSVersion (what php exif thinks it is)
+               // to GPSVersionID (what the exif standard thinks it is).
 
                if ( isset( $this->mFilteredExifData['GPSVersion'] ) ) {
                        $val = $this->mFilteredExifData['GPSVersion'];
@@ -448,7 +448,7 @@ class Exif {
                if ( isset( $this->mFilteredExifData[$prop] ) ) {
 
                        if ( strlen( $this->mFilteredExifData[$prop] ) <= 8 ) {
-                               //invalid. Must be at least 9 bytes long.
+                               // invalid. Must be at least 9 bytes long.
 
                                $this->debug( $this->mFilteredExifData[$prop], __FUNCTION__, false );
                                unset( $this->mFilteredExifData[$prop] );
@@ -460,13 +460,13 @@ class Exif {
 
                        switch ( $charCode ) {
                                case "\x4A\x49\x53\x00\x00\x00\x00\x00":
-                                       //JIS
+                                       // JIS
                                        $charset = "Shift-JIS";
                                        break;
                                case "UNICODE\x00":
                                        $charset = "UTF-16" . $this->byteOrder;
                                        break;
-                               default: //ascii or undefined.
+                               default: // ascii or undefined.
                                        $charset = "";
                                        break;
                        }
@@ -477,7 +477,7 @@ class Exif {
                        } else {
                                // if valid utf-8, assume that, otherwise assume windows-1252
                                $valCopy = $val;
-                               UtfNormal\Validator::quickIsNFCVerify( $valCopy ); //validates $valCopy.
+                               UtfNormal\Validator::quickIsNFCVerify( $valCopy ); // validates $valCopy.
                                if ( $valCopy !== $val ) {
                                        MediaWiki\suppressWarnings();
                                        $val = iconv( 'Windows-1252', 'UTF-8//IGNORE', $val );
@@ -485,17 +485,17 @@ class Exif {
                                }
                        }
 
-                       //trim and check to make sure not only whitespace.
+                       // trim and check to make sure not only whitespace.
                        $val = trim( $val );
                        if ( strlen( $val ) === 0 ) {
-                               //only whitespace.
+                               // only whitespace.
                                $this->debug( $this->mFilteredExifData[$prop], __FUNCTION__, "$prop: Is only whitespace" );
                                unset( $this->mFilteredExifData[$prop] );
 
                                return;
                        }
 
-                       //all's good.
+                       // all's good.
                        $this->mFilteredExifData[$prop] = $val;
                }
        }
index 5ba5c68..3537cc6 100644 (file)
@@ -110,7 +110,7 @@ class ExifBitmapHandler extends BitmapHandler {
                        if ( isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
                                && $exif['MEDIAWIKI_EXIF_VERSION'] == 1
                        ) {
-                               //back-compatible but old
+                               // back-compatible but old
                                wfDebug( __METHOD__ . ": back-compat version\n" );
 
                                return self::METADATA_COMPATIBLE;
@@ -269,9 +269,11 @@ class ExifBitmapHandler extends BitmapHandler {
        }
 
        /**
-        * Swaps an embedded ICC profile for another, if found. Depends on exiftool, no-op if not installed.
+        * Swaps an embedded ICC profile for another, if found.
+        * Depends on exiftool, no-op if not installed.
         * @param string $filepath File to be manipulated (will be overwritten)
-        * @param string $oldProfileString Exact name of color profile to look for (the one that will be replaced)
+        * @param string $oldProfileString Exact name of color profile to look for
+        *  (the one that will be replaced)
         * @param string $profileFilepath ICC profile file to apply to the file
         * @since 1.26
         * @return bool
index 0fee8cc..a1cb01c 100644 (file)
@@ -1,4 +1,6 @@
 <?php
+// @codingStandardsIgnoreFile
+// PHPCS can't handle the level of nesting in this file
 /**
  * Formatting of image metadata values into human readable form.
  *
@@ -117,9 +119,9 @@ class FormatMetadata extends ContextSource {
                                $type = 'ul'; // default unordered list.
                        }
 
-                       //This is done differently as the tag is an array.
+                       // This is done differently as the tag is an array.
                        if ( $tag == 'GPSTimeStamp' && count( $vals ) === 3 ) {
-                               //hour min sec array
+                               // hour min sec array
 
                                $h = explode( '/', $vals[0] );
                                $m = explode( '/', $vals[1] );
@@ -413,7 +415,7 @@ class FormatMetadata extends ContextSource {
                                                        'mode' => ( $val & bindec( '00011000' ) ) >> 3,
                                                        'function' => ( $val & bindec( '00100000' ) ) >> 5,
                                                        'redeye' => ( $val & bindec( '01000000' ) ) >> 6,
-//                                             'reserved' => ($val & bindec( '10000000' )) >> 7,
+//                                             'reserved' => ($val & bindec( '10000000' )) >> 7,
                                                );
                                                $flashMsgs = array();
                                                # We do not need to handle unknown values since all are used.
@@ -597,7 +599,7 @@ class FormatMetadata extends ContextSource {
                                                }
                                                break;
 
-                                       //The GPS...Ref values are kept for compatibility, probably won't be reached.
+                                       // The GPS...Ref values are kept for compatibility, probably won't be reached.
                                        case 'GPSLatitudeRef':
                                        case 'GPSDestLatitudeRef':
                                                switch ( $val ) {
@@ -730,7 +732,7 @@ class FormatMetadata extends ContextSource {
 
                                        case 'Software':
                                                if ( is_array( $val ) ) {
-                                                       //if its a software, version array.
+                                                       // if its a software, version array.
                                                        $val = $this->msg( 'exif-software-version-value', $val[0], $val[1] )->text();
                                                } else {
                                                        $val = $this->exifMsg( $tag, '', $val );
@@ -1169,7 +1171,7 @@ class FormatMetadata extends ContextSource {
                $lowLang = strtolower( $lang );
                $langName = Language::fetchLanguageName( $lowLang );
                if ( $langName === '' ) {
-                       //try just the base language name. (aka en-US -> en ).
+                       // try just the base language name. (aka en-US -> en ).
                        list( $langPrefix ) = explode( '-', $lowLang, 2 );
                        $langName = Language::fetchLanguageName( $langPrefix );
                        if ( $langName === '' ) {
index 6ee23cd..f5772de 100644 (file)
@@ -102,14 +102,14 @@ class GIFMetadataExtractor {
                                // Found a frame
                                $frameCount++;
 
-                               ## Skip bounding box
+                               # # Skip bounding box
                                fread( $fh, 8 );
 
-                               ## Read BPP
+                               # # Read BPP
                                $buf = fread( $fh, 1 );
                                $bpp = self::decodeBPP( $buf );
 
-                               ## Read GCT
+                               # # Read GCT
                                self::readGCT( $fh, $bpp );
                                fread( $fh, 1 );
                                self::skipBlock( $fh );
index c3d58b8..98fbde3 100644 (file)
@@ -45,13 +45,13 @@ class IPTC {
                }
 
                $c = '';
-               //charset info contained in tag 1:90.
+               // charset info contained in tag 1:90.
                if ( isset( $parsed['1#090'] ) && isset( $parsed['1#090'][0] ) ) {
                        $c = self::getCharset( $parsed['1#090'][0] );
                        if ( $c === false ) {
-                               //Unknown charset. refuse to parse.
-                               //note: There is a different between
-                               //unknown and no charset specified.
+                               // Unknown charset. refuse to parse.
+                               // note: There is a different between
+                               // unknown and no charset specified.
                                return array();
                        }
                        unset( $parsed['1#090'] );
@@ -165,15 +165,15 @@ class IPTC {
                                        $software = self::convIPTC( $val, $c );
 
                                        if ( count( $software ) !== 1 ) {
-                                               //according to iim standard this cannot have multiple values
-                                               //so if there is more than one, something weird is happening,
-                                               //and we skip it.
+                                               // according to iim standard this cannot have multiple values
+                                               // so if there is more than one, something weird is happening,
+                                               // and we skip it.
                                                wfDebugLog( 'iptc', 'IPTC: Wrong count on 2:65 Software field' );
                                                break;
                                        }
 
                                        if ( isset( $parsed['2#070'] ) ) {
-                                               //if a version is set for the software.
+                                               // if a version is set for the software.
                                                $softwareVersion = self::convIPTC( $parsed['2#070'], $c );
                                                unset( $parsed['2#070'] );
                                                $data['Software'] = array( array( $software[0], $softwareVersion[0] ) );
@@ -220,8 +220,8 @@ class IPTC {
                                // according to spec.
                                // Should potentially store timezone as well.
                                case '2#055':
-                                       //Date created (not date digitized).
-                                       //Maps to exif DateTimeOriginal
+                                       // Date created (not date digitized).
+                                       // Maps to exif DateTimeOriginal
                                        if ( isset( $parsed['2#060'] ) ) {
                                                $time = $parsed['2#060'];
                                        } else {
@@ -234,8 +234,8 @@ class IPTC {
                                        break;
 
                                case '2#062':
-                                       //Date converted to digital representation.
-                                       //Maps to exif DateTimeDigitized
+                                       // Date converted to digital representation.
+                                       // Maps to exif DateTimeDigitized
                                        if ( isset( $parsed['2#063'] ) ) {
                                                $time = $parsed['2#063'];
                                        } else {
@@ -248,7 +248,7 @@ class IPTC {
                                        break;
 
                                case '2#030':
-                                       //Date released.
+                                       // Date released.
                                        if ( isset( $parsed['2#035'] ) ) {
                                                $time = $parsed['2#035'];
                                        } else {
@@ -261,7 +261,7 @@ class IPTC {
                                        break;
 
                                case '2#037':
-                                       //Date expires.
+                                       // Date expires.
                                        if ( isset( $parsed['2#038'] ) ) {
                                                $time = $parsed['2#038'];
                                        } else {
@@ -275,10 +275,10 @@ class IPTC {
 
                                case '2#000': /* iim version */
                                        // unlike other tags, this is a 2-byte binary number.
-                                       //technically this is required if there is iptc data
-                                       //but in practise it isn't always there.
+                                       // technically this is required if there is iptc data
+                                       // but in practise it isn't always there.
                                        if ( strlen( $val[0] ) == 2 ) {
-                                               //if is just to be paranoid.
+                                               // if is just to be paranoid.
                                                $versionValue = ord( substr( $val[0], 0, 1 ) ) * 256;
                                                $versionValue += ord( substr( $val[0], 1, 1 ) );
                                                $data['iimVersion'] = $versionValue;
@@ -335,7 +335,7 @@ class IPTC {
                                case '2#085':
                                case '2#038':
                                case '2#035':
-                                       //ignore. Handled elsewhere.
+                                       // ignore. Handled elsewhere.
                                        break;
 
                                default:
@@ -358,8 +358,8 @@ class IPTC {
         */
        private static function timeHelper( $date, $time, $c ) {
                if ( count( $date ) === 1 ) {
-                       //the standard says this should always be 1
-                       //just double checking.
+                       // the standard says this should always be 1
+                       // just double checking.
                        list( $date ) = self::convIPTC( $date, $c );
                } else {
                        return null;
@@ -369,7 +369,7 @@ class IPTC {
                        list( $time ) = self::convIPTC( $time, $c );
                        $dateOnly = false;
                } else {
-                       $time = '000000+0000'; //placeholder
+                       $time = '000000+0000'; // placeholder
                        $dateOnly = true;
                }
 
@@ -379,7 +379,7 @@ class IPTC {
                        && substr( $date, 4, 2 ) !== '00'
                        && substr( $date, 6, 2 ) !== '00'
                ) ) {
-                       //something wrong.
+                       // something wrong.
                        // Note, this rejects some valid dates according to iptc spec
                        // for example: the date 00000400 means the photo was taken in
                        // April, but the year and day is unknown. We don't process these
@@ -410,7 +410,7 @@ class IPTC {
                        return null;
                }
                if ( $dateOnly ) {
-                       //return the date only
+                       // return the date only
                        return substr( $finalTimestamp, 0, 10 );
                } else {
                        return $finalTimestamp;
@@ -453,12 +453,12 @@ class IPTC {
                                wfDebugLog( 'iptc', __METHOD__ . " Error converting iptc data charset $charset to utf-8" );
                        }
                } else {
-                       //treat as utf-8 if is valid utf-8. otherwise pretend its windows-1252
+                       // treat as utf-8 if is valid utf-8. otherwise pretend its windows-1252
                        // most of the time if there is no 1:90 tag, it is either ascii, latin1, or utf-8
                        $oldData = $data;
-                       UtfNormal\Validator::quickIsNFCVerify( $data ); //make $data valid utf-8
+                       UtfNormal\Validator::quickIsNFCVerify( $data ); // make $data valid utf-8
                        if ( $data === $oldData ) {
-                               return $data; //if validation didn't change $data
+                               return $data; // if validation didn't change $data
                        } else {
                                return self::convIPTCHelper( $oldData, 'Windows-1252' );
                        }
@@ -477,39 +477,39 @@ class IPTC {
         */
        static function getCharset( $tag ) {
 
-               //According to iim standard, charset is defined by the tag 1:90.
-               //in which there are iso 2022 escape sequences to specify the character set.
-               //the iim standard seems to encourage that all necessary escape sequences are
-               //in the 1:90 tag, but says it doesn't have to be.
+               // According to iim standard, charset is defined by the tag 1:90.
+               // in which there are iso 2022 escape sequences to specify the character set.
+               // the iim standard seems to encourage that all necessary escape sequences are
+               // in the 1:90 tag, but says it doesn't have to be.
 
-               //This is in need of more testing probably. This is definitely not complete.
-               //however reading the docs of some other iptc software, it appears that most iptc software
-               //only recognizes utf-8. If 1:90 tag is not present content is
+               // This is in need of more testing probably. This is definitely not complete.
+               // however reading the docs of some other iptc software, it appears that most iptc software
+               // only recognizes utf-8. If 1:90 tag is not present content is
                // usually ascii or iso-8859-1 (and sometimes utf-8), but no guarantee.
 
-               //This also won't work if there are more than one escape sequence in the 1:90 tag
-               //or if something is put in the G2, or G3 charsets, etc. It will only reliably recognize utf-8.
+               // This also won't work if there are more than one escape sequence in the 1:90 tag
+               // or if something is put in the G2, or G3 charsets, etc. It will only reliably recognize utf-8.
 
                // This is just going through the charsets mentioned in appendix C of the iim standard.
 
                //  \x1b = ESC.
                switch ( $tag ) {
-                       case "\x1b%G": //utf-8
-                       //Also call things that are compatible with utf-8, utf-8 (e.g. ascii)
+                       case "\x1b%G": // utf-8
+                       // Also call things that are compatible with utf-8, utf-8 (e.g. ascii)
                        case "\x1b(B": // ascii
                        case "\x1b(@": // iso-646-IRV (ascii in latest version, $ different in older version)
                                $c = 'UTF-8';
                                break;
-                       case "\x1b(A": //like ascii, but british.
+                       case "\x1b(A": // like ascii, but british.
                                $c = 'ISO646-GB';
                                break;
-                       case "\x1b(C": //some obscure sweedish/finland encoding
+                       case "\x1b(C": // some obscure sweedish/finland encoding
                                $c = 'ISO-IR-8-1';
                                break;
                        case "\x1b(D":
                                $c = 'ISO-IR-8-2';
                                break;
-                       case "\x1b(E": //some obscure danish/norway encoding
+                       case "\x1b(E": // some obscure danish/norway encoding
                                $c = 'ISO-IR-9-1';
                                break;
                        case "\x1b(F":
@@ -533,22 +533,22 @@ class IPTC {
                        case "\x1b(K":
                                $c = "ISO646-DE";
                                break;
-                       case "\x1b(N": //crylic
+                       case "\x1b(N": // crylic
                                $c = "ISO_5427";
                                break;
-                       case "\x1b(`": //iso646-NO
+                       case "\x1b(`": // iso646-NO
                                $c = "NS_4551-1";
                                break;
-                       case "\x1b(f": //iso646-FR
+                       case "\x1b(f": // iso646-FR
                                $c = "NF_Z_62-010";
                                break;
                        case "\x1b(g":
-                               $c = "PT2"; //iso646-PT2
+                               $c = "PT2"; // iso646-PT2
                                break;
                        case "\x1b(h":
                                $c = "ES2";
                                break;
-                       case "\x1b(i": //iso646-HU
+                       case "\x1b(i": // iso646-HU
                                $c = "MSZ_7795.3";
                                break;
                        case "\x1b(w":
@@ -594,7 +594,7 @@ class IPTC {
                                break;
                        default:
                                wfDebugLog( 'iptc', __METHOD__ . 'Unknown charset in iptc 1:90: ' . bin2hex( $tag ) );
-                               //at this point just give up and refuse to parse iptc?
+                               // at this point just give up and refuse to parse iptc?
                                $c = false;
                }
                return $c;
index db74bb3..c2870c2 100644 (file)
@@ -61,7 +61,7 @@ abstract class ImageHandler extends MediaHandler {
                }
 
                # Removed for ProofreadPage
-               #$width = intval( $width );
+               # $width = intval( $width );
                return "{$width}px";
        }
 
index 3a59996..015eb5a 100644 (file)
@@ -180,7 +180,7 @@ abstract class MediaHandler {
        function convertMetadataVersion( $metadata, $version = 1 ) {
                if ( !is_array( $metadata ) ) {
 
-                       //unserialize to keep return parameter consistent.
+                       // unserialize to keep return parameter consistent.
                        MediaWiki\suppressWarnings();
                        $ret = unserialize( $metadata );
                        MediaWiki\restoreWarnings();
@@ -866,14 +866,21 @@ abstract class MediaHandler {
         * Gets configuration for the file warning message. Return value of
         * the following structure:
         *   array(
-        *     'module' => 'example.filewarning.messages', // Required, module with messages loaded for the client
-        *     'messages' => array( // Required, array of names of messages
-        *       'main' => 'example-filewarning-main', // Required, main warning message
-        *       'header' => 'example-filewarning-header', // Optional, header for warning dialog
-        *       'footer' => 'example-filewarning-footer', // Optional, footer for warning dialog
-        *       'info' => 'example-filewarning-info', // Optional, text for more-information link (see below)
+        *     // Required, module with messages loaded for the client
+        *     'module' => 'example.filewarning.messages',
+        *     // Required, array of names of messages
+        *     'messages' => array(
+        *       // Required, main warning message
+        *       'main' => 'example-filewarning-main',
+        *       // Optional, header for warning dialog
+        *       'header' => 'example-filewarning-header',
+        *       // Optional, footer for warning dialog
+        *       'footer' => 'example-filewarning-footer',
+        *       // Optional, text for more-information link (see below)
+        *       'info' => 'example-filewarning-info',
         *     ),
-        *     'link' => 'http://example.com', // Optional, link for more information
+        *     // Optional, link for more information
+        *     'link' => 'http://example.com',
         *   )
         *
         * Returns null if no warning is necessary.
index ff4dcee..f894618 100644 (file)
@@ -102,7 +102,7 @@ class WebPHandler extends BitmapHandler {
 
                if ( $info['fourCC'] != 'WEBP' ) {
                        wfDebugLog( 'WebP', __METHOD__ . ': FourCC was not WEBP: ' .
-                               bin2hex( $info['fourCC'] ) .  " \n" );
+                               bin2hex( $info['fourCC'] ) . " \n" );
                        return false;
                }
 
@@ -187,7 +187,7 @@ class WebPHandler extends BitmapHandler {
                // Bytes 4-7 are chunk stream size
                // Byte 8 is 0x2F called the signature
                if ( $header{8} != "\x2F" ) {
-                       wfDebugLog( 'WebP',  __METHOD__ . ': Invalid signature: ' .
+                       wfDebugLog( 'WebP', __METHOD__ . ': Invalid signature: ' .
                                bin2hex( $header{8} ) . "\n" );
                        return array();
                }
index 16e11dc..41e1d54 100644 (file)
@@ -106,21 +106,23 @@ class XCFHandler extends BitmapHandler {
                $binaryHeader = fread( $f, 26 );
                fclose( $f );
 
-               # Master image structure:
-               #
-               # byte[9] "gimp xcf "  File type magic
-               # byte[4] version      XCF version
-               #                        "file" - version 0
-               #                        "v001" - version 1
-               #                        "v002" - version 2
-               # byte    0            Zero-terminator for version tag
-               # uint32  width        With of canvas
-               # uint32  height       Height of canvas
-               # uint32  base_type    Color mode of the image; one of
-               #                         0: RGB color
-               #                         1: Grayscale
-               #                         2: Indexed color
-               #        (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h)
+               /**
+                * Master image structure:
+                *
+                * byte[9] "gimp xcf "  File type magic
+                * byte[4] version      XCF version
+                *                        "file" - version 0
+                *                        "v001" - version 1
+                *                        "v002" - version 2
+                * byte    0            Zero-terminator for version tag
+                * uint32  width        With of canvas
+                * uint32  height       Height of canvas
+                * uint32  base_type    Color mode of the image; one of
+                *                         0: RGB color
+                *                         1: Grayscale
+                *                         2: Indexed color
+                *        (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h)
+                */
                try {
                        $header = wfUnpack(
                                "A9magic" . # A: space padded
index 64a7e8a..fb840c2 100644 (file)
@@ -329,7 +329,7 @@ class XMPReader implements LoggerAwareInterface {
                                                        $this->charset = 'UTF-8';
                                                        break;
                                                default:
-                                                       //this should be impossible to get to
+                                                       // this should be impossible to get to
                                                        throw new RuntimeException( "Invalid BOM" );
                                        }
                                } else {
@@ -338,7 +338,7 @@ class XMPReader implements LoggerAwareInterface {
                                }
                        }
                        if ( $this->charset !== 'UTF-8' ) {
-                               //don't convert if already utf-8
+                               // don't convert if already utf-8
                                MediaWiki\suppressWarnings();
                                $content = iconv( $this->charset, 'UTF-8//IGNORE', $content );
                                MediaWiki\restoreWarnings();
@@ -429,8 +429,14 @@ class XMPReader implements LoggerAwareInterface {
                }
                $len = unpack( 'Nlength/Noffset', substr( $content, 32, 8 ) );
 
-               if ( !$len || $len['length'] < 4 || $len['offset'] < 0 || $len['offset'] > $len['length'] ) {
-                       $this->logger->info( __METHOD__ . 'Error reading extended XMP block, invalid length or offset.' );
+               if ( !$len ||
+                       $len['length'] < 4 ||
+                       $len['offset'] < 0 ||
+                       $len['offset'] > $len['length']
+               ) {
+                       $this->logger->info(
+                               __METHOD__ . 'Error reading extended XMP block, invalid length or offset.'
+                       );
 
                        return false;
                }
@@ -441,9 +447,8 @@ class XMPReader implements LoggerAwareInterface {
                // immediately following the StandardXMP. However, the JPEG standard
                // does not require preservation of marker segment order. A robust JPEG
                // reader should tolerate the marker segments in any order."
-               //
-               // otoh the probability that an image will have more than 128k of
-               // metadata is rather low... so the probability that it will have
+               // On the other hand, the probability that an image will have more than
+               // 128k of metadata is rather low... so the probability that it will have
                // > 128k, and be in the wrong order is very low...
 
                if ( $len['offset'] !== $this->extendedXMPOffset ) {
@@ -710,7 +715,6 @@ class XMPReader implements LoggerAwareInterface {
         * @throws RuntimeException
         */
        private function endElementModeLi( $elm ) {
-
                list( $ns, $tag ) = explode( ' ', $this->curItem[0], 2 );
                $info = $this->items[$ns][$tag];
                $finalName = isset( $info['map_name'] )
@@ -734,7 +738,9 @@ class XMPReader implements LoggerAwareInterface {
                                $this->results['xmp-' . $info['map_group']][$finalName]['_type'] = 'lang';
                        }
                } else {
-                       throw new RuntimeException( __METHOD__ . " expected </rdf:seq> or </rdf:bag> but instead got $elm." );
+                       throw new RuntimeException(
+                               __METHOD__ . " expected </rdf:seq> or </rdf:bag> but instead got $elm."
+                       );
                }
        }
 
@@ -1206,8 +1212,7 @@ class XMPReader implements LoggerAwareInterface {
                        // In practise I have yet to see a file that
                        // uses this element, however it is mentioned
                        // on page 25 of part 1 of the xmp standard.
-                       //
-                       // also it seems as if exiv2 and exiftool do not support
+                       // Also it seems as if exiv2 and exiftool do not support
                        // this either (That or I misunderstand the standard)
                        $this->logger->info( __METHOD__ . ' Encountered <rdf:type> which isn\'t currently supported' );
                }
index 1d8d777..6fc2343 100644 (file)
@@ -705,7 +705,7 @@ class XMPInfo {
                        ),
                        'creator' => array(
                                'map_group' => 'general',
-                               'map_name' => 'Artist', //map with exif Artist, iptc byline (2:80)
+                               'map_name' => 'Artist', // map with exif Artist, iptc byline (2:80)
                                'mode' => XMPReader::MODE_SEQ,
                        ),
                        'date' => array(
@@ -872,7 +872,7 @@ class XMPInfo {
                                'mode' => XMPReader::MODE_SIMPLE,
                        ),
                ),
-               //Note, this property affects how jpeg metadata is extracted.
+               // Note, this property affects how jpeg metadata is extracted.
                'http://ns.adobe.com/xmp/note/' => array(
                        'HasExtendedXMP' => array(
                                'map_group' => 'special',
index 55e8ce7..519c420 100644 (file)
@@ -167,7 +167,7 @@ class XMPValidate implements LoggerAwareInterface {
                        return;
                }
 
-               //check if its in a numeric range
+               // check if its in a numeric range
                $inRange = false;
                if ( isset( $info['rangeLow'] )
                        && isset( $info['rangeHigh'] )
@@ -231,7 +231,7 @@ class XMPValidate implements LoggerAwareInterface {
                        return;
                }
                if ( !preg_match( '/^[-A-Za-z0-9]{2,}$/D', $val ) ) {
-                       //this is a rather naive check.
+                       // this is a rather naive check.
                        $this->logger->info( __METHOD__ . " Expected Lang code but got $val" );
                        $val = null;
                }
@@ -292,8 +292,8 @@ class XMPValidate implements LoggerAwareInterface {
                                return;
                        }
 
-                       if ( !isset( $res[4] ) ) { //hour
-                               //just have the year month day (if that)
+                       if ( !isset( $res[4] ) ) { // hour
+                               // just have the year month day (if that)
                                $val = $res[1];
                                if ( isset( $res[2] ) ) {
                                        $val .= ':' . $res[2];
@@ -306,7 +306,7 @@ class XMPValidate implements LoggerAwareInterface {
                        }
 
                        if ( !isset( $res[7] ) || $res[7] === 'Z' ) {
-                               //if hour is set, then minute must also be or regex above will fail.
+                               // if hour is set, then minute must also be or regex above will fail.
                                $val = $res[1] . ':' . $res[2] . ':' . $res[3]
                                        . ' ' . $res[4] . ':' . $res[5];
                                if ( isset( $res[6] ) && $res[6] !== '' ) {
index 1a52930..cb3754a 100644 (file)
@@ -60,7 +60,9 @@ class MultiWriteBagOStuff extends BagOStuff {
                parent::__construct( $params );
 
                if ( empty( $params['caches'] ) || !is_array( $params['caches'] ) ) {
-                       throw new InvalidArgumentException( __METHOD__ . ': "caches" parameter must be an array of caches' );
+                       throw new InvalidArgumentException(
+                               __METHOD__ . ': "caches" parameter must be an array of caches'
+                       );
                }
 
                $this->caches = array();
index 56b9520..defd029 100644 (file)
@@ -379,7 +379,7 @@ class Article implements Page {
 
                # Pre-fill content with error message so that if something
                # fails we'll have something telling us what we intended.
-               //XXX: this isn't page content but a UI message. horrible.
+               // XXX: this isn't page content but a UI message. horrible.
                $this->mContentObject = new MessageContent( 'missing-revision', array( $oldid ) );
 
                if ( $oldid ) {
@@ -1937,7 +1937,7 @@ class Article implements Page {
         * @return ParserOutput|bool ParserOutput or false if the given revision ID is not found
         */
        public function getParserOutput( $oldid = null, User $user = null ) {
-               //XXX: bypasses mParserOptions and thus setParserOptions()
+               // XXX: bypasses mParserOptions and thus setParserOptions()
 
                if ( $user === null ) {
                        $parserOptions = $this->getParserOptions();
@@ -2010,7 +2010,7 @@ class Article implements Page {
         */
        public function __get( $fname ) {
                if ( property_exists( $this->mPage, $fname ) ) {
-                       #wfWarn( "Access to raw $fname field " . __CLASS__ );
+                       # wfWarn( "Access to raw $fname field " . __CLASS__ );
                        return $this->mPage->$fname;
                }
                trigger_error( 'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
@@ -2025,7 +2025,7 @@ class Article implements Page {
         */
        public function __set( $fname, $fvalue ) {
                if ( property_exists( $this->mPage, $fname ) ) {
-                       #wfWarn( "Access to raw $fname field of " . __CLASS__ );
+                       # wfWarn( "Access to raw $fname field of " . __CLASS__ );
                        $this->mPage->$fname = $fvalue;
                // Note: extensions may want to toss on new fields
                } elseif ( !in_array( $fname, array( 'mContext', 'mPage' ) ) ) {
@@ -2045,7 +2045,7 @@ class Article implements Page {
         */
        public function __call( $fname, $args ) {
                if ( is_callable( array( $this->mPage, $fname ) ) ) {
-                       #wfWarn( "Call to " . __CLASS__ . "::$fname; please use WikiPage instead" );
+                       # wfWarn( "Call to " . __CLASS__ . "::$fname; please use WikiPage instead" );
                        return call_user_func_array( array( $this->mPage, $fname ), $args );
                }
                trigger_error( 'Inaccessible function via __call(): ' . $fname, E_USER_ERROR );
index 9b9e3cb..e1cd76c 100644 (file)
@@ -248,7 +248,9 @@ class ImagePage extends Article {
                Hooks::run( 'ImagePageShowTOC', array( $this, &$r ) );
 
                if ( $metadata ) {
-                       $r[] = '<li><a href="#metadata">' . $this->getContext()->msg( 'metadata' )->escaped() . '</a></li>';
+                       $r[] = '<li><a href="#metadata">' .
+                               $this->getContext()->msg( 'metadata' )->escaped() .
+                               '</a></li>';
                }
 
                return '<ul id="filetoc">' . implode( "\n", $r ) . '</ul>';
@@ -389,9 +391,13 @@ class ImagePage extends Article {
                                        }
                                        if ( count( $otherSizes ) ) {
                                                $msgsmall .= ' ' .
-                                               Html::rawElement( 'span', array( 'class' => 'mw-filepage-other-resolutions' ),
-                                                       $this->getContext()->msg( 'show-big-image-other' )->rawParams( $lang->pipeList( $otherSizes ) )->
-                                                       params( count( $otherSizes ) )->parse()
+                                               Html::rawElement(
+                                                       'span',
+                                                       array( 'class' => 'mw-filepage-other-resolutions' ),
+                                                       $this->getContext()->msg( 'show-big-image-other' )
+                                                               ->rawParams( $lang->pipeList( $otherSizes ) )
+                                                               ->params( count( $otherSizes ) )
+                                                               ->parse()
                                                );
                                        }
                                } elseif ( $width == 0 && $height == 0 ) {
@@ -667,9 +673,14 @@ EOT
                $wrap = "<div class=\"sharedUploadNotice\">\n$1\n</div>\n";
                $repo = $this->mPage->getFile()->getRepo()->getDisplayName();
 
-               if ( $descUrl && $descText && $this->getContext()->msg( 'sharedupload-desc-here' )->plain() !== '-' ) {
+               if ( $descUrl &&
+                       $descText &&
+                       $this->getContext()->msg( 'sharedupload-desc-here' )->plain() !== '-'
+               ) {
                        $out->wrapWikiMsg( $wrap, array( 'sharedupload-desc-here', $repo, $descUrl ) );
-               } elseif ( $descUrl && $this->getContext()->msg( 'sharedupload-desc-there' )->plain() !== '-' ) {
+               } elseif ( $descUrl &&
+                       $this->getContext()->msg( 'sharedupload-desc-there' )->plain() !== '-'
+               ) {
                        $out->wrapWikiMsg( $wrap, array( 'sharedupload-desc-there', $repo, $descUrl ) );
                } else {
                        $out->wrapWikiMsg( $wrap, array( 'sharedupload', $repo ), ''/*BACKCOMPAT*/ );
@@ -854,7 +865,9 @@ EOT
                                $liContents = $link;
                        } elseif ( count( $redirects[$element->page_title] ) === 0 ) {
                                # Redirect without usages
-                               $liContents = $this->getContext()->msg( 'linkstoimage-redirect' )->rawParams( $link, '' )->parse();
+                               $liContents = $this->getContext()->msg( 'linkstoimage-redirect' )
+                                       ->rawParams( $link, '' )
+                                       ->parse();
                        } else {
                                # Redirect with usages
                                $li = '';
@@ -923,7 +936,10 @@ EOT
                        } else {
                                $link = Linker::makeExternalLink( $file->getDescriptionUrl(),
                                        $file->getTitle()->getPrefixedText() );
-                               $fromSrc = $this->getContext()->msg( 'shared-repo-from', $file->getRepo()->getDisplayName() )->text();
+                               $fromSrc = $this->getContext()->msg(
+                                       'shared-repo-from',
+                                       $file->getRepo()->getDisplayName()
+                               )->text();
                        }
                        $out->addHTML( "<li>{$link} {$fromSrc}</li>\n" );
                }
@@ -1068,8 +1084,10 @@ EOT
                );
                $submit = Xml::submitButton( $this->getContext()->msg( 'img-lang-go' )->text() );
 
-               $formContents = $this->getContext()->msg( 'img-lang-info' )->rawParams( $select, $submit )->parse()
-                       . Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() );
+               $formContents = $this->getContext()->msg( 'img-lang-info' )
+                       ->rawParams( $select, $submit )
+                       ->parse();
+               $formContents .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() );
 
                $langSelectLine = Html::rawElement( 'div', array( 'id' => 'mw-imglangselector-line' ),
                        Html::rawElement( 'form', array( 'action' => $wgScript ), $formContents )
@@ -1141,7 +1159,9 @@ EOT
                } else {
                        # Creating thumb links triggers thumbnail generation.
                        # Just generate the thumb for the current users prefs.
-                       $thumbSizes = array( $this->getImageLimitsFromOption( $this->getContext()->getUser(), 'thumbsize' ) );
+                       $thumbSizes = array(
+                               $this->getImageLimitsFromOption( $this->getContext()->getUser(), 'thumbsize' )
+                       );
                        if ( !$this->displayImg->mustRender() ) {
                                // We can safely include a link to the "full-size" preview,
                                // without actually rendering.
index c99928a..2fde832 100644 (file)
@@ -950,7 +950,6 @@ class WikiPage implements Page, IDBAccessObject {
                if ( $rt->isExternal() ) {
                        if ( $rt->isLocal() ) {
                                // Offsite wikis need an HTTP redirect.
-                               //
                                // This can be hard to reverse and may produce loops,
                                // so they may be disabled in the site configuration.
                                $source = $this->mTitle->getFullURL( 'redirect=no' );
@@ -964,10 +963,8 @@ class WikiPage implements Page, IDBAccessObject {
 
                if ( $rt->isSpecialPage() ) {
                        // Gotta handle redirects to special pages differently:
-                       // Fill the HTTP response "Location" header and ignore
-                       // the rest of the page we're on.
-                       //
-                       // Some pages are not valid targets
+                       // Fill the HTTP response "Location" header and ignore the rest of the page we're on.
+                       // Some pages are not valid targets.
                        if ( $rt->isValidRedirectTarget() ) {
                                return $rt->getFullURL();
                        } else {
@@ -1434,7 +1431,7 @@ class WikiPage implements Page, IDBAccessObject {
        ) {
                ContentHandler::deprecated( __METHOD__, '1.21' );
 
-               //NOTE: keep condition in sync with condition in replaceSectionContent!
+               // NOTE: keep condition in sync with condition in replaceSectionContent!
                if ( strval( $sectionId ) === '' ) {
                        // Whole-page edit; let the whole text through
                        return $text;
@@ -1811,8 +1808,7 @@ class WikiPage implements Page, IDBAccessObject {
                                }
                                $revisionId = $revision->insertOn( $dbw );
 
-                               // Update page
-                               //
+                               // Update page.
                                // We check for conflicts by comparing $oldid with the current latest revision ID.
                                $ok = $this->updateRevisionOn( $dbw, $revision, $oldid, $oldIsRedirect );
 
@@ -2046,7 +2042,7 @@ class WikiPage implements Page, IDBAccessObject {
                }
 
                $user = is_null( $user ) ? $wgUser : $user;
-               //XXX: check $user->getId() here???
+               // XXX: check $user->getId() here???
 
                // Use a sane default for $serialFormat, see bug 57026
                if ( $serialFormat === null ) {
@@ -2409,6 +2405,7 @@ class WikiPage implements Page, IDBAccessObject {
 
                $logRelationsValues = array();
                $logRelationsField = null;
+               $logParamsDetails = array();
 
                if ( $id ) { // Protection of existing page
                        if ( !Hooks::run( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
@@ -2467,6 +2464,7 @@ class WikiPage implements Page, IDBAccessObject {
                                        __METHOD__
                                );
                                if ( $restrictions != '' ) {
+                                       $cascadeValue = ( $cascade && $action == 'edit' ) ? 1 : 0;
                                        $dbw->insert(
                                                'page_restrictions',
                                                array(
@@ -2474,12 +2472,18 @@ class WikiPage implements Page, IDBAccessObject {
                                                        'pr_page' => $id,
                                                        'pr_type' => $action,
                                                        'pr_level' => $restrictions,
-                                                       'pr_cascade' => ( $cascade && $action == 'edit' ) ? 1 : 0,
+                                                       'pr_cascade' => $cascadeValue,
                                                        'pr_expiry' => $dbw->encodeExpiry( $expiry[$action] )
                                                ),
                                                __METHOD__
                                        );
                                        $logRelationsValues[] = $dbw->insertId();
+                                       $logParamsDetails[] = array(
+                                               'type' => $action,
+                                               'level' => $restrictions,
+                                               'expiry' => $expiry[$action],
+                                               'cascade' => (bool)$cascadeValue,
+                                       );
                                }
                        }
 
@@ -2510,6 +2514,11 @@ class WikiPage implements Page, IDBAccessObject {
                                                'pt_reason' => $reason,
                                        ), __METHOD__
                                );
+                               $logParamsDetails[] = array(
+                                       'type' => 'create',
+                                       'level' => $limit['create'],
+                                       'expiry' => $expiry['create'],
+                               );
                        } else {
                                $dbw->delete( 'protected_titles',
                                        array(
@@ -2527,15 +2536,24 @@ class WikiPage implements Page, IDBAccessObject {
                        $params = array();
                } else {
                        $protectDescriptionLog = $this->protectDescriptionLog( $limit, $expiry );
-                       $params = array( $protectDescriptionLog, $cascade ? 'cascade' : '' );
+                       $params = array(
+                               '4::description' => $protectDescriptionLog, // parameter for IRC
+                               '5:bool:cascade' => $cascade,
+                               'details' => $logParamsDetails, // parameter for localize and api
+                       );
                }
 
                // Update the protection log
-               $log = new LogPage( 'protect' );
-               $logId = $log->addEntry( $logAction, $this->mTitle, $reason, $params, $user );
+               $logEntry = new ManualLogEntry( 'protect', $logAction );
+               $logEntry->setTarget( $this->mTitle );
+               $logEntry->setComment( $reason );
+               $logEntry->setPerformer( $user );
+               $logEntry->setParameters( $params );
                if ( $logRelationsField !== null && count( $logRelationsValues ) ) {
-                       $log->addRelations( $logRelationsField, $logRelationsValues, $logId );
+                       $logEntry->setRelations( array( $logRelationsField => $logRelationsValues ) );
                }
+               $logId = $logEntry->insert();
+               $logEntry->publish( $logId );
 
                return Status::newGood();
        }
@@ -2795,16 +2813,18 @@ class WikiPage implements Page, IDBAccessObject {
                        $bitfield = 'rev_deleted';
                }
 
-               // For now, shunt the revision data into the archive table.
-               // Text is *not* removed from the text table; bulk storage
-               // is left intact to avoid breaking block-compression or
-               // immutable storage schemes.
-               //
-               // For backwards compatibility, note that some older archive
-               // table entries will have ar_text and ar_flags fields still.
-               //
-               // In the future, we may keep revisions and mark them with
-               // the rev_deleted field, which is reserved for this purpose.
+               /**
+                * For now, shunt the revision data into the archive table.
+                * Text is *not* removed from the text table; bulk storage
+                * is left intact to avoid breaking block-compression or
+                * immutable storage schemes.
+                *
+                * For backwards compatibility, note that some older archive
+                * table entries will have ar_text and ar_flags fields still.
+                *
+                * In the future, we may keep revisions and mark them with
+                * the rev_deleted field, which is reserved for this purpose.
+                */
 
                $row = array(
                        'ar_namespace'  => 'page_namespace',
index c450689..7acfe38 100644 (file)
@@ -32,10 +32,17 @@ class CacheTime {
         */
        public $mUsedOptions;
 
-       public $mVersion = Parser::VERSION,  # Compatibility check
-               $mCacheTime = '',             # Time when this object was generated, or -1 for uncacheable. Used in ParserCache.
-               $mCacheExpiry = null,         # Seconds after which the object should expire, use 0 for uncacheable. Used in ParserCache.
-               $mCacheRevisionId = null;     # Revision ID that was parsed
+       # Compatibility check
+       public $mVersion = Parser::VERSION;
+
+       # Time when this object was generated, or -1 for uncacheable. Used in ParserCache.
+       public $mCacheTime = '';
+
+       # Seconds after which the object should expire, use 0 for uncacheable. Used in ParserCache.
+       public $mCacheExpiry = null;
+
+       # Revision ID that was parsed
+       public $mCacheRevisionId = null;
 
        /**
         * @return string TS_MW timestamp
index 7639e2f..42091a0 100644 (file)
@@ -60,7 +60,11 @@ class CoreParserFunctions {
                        $parser->setFunctionHook( $func, array( __CLASS__, $func ), Parser::SFH_NO_HASH );
                }
 
-               $parser->setFunctionHook( 'namespace', array( __CLASS__, 'mwnamespace' ), Parser::SFH_NO_HASH );
+               $parser->setFunctionHook(
+                       'namespace',
+                       array( __CLASS__, 'mwnamespace' ),
+                       Parser::SFH_NO_HASH
+               );
                $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), Parser::SFH_NO_HASH );
                $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
                $parser->setFunctionHook( 'speciale', array( __CLASS__, 'speciale' ) );
@@ -68,7 +72,11 @@ class CoreParserFunctions {
                $parser->setFunctionHook( 'formatdate', array( __CLASS__, 'formatDate' ) );
 
                if ( $wgAllowDisplayTitle ) {
-                       $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), Parser::SFH_NO_HASH );
+                       $parser->setFunctionHook(
+                               'displaytitle',
+                               array( __CLASS__, 'displaytitle' ),
+                               Parser::SFH_NO_HASH
+                       );
                }
                if ( $wgAllowSlowParserFunctions ) {
                        $parser->setFunctionHook(
@@ -696,15 +704,15 @@ class CoreParserFunctions {
 
                // split the given option to its variable
                if ( self::matchAgainstMagicword( 'rawsuffix', $arg1 ) ) {
-                       //{{pagesincategory:|raw[|type]}}
+                       // {{pagesincategory:|raw[|type]}}
                        $raw = $arg1;
                        $type = $magicWords->matchStartToEnd( $arg2 );
                } else {
-                       //{{pagesincategory:[|type[|raw]]}}
+                       // {{pagesincategory:[|type[|raw]]}}
                        $type = $magicWords->matchStartToEnd( $arg1 );
                        $raw = $arg2;
                }
-               if ( !$type ) { //backward compatibility
+               if ( !$type ) { // backward compatibility
                        $type = 'pagesincategory_all';
                }
 
@@ -810,7 +818,9 @@ class CoreParserFunctions {
         * @param int $direction
         * @return string
         */
-       public static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) {
+       public static function pad(
+               $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT
+       ) {
                $padding = $parser->killMarkers( $padding );
                $lengthOfPadding = mb_strlen( $padding );
                if ( $lengthOfPadding == 0 ) {
index b4ca7c8..41b5dec 100644 (file)
@@ -364,13 +364,13 @@ class LinkHolderArray {
                                # The redirect status and length is passed to getLinkColour via the LinkCache
                                # Use formal parameters instead
                                $colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
-                               //add id to the extension todolist
+                               // add id to the extension todolist
                                $linkcolour_ids[$s->page_id] = $pdbk;
                        }
                        unset( $res );
                }
                if ( count( $linkcolour_ids ) ) {
-                       //pass an array of page_ids to an extension
+                       // pass an array of page_ids to an extension
                        Hooks::run( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
                }
 
index 807842b..3a2bb17 100644 (file)
@@ -45,7 +45,7 @@ class MWTidy {
        public static function tidy( $text ) {
                $driver = self::singleton();
                if ( !$driver ) {
-                       throw new MWException( __METHOD__.
+                       throw new MWException( __METHOD__ .
                                ': tidy is disabled, caller should have checked MWTidy::isEnabled()' );
                }
                return $driver->tidy( $text );
@@ -61,7 +61,7 @@ class MWTidy {
        public static function checkErrors( $text, &$errorStr = null ) {
                $driver = self::singleton();
                if ( !$driver ) {
-                       throw new MWException( __METHOD__.
+                       throw new MWException( __METHOD__ .
                                ': tidy is disabled, caller should have checked MWTidy::isEnabled()' );
                }
                if ( $driver->supportsValidate() ) {
index 12bb175..3b49ccf 100644 (file)
@@ -511,7 +511,10 @@ class Parser {
                        }
                        $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
                        $limitReport .= 'Cache expiry: ' . $this->mOutput->getCacheExpiry() . "\n";
-                       $limitReport .= 'Dynamic content: ' . ( $this->mOutput->hasDynamicContent() ? 'true' : 'false' ) . "\n";
+                       $limitReport .= 'Dynamic content: ' .
+                               ( $this->mOutput->hasDynamicContent() ? 'true' : 'false' ) .
+                               "\n";
+
                        foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
                                if ( Hooks::run( 'ParserLimitReportFormat',
                                        array( $key, &$value, &$limitReport, false, false )
@@ -1468,7 +1471,6 @@ class Parser {
         * @private
         */
        public function makeFreeExternalLink( $url, $numPostProto ) {
-
                $trail = '';
 
                # The characters '<' and '>' (which were escaped by
@@ -1476,7 +1478,12 @@ class Parser {
                # URLs, per RFC 2396.
                # Make &nbsp; terminate a URL as well (bug T84937)
                $m2 = array();
-               if ( preg_match( '/&(lt|gt|nbsp|#x0*(3[CcEe]|[Aa]0)|#0*(60|62|160));/', $url, $m2, PREG_OFFSET_CAPTURE ) ) {
+               if ( preg_match(
+                       '/&(lt|gt|nbsp|#x0*(3[CcEe]|[Aa]0)|#0*(60|62|160));/',
+                       $url,
+                       $m2,
+                       PREG_OFFSET_CAPTURE
+               ) ) {
                        $trail = substr( $url, $m2[0][1] ) . $trail;
                        $url = substr( $url, 0, $m2[0][1] );
                }
@@ -5318,7 +5325,6 @@ class Parser {
                $ig->setParser( $this );
                $ig->setHideBadImages();
                $ig->setAttributes( Sanitizer::validateTagAttributes( $params, 'table' ) );
-               $this->getOutput()->addModuleStyles( 'mediawiki.page.gallery.styles' );
 
                if ( isset( $params['showfilename'] ) ) {
                        $ig->setShowFilename( true );
index abff543..c03b5c2 100644 (file)
@@ -226,11 +226,17 @@ class ParserCache {
                        wfIncrStats( "pcache.miss.revid" );
                        $revId = $article->getLatest();
                        $cachedRevId = $value->getCacheRevisionId();
-                       wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" );
+                       wfDebug(
+                               "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n"
+                       );
                        $value = false;
-               } elseif ( Hooks::run( 'RejectParserCacheValue', array( $value, $wikiPage, $popts ) ) === false ) {
+               } elseif (
+                       Hooks::run( 'RejectParserCacheValue', array( $value, $wikiPage, $popts ) ) === false
+               ) {
                        wfIncrStats( 'pcache.miss.rejected' );
-                       wfDebug( "ParserOutput key valid, but rejected by RejectParserCacheValue hook handler.\n" );
+                       wfDebug(
+                               "ParserOutput key valid, but rejected by RejectParserCacheValue hook handler.\n"
+                       );
                        $value = false;
                } else {
                        wfIncrStats( "pcache.hit" );
@@ -284,7 +290,10 @@ class ParserCache {
                        // ...and its pointer
                        $this->mMemc->set( $this->getOptionsKey( $page ), $optionsKey, $expire );
 
-                       Hooks::run( 'ParserCacheSaveComplete', array( $this, $parserOutput, $page->getTitle(), $popts, $revId ) );
+                       Hooks::run(
+                               'ParserCacheSaveComplete',
+                               array( $this, $parserOutput, $page->getTitle(), $popts, $revId )
+                       );
                } else {
                        wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
                }
index 1073aed..e6d5274 100644 (file)
@@ -831,8 +831,8 @@ class ParserOptions {
        }
 
        /**
-        * Sets a hook to force that a page exists, and sets a current revision callback to return a
-        * revision with custom content when the current revision of the page is requested.
+        * Sets a hook to force that a page exists, and sets a current revision callback to return
+        * revision with custom content when the current revision of the page is requested.
         *
         * @since 1.25
         * @param Title $title
@@ -841,20 +841,25 @@ class ParserOptions {
         * @return ScopedCallback to unset the hook
         */
        public function setupFakeRevision( $title, $content, $user ) {
-               $oldCallback = $this->setCurrentRevisionCallback( function ( $titleToCheck, $parser = false ) use ( $title, $content, $user, &$oldCallback ) {
-                       if ( $titleToCheck->equals( $title ) ) {
-                               return new Revision( array(
-                                       'page' => $title->getArticleID(),
-                                       'user_text' => $user->getName(),
-                                       'user' => $user->getId(),
-                                       'parent_id' => $title->getLatestRevId(),
-                                       'title' => $title,
-                                       'content' => $content
-                               ) );
-                       } else {
-                               return call_user_func( $oldCallback, $titleToCheck, $parser );
+               $oldCallback = $this->setCurrentRevisionCallback(
+                       function (
+                               $titleToCheck, $parser = false ) use ( $title, $content, $user, &$oldCallback
+                       ) {
+                               if ( $titleToCheck->equals( $title ) ) {
+                                       return new Revision( array(
+                                               'page' => $title->getArticleID(),
+                                               'user_text' => $user->getName(),
+                                               'user' => $user->getId(),
+                                               'parent_id' => $title->getLatestRevId(),
+                                               'title' => $title,
+                                               'content' => $content
+                                       ) );
+                               } else {
+                                       return call_user_func( $oldCallback, $titleToCheck, $parser );
+                               }
                        }
-               } );
+               );
+
                global $wgHooks;
                $wgHooks['TitleExists'][] =
                        function ( $titleToCheck, &$exists ) use ( $title ) {
index 2eb1dc9..3745238 100644 (file)
  * @ingroup Parser
  */
 class ParserOutput extends CacheTime {
-       public $mText,                       # The output text
-               $mLanguageLinks,              # List of the full text of language links, in the order they appear
-               $mCategories,                 # Map of category names to sort keys
-               $mIndicators = array(),       # Page status indicators, usually displayed in top-right corner
-               $mTitleText,                  # title text of the chosen language variant
-               $mLinks = array(),            # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken.
-               $mTemplates = array(),        # 2-D map of NS/DBK to ID for the template references. ID=zero for broken.
-               $mTemplateIds = array(),      # 2-D map of NS/DBK to rev ID for the template references. ID=zero for broken.
-               $mImages = array(),           # DB keys of the images used, in the array key only
-               $mFileSearchOptions = array(), # DB keys of the images used mapped to sha1 and MW timestamp
-               $mExternalLinks = array(),    # External link URLs, in the key only
-               $mInterwikiLinks = array(),   # 2-D map of prefix/DBK (in keys only) for the inline interwiki links in the document.
-               $mNewSection = false,         # Show a new section link?
-               $mHideNewSection = false,     # Hide the new section link?
-               $mNoGallery = false,          # No gallery on category page? (__NOGALLERY__)
-               $mHeadItems = array(),        # Items to put in the <head> section
-               $mModules = array(),          # Modules to be loaded by the resource loader
-               $mModuleScripts = array(),    # Modules of which only the JS will be loaded by the resource loader
-               $mModuleStyles = array(),     # Modules of which only the CSSS will be loaded by the resource loader
-               $mJsConfigVars = array(),     # JavaScript config variable for mw.config combined with this page
-               $mOutputHooks = array(),      # Hook tags as per $wgParserOutputHooks
-               $mWarnings = array(),         # Warning text to be returned to the user. Wikitext formatted, in the key only
-               $mSections = array(),         # Table of contents
-               $mEditSectionTokens = false,  # prefix/suffix markers if edit sections were output as tokens
-               $mProperties = array(),       # Name/value pairs to be cached in the DB
-               $mTOCHTML = '',               # HTML of the TOC
-               $mTimestamp,                  # Timestamp of the revision
-               $mTOCEnabled = true,          # Whether TOC should be shown, can't override __NOTOC__
-               $mEnableOOUI = false;         # Whether OOUI should be enabled
-       private $mIndexPolicy = '';       # 'index' or 'noindex'?  Any other value will result in no change.
-       private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys)
-       private $mExtensionData = array(); # extra data used by extensions
-       private $mLimitReportData = array(); # Parser limit report data
-       private $mParseStartTime = array(); # Timestamps for getTimeSinceStart()
-       private $mPreventClickjacking = false; # Whether to emit X-Frame-Options: DENY
-       private $mFlags = array();        # Generic flags
+       /**
+        * @var string $mText The output text
+        */
+       public $mText;
+
+       /**
+        * @var array $mLanguageLinks List of the full text of language links,
+        *  in the order they appear.
+        */
+       public $mLanguageLinks;
+
+       /**
+        * @var array $mCategoriesMap of category names to sort keys
+        */
+       public $mCategories;
+
+       /**
+        * @var array $mIndicators Page status indicators, usually displayed in top-right corner.
+        */
+       public $mIndicators = array();
+
+       /**
+        * @var string $mTitleText Title text of the chosen language variant
+        */
+       public $mTitleText;
+
+       /**
+        * @var array $mLinks 2-D map of NS/DBK to ID for the links in the document.
+        *  ID=zero for broken.
+        */
+       public $mLinks = array();
+
+       /**
+        * @var array $mTemplates 2-D map of NS/DBK to ID for the template references.
+        *  ID=zero for broken.
+        */
+       public $mTemplates = array();
+
+       /**
+        * @var array $mTemplateIds 2-D map of NS/DBK to rev ID for the template references.
+        *  ID=zero for broken.
+        */
+       public $mTemplateIds = array();
+
+       /**
+        * @var array $mImages DB keys of the images used, in the array key only
+        */
+       public $mImages = array();
+
+       /**
+        * @var array $mFileSearchOptions DB keys of the images used mapped to sha1 and MW timestamp.
+        */
+       public $mFileSearchOptions = array();
+
+       /**
+        * @var array $mExternalLinks External link URLs, in the key only.
+        */
+       public $mExternalLinks = array();
+
+       /**
+        * @var array $mInterwikiLinks 2-D map of prefix/DBK (in keys only)
+        *  for the inline interwiki links in the document.
+        */
+       public $mInterwikiLinks = array();
+
+       /**
+        * @var bool $mNewSection Show a new section link?
+        */
+       public $mNewSection = false;
+
+       /**
+        * @var bool $mHideNewSection Hide the new section link?
+        */
+       public $mHideNewSection = false;
+
+       /**
+        * @var bool $mNoGallery No gallery on category page? (__NOGALLERY__).
+        */
+       public $mNoGallery = false;
+
+       /**
+        * @var array $mHeadItems Items to put in the <head> section
+        */
+       public $mHeadItems = array();
+
+       /**
+        * @var array $mModules Modules to be loaded by the resource loader
+        */
+       public $mModules = array();
+
+       /**
+        * @var array $mModuleScripts Modules of which only the JS will be loaded by
+        *  the resource loader.
+        */
+       public $mModuleScripts = array();
+
+       /**
+        * @var array $mModuleStyles Modules of which only the CSSS will be loaded by
+        *  the resource loader.
+        */
+       public $mModuleStyles = array();
+
+       /**
+        * @var array $mJsConfigVars JavaScript config variable for mw.config combined with this page.
+        */
+       public $mJsConfigVars = array();
+
+       /**
+        * @var array $mOutputHooks Hook tags as per $wgParserOutputHooks.
+        */
+       public $mOutputHooks = array();
+
+       /**
+        * @var array $mWarnings Warning text to be returned to the user.
+        *  Wikitext formatted, in the key only.
+        */
+       public $mWarnings = array();
+
+       /**
+        * @var array $mSections Table of contents
+        */
+       public $mSections = array();
+
+       /**
+        * @var bool $mEditSectionTokens prefix/suffix markers if edit sections were output as tokens.
+        */
+       public $mEditSectionTokens = false;
+
+       /**
+        * @var array $mProperties Name/value pairs to be cached in the DB.
+        */
+       public $mProperties = array();
+
+       /**
+        * @var string $mTOCHTML HTML of the TOC.
+        */
+       public $mTOCHTML = '';
+
+       /**
+        * @var string $mTimestamp Timestamp of the revision.
+        */
+       public $mTimestamp;
+
+       /**
+        * @var bool $mTOCEnabled Whether TOC should be shown, can't override __NOTOC__.
+        */
+       public $mTOCEnabled = true;
+
+       /**
+        * @var bool $mEnableOOUI Whether OOUI should be enabled.
+        */
+       public $mEnableOOUI = false;
+
+       /**
+        * @var string $mIndexPolicy 'index' or 'noindex'?  Any other value will result in no change.
+        */
+       private $mIndexPolicy = '';
+
+       /**
+        * @var array $mAccessedOptions List of ParserOptions (stored in the keys).
+        */
+       private $mAccessedOptions = array();
+
+       /**
+        * @var array $mExtensionData extra data used by extensions.
+        */
+       private $mExtensionData = array();
+
+       /**
+        * @var array $mLimitReportData Parser limit report data.
+        */
+       private $mLimitReportData = array();
+
+       /**
+        * @var array $mParseStartTime Timestamps for getTimeSinceStart().
+        */
+       private $mParseStartTime = array();
+
+       /**
+        * @var bool $mPreventClickjacking Whether to emit X-Frame-Options: DENY.
+        */
+       private $mPreventClickjacking = false;
+
+       /**
+        * @var array $mFlags Generic flags.
+        */
+       private $mFlags = array();
 
        const EDITSECTION_REGEX =
                '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#';
@@ -715,7 +866,11 @@ class ParserOutput extends CacheTime {
         */
        public function addSecondaryDataUpdate( DataUpdate $update ) {
                wfDeprecated( __METHOD__, '1.25' );
-               throw new MWException( 'ParserOutput::addSecondaryDataUpdate() is no longer supported. Override Content::getSecondaryDataUpdates() or use the SecondaryDataUpdates hook instead.' );
+               throw new MWException(
+                       'ParserOutput::addSecondaryDataUpdate() is no longer supported. ' .
+                               'Override Content::getSecondaryDataUpdates() ' .
+                               'or use the SecondaryDataUpdates hook instead.'
+               );
        }
 
        /**
index 8a09be8..562062f 100644 (file)
@@ -71,7 +71,7 @@ class Preprocessor_DOM implements Preprocessor {
         * @throws MWException
         */
        public function newPartNodeArray( $values ) {
-               //NOTE: DOM manipulation is slower than building & parsing XML! (or so Tim sais)
+               // NOTE: DOM manipulation is slower than building & parsing XML! (or so Tim sais)
                $xml = "<list>";
 
                foreach ( $values as $k => $val ) {
@@ -257,7 +257,7 @@ class Preprocessor_DOM implements Preprocessor {
 
                $stack = new PPDStack;
 
-               $searchBase = "[{<\n"; #}
+               $searchBase = "[{<\n"; # }
                // For fast reverse searches
                $revText = strrev( $text );
                $lengthText = strlen( $text );
@@ -282,7 +282,7 @@ class Preprocessor_DOM implements Preprocessor {
                $fakeLineStart = true;
 
                while ( true ) {
-                       //$this->memCheck();
+                       // $this->memCheck();
 
                        if ( $findOnlyinclude ) {
                                // Ignore all input up to the next <onlyinclude>
index 9429e44..f536d82 100644 (file)
@@ -200,7 +200,7 @@ class Preprocessor_Hash implements Preprocessor {
                $fakeLineStart = true;
 
                while ( true ) {
-                       //$this->memCheck();
+                       // $this->memCheck();
 
                        if ( $findOnlyinclude ) {
                                // Ignore all input up to the next <onlyinclude>
@@ -1154,7 +1154,7 @@ class PPFrame_Hash implements PPFrame {
                                        ) {
                                                $out .= $contextNode->firstChild->value;
                                        } else {
-                                               //$out .= '';
+                                               // $out .= '';
                                        }
                                } elseif ( $contextNode->name == 'ext' ) {
                                        # Extension tag
index a286f6b..84e873d 100644 (file)
@@ -58,7 +58,7 @@ class ExtensionProcessor implements Processor {
                'wgRevokePermissions' => 'array_plus_2d',
                'wgHooks' => 'array_merge_recursive',
                // credits are handled in the ExtensionRegistry
-               //'wgExtensionCredits' => 'array_merge_recursive',
+               // 'wgExtensionCredits' => 'array_merge_recursive',
                'wgExtraGenderNamespaces' => 'array_plus',
                'wgNamespacesWithSubpages' => 'array_plus',
                'wgNamespaceContentModels' => 'array_plus',
index 23e29d8..59b9249 100644 (file)
@@ -114,12 +114,22 @@ class ExtensionRegistry {
        }
 
        public function loadFromQueue() {
+               global $wgVersion;
                if ( !$this->queued ) {
                        return;
                }
 
+               // A few more things to vary the cache on
+               $versions = array(
+                       'registration' => self::CACHE_VERSION,
+                       'mediawiki' => $wgVersion
+               );
+
                // See if this queue is in APC
-               $key = wfMemcKey( 'registration', md5( json_encode( $this->queued ) ), self::CACHE_VERSION );
+               $key = wfMemcKey(
+                       'registration',
+                       md5( json_encode( $this->queued + $versions ) )
+               );
                $data = $this->cache->get( $key );
                if ( $data ) {
                        $this->exportExtractedData( $data );
@@ -194,7 +204,7 @@ class ExtensionRegistry {
                        ) {
                                // Doesn't match, mark it as incompatible.
                                $incompatible[] = "{$info['name']} is not compatible with the current "
-                                       . "MediaWiki core (version {$wgVersion}), it requires: ". $requires[self::MEDIAWIKI_CORE]
+                                       . "MediaWiki core (version {$wgVersion}), it requires: " . $requires[self::MEDIAWIKI_CORE]
                                        . '.';
                                continue;
                        }
index 1f48514..dacf013 100644 (file)
@@ -208,7 +208,12 @@ class ResourceLoader implements LoggerAwareInterface {
                if ( !$options['cache'] ) {
                        $result = self::applyFilter( $filter, $data, $this->config );
                } else {
-                       $key = wfGlobalCacheKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) );
+                       $key = wfGlobalCacheKey(
+                               'resourceloader',
+                               'filter',
+                               $filter,
+                               self::$filterCacheVersion, md5( $data )
+                       );
                        $cache = wfGetCache( wfIsHHVM() ? CACHE_ACCEL : CACHE_ANYTHING );
                        $cacheEntry = $cache->get( $key );
                        if ( is_string( $cacheEntry ) ) {
@@ -747,7 +752,7 @@ class ResourceLoader implements LoggerAwareInterface {
 
                if ( $context->getImageObj() && $this->errors ) {
                        // We can't show both the error messages and the response when it's an image.
-                       $response = implode( "\n\n",  $this->errors );
+                       $response = implode( "\n\n", $this->errors );
                } elseif ( $this->errors ) {
                        $errorText = implode( "\n\n", $this->errors );
                        $errorResponse = self::makeComment( $errorText );
@@ -941,18 +946,18 @@ class ResourceLoader implements LoggerAwareInterface {
                global $wgShowExceptionDetails;
 
                if ( !$wgShowExceptionDetails ) {
-                       return 'Internal error';
+                       return MWExceptionHandler::getPublicLogMessage( $e );
                }
 
-               return $e->__toString();
+               return MWExceptionHandler::getLogMessage( $e );
        }
 
        /**
         * Generate code for a response.
         *
         * @param ResourceLoaderContext $context Context in which to generate a response
-        * @param array $modules List of module objects keyed by module name
-        * @param array $missing List of requested module names that are unregistered (optional)
+        * @param ResourceLoaderModule[] $modules List of module objects keyed by module name
+        * @param string[] $missing List of requested module names that are unregistered (optional)
         * @return string Response data
         */
        public function makeModuleResponse( ResourceLoaderContext $context,
@@ -1241,7 +1246,7 @@ MESSAGE;
        }
 
        private static function isEmptyObject( stdClass $obj ) {
-               foreach ( $obj as $key => &$value ) {
+               foreach ( $obj as $key => $value ) {
                        return false;
                }
                return true;
@@ -1380,7 +1385,8 @@ MESSAGE;
         * @return string
         */
        public static function makeLoaderConditionalScript( $script ) {
-               return "window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n" . trim( $script ) . "\n} );";
+               return "window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n" .
+                       trim( $script ) . "\n} );";
        }
 
        /**
@@ -1605,12 +1611,15 @@ MESSAGE;
        /**
         * Returns LESS compiler set up for use with MediaWiki
         *
+        * @since 1.22
+        * @since 1.26 added $extraVars parameter
         * @param Config $config
+        * @param array $extraVars Associative array of extra (i.e., other than the
+        *   globally-configured ones) that should be used for compilation.
         * @throws MWException
-        * @since 1.22
         * @return Less_Parser
         */
-       public static function getLessCompiler( Config $config ) {
+       public static function getLessCompiler( Config $config, $extraVars = array() ) {
                // When called from the installer, it is possible that a required PHP extension
                // is missing (at least for now; see bug 47564). If this is the case, throw an
                // exception (caught by the installer) to prevent a fatal error later on.
@@ -1619,7 +1628,7 @@ MESSAGE;
                }
 
                $parser = new Less_Parser;
-               $parser->ModifyVars( self::getLessVars( $config ) );
+               $parser->ModifyVars( array_merge( self::getLessVars( $config ), $extraVars ) );
                $parser->SetImportDirs( array_fill_keys( $config->get( 'ResourceLoaderLESSImportPaths' ), '' ) );
                $parser->SetOption( 'relativeUrls', false );
                $parser->SetCacheDir( $config->get( 'CacheDirectory' ) ?: wfTempDir() );
@@ -1638,8 +1647,6 @@ MESSAGE;
                if ( !self::$lessVars ) {
                        $lessVars = $config->get( 'ResourceLoaderLESSVars' );
                        Hooks::run( 'ResourceLoaderGetLessVars', array( &$lessVars ) );
-                       // Sort by key to ensure consistent hashing for cache lookups.
-                       ksort( $lessVars );
                        self::$lessVars = $lessVars;
                }
                return self::$lessVars;
index da729fd..fca7961 100644 (file)
  * @since 1.24
  */
 class ResourceLoaderEditToolbarModule extends ResourceLoaderFileModule {
-       /**
-        * Serialize a string (escape and quote) for use as a CSS string value.
-        * http://www.w3.org/TR/2013/WD-cssom-20131205/#serialize-a-string
-        *
-        * @param string $value
-        * @return string
-        * @throws Exception
-        */
-       private static function cssSerializeString( $value ) {
-               if ( strstr( $value, "\0" ) ) {
-                       throw new Exception( "Invalid character in CSS string" );
-               }
-               $value = strtr( $value, array( '\\' => '\\\\', '"' => '\\"' ) );
-               $value = preg_replace_callback( '/[\x01-\x1f\x7f-\x9f]/', function ( $match ) {
-                       return '\\' . base_convert( ord( $match[0] ), 10, 16 ) . ' ';
-               }, $value );
-               return '"' . $value . '"';
-       }
-
        /**
         * Get language-specific LESS variables for this module.
         *
+        * @since 1.26
+        * @param ResourceLoaderContext $context
         * @return array
         */
-       private function getLessVars( ResourceLoaderContext $context ) {
+       protected function getLessVars( ResourceLoaderContext $context ) {
+               $vars = parent::getLessVars( $context );
                $language = Language::factory( $context->getLanguage() );
-
-               // This is very conveniently formatted and we can pass it right through
-               $vars = $language->getImageFiles();
-
-               // less.php tries to be helpful and parse our variables as LESS source code
-               foreach ( $vars as $key => &$value ) {
-                       $value = self::cssSerializeString( $value );
+               foreach ( $language->getImageFiles() as $key => $value ) {
+                       $vars[ $key ] = CSSMin::serializeStringValue( $value );
                }
-
                return $vars;
        }
-
-       /**
-        * @return bool
-        */
-       public function enableModuleContentVersion() {
-               return true;
-       }
-
-       /**
-        * Get a LESS compiler instance for this module.
-        *
-        * Set our variables in it.
-        *
-        * @throws MWException
-        * @param ResourceLoaderContext $context
-        * @return Less_Parser
-        */
-       protected function getLessCompiler( ResourceLoaderContext $context = null ) {
-               $parser = parent::getLessCompiler();
-               $parser->ModifyVars( $this->getLessVars( $context ) );
-               return $parser;
-       }
 }
index ca10ab7..0df2892 100644 (file)
@@ -854,13 +854,21 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @param array $styles List of media type/list of file paths pairs, to read, remap and
         * concetenate
         * @param bool $flip
-        * @param ResourceLoaderContext $context (optional)
+        * @param ResourceLoaderContext $context
         *
         * @throws MWException
         * @return array List of concatenated and remapped CSS data from $styles,
         *     keyed by media type
+        *
+        * @since 1.26 Calling this method without a ResourceLoaderContext instance
+        *   is deprecated.
         */
        public function readStyleFiles( array $styles, $flip, $context = null ) {
+               if ( $context === null ) {
+                       wfDeprecated( __METHOD__ . ' without a ResourceLoader context', '1.26' );
+                       $context = ResourceLoaderContext::newDummyContext();
+               }
+
                if ( empty( $styles ) ) {
                        return array();
                }
@@ -882,12 +890,12 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         *
         * @param string $path File path of style file to read
         * @param bool $flip
-        * @param ResourceLoaderContext $context (optional)
+        * @param ResourceLoaderContext $context
         *
         * @return string CSS data in script file
         * @throws MWException If the file doesn't exist
         */
-       protected function readStyleFile( $path, $flip, $context = null ) {
+       protected function readStyleFile( $path, $flip, $context ) {
                $localPath = $this->getLocalPath( $path );
                $remotePath = $this->getRemotePath( $path );
                if ( !file_exists( $localPath ) ) {
@@ -897,8 +905,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                }
 
                if ( $this->getStyleSheetLang( $localPath ) === 'less' ) {
-                       $compiler = $this->getLessCompiler( $context );
-                       $style = $this->compileLessFile( $localPath, $compiler );
+                       $style = $this->compileLessFile( $localPath, $context );
                        $this->hasGeneratedStyles = true;
                } else {
                        $style = file_get_contents( $localPath );
@@ -947,12 +954,13 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * Keeps track of all used files and adds them to localFileRefs.
         *
         * @since 1.22
+        * @since 1.26 Added $context paramter.
         * @throws Exception If less.php encounters a parse error
         * @param string $fileName File path of LESS source
-        * @param Less_Parser $parser Compiler to use, if not default
+        * @param ResourceLoaderContext $context Context in which to generate script
         * @return string CSS source
         */
-       protected function compileLessFile( $fileName, $compiler = null ) {
+       protected function compileLessFile( $fileName, ResourceLoaderContext $context ) {
                static $cache;
 
                if ( !$cache ) {
@@ -961,7 +969,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
 
                // Construct a cache key from the LESS file name and a hash digest
                // of the LESS variables used for compilation.
-               $varsHash = hash( 'md4', serialize( ResourceLoader::getLessVars( $this->getConfig() ) ) );
+               $vars = $this->getLessVars( $context );
+               ksort( $vars );
+               $varsHash = hash( 'md4', serialize( $vars ) );
                $cacheKey = wfGlobalCacheKey( 'LESS', $fileName, $varsHash );
                $cachedCompile = $cache->get( $cacheKey );
 
@@ -976,10 +986,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                        }
                }
 
-               if ( !$compiler ) {
-                       $compiler = $this->getLessCompiler();
-               }
-
+               $compiler = ResourceLoader::getLessCompiler( $this->getConfig(), $vars );
                $css = $compiler->parseFile( $fileName )->getCss();
                $files = $compiler->AllParsedFiles();
                $this->localFileRefs = array_merge( $this->localFileRefs, $files );
@@ -993,20 +1000,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                return $css;
        }
 
-       /**
-        * Get a LESS compiler instance for this module in given context.
-        *
-        * Just calls ResourceLoader::getLessCompiler() by default to get a global compiler.
-        *
-        * @param ResourceLoaderContext $context
-        * @throws MWException
-        * @since 1.24
-        * @return Less_Parser
-        */
-       protected function getLessCompiler( ResourceLoaderContext $context = null ) {
-               return ResourceLoader::getLessCompiler( $this->getConfig() );
-       }
-
        /**
         * Takes named templates by the module and returns an array mapping.
         * @return array of templates mapping template alias to content
index 2338c90..9d5fe38 100644 (file)
@@ -315,21 +315,23 @@ class ResourceLoaderImage {
         * @return string|bool PNG image data, or false on failure
         */
        protected function rasterize( $svg ) {
-               // This code should be factored out to a separate method on SvgHandler, or perhaps a separate
-               // class, with a separate set of configuration settings.
-               //
-               // This is a distinct use case from regular SVG rasterization:
-               // * We can skip many sanity and security checks (as the images come from a trusted source,
-               //   rather than from the user).
-               // * We need to provide extra options to some converters to achieve acceptable quality for very
-               //   small images, which might cause performance issues in the general case.
-               // * We want to directly pass image data to the converter, rather than a file path.
-               //
-               // See https://phabricator.wikimedia.org/T76473#801446 for examples of what happens with the
-               // default settings.
-               //
-               // For now, we special-case rsvg (used in WMF production) and do a messy workaround for other
-               // converters.
+               /**
+                * This code should be factored out to a separate method on SvgHandler, or perhaps a separate
+                * class, with a separate set of configuration settings.
+                *
+                * This is a distinct use case from regular SVG rasterization:
+                * * We can skip many sanity and security checks (as the images come from a trusted source,
+                *   rather than from the user).
+                * * We need to provide extra options to some converters to achieve acceptable quality for very
+                *   small images, which might cause performance issues in the general case.
+                * * We want to directly pass image data to the converter, rather than a file path.
+                *
+                * See https://phabricator.wikimedia.org/T76473#801446 for examples of what happens with the
+                * default settings.
+                *
+                * For now, we special-case rsvg (used in WMF production) and do a messy workaround for other
+                * converters.
+                */
 
                global $wgSVGConverter, $wgSVGConverterPath;
 
index 80c8220..1551ae3 100644 (file)
@@ -485,6 +485,17 @@ abstract class ResourceLoaderModule {
                $this->msgBlobMtime[$lang] = $mtime;
        }
 
+       /**
+        * Get module-specific LESS variables, if any.
+        *
+        * @since 1.26
+        * @param ResourceLoaderContext $context
+        * @return array Module-specific LESS variables.
+        */
+       protected function getLessVars( ResourceLoaderContext $context ) {
+               return array();
+       }
+
        /**
         * Get an array of this module's resources. Ready for serving to the web.
         *
index c704c1a..0553df0 100644 (file)
@@ -356,7 +356,11 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        '$VARS.configuration' => $this->getConfigSettings( $context ),
                        '$VARS.baseModulesUri' => self::getStartupModulesUrl( $context ),
                ) );
-               $pairs['$CODE.registrations()'] = str_replace( "\n", "\n\t", trim( $this->getModuleRegistrations( $context ) ) );
+               $pairs['$CODE.registrations()'] = str_replace(
+                       "\n",
+                       "\n\t",
+                       trim( $this->getModuleRegistrations( $context ) )
+               );
 
                return strtr( $out, $pairs );
        }
index 7d5d38f..98c05b5 100644 (file)
@@ -547,7 +547,9 @@ class SearchHighlighter {
                $text = ltrim( $text ) . "\n"; // make sure the preg_match may find the last line
                $text = str_replace( "\n\n", "\n", $text ); // remove empty lines
                preg_match( "/^(.*\n){0,$contextlines}/", $text, $match );
-               $text = htmlspecialchars( substr( trim( $match[0] ), 0, $contextlines * $contextchars ) ); // trim and limit to max number of chars
+
+               // Trim and limit to max number of chars
+               $text = htmlspecialchars( substr( trim( $match[0] ), 0, $contextlines * $contextchars ) );
                return str_replace( "\n", '<br>', $text );
        }
 }
index 246f115..1442671 100644 (file)
@@ -406,7 +406,6 @@ class SearchMySQL extends SearchDatabase {
                // Periods within things like hostnames and IP addresses
                // are also important -- we want a search for "example.com"
                // or "192.168.1.1" to work sanely.
-               //
                // MySQL's search seems to ignore them, so you'd match on
                // "example.wikipedia.com" and "192.168.83.1" as well.
                $out = preg_replace(
index 71e3b63..60c4249 100644 (file)
@@ -65,14 +65,14 @@ class SearchPostgres extends SearchDatabase {
 
                wfDebug( "parseQuery received: $term \n" );
 
-               ## No backslashes allowed
+               # # No backslashes allowed
                $term = preg_replace( '/\\\/', '', $term );
 
-               ## Collapse parens into nearby words:
+               # # Collapse parens into nearby words:
                $term = preg_replace( '/\s*\(\s*/', ' (', $term );
                $term = preg_replace( '/\s*\)\s*/', ') ', $term );
 
-               ## Treat colons as word separators:
+               # # Treat colons as word separators:
                $term = preg_replace( '/:/', ' ', $term );
 
                $searchstring = '';
@@ -97,22 +97,22 @@ class SearchPostgres extends SearchDatabase {
                        }
                }
 
-               ## Strip out leading junk
+               # # Strip out leading junk
                $searchstring = preg_replace( '/^[\s\&\|]+/', '', $searchstring );
 
-               ## Remove any doubled-up operators
+               # # Remove any doubled-up operators
                $searchstring = preg_replace( '/([\!\&\|]) +(?:[\&\|] +)+/', "$1 ", $searchstring );
 
-               ## Remove any non-spaced operators (e.g. "Zounds!")
+               # # Remove any non-spaced operators (e.g. "Zounds!")
                $searchstring = preg_replace( '/([^ ])[\!\&\|]/', "$1", $searchstring );
 
-               ## Remove any trailing whitespace or operators
+               # # Remove any trailing whitespace or operators
                $searchstring = preg_replace( '/[\s\!\&\|]+$/', '', $searchstring );
 
-               ## Remove unnecessary quotes around everything
+               # # Remove unnecessary quotes around everything
                $searchstring = preg_replace( '/^[\'"](.*)[\'"]$/', "$1", $searchstring );
 
-               ## Quote the whole thing
+               # # Quote the whole thing
                $searchstring = $this->db->addQuotes( $searchstring );
 
                wfDebug( "parseQuery returned: $searchstring \n" );
@@ -132,18 +132,18 @@ class SearchPostgres extends SearchDatabase {
                # Get the SQL fragment for the given term
                $searchstring = $this->parseQuery( $term );
 
-               ## We need a separate query here so gin does not complain about empty searches
+               # # We need a separate query here so gin does not complain about empty searches
                $sql = "SELECT to_tsquery($searchstring)";
                $res = $this->db->query( $sql );
                if ( !$res ) {
-                       ## TODO: Better output (example to catch: one 'two)
+                       # # TODO: Better output (example to catch: one 'two)
                        die( "Sorry, that was not a valid search string. Please go back and try again" );
                }
                $top = $res->fetchRow();
                $top = $top[0];
 
                $this->searchTerms = array();
-               if ( $top === "" ) { ## e.g. if only stopwords are used XXX return something better
+               if ( $top === "" ) { # # e.g. if only stopwords are used XXX return something better
                        $query = "SELECT page_id, page_namespace, page_title, 0 AS score " .
                                "FROM page p, revision r, pagecontent c WHERE p.page_latest = r.rev_id " .
                                "AND r.rev_text_id = c.old_id AND 1=0";
@@ -162,7 +162,7 @@ class SearchPostgres extends SearchDatabase {
                        "AND r.rev_text_id = c.old_id AND $fulltext @@ to_tsquery($searchstring)";
                }
 
-               ## Namespaces - defaults to 0
+               # # Namespaces - defaults to 0
                if ( !is_null( $this->namespaces ) ) { // null -> search all
                        if ( count( $this->namespaces ) < 1 ) {
                                $query .= ' AND page_namespace = 0';
@@ -181,10 +181,10 @@ class SearchPostgres extends SearchDatabase {
                return $query;
        }
 
-       ## Most of the work of these two functions are done automatically via triggers
+       # # Most of the work of these two functions are done automatically via triggers
 
        function update( $pageid, $title, $text ) {
-               ## We don't want to index older revisions
+               # # We don't want to index older revisions
                $sql = "UPDATE pagecontent SET textvector = NULL WHERE textvector IS NOT NULL and old_id IN " .
                                "(SELECT DISTINCT rev_text_id FROM revision WHERE rev_page = " . intval( $pageid ) .
                                " ORDER BY rev_text_id DESC OFFSET 1)";
index 95631f8..029919c 100644 (file)
@@ -113,9 +113,9 @@ class MediaWikiSite extends Site {
                        return $t->getPrefixedText();
                } else {
 
-                       // Make sure the string is normalized into NFC (due to the bug 40017)
+                       // Make sure the string is normalized into NFC (due to T42017)
                        // but do nothing to the whitespaces, that should work appropriately.
-                       // @see https://bugzilla.wikimedia.org/show_bug.cgi?id=40017
+                       // @see https://phabricator.wikimedia.org/T42017
                        $pageName = UtfNormal\Validator::cleanUp( $pageName );
 
                        // Build the args for the specific call
index 169c0d8..294f1db 100644 (file)
@@ -105,8 +105,8 @@ class SiteExporter {
                        }
                }
 
-               //@todo: export <data>
-               //@todo: export <config>
+               // @todo: export <data>
+               // @todo: export <config>
 
                fwrite( $this->sink, "\t" . Xml::closeElement( 'site' ) . "\n" );
        }
index a05bad5..9aefea2 100644 (file)
@@ -183,8 +183,8 @@ class SiteImporter {
                        $site->addLocalId( $idType, $id );
                }
 
-               //@todo: import <data>
-               //@todo: import <config>
+               // @todo: import <data>
+               // @todo: import <config>
 
                return $site;
        }
index 2d9f22d..da883d9 100644 (file)
@@ -319,7 +319,7 @@ class SiteList extends GenericArrayObject {
         * @return array
         */
        protected function getSerializationData() {
-               //NOTE: When changing the structure, either implement unserialize() to handle the
+               // NOTE: When changing the structure, either implement unserialize() to handle the
                //      old structure too, or update SERIAL_VERSION_ID to kill any caches.
                return array_merge(
                        parent::getSerializationData(),
index baf9d95..ae69934 100644 (file)
@@ -928,7 +928,7 @@ class SkinTemplate extends Skin {
                                        // section link
                                        if ( $showNewSection ) {
                                                // Adds new section link
-                                               //$content_navigation['actions']['addsection']
+                                               // $content_navigation['actions']['addsection']
                                                $content_navigation['views']['addsection'] = array(
                                                        'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
                                                        'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )
index 3c8b742..bfb29ae 100644 (file)
@@ -450,14 +450,13 @@ abstract class QueryPage extends SpecialPage {
                } else {
                        $options['ORDER BY'] = 'qc_value ASC';
                }
-               $res = $dbr->select( 'querycache', array( 'qc_type',
+               return $dbr->select( 'querycache', array( 'qc_type',
                                'namespace' => 'qc_namespace',
                                'title' => 'qc_title',
                                'value' => 'qc_value' ),
                                array( 'qc_type' => $this->getName() ),
                                __METHOD__, $options
                );
-               return $dbr->resultObject( $res );
        }
 
        public function getCachedTimestamp() {
index e794a5d..47b4fc8 100644 (file)
@@ -391,7 +391,7 @@ class SpecialPageFactory {
                                        'closure_expansion' => false,
                                ) );
                        } elseif ( $rec instanceof SpecialPage ) {
-                               $page = $rec; //XXX: we should deep clone here
+                               $page = $rec; // XXX: we should deep clone here
                        } else {
                                $page = null;
                        }
index 7028fdc..53798c0 100644 (file)
@@ -171,7 +171,7 @@ class SpecialBookSources extends SpecialPage {
                        $content = $rev->getContent();
 
                        if ( $content instanceof TextContent ) {
-                               //XXX: in the future, this could be stored as structured data, defining a list of book sources
+                               // XXX: in the future, this could be stored as structured data, defining a list of book sources
 
                                $text = $content->getNativeData();
                                $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $text ) );
index 3a13b7e..cea6ceb 100644 (file)
@@ -134,7 +134,7 @@ class CategoryPager extends AlphabeticPager {
        }
 
        function getIndexField() {
-#              return array( 'abc' => 'cat_title', 'count' => 'cat_pages' );
+#              return array( 'abc' => 'cat_title', 'count' => 'cat_pages' );
                return 'cat_title';
        }
 
@@ -145,13 +145,13 @@ class CategoryPager extends AlphabeticPager {
                return $this->mDefaultQuery;
        }
 
-#      protected function getOrderTypeMessages() {
-#              return array( 'abc' => 'special-categories-sort-abc',
-#                      'count' => 'special-categories-sort-count' );
-#      }
+#      protected function getOrderTypeMessages() {
+#              return array( 'abc' => 'special-categories-sort-abc',
+#                      'count' => 'special-categories-sort-count' );
+#      }
 
        protected function getDefaultDirections() {
-#              return array( 'abc' => false, 'count' => true );
+#              return array( 'abc' => false, 'count' => true );
                return false;
        }
 
index cce5da5..b0def59 100644 (file)
@@ -139,7 +139,7 @@ class SpecialChangeContentModel extends FormSpecialPage {
                        throw new RuntimeException( "Form submission was not POSTed" );
                }
 
-               $this->title = Title::newFromText( $data['pagetitle' ] );
+               $this->title = Title::newFromText( $data['pagetitle'] );
                $user = $this->getUser();
                // Check permissions and make sure the user has permission to edit the specific page
                $errors = $this->title->getUserPermissionsErrors( 'editcontentmodel', $user );
index 74662ae..64a93a0 100644 (file)
@@ -71,6 +71,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                $this->outputHeader();
                $this->outputSubtitle();
+               $out->addModuleStyles( 'mediawiki.special' );
 
                # B/C: $mode used to be waaay down the parameter list, and the first parameter
                # was $wgUser
@@ -403,7 +404,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         */
        private function cleanupWatchlist() {
                if ( !count( $this->badItems ) ) {
-                       return; //nothing to do
+                       return; // nothing to do
                }
 
                $dbw = wfGetDB( DB_MASTER );
index 92cb8bf..6b0d1ec 100644 (file)
@@ -329,29 +329,33 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                }
 
                if ( $config->get( 'UserEmailUseReplyTo' ) ) {
-                       // Put the generic wiki autogenerated address in the From:
-                       // header and reserve the user for Reply-To.
-                       //
-                       // This is a bit ugly, but will serve to differentiate
-                       // wiki-borne mails from direct mails and protects against
-                       // SPF and bounce problems with some mailers (see below).
+                       /**
+                        * Put the generic wiki autogenerated address in the From:
+                        * header and reserve the user for Reply-To.
+                        *
+                        * This is a bit ugly, but will serve to differentiate
+                        * wiki-borne mails from direct mails and protects against
+                        * SPF and bounce problems with some mailers (see below).
+                        */
                        $mailFrom = new MailAddress( $config->get( 'PasswordSender' ),
                                wfMessage( 'emailsender' )->inContentLanguage()->text() );
                        $replyTo = $from;
                } else {
-                       // Put the sending user's e-mail address in the From: header.
-                       //
-                       // This is clean-looking and convenient, but has issues.
-                       // One is that it doesn't as clearly differentiate the wiki mail
-                       // from "directly" sent mails.
-                       //
-                       // Another is that some mailers (like sSMTP) will use the From
-                       // address as the envelope sender as well. For open sites this
-                       // can cause mails to be flunked for SPF violations (since the
-                       // wiki server isn't an authorized sender for various users'
-                       // domains) as well as creating a privacy issue as bounces
-                       // containing the recipient's e-mail address may get sent to
-                       // the sending user.
+                       /**
+                        * Put the sending user's e-mail address in the From: header.
+                        *
+                        * This is clean-looking and convenient, but has issues.
+                        * One is that it doesn't as clearly differentiate the wiki mail
+                        * from "directly" sent mails.
+                        *
+                        * Another is that some mailers (like sSMTP) will use the From
+                        * address as the envelope sender as well. For open sites this
+                        * can cause mails to be flunked for SPF violations (since the
+                        * wiki server isn't an authorized sender for various users'
+                        * domains) as well as creating a privacy issue as bounces
+                        * containing the recipient's e-mail address may get sent to
+                        * the sending user.
+                        */
                        $mailFrom = $from;
                        $replyTo = null;
                }
index 39c4d77..642ea69 100644 (file)
@@ -385,7 +385,7 @@ class SpecialExport extends SpecialPage {
                        $exporter->allPages();
                } else {
                        foreach ( $pages as $page ) {
-                               #Bug 8824: Only export pages the user can read
+                               # Bug 8824: Only export pages the user can read
                                $title = Title::newFromText( $page );
                                if ( is_null( $title ) ) {
                                        // @todo Perhaps output an <error> tag or something.
index 2d79aaf..3ea56c6 100644 (file)
@@ -52,7 +52,7 @@ class SpecialListFiles extends IncludableSpecialPage {
                if ( $this->including() ) {
                        $out->addParserOutputContent( $pager->getBodyOutput() );
                } else {
-                       $out->addHTML( $pager->getForm() );
+                       $pager->getForm();
                        $out->addParserOutputContent( $pager->getFullOutput() );
                }
        }
index 828a93b..382b03f 100644 (file)
@@ -234,7 +234,7 @@ class SpecialListGroupRights extends SpecialPage {
        private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
                $r = array();
                foreach ( $permissions as $permission => $granted ) {
-                       //show as granted only if it isn't revoked to prevent duplicate display of permissions
+                       // show as granted only if it isn't revoked to prevent duplicate display of permissions
                        if ( $granted && ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) ) {
                                $r[] = $this->msg( 'listgrouprights-right-display',
                                        User::getRightDescription( $permission ),
index 31200c8..274a95a 100644 (file)
@@ -163,7 +163,7 @@ class UsersPager extends AlphabeticPager {
         * @return string
         */
        function formatRow( $row ) {
-               if ( $row->user_id == 0 ) { #Bug 16487
+               if ( $row->user_id == 0 ) { # Bug 16487
                        return '';
                }
 
index 7edf961..145a12a 100644 (file)
@@ -61,6 +61,9 @@ class SpecialMergeHistory extends SpecialPage {
        /** @var Title */
        protected $mDestObj;
 
+       /** @var int[] */
+       public $prevId;
+
        public function __construct() {
                parent::__construct( 'MergeHistory', 'mergehistory' );
        }
@@ -94,18 +97,6 @@ class SpecialMergeHistory extends SpecialPage {
                        $this->mTargetObj = null;
                        $this->mDestObj = null;
                }
-               $this->preCacheMessages();
-       }
-
-       /**
-        * As we use the same small set of messages in various methods and that
-        * they are called often, we call them once and save them in $this->message
-        */
-       function preCacheMessages() {
-               // Precache various messages
-               if ( !isset( $this->message ) ) {
-                       $this->message['last'] = $this->msg( 'last' )->escaped();
-               }
        }
 
        public function execute( $par ) {
@@ -283,7 +274,7 @@ class SpecialMergeHistory extends SpecialPage {
                $rev = new Revision( $row );
 
                $stxt = '';
-               $last = $this->message['last'];
+               $last = $this->msg( 'last' )->escaped();
 
                $ts = wfTimestamp( TS_MW, $row->rev_timestamp );
                $checkBox = Xml::radio( 'mergepoint', $ts, ( $this->mTimestamp === $ts ) );
@@ -302,11 +293,11 @@ class SpecialMergeHistory extends SpecialPage {
 
                # Last link
                if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
-                       $last = $this->message['last'];
+                       $last = $this->msg( 'last' )->escaped();
                } elseif ( isset( $this->prevId[$row->rev_id] ) ) {
                        $last = Linker::linkKnown(
                                $rev->getTitle(),
-                               $this->message['last'],
+                               $this->msg( 'last' )->escaped(),
                                array(),
                                array(
                                        'diff' => $row->rev_id,
@@ -501,13 +492,13 @@ class SpecialMergeHistory extends SpecialPage {
 }
 
 class MergeHistoryPager extends ReverseChronologicalPager {
-       /** @var IContextSource */
+       /** @var SpecialMergeHistory */
        public $mForm;
 
        /** @var array */
        public $mConds;
 
-       function __construct( $form, $conds, $source, $dest ) {
+       function __construct( SpecialMergeHistory $form, $conds, Title $source, Title $dest ) {
                $this->mForm = $form;
                $this->mConds = $conds;
                $this->title = $source;
index 8091f1b..aa71d3c 100644 (file)
@@ -342,6 +342,7 @@ class MovePageForm extends UnlistedSpecialPage {
                                'id' => 'wpReason',
                                'maxLength' => 200,
                                'infusable' => true,
+                               'value' => $this->reason,
                        ) ),
                        array(
                                'label' => $this->msg( 'movereason' )->text(),
@@ -445,8 +446,6 @@ class MovePageForm extends UnlistedSpecialPage {
                }
 
                if ( $confirm ) {
-                       $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' )
-                               || $user->isWatched( $this->oldTitle ) );
                        $fields[] = new OOUI\FieldLayout(
                                new OOUI\CheckboxInputWidget( array(
                                        'name' => 'wpConfirm',
@@ -465,7 +464,7 @@ class MovePageForm extends UnlistedSpecialPage {
                                'name' => $submitVar,
                                'value' => $movepagebtn,
                                'label' => $movepagebtn,
-                               'flags' => array( 'progressive', 'primary' ),
+                               'flags' => array( 'constructive', 'primary' ),
                                'type' => 'submit',
                        ) ),
                        array(
@@ -617,7 +616,7 @@ class MovePageForm extends UnlistedSpecialPage {
                $newText = $nt->getPrefixedText();
 
                if ( $ot->exists() ) {
-                       //NOTE: we assume that if the old title exists, it's because it was re-created as
+                       // NOTE: we assume that if the old title exists, it's because it was re-created as
                        // a redirect to the new title. This is not safe, but what we did before was
                        // even worse: we just determined whether a redirect should have been created,
                        // and reported that it was created if it should have, without any checks.
@@ -644,17 +643,19 @@ class MovePageForm extends UnlistedSpecialPage {
                        $this->moveSubpages = false;
                }
 
-               # Next make a list of id's.  This might be marginally less efficient
-               # than a more direct method, but this is not a highly performance-cri-
-               # tical code path and readable code is more important here.
-               #
-               # Note: this query works nicely on MySQL 5, but the optimizer in MySQL
-               # 4 might get confused.  If so, consider rewriting as a UNION.
-               #
-               # If the target namespace doesn't allow subpages, moving with subpages
-               # would mean that you couldn't move them back in one operation, which
-               # is bad.
-               # @todo FIXME: A specific error message should be given in this case.
+               /**
+                * Next make a list of id's.  This might be marginally less efficient
+                * than a more direct method, but this is not a highly performance-cri-
+                * tical code path and readable code is more important here.
+                *
+                * Note: this query works nicely on MySQL 5, but the optimizer in MySQL
+                * 4 might get confused.  If so, consider rewriting as a UNION.
+                *
+                * If the target namespace doesn't allow subpages, moving with subpages
+                * would mean that you couldn't move them back in one operation, which
+                * is bad.
+                * @todo FIXME: A specific error message should be given in this case.
+                */
 
                // @todo FIXME: Use Title::moveSubpages() here
                $dbr = wfGetDB( DB_MASTER );
index c8d4aa6..0fa4857 100644 (file)
@@ -463,7 +463,7 @@ class SpecialNewpages extends IncludableSpecialPage {
        protected function feedItemDesc( $row ) {
                $revision = Revision::newFromId( $row->rev_id );
                if ( $revision ) {
-                       //XXX: include content model/type in feed item?
+                       // XXX: include content model/type in feed item?
                        return '<p>' . htmlspecialchars( $revision->getUserText() ) .
                                $this->msg( 'colon-separator' )->inContentLanguage()->escaped() .
                                htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
index 5a67d92..d92010a 100644 (file)
@@ -180,7 +180,7 @@ class SpecialPrefixindex extends SpecialAllPages {
                        list( $namespace, $prefixKey, $prefix ) = $prefixList;
                        list( /* $fromNS */, $fromKey, ) = $fromList;
 
-                       ### @todo FIXME: Should complain if $fromNs != $namespace
+                       # ## @todo FIXME: Should complain if $fromNs != $namespace
 
                        $dbr = wfGetDB( DB_SLAVE );
 
@@ -205,7 +205,7 @@ class SpecialPrefixindex extends SpecialAllPages {
                                )
                        );
 
-                       ### @todo FIXME: Side link to previous
+                       # ## @todo FIXME: Side link to previous
 
                        $n = 0;
                        if ( $res->numRows() > 0 ) {
index 06cad42..91e84e4 100644 (file)
@@ -115,6 +115,7 @@ class SpecialSearch extends SpecialPage {
                        return;
                }
 
+               $out->addJsConfigVars( array( 'searchTerm' => $search ) );
                $this->searchEngineType = $request->getVal( 'srbackend' );
 
                if ( $request->getVal( 'fulltext' )
@@ -415,10 +416,7 @@ class SpecialSearch extends SpecialPage {
                        return false;
                }
 
-               // Generate a random number between 0 and 1. If the
-               // number is less than the desired percentages run it.
-               $rand = rand( 0, getrandmax() ) / getrandmax();
-               return $this->getConfig()->get( 'SearchRunSuggestedQueryPercent' ) > $rand;
+               return $this->getConfig()->get( 'SearchRunSuggestedQuery' );
        }
 
        /**
@@ -436,11 +434,11 @@ class SpecialSearch extends SpecialPage {
                $suggest = Linker::linkKnown(
                        $this->getPageTitle(),
                        $textMatches->getSuggestionSnippet() ?: null,
-                       array(),
+                       array( 'id' => 'mw-search-DYM-suggestion' ),
                        $stParams
                );
 
-               # html of did you mean... search suggestion link
+               # HTML of did you mean... search suggestion link
                return Html::rawElement(
                        'div',
                        array( 'class' => 'searchdidyoumean' ),
@@ -470,7 +468,7 @@ class SpecialSearch extends SpecialPage {
                $rewritten = Linker::linkKnown(
                        $this->getPageTitle(),
                        $textMatches->getQueryAfterRewriteSnippet() ?: null,
-                       array(),
+                       array( 'id' => 'mw-search-DYM-rewritten' ),
                        $stParams
                );
 
@@ -479,7 +477,7 @@ class SpecialSearch extends SpecialPage {
                $original = Linker::linkKnown(
                        $this->getPageTitle(),
                        htmlspecialchars( $term ),
-                       array(),
+                       array( 'id' => 'mw-search-DYM-original' ),
                        $stParams
                );
 
@@ -648,8 +646,9 @@ class SpecialSearch extends SpecialPage {
 
                $out = "<ul class='mw-search-results'>\n";
                $result = $matches->next();
+               $pos = $this->offset;
                while ( $result ) {
-                       $out .= $this->showHit( $result, $terms );
+                       $out .= $this->showHit( $result, $terms, ++$pos );
                        $result = $matches->next();
                }
                $out .= "</ul>\n";
@@ -665,10 +664,11 @@ class SpecialSearch extends SpecialPage {
         *
         * @param SearchResult $result
         * @param array $terms Terms to highlight
+        * @param int $position Position within the search results, including offset.
         *
         * @return string
         */
-       protected function showHit( $result, $terms ) {
+       protected function showHit( $result, $terms, $position ) {
 
                if ( $result->isBrokenTitle() ) {
                        return '';
@@ -689,12 +689,13 @@ class SpecialSearch extends SpecialPage {
 
                $link = Linker::linkKnown(
                        $link_t,
-                       $titleSnippet
+                       $titleSnippet,
+                       array( 'data-serp-pos' => $position ) // HTML attributes
                );
 
-               //If page content is not readable, just return the title.
-               //This is not quite safe, but better than showing excerpts from non-readable pages
-               //Note that hiding the entry entirely would screw up paging.
+               // If page content is not readable, just return the title.
+               // This is not quite safe, but better than showing excerpts from non-readable pages
+               // Note that hiding the entry entirely would screw up paging.
                if ( !$title->userCan( 'read', $this->getUser() ) ) {
                        return "<li>{$link}</li>\n";
                }
index a66a3d1..b168b12 100644 (file)
@@ -555,7 +555,7 @@ class PageArchive {
                $user = User::newFromName( $revision->getUserText( Revision::RAW ), false );
                $content = $revision->getContent( Revision::RAW );
 
-               //NOTE: article ID may not be known yet. prepareSave() should not modify the database.
+               // NOTE: article ID may not be known yet. prepareSave() should not modify the database.
                $status = $content->prepareSave( $article, 0, -1, $user );
 
                if ( !$status->isOK() ) {
index dd90590..eb34008 100644 (file)
@@ -36,14 +36,16 @@ class SpecialUploadStash extends UnlistedSpecialPage {
        // UploadStash
        private $stash;
 
-       // Since we are directly writing the file to STDOUT,
-       // we should not be reading in really big files and serving them out.
-       //
-       // We also don't want people using this as a file drop, even if they
-       // share credentials.
-       //
-       // This service is really for thumbnails and other such previews while
-       // uploading.
+       /**
+        * Since we are directly writing the file to STDOUT,
+        * we should not be reading in really big files and serving them out.
+        *
+        * We also don't want people using this as a file drop, even if they
+        * share credentials.
+        *
+        * This service is really for thumbnails and other such previews while
+        * uploading.
+        */
        const MAX_SERVE_BYTES = 1048576; // 1MB
 
        public function __construct() {
index 21f1194..085cfee 100644 (file)
@@ -276,13 +276,17 @@ class LoginForm extends SpecialPage {
                }
                $this->setHeaders();
 
-               // 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.
+               /**
+                * 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 &&
@@ -357,10 +361,10 @@ class LoginForm extends SpecialPage {
                }
 
                $status = $this->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt with mailed password', array(
-                       'event' => 'accountcreation',
-                       'status' => $status,
-               ) );
+               LoggerFactory::getInstance( 'authmanager' )->info(
+                       'Account creation attempt with mailed password',
+                       array( 'event' => 'accountcreation', 'status' => $status )
+               );
                if ( !$status->isGood() ) {
                        $error = $status->getMessage();
                        $this->mainLoginForm( $error->toString() );
@@ -787,22 +791,24 @@ class LoginForm extends SpecialPage {
                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 o-
-                               // pen 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.
+                               /**
+                                * 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();
@@ -1380,7 +1386,7 @@ class LoginForm extends SpecialPage {
 
                if ( $this->mType == 'signup' ) {
                        // XXX hack pending RL or JS parse() support for complex content messages
-                       // https://bugzilla.wikimedia.org/show_bug.cgi?id=25349
+                       // https://phabricator.wikimedia.org/T27349
                        $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp',
                                $this->msg( 'createacct-imgcaptcha-help' )->parse() );
 
@@ -1459,7 +1465,9 @@ class LoginForm extends SpecialPage {
                $template->set( 'emailothers', $wgEnableUserEmail );
                $template->set( 'canreset', $wgAuth->allowPasswordChange() );
                $template->set( 'resetlink', $resetLink );
-               $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ? ( $wgCookieExpiration > 0 ) : ( $wgExtendedLoginCookieExpiration > 0 ) );
+               $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
+                       ( $wgCookieExpiration > 0 ) :
+                       ( $wgExtendedLoginCookieExpiration > 0 ) );
                $template->set( 'usereason', $user->isLoggedIn() );
                $template->set( 'remember', $this->mRemember );
                $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
index dd4eb0a..02a1f73 100644 (file)
@@ -43,10 +43,10 @@ class WantedPagesPage extends WantedQueryPage {
                        $parts = explode( '/', $par, 2 );
                        $this->limit = (int)$parts[0];
                        // @todo FIXME: nlinks is ignored
-                       //$nlinks = isset( $parts[1] ) && $parts[1] === 'nlinks';
+                       // $nlinks = isset( $parts[1] ) && $parts[1] === 'nlinks';
                        $this->offset = 0;
                } else {
-                       //$nlinks = true;
+                       // $nlinks = true;
                }
                $this->setListoutput( $inc );
                $this->shownavigation = !$inc;
index 23e445f..e2187f0 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 namespace MediaWiki\Tidy;
+
 use MWHttpRequest;
 use Exception;
 
index 1193318..c21bcf8 100644 (file)
@@ -37,7 +37,7 @@ class RaggettExternal extends RaggettBase {
                        "{$this->config['tidyBin']} -config {$this->config['tidyConfigFile']} " .
                        $this->config['tidyCommandLine'] . $opts, $descriptorspec, $pipes );
 
-               //NOTE: At least on linux, the process will be created even if tidy is not installed.
+               // NOTE: At least on linux, the process will be created even if tidy is not installed.
                //      This means that missing tidy will be treated as a validation failure.
 
                if ( is_resource( $process ) ) {
index 1d994aa..61fd3e4 100644 (file)
@@ -36,5 +36,5 @@ abstract class TidyDriverBase {
         * @param string HTML document fragment to clean up
         * @param string The corrected HTML output
         */
-       public abstract function tidy( $text );
+       abstract public function tidy( $text );
 }
index 0892ce4..5b8b643 100644 (file)
@@ -33,7 +33,9 @@ class MalformedTitleException extends Exception {
         * @param string[] $errorMessageParameters Additional parameters for the error message.
         * $titleText will be appended if it's not null. (since MW 1.26)
         */
-       public function __construct( $errorMessage = null, $titleText = null, $errorMessageParameters = array() ) {
+       public function __construct(
+               $errorMessage = null, $titleText = null, $errorMessageParameters = array()
+       ) {
                $this->errorMessage = $errorMessage;
                $this->titleText = $titleText;
                if ( $titleText !== null ) {
index 9ee4841..27574fa 100644 (file)
@@ -68,8 +68,8 @@ class MediaWikiPageLinkRenderer implements PageLinkRenderer {
         * @return string
         */
        public function getPageUrl( TitleValue $page, $params = array() ) {
-               //TODO: move the code from Linker::linkUrl here!
-               //The below is just a rough estimation!
+               // TODO: move the code from Linker::linkUrl here!
+               // The below is just a rough estimation!
 
                $name = $this->formatter->getPrefixedText( $page );
                $name = str_replace( ' ', '_', $name );
index 01575ac..6b2e877 100644 (file)
@@ -76,7 +76,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
                        MWNamespace::hasGenderDistinction( $namespace )
                ) {
 
-                       //NOTE: we are assuming here that the title text is a user name!
+                       // NOTE: we are assuming here that the title text is a user name!
                        $gender = $this->genderCache->getGenderOf( $text, __METHOD__ );
                        $name = $this->language->getGenderNsText( $namespace, $gender );
                } else {
@@ -265,7 +265,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
                                                        # Disallow Talk:File:x type titles...
                                                        throw new MalformedTitleException( 'title-invalid-talk-namespace', $text );
                                                } elseif ( Interwiki::isValidInterwiki( $x[1] ) ) {
-                                                       //TODO: get rid of global state!
+                                                       // TODO: get rid of global state!
                                                        # Disallow Talk:Interwiki:x type titles...
                                                        throw new MalformedTitleException( 'title-invalid-talk-namespace', $text );
                                                }
index 6c8bcc0..2c2f94b 100644 (file)
@@ -45,16 +45,18 @@ class NaiveForeignTitleFactory implements ForeignTitleFactory {
 
                global $wgContLang;
 
-               // Can we assume that the part of the page title before the colon is a
-               // namespace name?
-               //
-               // XML export schema version 0.5 and earlier (MW 1.18 and earlier) does not
-               // contain a <ns> tag, so we need to be able to handle that case.
-               //
-               // If we know the namespace ID, we assume a non-zero namespace ID means
-               // the ':' sets off a valid namespace name. If we don't know the namespace
-               // ID, we fall back to using the local wiki's namespace names to resolve
-               // this -- better than nothing, and mimics the old crappy behavior
+               /**
+                * Can we assume that the part of the page title before the colon is a
+                * namespace name?
+                *
+                * XML export schema version 0.5 and earlier (MW 1.18 and earlier) does not
+                * contain a <ns> tag, so we need to be able to handle that case.
+                *
+                * If we know the namespace ID, we assume a non-zero namespace ID means
+                * the ':' sets off a valid namespace name. If we don't know the namespace
+                * ID, we fall back to using the local wiki's namespace names to resolve
+                * this -- better than nothing, and mimics the old crappy behavior
+                */
                $isNamespacePartValid = is_null( $ns ) ?
                        ( $wgContLang->getNsIndex( $pieces[0] ) !== false ) :
                        $ns != 0;
index 30a85ae..1568859 100644 (file)
@@ -1118,10 +1118,10 @@ abstract class UploadBase {
                        '<a href',
                        '<body',
                        '<head',
-                       '<html', #also in safari
+                       '<html', # also in safari
                        '<img',
                        '<pre',
-                       '<script', #also in safari
+                       '<script', # also in safari
                        '<table'
                );
 
@@ -1492,7 +1492,7 @@ abstract class UploadBase {
                        }
                }
 
-               return false; //No scripts detected
+               return false; // No scripts detected
        }
 
        /**
@@ -1655,7 +1655,7 @@ abstract class UploadBase {
                        $output = trim( $output );
 
                        if ( !$output ) {
-                               $output = true; #if there's no output, return true
+                               $output = true; # if there's no output, return true
                        } elseif ( $msgPattern ) {
                                $groups = array();
                                if ( preg_match( $msgPattern, $output, $groups ) ) {
index b4e815f..75540c1 100644 (file)
@@ -36,7 +36,7 @@ class UploadFromStash extends UploadBase {
        // an instance of UploadStash
        private $stash;
 
-       //LocalFile repo
+       // LocalFile repo
        private $repo;
 
        /**
index c07665a..1f796a4 100644 (file)
@@ -747,4 +747,3 @@ class UploadStashWrongOwnerException extends UploadStashException {
 
 class UploadStashNoSuchKeyException extends UploadStashException {
 }
-
index 4f8e0b1..b9d30d7 100644 (file)
@@ -36,25 +36,25 @@ class AvroValidator {
         *  returned.
         */
        public static function getErrors( AvroSchema $schema, $datum ) {
-               switch ( $schema->type) {
+               switch ( $schema->type ) {
                case AvroSchema::NULL_TYPE:
-                       if ( !is_null($datum) ) {
+                       if ( !is_null( $datum ) ) {
                                return self::wrongType( 'null', $datum );
                        }
                        return array();
                case AvroSchema::BOOLEAN_TYPE:
-                       if ( !is_bool($datum) ) {
+                       if ( !is_bool( $datum ) ) {
                                return self::wrongType( 'boolean', $datum );
                        }
                        return array();
                case AvroSchema::STRING_TYPE:
                case AvroSchema::BYTES_TYPE:
-                       if ( !is_string($datum) ) {
+                       if ( !is_string( $datum ) ) {
                                return self::wrongType( 'string', $datum );
                        }
                        return array();
                case AvroSchema::INT_TYPE:
-                       if ( !is_int($datum) ) {
+                       if ( !is_int( $datum ) ) {
                                return self::wrongType( 'integer', $datum );
                        }
                        if ( AvroSchema::INT_MIN_VALUE > $datum
@@ -68,7 +68,7 @@ class AvroValidator {
                        }
                        return array();
                case AvroSchema::LONG_TYPE:
-                       if ( !is_int($datum) ) {
+                       if ( !is_int( $datum ) ) {
                                return self::wrongType( 'integer', $datum );
                        }
                        if ( AvroSchema::LONG_MIN_VALUE > $datum
@@ -83,32 +83,29 @@ class AvroValidator {
                        return array();
                case AvroSchema::FLOAT_TYPE:
                case AvroSchema::DOUBLE_TYPE:
-                       if ( !is_float($datum) && !is_int($datum) ) {
+                       if ( !is_float( $datum ) && !is_int( $datum ) ) {
                                return self::wrongType( 'float or integer', $datum );
                        }
                        return array();
                case AvroSchema::ARRAY_SCHEMA:
-                       if (!is_array($datum)) {
+                       if ( !is_array( $datum ) ) {
                                return self::wrongType( 'array', $datum );
                        }
                        $errors = array();
-                       foreach ($datum as $d) {
-                               $result = $this->validate( $schema->items(), $d );
+                       foreach ( $datum as $d ) {
+                               $result = self::getErrors( $schema->items(), $d );
                                if ( $result ) {
                                        $errors[] = $result;
                                }
                        }
-                       if ( $errors ) {
-                               return $errors;
-                       }
-                       return array();
+                       return $errors;
                case AvroSchema::MAP_SCHEMA:
-                       if (!is_array($datum)) {
+                       if ( !is_array( $datum ) ) {
                                return self::wrongType( 'array', $datum );
                        }
                        $errors = array();
-                       foreach ($datum as $k => $v) {
-                       if ( !is_string($k) ) {
+                       foreach ( $datum as $k => $v ) {
+                               if ( !is_string( $k ) ) {
                                        $errors[] = self::wrongType( 'string key', $k );
                                }
                                $result = self::getErrors( $schema->values(), $v );
@@ -119,7 +116,7 @@ class AvroValidator {
                        return $errors;
                case AvroSchema::UNION_SCHEMA:
                        $errors = array();
-                       foreach ($schema->schemas() as $schema) {
+                       foreach ( $schema->schemas() as $schema ) {
                                $result = self::getErrors( $schema, $datum );
                                if ( !$result ) {
                                        return array();
index 9441608..fb2ae2a 100644 (file)
@@ -90,7 +90,7 @@ class BatchRowIterator implements RecursiveIterator {
                }
                $this->db = $db;
                $this->table = $table;
-               $this->primaryKey = (array) $primaryKey;
+               $this->primaryKey = (array)$primaryKey;
                $this->fetchColumns = $this->primaryKey;
                $this->orderBy = implode( ' ASC,', $this->primaryKey ) . ' ASC';
                $this->batchSize = $batchSize;
@@ -169,7 +169,7 @@ class BatchRowIterator implements RecursiveIterator {
         * @return boolean True when the iterator is in a valid state
         */
        public function valid() {
-               return (bool) $this->current;
+               return (bool)$this->current;
        }
 
        /**
index a4257a5..e739be3 100644 (file)
@@ -71,7 +71,9 @@ class BatchRowUpdate {
         * @param RowUpdateGenerator $generator Generates single row updates
         *  based on the rows content
         */
-       public function __construct( BatchRowIterator $reader, BatchRowWriter $writer, RowUpdateGenerator $generator ) {
+       public function __construct(
+               BatchRowIterator $reader, BatchRowWriter $writer, RowUpdateGenerator $generator
+       ) {
                $this->reader = $reader;
                $this->writer = $writer;
                $this->generator = $generator;
diff --git a/includes/utils/FileContentsHasher.php b/includes/utils/FileContentsHasher.php
new file mode 100644 (file)
index 0000000..655c1d0
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Generate hash digests of file contents to help with cache invalidation.
+ *
+ * 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
+ */
+class FileContentsHasher {
+
+       /** @var BagOStuff */
+       protected $cache;
+
+       /** @var FileContentsHasher */
+       private static $instance;
+
+       /**
+        * Constructor.
+        */
+       public function __construct() {
+               $this->cache = ObjectCache::newAccelerator( 'hash' );
+       }
+
+       /**
+        * Get the singleton instance of this class.
+        *
+        * @return FileContentsHasher
+        */
+       public static function singleton() {
+               if ( !self::$instance ) {
+                       self::$instance = new self;
+               }
+
+               return self::$instance;
+       }
+
+       /**
+        * Get a hash of a file's contents, either by retrieving a previously-
+        * computed hash from the cache, or by computing a hash from the file.
+        *
+        * @private
+        * @param string $filePath Full path to the file.
+        * @param string $algo Name of selected hashing algorithm.
+        * @return string|bool Hash of file contents, or false if the file could not be read.
+        */
+       public function getFileContentsHashInternal( $filePath, $algo = 'md4' ) {
+               $mtime = MediaWiki\quietCall( 'filemtime', $filePath );
+               if ( $mtime === false ) {
+                       return false;
+               }
+
+               $cacheKey = wfGlobalCacheKey( __CLASS__, $filePath, $mtime, $algo );
+               $hash = $this->cache->get( $cacheKey );
+
+               if ( $hash ) {
+                       return $hash;
+               }
+
+               $contents = MediaWiki\quietCall( 'file_get_contents', $filePath );
+               if ( $contents === false ) {
+                       return false;
+               }
+
+               $hash = hash( $algo, $contents );
+               $this->cache->set( $cacheKey, $hash, 60 * 60 * 24 );  // 24h
+
+               return $hash;
+       }
+
+       /**
+        * Get a hash of the combined contents of one or more files, either by
+        * retrieving a previously-computed hash from the cache, or by computing
+        * a hash from the files.
+        *
+        * @param string|string[] $filePaths One or more file paths.
+        * @param string $algo Name of selected hashing algorithm.
+        * @return string|bool Hash of files' contents, or false if no file could not be read.
+        */
+       public static function getFileContentsHash( $filePaths, $algo = 'md4' ) {
+               $instance = self::singleton();
+
+               if ( !is_array( $filePaths ) ) {
+                       $filePaths = (array)$filePaths;
+               }
+
+               if ( count( $filePaths ) === 1 ) {
+                       return $instance->getFileContentsHashInternal( $filePaths[0], $algo );
+               }
+
+               sort( $filePaths );
+               $hashes = array_map( function ( $filePath ) use ( $instance, $algo ) {
+                       return $instance->getFileContentsHashInternal( $filePath, $algo ) ?: '';
+               }, $filePaths );
+
+               $hashes = implode( '', $hashes );
+               return $hashes ? hash( $algo, $hashes ) : false;
+       }
+}
index 21c5709..dc95e75 100644 (file)
@@ -22,19 +22,19 @@ class ComplexNamespaceInputWidget extends \OOUI\Widget {
 
        /**
         * @param array $config Configuration options
-        * @param array $config['namespace'] Configuration for the NamespaceInputWidget dropdown with list
-        *     of namespaces
-        * @param string $config['namespace']['includeAllValue'] If specified, add a "all namespaces"
-        *     option to the dropdown, and use this as the input value for it
-        * @param array|null $config['invert'] Configuration for the "invert selection" CheckboxInputWidget. If
-        *     null, the checkbox will not be generated.
+        * @param array $config['namespace'] Configuration for the NamespaceInputWidget
+        *  dropdown with list of namespaces
+        * @param string $config['namespace']['includeAllValue'] If specified,
+        *  add an "all namespaces" option to the dropdown, and use this as the input value for it
+        * @param array|null $config['invert'] Configuration for the "invert selection"
+        *  CheckboxInputWidget. If null, the checkbox will not be generated.
         * @param array|null $config['associated'] Configuration for the "include associated namespace"
-        *     CheckboxInputWidget. If null, the checkbox will not be generated.
-        * @param array $config['invertLabel'] Configuration for the FieldLayout with label wrapping the
-        *     "invert selection" checkbox
+        *  CheckboxInputWidget. If null, the checkbox will not be generated.
+        * @param array $config['invertLabel'] Configuration for the FieldLayout with label
+        *  wrapping the "invert selection" checkbox
         * @param string $config['invertLabel']['label'] Label text for the label
-        * @param array $config['associatedLabel'] Configuration for the FieldLayout with label wrapping
-        *     the "include associated namespace" checkbox
+        * @param array $config['associatedLabel'] Configuration for the FieldLayout with label
+        *  wrapping the "include associated namespace" checkbox
         * @param string $config['associatedLabel']['label'] Label text for the label
         */
        public function __construct( array $config = array() ) {
@@ -102,7 +102,16 @@ class ComplexNamespaceInputWidget extends \OOUI\Widget {
                        $config,
                        array_intersect_key(
                                $this->config,
-                               array_fill_keys( array( 'namespace', 'invert', 'invertLabel', 'associated', 'associatedLabel' ), true )
+                               array_fill_keys(
+                                       array(
+                                               'namespace',
+                                               'invert',
+                                               'invertLabel',
+                                               'associated',
+                                               'associatedLabel'
+                                       ),
+                                       true
+                               )
                        )
                );
                return parent::getConfig( $config );
index 73ef54c..ea0ef9e 100644 (file)
@@ -19,8 +19,8 @@ class ComplexTitleInputWidget extends \OOUI\Widget {
         * Like TitleInputWidget, but the namespace has to be input through a separate dropdown field.
         *
         * @param array $config Configuration options
-        * @param array $config['namespace'] Configuration for the NamespaceInputWidget dropdown with list
-        *     of namespaces
+        * @param array $config['namespace'] Configuration for the NamespaceInputWidget dropdown
+        *  with list of namespaces
         * @param array $config['title'] Configuration for the TitleInputWidget text field
         */
        public function __construct( array $config = array() ) {
@@ -42,10 +42,13 @@ class ComplexTitleInputWidget extends \OOUI\Widget {
                $this->title = new TitleInputWidget( array_merge(
                        $config['title'],
                        array(
-                               // The inner TitleInputWidget shouldn't be infusable, only the ComplexTitleInputWidget itself can be.
+                               // The inner TitleInputWidget shouldn't be infusable,
+                               // only the ComplexTitleInputWidget itself can be.
                                'infusable' => false,
                                'relative' => true,
-                               'namespace' => isset( $config['namespace']['value'] ) ? $config['namespace']['value'] : null,
+                               'namespace' => isset( $config['namespace']['value'] ) ?
+                                       $config['namespace']['value'] :
+                                       null,
                        )
                ) );
 
index 8ac7014..5550a21 100644 (file)
@@ -19,12 +19,15 @@ class TitleInputWidget extends \OOUI\TextInputWidget {
        /**
         * @param array $config Configuration options
         * @param int|null $config['namespace'] Namespace to prepend to queries
-        * @param bool|null $config['relative'] If a namespace is set, return a title relative to it (default: true)
+        * @param bool|null $config['relative'] If a namespace is set,
+        *  return a title relative to it (default: true)
         * @param bool|null $config['suggestions'] Display search suggestions (default: true)
         */
        public function __construct( array $config = array() ) {
                // Parent constructor
-               parent::__construct( array_merge( array( 'infusable' => true, 'maxLength' => 255 ), $config ) );
+               parent::__construct(
+                       array_merge( array( 'infusable' => true, 'maxLength' => 255 ), $config )
+               );
 
                // Properties, which are ignored in PHP and just shipped back to JS
                if ( isset( $config['namespace'] ) ) {
index 1613536..50ed513 100644 (file)
@@ -34,6 +34,8 @@ if ( function_exists( 'mb_strtoupper' ) ) {
        mb_internal_encoding( 'UTF-8' );
 }
 
+use CLDRPluralRuleParser\Evaluator;
+
 /**
  * Internationalisation code
  * @ingroup Language
@@ -2549,10 +2551,13 @@ class Language {
         *
         * @param MWTimestamp $time
         * @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
-        * @param User|null $user User the timestamp is being generated for (or null to use main context's user)
+        * @param User|null $user User the timestamp is being generated for
+        *  (or null to use main context's user)
         * @return string Formatted timestamp
         */
-       public function getHumanTimestamp( MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null ) {
+       public function getHumanTimestamp(
+               MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null
+       ) {
                if ( $relativeTo === null ) {
                        $relativeTo = new MWTimestamp();
                }
@@ -2587,7 +2592,9 @@ class Language {
         * @return string Human timestamp
         * @since 1.26
         */
-       private function getHumanTimestampInternal( MWTimestamp $ts, MWTimestamp $relativeTo, User $user ) {
+       private function getHumanTimestampInternal(
+               MWTimestamp $ts, MWTimestamp $relativeTo, User $user
+       ) {
                $diff = $ts->diff( $relativeTo );
                $diffDay = (bool)( (int)$ts->timestamp->format( 'w' ) -
                        (int)$relativeTo->timestamp->format( 'w' ) );
@@ -2678,7 +2685,7 @@ class Language {
                # Even with //IGNORE iconv can whine about illegal characters in
                # *input* string. We just ignore those too.
                # REF: http://bugs.php.net/bug.php?id=37166
-               # REF: https://bugzilla.wikimedia.org/show_bug.cgi?id=16885
+               # REF: https://phabricator.wikimedia.org/T18885
                MediaWiki\suppressWarnings();
                $text = iconv( $in, $out . '//IGNORE', $string );
                MediaWiki\restoreWarnings();
@@ -4968,7 +4975,7 @@ class Language {
         */
        public function getPluralRuleIndexNumber( $number ) {
                $pluralRules = $this->getCompiledPluralRules();
-               $form = CLDRPluralRuleEvaluator::evaluateCompiled( $number, $pluralRules );
+               $form = Evaluator::evaluateCompiled( $number, $pluralRules );
                return $form;
        }
 
index 7879309..78b3572 100644 (file)
@@ -539,27 +539,45 @@ class LanguageConverter {
         * @return string Namespace name for display
         */
        public function convertNamespace( $index, $variant = null ) {
+               if ( $index === NS_MAIN ) {
+                       return '';
+               }
+
                if ( $variant === null ) {
                        $variant = $this->getPreferredVariant();
                }
-               if ( $index === NS_MAIN ) {
-                       return '';
-               } else {
-                       // First check if a message gives a converted name in the target variant.
-                       $nsConvMsg = wfMessage( 'conversion-ns' . $index )->inLanguage( $variant );
-                       if ( $nsConvMsg->exists() ) {
-                               return $nsConvMsg->plain();
-                       }
-                       // Then check if a message gives a converted name in content language
-                       // which needs extra translation to the target variant.
+
+               $cache = ObjectCache::newAccelerator( CACHE_NONE );
+               $key = wfMemcKey( 'languageconverter', 'namespace-text', $index, $variant );
+               $nsVariantText = $cache->get( $key );
+               if ( $nsVariantText !== false ) {
+                       return $nsVariantText;
+               }
+
+               // First check if a message gives a converted name in the target variant.
+               $nsConvMsg = wfMessage( 'conversion-ns' . $index )->inLanguage( $variant );
+               if ( $nsConvMsg->exists() ) {
+                       $nsVariantText = $nsConvMsg->plain();
+               }
+
+               // Then check if a message gives a converted name in content language
+               // which needs extra translation to the target variant.
+               if ( $nsVariantText === false ) {
                        $nsConvMsg = wfMessage( 'conversion-ns' . $index )->inContentLanguage();
                        if ( $nsConvMsg->exists() ) {
-                               return $this->translate( $nsConvMsg->plain(), $variant );
+                               $nsVariantText = $this->translate( $nsConvMsg->plain(), $variant );
                        }
+               }
+
+               if ( $nsVariantText === false ) {
                        // No message exists, retrieve it from the target variant's namespace names.
                        $langObj = $this->mLangObj->factory( $variant );
-                       return $langObj->getFormattedNsText( $index );
+                       $nsVariantText = $langObj->getFormattedNsText( $index );
                }
+
+               $cache->set( $key, $nsVariantText, 60 );
+
+               return $nsVariantText;
        }
 
        /**
@@ -1092,13 +1110,13 @@ class LanguageConverter {
                        // text should be splited by ";" only if a valid variant
                        // name exist after the markup, for example:
                        //  -{zh-hans:<span style="font-size:120%;">xxx</span>;zh-hant:\
-                       //      <span style="font-size:120%;">yyy</span>;}-
+                       //      <span style="font-size:120%;">yyy</span>;}-
                        // we should split it as:
                        //  array(
-                       //        [0] => 'zh-hans:<span style="font-size:120%;">xxx</span>'
-                       //        [1] => 'zh-hant:<span style="font-size:120%;">yyy</span>'
-                       //        [2] => ''
-                       //       )
+                       //        [0] => 'zh-hans:<span style="font-size:120%;">xxx</span>'
+                       //        [1] => 'zh-hant:<span style="font-size:120%;">yyy</span>'
+                       //        [2] => ''
+                       //       )
                        $pat = '/;\s*(?=';
                        foreach ( $this->mVariants as $variant ) {
                                // zh-hans:xxx;zh-hant:yyy
index a96b0a9..bf09252 100644 (file)
@@ -42,8 +42,8 @@ class LanguageFi extends Language {
                        return $wgGrammarForms['fi'][$case][$word];
                }
 
-               # These rules are not perfect, but they are currently only used for site names so it doesn't
-               # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
+               # These rules don't cover the whole language.
+               # They are used only for site names.
 
                # wovel harmony flag
                $aou = preg_match( '/[aou][^äöy]*$/i', $word );
index 226e313..60384a8 100644 (file)
@@ -24,7 +24,9 @@
 /**
  * Russian (русский язык)
  *
- * You can contact Alexander Sigachov (alexander.sigachov at Googgle Mail)
+ * You can contact:
+ * Alexander Sigachov (alexander.sigachov at Googgle Mail)
+ * Amir E. Aharoni (amir.aharoni@mail.huji.ac.il)
  *
  * @ingroup Language
  */
@@ -44,63 +46,22 @@ class LanguageRu extends Language {
                        return $wgGrammarForms['ru'][$case][$word];
                }
 
-               # These rules are not perfect, but they are currently only used for Wikimedia
-               # site names so it doesn't matter if they are wrong sometimes.
-               # Just add a special case for your site name if necessary.
+               $grammarDataFile = __DIR__ . '/data/grammar.ru.json';
+               $grammarData = FormatJson::decode( file_get_contents( $grammarDataFile ), true );
+
+               if ( array_key_exists( $case, $grammarData ) ) {
+                       foreach ( array_keys( $grammarData[$case] ) as $form ) {
+                               if ( $form === '@metadata' ) {
+                                       continue;
+                               }
+
+                               $regex = "/$form/";
+
+                               if ( preg_match( $regex, $word ) ) {
+                                       $word = preg_replace( $regex, $grammarData[$case][$form], $word );
 
-               # substr doesn't support Unicode and mb_substr has issues,
-               # so break it to characters using preg_match_all and then use array_slice and join
-               $chars = array();
-               preg_match_all( '/./us', $word, $chars );
-               if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
-                       switch ( $case ) {
-                               case 'genitive': # родительный падеж
-                                       if ( join( '', array_slice( $chars[0], -1 ) ) === 'ь' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'я';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ия' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'ии';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ка' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'ки';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ти' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'тей';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ды' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'дов';
-                                       } elseif ( join( '', array_slice( $chars[0], -1 ) ) === 'д' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'да';
-                                       } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ник' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'ника';
-                                       } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ные' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'ных';
-                                       }
-                                       break;
-                               case 'dative': # дательный падеж
-                                       # stub
-                                       break;
-                               case 'accusative': # винительный падеж
-                                       # stub
-                                       break;
-                               case 'instrumental': # творительный падеж
-                                       # stub
-                                       break;
-                               case 'prepositional': # предложный падеж
-                                       if ( join( '', array_slice( $chars[0], -1 ) ) === 'ь' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'е';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ия' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'ии';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ка' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'ке';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ти' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'тях';
-                                       } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ды' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'дах';
-                                       } elseif ( join( '', array_slice( $chars[0], -1 ) ) === 'д' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'де';
-                                       } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ник' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'нике';
-                                       } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ные' ) {
-                                               $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'ных';
-                                       }
                                        break;
+                               }
                        }
                }
 
index 429d0a6..a2a8831 100644 (file)
@@ -44,28 +44,23 @@ class LanguageTyv extends Language {
                }
 
                // Set up some constants...
-               $allVowels = array( "е", "и", "э", "ө", "ү", "а", "ё", "о", "у", "ы",
-                       "ю", "я", "a", "e", "i", "o", "ö", "u", "ü", "y" );
-               $frontVowels = array( "е", "и", "э", "ө", "ү", "e", "i", "ö", "ü" );
-               $backVowels = array( "а", "ё", "о", "у", "ы", "ю", "я", "a", "o", "u", "y" );
-               $unroundFrontVowels = array( "е", "и", "э", "e", "i" );
-               $roundFrontVowels = array( "ө", "ү", "ö", "ü" );
-               $unroundBackVowels = array( "а", "ы", "я", "a", "y" );
-               $roundBackVowels = array( "ё", "о", "у", "ю", "o", "u" );
-               //$voicedPhonemes = array( "д", "б", "з", "ж", "г", "d", "b", "z", "g" );
-               $unvoicedPhonemes = array( "т", "п", "с", "ш", "к", "ч", "х", "t", "p", "s", "k", "x" );
-               $directiveUnvoicedStems = array( "т", "п", "с", "ш", "к", "ч", "х", "л",
-                       "м", "н", "ң", "t", "p", "s", "k", "x", "l", "m", "n", "ŋ" );
-               $directiveVoicedStems = array( "д", "б", "з", "ж", "г", "р", "й", "d", "b", "z", "g", "r", "j" );
+               $allVowels = array( "е", "и", "э", "ө", "ү", "а", "ё", "о", "у", "ы", "ю", "я" );
+               $frontVowels = array( "е", "и", "э", "ө", "ү" );
+               $backVowels = array( "а", "ё", "о", "у", "ы", "ю", "я" );
+               $unroundFrontVowels = array( "е", "и", "э" );
+               $roundFrontVowels = array( "ө", "ү" );
+               $unroundBackVowels = array( "а", "ы", "я" );
+               $roundBackVowels = array( "ё", "о", "у", "ю" );
+               $unvoicedPhonemes = array( "т", "п", "с", "ш", "к", "ч", "х" );
+               $directiveUnvoicedStems = array( "т", "п", "с", "ш", "к", "ч", "х", "л", "м", "н", "ң" );
+               $directiveVoicedStems = array( "д", "б", "з", "ж", "г", "р", "й" );
 
-               //$allSonants = array("л", "м", "н", "ң", "р", "й");
-               //$allNasals = array("м", "н", "ң");
-
-               //Put the word in a form we can play with since we're using UTF-8
+               // Put the word in a form we can play with since we're using UTF-8
                preg_match_all( '/./us', $word, $ar );
 
                // Here's the last letter in the word
                $wordEnding = $ar[0][count( $ar[0] ) - 1];
+
                // Here's an array with the order of the letters in the word reversed so
                // we can find a match quicker. *shrug*
                $wordReversed = array_reverse( $ar[0] );
@@ -81,6 +76,7 @@ class LanguageTyv extends Language {
                                        continue;
                                }
                        }
+
                        if ( $wordLastVowel !== null ) {
                                break;
                        } else {
@@ -102,7 +98,7 @@ class LanguageTyv extends Language {
                                                $word = implode( "", $ar[0] ) . "тың";
                                        } else {
                                        }
-                               } elseif ( $wordEnding === "л" || $wordEnding === "l" ) {
+                               } elseif ( $wordEnding === "л" ) {
                                        if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
                                                $word = implode( "", $ar[0] ) . "дүң";
                                        } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
@@ -155,7 +151,7 @@ class LanguageTyv extends Language {
                                                $word = implode( "", $ar[0] ) . "ты";
                                        } else {
                                        }
-                               } elseif ( $wordEnding === "л" || $wordEnding === "l" ) {
+                               } elseif ( $wordEnding === "л" ) {
                                        if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
                                                $word = implode( "", $ar[0] ) . "дү";
                                        } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
@@ -249,6 +245,7 @@ class LanguageTyv extends Language {
                        default:
                                break;
                }
+
                return $word;
        }
 }
index 5215da0..8261f11 100644 (file)
@@ -42,8 +42,8 @@ class LanguageUk extends Language {
                        return $wgGrammarForms['uk'][$case][$word];
                }
 
-               # These rules are not perfect, but they are currently only used for site names so it doesn't
-               # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
+               # These rules don't cover the whole language.
+               # They are used only for site names.
 
                # join and array_slice instead mb_substr
                $ar = array();
@@ -51,40 +51,21 @@ class LanguageUk extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # родовий відмінок
-                                       if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вікі' )
-                                               || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вікі' )
-                                       ) {
-                                       } elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ь' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'я';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ія' ) {
+                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
                                                $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ка' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ки';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ти' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'тей';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ди' ) {
+                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ти' ) {
+                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'т';
+                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ди' ) {
                                                $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
-                                       } elseif ( join( '', array_slice( $ar[0], -3 ) ) == 'ник' ) {
+                                       } elseif ( join( '', array_slice( $ar[0], -3 ) ) === 'ник' ) {
                                                $word = join( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
                                        }
                                        break;
-                               case 'dative':  # давальний відмінок
-                                       # stub
-                                       break;
                                case 'accusative': # знахідний відмінок
-                                       if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вікі' )
-                                               || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вікі' )
-                                       ) {
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ія' ) {
+                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
                                                $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
                                        }
                                        break;
-                               case 'instrumental':  # орудний відмінок
-                                       # stub
-                                       break;
-                               case 'prepositional': # місцевий відмінок
-                                       # stub
-                                       break;
                        }
                }
                return $word;
@@ -99,7 +80,11 @@ class LanguageUk extends Language {
         */
        function commafy( $_ ) {
                if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
+                       return strrev( (string)preg_replace(
+                               '/(\d{3})(?=\d)(?!\d*\.)/',
+                               '$1,',
+                               strrev( $_ )
+                       ) );
                } else {
                        return $_;
                }
diff --git a/languages/classes/data/grammar.ru.json b/languages/classes/data/grammar.ru.json
new file mode 100644 (file)
index 0000000..446163b
--- /dev/null
@@ -0,0 +1,51 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Alexander Sigachov (alexander.sigachov at Googgle Mail)",
+                       "Amir E. Aharoni (amir.aharoni@mail.huji.ac.il)"
+               ],
+               "comment": "These rules don't cover the whole grammar of the language, and are intended only for names of languages and Wikimedia projects."
+       },
+       "genitive": {
+               "(.+)ь$": "$1я",
+               "(.+)ия$": "$1ии",
+               "(.+)ка$": "$1ки",
+               "(.+)ти$": "$1тей",
+               "(.+)ды$": "$1дов",
+               "(.+)д$": "$1да",
+               "(.+)ник$": "$1ника",
+               "(.+)ные$": "$1ных"
+       },
+       "prepositional": {
+               "(.+)ь$": "$1е",
+               "(.+)ия$": "$1ии",
+               "(.+)ка$": "$1ке",
+               "(.+)ти$": "$1тях",
+               "(.+)ды$": "$1дах",
+               "(.+)д$": "$1де",
+               "(.+)ник$": "$1нике",
+               "(.+)ные$": "$1ных"
+       },
+       "languagegen": {
+               "@metadata": "язык в родительном падеже: '(с) русского'",
+               "(.+)кий$": "$1кого",
+               "иврит$": "иврита",
+               "идиш$": "идиша",
+               "(.+)$": "$1"
+       },
+       "languageprep": {
+               "@metadata": "язык в предложном падеже: '(на) русском'",
+               "(.+)кий$": "$1ком",
+               "иврит$": "иврите",
+               "идиш$": "идише",
+               "(.+)$": "$1"
+       },
+       "languageadverb": {
+               "@metadata": "наречие с названием языка: 'по-русски'",
+               "(.+)кий$": "по-$1ки",
+               "иврит$": "на иврите",
+               "идиш$": "на идише",
+               "(идо|урду|хинди|эсперанто)$": "на $1",
+               "(.+)$": "на языке $1"
+       }
+}
index 2b6bd58..5a8466f 100644 (file)
        "nstab-template": "Шапхъэ",
        "nstab-help": "IэпыIэгъу нэкIубгъу",
        "nstab-category": "Категорие",
+       "mainpage-nstab": "НэкӀубгъо шъхьаӀ",
        "nosuchaction": "Ащ фэдэ шIагъэ щыIэп",
        "nosuchspecialpage": "Афэдэ специал нэкIубгъо щыIэп",
        "error": "Къончагъэ",
        "cannotdelete-title": "НэкIубгъоу \"$1\" тегъэкIыгъэн лъэкIырэп",
        "badtitle": "ЦӀэ дэгъуэп",
        "badtitletext": "УзкIэупчIэрэ нэкIубгъом ыцIэр къуанчэ, е нэкIы, е бзэзэпыщэ е интервики гъэнэфагъэп.\nМыхъущт символ агъэфедагъэнкIи мэхъу.",
+       "title-invalid-characters": "УзыкIэупчIэрэ нэкIубгъуацIэм символ фыкъуагъэ хэт: \"$1\".",
        "viewsource": "Еплъ лъапсэм",
        "viewsource-title": "Еплъ лъапсэм $1 пае",
        "protectedpagetext": "ЕIэзэнхэм ыкIи нэмыкI шIэнмэ яягъэ къэмыкIынэу мы нэкIубгъор ухъумагъэу щыт.",
        "createaccounterror": "Аккаунт ублэн лъэкIыгъэп: $1",
        "noname": "НэбгырацIэ тэрэз итхагъэп.",
        "loginsuccesstitle": "ШIоу ухэхьагъ",
+       "nosuchusershort": "\"$1\", афэдэ цIэ зиIэу нэбгырэ щыIэп.\nТхыкIэр уплъэкIужь.",
        "nouserspecified": "НэбгырацIэр птхын фае.",
+       "login-userblocked": "Мы нэбгырэр блокыгъэ. Системэм хэхьашъущтэп.",
        "wrongpassword": "ШъэфгущыIэр тэрэзэп.\nДжыри зэ еплъ.",
        "wrongpasswordempty": "ШъэфгущыIэр нэкIы.\nДжыри зэ еплъ.",
        "passwordtooshort": "ШъэфгущыIэр мыхъуми {{PLURAL:$1|1 символ |символ $1}} хъун фае.",
+       "passwordtoolong": "ШъэфгущыIэр мыщ нахь кIыхьэ хъун лъэкIыщтэп: {{PLURAL:$1 символ|$1 символ}}.",
        "password-name-match": "Уи шъэфгущыIэр уи нэбгырацIэм фэдапэ хъущтэп.",
+       "password-login-forbidden": "Мы ныбгырацIэмрэ шъэфгущыIэмрэ бгъэфедэ хъужьыщтэп.",
        "mailmypassword": "Зэтедз шъэфгущыIэр",
        "noemailcreate": "Емэйл тэрэз птхын фае.",
        "mailerror": "Емэйл егъэхьыныр къуанчэ: $1",
        "passwordreset-emailsent": "ШъэфгущыIэм и зэтедзым пае емэйл агъэхьыгъ.",
        "passwordreset-emailsent-capture": "ШъэфгущыIэм изэтедз фэгъэхьыгъэ емэйлыр гъахьыгъэ, ычIэгъкIэ ар олъэгъу.",
        "changeemail": "Зэблэхъу емэйл адресыр",
+       "changeemail-no-info": "Мы нэкIубгъом занкIэу укIонэу уфаемэ, системэм ухэхьэгъэн фае.",
        "changeemail-oldemail": "Джырэ емэйл адрес:",
        "changeemail-newemail": "Емэйл адресыкIэр:",
        "changeemail-none": "(зи)",
        "upload-misc-error": "ЗэхэмышIыкIыгъэ илъхьан фыкъуагъэ",
        "upload-http-error": "HTTP фыкъуагъэ горэ хъугъэ: $1",
        "upload-dialog-title": "Файлыр илъхь",
-       "upload-dialog-error": "Фыкъуагъэ горэ хъугъэ",
        "upload-dialog-button-cancel": "Ыуж икӀ",
        "upload-dialog-button-done": "ЗэшIуэкIыгъэ",
        "upload-dialog-button-save": "Итх",
        "upload-dialog-button-upload": "Илъхь",
-       "upload-dialog-label-select-file": "Къыхэх файл",
-       "upload-dialog-label-infoform-title": "Къэбар",
-       "upload-dialog-label-infoform-name": "ЦIэ",
-       "upload-dialog-label-infoform-description": "АгурыбгъэIон",
-       "upload-dialog-label-usage-title": "Гъэфедэныгъэ",
-       "upload-dialog-label-usage-filename": "ФайлыцIэ",
+       "upload-process-error": "Фыкъуагъэ горэ хъугъэ",
+       "upload-form-label-select-file": "Къыхэх файл",
+       "upload-form-label-infoform-title": "Къэбар",
+       "upload-form-label-infoform-name": "ЦIэ",
+       "upload-form-label-infoform-description": "АгурыбгъэIон",
+       "upload-form-label-usage-title": "Гъэфедэныгъэ",
+       "upload-form-label-usage-filename": "ФайлыцIэ",
        "backend-fail-notexists": "Файлэу $1 щыIэп.",
        "backend-fail-delete": "Файлэу \"$1\" тегъэкIын лъэкIырэп.",
        "backend-fail-read": "Файлэу \"$1\" еплъын лъэкIырэп.",
index f2ee892..8835795 100644 (file)
        "upload-http-error": "'n HTTP-fout het voorgekom: $1",
        "upload-copy-upload-invalid-domain": "Gekopieerde oplaaie word nie vanuit die domein toegelaat nie.",
        "upload-dialog-title": "Laai lêer op",
-       "upload-dialog-error": "'n Fout het voorgekom",
-       "upload-dialog-warning": "'n Waarskuwing is uitgereik",
        "upload-dialog-button-cancel": "Kanselleer",
        "upload-dialog-button-done": "Gedoen",
        "upload-dialog-button-save": "Stoor",
        "upload-dialog-button-upload": "Oplaai",
-       "upload-dialog-label-select-file": "Kies lêer",
-       "upload-dialog-label-infoform-title": "Details",
-       "upload-dialog-label-infoform-name": "Naam",
-       "upload-dialog-label-infoform-description": "Beskrywing",
-       "upload-dialog-label-usage-title": "Gebruik",
-       "upload-dialog-label-usage-filename": "Lêernaam",
+       "upload-process-error": "'n Fout het voorgekom",
+       "upload-process-warning": "'n Waarskuwing is uitgereik",
+       "upload-form-label-select-file": "Kies lêer",
+       "upload-form-label-infoform-title": "Details",
+       "upload-form-label-infoform-name": "Naam",
+       "upload-form-label-infoform-description": "Beskrywing",
+       "upload-form-label-usage-title": "Gebruik",
+       "upload-form-label-usage-filename": "Lêernaam",
        "backend-fail-stream": "Kon nie die lêer $1 uitstroom nie.",
        "backend-fail-backup": "Kon nie 'n rugsteunkopie van die lêer $1 maak nie.",
        "backend-fail-notexists": "Die lêer $1 bestaan nie.",
index 3b8eee3..57cf274 100644 (file)
@@ -7,7 +7,8 @@
                        "Mdupont",
                        "아라",
                        "Ammartivari",
-                       "Olsi"
+                       "Olsi",
+                       "Kosovastar"
                ]
        },
        "tog-underline": "Nënvizoji vegzat",
        "nohistory": "Nuk ka histori redaktimesh për këtë faqe.",
        "currentrev": "Versioni i tanishëm",
        "currentrev-asof": "Redaktimi aktual i datës $1",
-       "revisionasof": "Versioni i $1",
+       "revisionasof": "Versioni i datës $1",
        "revision-info": "Versioni me $1 nga $2",
        "previousrevision": "← Verzion ma i vjetër",
        "nextrevision": "Redaktimi mâ i ri →",
index 11bf0a2..ef386b1 100644 (file)
        "nstab-template": "قالب",
        "nstab-help": "صفحة مساعدة",
        "nstab-category": "تصنيف",
+       "mainpage-nstab": "الصفحة الرئيسية",
        "nosuchaction": "لا يوجد فعل كالذي طلبت",
        "nosuchactiontext": "الفعل المحدد بواسطة المسار غير صحيح.\nربما تكون قد كتبت المسار بطريقة غير صحيحة، أو اتبعت رابطا غير صحيح.\nو قد يكون مرجع هذا علة في {{SITENAME}}.",
        "nosuchspecialpage": "لا توجد صفحة خاصة بهذا الاسم",
        "upload-http-error": "صودف خطأ HTTP: $1",
        "upload-copy-upload-invalid-domain": "رفع النسخ غير متاح من هذا الموقع",
        "upload-dialog-title": "رفع الملف",
-       "upload-dialog-error": "حدث خطأ",
-       "upload-dialog-warning": "حدث تنبيه",
        "upload-dialog-button-cancel": "إلغاء",
        "upload-dialog-button-done": "تم",
        "upload-dialog-button-save": "احفظ",
        "upload-dialog-button-upload": "رفع",
-       "upload-dialog-label-select-file": "اختر ملفا",
-       "upload-dialog-label-infoform-title": "التفاصيل",
-       "upload-dialog-label-infoform-name": "الاسم",
-       "upload-dialog-label-infoform-description": "الوصف",
-       "upload-dialog-label-usage-title": "الاستخدام",
-       "upload-dialog-label-usage-filename": "اسم الملف",
+       "upload-process-error": "حدث خطأ",
+       "upload-process-warning": "حدث تنبيه",
+       "upload-form-label-select-file": "اختر ملفا",
+       "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": "اسم الملف",
        "backend-fail-stream": "لا يمكن عرض الملف $1.",
        "backend-fail-backup": "لا يمكن صنع نسخة أحتياطية للملف $1.",
        "backend-fail-notexists": "الملف $1 غير موجود.",
        "unusedimages": "ملفات غير مستخدمة",
        "wantedcategories": "تصنيفات مطلوبة",
        "wantedpages": "صفحات مطلوبة",
+       "wantedpages-summary": "قائمة بالصفحات غير الموجودة التي لديها أكثر وصلات لها، باستثناء الصفحات التي تحويلات فقط تصل إليها. لقائمة بالصفحات غير الموجودة التي توجد تحويلات تصل إليها، انظر [[{{#special:BrokenRedirects}}|قائمة التحويلات المكسورة]].",
        "wantedpages-badtitle": "عنوان غير صحيح في مجموعة النتائج: $1",
        "wantedfiles": "ملفات مطلوبة",
        "wantedfiletext-cat": "الملفات التالية مستعملة ولكن لا وجود لها. يمكن سرد ملفات من مستودعات خارجية بالرغم من وجودها. سيتم <del>محو</del> أي أيجابيات كاذبة. بالإضافة، أي صفحات تتضمن الملفات الغير موجودة تم سردها في [[:$1]].",
        "version-entrypoints-header-url": "المسار",
        "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath مسار المقالات]",
        "version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath مسار السكريبت]",
-       "version-libraries": "مكتبات مثبته",
+       "version-libraries": "مكتبات مثبتة",
        "version-libraries-library": "المكتبة",
        "version-libraries-version": "الإصدارة",
        "version-libraries-license": "الترخيص",
index e183181..d55e744 100644 (file)
        "upload-http-error": "এটা HTTP ত্ৰুটিয়ে দেখা দিছে: $1",
        "upload-copy-upload-invalid-domain": "এই ডমেইনত কপী আপল'ড নাপাব।",
        "upload-dialog-title": "ফাইল আপল’ড কৰক",
-       "upload-dialog-error": "এটা ত্ৰুটি পোৱা গৈছে",
-       "upload-dialog-warning": "এটা সতৰ্কবাণী পোৱা গৈছে",
        "upload-dialog-button-cancel": "বাতিল কৰক",
        "upload-dialog-button-done": "কৰা হ’ল",
        "upload-dialog-button-save": "সাঁচি থওক",
        "upload-dialog-button-upload": "আপল'ড",
-       "upload-dialog-label-select-file": "ফাইল নিৰ্বাচন কৰক",
-       "upload-dialog-label-infoform-title": "বিস্তাৰিত",
-       "upload-dialog-label-infoform-name": "নাম",
-       "upload-dialog-label-infoform-description": "বিৱৰণ",
-       "upload-dialog-label-usage-title": "ব্যৱহাৰ",
-       "upload-dialog-label-usage-filename": "ফাইলৰ নাম",
+       "upload-process-error": "এটা ত্ৰুটি পোৱা গৈছে",
+       "upload-process-warning": "এটা সতৰ্কবাণী পোৱা গৈছে",
+       "upload-form-label-select-file": "ফাইল নিৰ্বাচন কৰক",
+       "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": "ফাইলৰ নাম",
        "backend-fail-stream": "$1 ফাইলটো ষ্ট্ৰীম কৰিব পৰা নগ'ল।",
        "backend-fail-backup": "$1 ফাইলটো বেকআপ্‌ কৰিব পৰা নগ'ল।",
        "backend-fail-notexists": "$1 ফাইলটোৰ কোনো অস্তিত্ব নাই।",
index 76940e6..4e6f970 100644 (file)
        "upload-http-error": "Hebo un error HTTP: $1",
        "upload-copy-upload-invalid-domain": "La xubida de copies nun ta disponible dende esti dominiu.",
        "upload-dialog-title": "Xubir ficheru",
-       "upload-dialog-error": "Hebo un error",
-       "upload-dialog-warning": "Hebo un avisu",
        "upload-dialog-button-cancel": "Encaboxar",
        "upload-dialog-button-done": "Fecho",
        "upload-dialog-button-save": "Guardar",
        "upload-dialog-button-upload": "Xubir",
-       "upload-dialog-label-select-file": "Seleiciona un ficheru",
-       "upload-dialog-label-infoform-title": "Detalles",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descripción",
-       "upload-dialog-label-usage-title": "Usu",
-       "upload-dialog-label-usage-filename": "Nome del ficheru",
+       "upload-process-error": "Hebo un error",
+       "upload-process-warning": "Hebo un avisu",
+       "upload-form-label-select-file": "Seleiciona un ficheru",
+       "upload-form-label-infoform-title": "Detalles",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descripción",
+       "upload-form-label-usage-title": "Usu",
+       "upload-form-label-usage-filename": "Nome del ficheru",
        "backend-fail-stream": "Nun se pudo tresmitir el ficheru $1.",
        "backend-fail-backup": "Nun se pudo facer copia de seguridá del ficheru $1.",
        "backend-fail-notexists": "El ficheru $1 nun esiste.",
index f14fe86..869310e 100644 (file)
        "viewtalkpage": "دانیشیغا باخ",
        "otherlanguages": "آیری دیل‌لرده",
        "redirectedfrom": "($1-دن يوْل‌لاندیریلمیش)",
-       "redirectpagesub": "یوْللاندیرما صفحه‌سی",
+       "redirectpagesub": "یوْللاندیرما صفحه‌سی",
        "redirectto": "مسیزپرین دَییشیب:",
        "lastmodifiedat": "بۇ صفحه‌‌ سوْن دفعه $1، $2 تاریخینده دَییشیلمیشدیر.",
        "viewcount": "بۇ صحیفه {{PLURAL:$1|بیر|$1}} دفعه گؤرولوبدور.",
        "sort-ascending": "چوْخالان سیرالاماق",
        "nstab-main": "صفحه",
        "nstab-user": "ایشلدن صفحه‌سی",
-       "nstab-media": "مدیا",
+       "nstab-media": "مدیاصفحه‌سی",
        "nstab-special": "اؤزل صفحه",
        "nstab-project": "پروژه صفحه‌سی",
        "nstab-image": "فایل",
        "rc-enhanced-expand": "تفصیل‌لری گؤستر",
        "rc-enhanced-hide": "تفصیل‌لری گیزلت",
        "rc-old-title": "ایلک‌جه «$1» آدی‌له یارانمیشدیر",
-       "recentchangeslinked": "مربوط دَییشیکلیکلر",
-       "recentchangeslinked-feed": "مربوط دَییشیکلیکلر",
-       "recentchangeslinked-toolbox": "مربوط دَییشیکلیکلر",
+       "recentchangeslinked": "ایلگیلی دَییشیکلیکلر",
+       "recentchangeslinked-feed": "ایلگیلی دَییشیکلیکلر",
+       "recentchangeslinked-toolbox": "ایلگیلی دَییشیکلیکلر",
        "recentchangeslinked-title": "''$1'' ایله ایلگی‌لی دییشیکلر",
        "recentchangeslinked-summary": "آشاغیداکی سیياهی، قئيد اوْلونان صحیفه‌‌يه (و يا قئيد اوْلونان کاتئقوْرياداکی صحیفه‌‌لره) داخیلی کئچید وئرن صحیفه‌‌لرده ائدیلمیش سوْن ديَیشیکلیکلرین سیياهیسیدیر. \n[[Special:Watchlist|ایزله‌مه سیياهینیزداکی]] صحیفه‌‌لر '''قالین''' شریفتله گؤستریلمیشدیر.",
        "recentchangeslinked-page": "صفحه آدی:",
        "upload-too-many-redirects": "آدرس ده چوخ یؤنلندیرمه وار",
        "upload-http-error": "اچ تی تی پی ختاسی وار : $1",
        "upload-copy-upload-invalid-domain": "فایل یوکلنمه سی بو بازه ده امکانی یوخدور",
+       "upload-dialog-button-cancel": "وازگئچ",
+       "upload-dialog-button-done": "اولدو",
+       "upload-dialog-button-save": "ذخیره ائت",
+       "upload-dialog-button-upload": "یوکله",
+       "upload-process-error": "بیر یالنیشلیق اولدو",
+       "upload-process-warning": "بیر خطا باش وئردی",
+       "upload-form-label-select-file": "فایل سئچ",
+       "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": "فایل آدی",
        "backend-fail-stream": "$1 فای‌لی یولانمامادی.",
        "backend-fail-backup": "بو فایل $1 اوچون نوسخه پشتیان یارتماق اولماز",
        "backend-fail-notexists": "\"$1\" فای‌لی مؤوجود دئییل",
        "version-libraries": "نصب اولونموش کیتابخانا",
        "version-libraries-library": "کیتاب‌ائوی",
        "version-libraries-version": "نوسخه‌",
+       "version-libraries-description": "آچیقلاما",
        "version-libraries-authors": "یازارلار",
        "redirect": "فایل، ایستیفاده‌چی، صفحه یا نوسخه آی‌دی-سی ایله یول‌لاندیرما",
        "redirect-legend": "بیر فایل یا صحیفه‌یه یول‌لاندیرما",
        "tags-edit": "دَییشدیر",
        "tags-delete": "سیل",
        "tags-activate": "ائتکینلشدیر",
+       "tags-deactivate": "چالیشقان اولمایان",
        "tags-hitcount": "$1 {{PLURAL:$1|دییشیکلیک|دییشیک‌لیک}}",
+       "tags-create-reason": "ندن:",
        "tags-create-submit": "یارات",
+       "tags-delete-reason": "ندن:",
+       "tags-activate-reason": "ندن:",
+       "tags-deactivate-reason": "ندن:",
        "tags-edit-title": "اِتیکِتلری دَییشدیر",
        "tags-edit-manage-link": "اِتیکِتلری ایداره ائت",
        "tags-edit-revision-selected": "[[:$2]]-نین سئچیلمیش {{PLURAL:$1|نوسخه‌سی|نوسخه‌لری}}:",
index 9155990..a30e9b1 100644 (file)
        "createacct-captcha": "Праверка бясьпекі",
        "createacct-imgcaptcha-ph": "Увядзіце тэкст, што бачыце вышэй",
        "createacct-submit": "Стварыць рахунак",
-       "createacct-another-submit": "СÑ\82ваÑ\80Ñ\8bÑ\86Ñ\8c Ñ\96нÑ\88Ñ\8b Ñ\80аÑ\85Ñ\83нак",
+       "createacct-another-submit": "Стварыць рахунак",
        "createacct-benefit-heading": "{{SITENAME}} створаная людзьмі, такімі як вы.",
        "createacct-benefit-body1": "{{PLURAL:$1|праўка|праўкі|правак}}",
        "createacct-benefit-body2": "{{PLURAL:$1|старонка|старонкі|старонак}}",
        "permissionserrorstext-withaction": "Вы ня маеце дазволу на $2 з {{PLURAL:$1|1=наступнай прычыны|наступных прычынаў}}:",
        "recreate-moveddeleted-warn": "'''Увага: Вы ствараеце старонку, якая раней была выдаленая.'''\n\nУпэўніцеся, што стварэньне гэтай старонкі неабходнае.\nНіжэй пададзеныя журналы выдаленьняў і пераносаў гэтай старонкі:",
        "moveddeleted-notice": "Гэта старонка была выдаленая. Журналы выдаленьняў і пераносаў для гэтай старонкі пададзеныя ніжэй.",
+       "moveddeleted-notice-recent": "Выбачайце, гэтая старонка была нядаўна выдаленая (цягам апошніх 24 гадзінаў).\nЖурналы выдаленьняў і пераносаў для гэтай старонкі пададзеныя ніжэй для даведкі.",
        "log-fulllog": "Паказаць журнал цалкам",
        "edit-hook-aborted": "Рэдагаваньне скасаванае працэдурай-перахопнікам.\nТлумачэньняў не было.",
        "edit-gone-missing": "Немагчыма абнавіць старонку.\nПадобна, што яна была выдаленая.",
        "upload-http-error": "Узьнікла памылка HTTP: $1",
        "upload-copy-upload-invalid-domain": "Капіяваньне загрузак не дазволенае ў гэтым дамэне.",
        "upload-dialog-title": "Загрузка файла",
-       "upload-dialog-error": "Адбылася памылка",
-       "upload-dialog-warning": "Зьявілася папярэджаньне",
        "upload-dialog-button-cancel": "Адмяніць",
        "upload-dialog-button-done": "Зроблена",
        "upload-dialog-button-save": "Захаваць",
        "upload-dialog-button-upload": "Загрузіць",
-       "upload-dialog-label-select-file": "Абраць файл",
-       "upload-dialog-label-infoform-title": "Падрабязнасьці",
-       "upload-dialog-label-infoform-name": "Назва",
-       "upload-dialog-label-infoform-description": "Апісаньне",
-       "upload-dialog-label-usage-title": "Выкарыстаньне",
-       "upload-dialog-label-usage-filename": "Назва файлу",
+       "upload-process-error": "Адбылася памылка",
+       "upload-process-warning": "Зьявілася папярэджаньне",
+       "upload-form-label-select-file": "Абраць файл",
+       "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": "Назва файлу",
        "backend-fail-stream": "Немагчыма накіраваць файл $1.",
        "backend-fail-backup": "Немагчыма зрабіць рэзэрвовую копію файла $1.",
        "backend-fail-notexists": "Файл $1 не існуе.",
        "filerevert-legend": "Вярнуць папярэднюю вэрсію файла",
        "filerevert-intro": "Вы вяртаеце '''[[Media:$1|$1]]''' да [вэрсіі $4 ад $3, $2].",
        "filerevert-comment": "Прычына:",
-       "filerevert-defaultcomment": "Вернутая вэрсія ад $2, $1",
+       "filerevert-defaultcomment": "Вернутая вэрсія ад $2 $1 ($3)",
        "filerevert-submit": "Вярнуць",
        "filerevert-success": "'''[[Media:$1|$1]]''' быў вернуты да [вэрсіі $4 ад $3, $2].",
        "filerevert-badversion": "Не існуе папярэдняй лякальнай вэрсіі гэтага файла з пазначанай датай.",
        "emailccsubject": "Копія Вашага ліста да $1: $2",
        "emailsent": "Ліст адасланы",
        "emailsenttext": "Ваш ліст быў адасланы.",
-       "emailuserfooter": "Гэты ліст быў дасланы {{GENDER:$2|ўдзельнікам|ўдзельніцай}} $1 да {{GENDER:$2|ўдзельніка|ўдзельніцы}} $2 з дапамогай функцыі «{{int:emailuser}}» {{GRAMMAR:родны|{{SITENAME}}}}.",
+       "emailuserfooter": "Гэты ліст быў дасланы {{GENDER:$1|ўдзельнікам|ўдзельніцай}} $1 да {{GENDER:$2|ўдзельніка|ўдзельніцы}} $2 з дапамогай функцыі «{{int:emailuser}}» {{GRAMMAR:родны|{{SITENAME}}}}.",
        "usermessage-summary": "Паведамленьне пра выхад з сыстэмы.",
        "usermessage-editor": "Дастаўка сыстэмных паведамленьняў",
        "watchlist": "Сьпіс назіраньня",
        "deletepage": "Выдаліць старонку",
        "confirm": "Пацьвердзіць",
        "excontent": "колішні зьмест: «$1»",
-       "excontentauthor": "зьмест быў: «$1» (і адзіным аўтарам быў '[[Special:Contributions/$2|$2]]')",
+       "excontentauthor": "зьмест быў: «$1», адзіным аўтарам быў «[[Special:Contributions/$2|$2]]» ([[User talk:$2|гутаркі]])",
        "exbeforeblank": "зьмест да ачысткі: «$1»",
        "delete-confirm": "Выдаліць «$1»",
        "delete-legend": "Выдаліць",
index 9467810..92a1404 100644 (file)
        "upload-file-error": "इंटरनल खराबी",
        "upload-misc-error": "नामालूम अपलोड खराबी",
        "upload-dialog-title": "फाइल अपलोड",
-       "upload-dialog-error": "कौनो खराबी आ गइल",
-       "upload-dialog-warning": "कौनो चेतावनी बा",
        "upload-dialog-button-cancel": "कैंसिल",
        "upload-dialog-button-done": "पूरा भइल",
        "upload-dialog-button-save": "सहेजीं",
        "upload-dialog-button-upload": "अपलोड",
-       "upload-dialog-label-select-file": "फाइल चुनीं",
-       "upload-dialog-label-infoform-title": "डिटेल जानकारी",
-       "upload-dialog-label-infoform-name": "नाँव",
-       "upload-dialog-label-infoform-description": "विवरण",
-       "upload-dialog-label-usage-title": "इस्तेमाल",
-       "upload-dialog-label-usage-filename": "फाइल नाँव",
+       "upload-process-error": "कौनो खराबी आ गइल",
+       "upload-process-warning": "कौनो चेतावनी बा",
+       "upload-form-label-select-file": "फाइल चुनीं",
+       "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": "फाइल नाँव",
        "backend-fail-stream": "फाइल \"$1\" स्ट्रीम ना हो पावल।",
        "backend-fail-backup": "फाइल \"$1\" के बैकअप ना हो पावल।",
        "backend-fail-notexists": "फाइल $1 मौजूद नइखे।",
index c88085a..db39caf 100644 (file)
        "nstab-template": "টেমপ্লেট",
        "nstab-help": "সহায়িকা",
        "nstab-category": "বিষয়শ্রেণী",
+       "mainpage-nstab": "প্রধান পাতা",
        "nosuchaction": "এমন কোন কাজ নেই",
        "nosuchactiontext": "এই উআরএল এ নির্ধারিত কাজটি অবৈধ।\nআপনি হয়তো একটি ভুল লিঙ্ক দিয়েছেন অথবা ইউআরএল লিখতে ভুল করেছেন।\nএটি এমনও নির্দেশ করে যে {{SITENAME}} সাইটে ব্যবহৃত সফটওয়্যারটিতে একটি ত্রুটি রয়েছে।",
        "nosuchspecialpage": "এমন কোন বিশেষ পাতা নেই",
        "welcomecreation-msg": "আপনার অ্যাকাউন্ট তৈরী হয়েছে।\nআপনার [[Special:Preferences|{{SITENAME}} পছন্দসমূহ]]  পরিবর্তন করে নিতে ভুলবেন না।",
        "yourname": "ব্যবহারকারী নাম:",
        "userlogin-yourname": "ব্যবহারকারী নাম",
-       "userlogin-yourname-ph": "আপনার ব্যবহাকারী নাম লিখুন",
-       "createacct-another-username-ph": "আপনার ব্যবহাকারী নাম প্রবেশ করান",
+       "userlogin-yourname-ph": "à¦\86পনার à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦® à¦²à¦¿à¦\96à§\81ন",
+       "createacct-another-username-ph": "à¦\86পনার à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦® à¦ªà§\8dরবà§\87শ à¦\95রান",
        "yourpassword": "পাসওয়ার্ড:",
        "userlogin-yourpassword": "পাসওয়ার্ড",
        "userlogin-yourpassword-ph": "আপনার পাসওয়ার্ড লিখুন",
        "createacct-captcha": "নিরাপত্তা পরীক্ষা",
        "createacct-imgcaptcha-ph": "উপরে যে লেখা দেখতে পাচ্ছেন তা লিখুন",
        "createacct-submit": "আপনার অ্যাকাউন্ট তৈরি করুন",
-       "createacct-another-submit": "à¦\86রà§\87à¦\95à¦\9fি à¦\85à§\8dযাà¦\95াà¦\89নà§\8dà¦\9f à¦¤à§\88রি à¦\95রà§\81ন",
+       "createacct-another-submit": "অ্যাকাউন্ট তৈরি করুন",
        "createacct-benefit-heading": "{{SITENAME}} আপনার মত লোকের দ্বারাই তৈরি।",
        "createacct-benefit-body1": "{{PLURAL:$1|টি সম্পাদনা}}",
        "createacct-benefit-body2": "{{PLURAL:$1|টি পাতা}}",
        "noname": "আপনি সঠিক ব্যবহারকারী নাম নির্দিষ্ট করেননি।",
        "loginsuccesstitle": "প্রবেশ সফল",
        "loginsuccess": "'''আপনি এইমাত্র \"$1\" নামে {{SITENAME}}-তে প্রবেশ করেছেন।'''",
-       "nosuchuser": "\"$1\" à¦¨à¦¾à¦®à§\87 à¦\95à§\8bন à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à§\87à¦\87।\nবà§\8dযবহাà¦\95ারà§\80 à¦¨à¦¾à¦® আকার সংবেদনশীল।\nআপনার বানান পরীক্ষা করে দেখুন, অথবা [[Special:UserLogin/signup|নতুন একটি অ্যাকাউন্ট খুলুন]]।",
+       "nosuchuser": "\"$1\" à¦¨à¦¾à¦®à§\87 à¦\95à§\8bন à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à§\87à¦\87।\nবà§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦®à§\87র আকার সংবেদনশীল।\nআপনার বানান পরীক্ষা করে দেখুন, অথবা [[Special:UserLogin/signup|নতুন একটি অ্যাকাউন্ট খুলুন]]।",
        "nosuchusershort": "\"$1\" নামের কোন ব্যবহারকারী নেই। নামের বানান পরীক্ষা করুন।",
        "nouserspecified": "আপনাকে অবশ্যই ব্যবহারকারী নাম নির্দিষ্ট করতে হবে।",
        "login-userblocked": "এই ব্যবহারকারীকে বাধা দেওয়া হয়েছে। লগ-ইন সম্ভব নয়।",
        "changeemail-password": "আপনার {{SITENAME}} পাসওয়ার্ড:",
        "changeemail-submit": "ই-মেইল পরিবর্তন",
        "changeemail-throttled": "আপনি পরপর বেশ কয়েকবার প্রবেশের চেষ্টা করেছেন। পুনরায় চেষ্টা করার পূর্বে অনুগ্রহ করে $1 অপেক্ষা করুন।",
+       "changeemail-nochange": "দয়া করে একটি ভিন্ন নতুন ইমেইল ঠিকানা লিখুন।",
        "resettokens": "রিসেট টোকেন",
        "resettokens-text": "আপনি টোকেন রিসেট করতে পারেন, যা অ্যাকাউন্টের সাথে সম্পর্কিত আপনার ব্যক্তিগত তথ্য দেখার কাজে ব্যবহার করা হয়।",
        "resettokens-no-tokens": "রিসেট করার মত কোনো টোকেন নেই।",
        "columns": "কলাম:",
        "searchresultshead": "অনুসন্ধান",
        "stub-threshold": "<a href=\"#\" class=\"stub\">অসম্পূর্ণ নিবন্ধের সংযোগগুলির</a> বিশেষ ফরম্যাটিঙের সীমা (বাইটে):",
+       "stub-threshold-sample-link": "নমুনা",
        "stub-threshold-disabled": "নিস্ক্রিয়",
        "recentchangesdays": "সাম্প্রতিক পরিবর্তনে দিনসমূহ দেখানোর জন্য:",
        "recentchangesdays-max": "সর্বোচ্চ $1 {{PLURAL:$1|দিন|দিন}}",
        "group-bot": "বট",
        "group-sysop": "প্রশাসক",
        "group-bureaucrat": "ব্যুরোক্র্যাট",
-       "group-suppress": "à¦\93ভারসাà¦\87à¦\9f",
+       "group-suppress": "দমনà¦\95ারà§\80",
        "group-all": "(সমস্ত)",
        "group-user-member": "{{GENDER:$1|ব্যবহারকারী}}",
        "group-autoconfirmed-member": "স্বয়ংনিশ্চিতকৃত ব্যবহারকারী",
        "group-bot-member": "বট",
        "group-sysop-member": "প্রশাসক",
        "group-bureaucrat-member": "ব্যুরোক্র্যাট",
-       "group-suppress-member": "ওভারসাইট",
+       "group-suppress-member": "{{GENDER:$1|দমনকারী}}",
        "grouppage-user": "{{ns:project}}:ব্যবহারকারী",
        "grouppage-autoconfirmed": "{{ns:project}}:স্বয়ংক্রিয়ভাবে নিশ্চিতকৃত ব্যবহারকারী",
        "grouppage-bot": "{{ns:project}}:বট",
        "grouppage-sysop": "{{ns:project}}:প্রশাসক",
        "grouppage-bureaucrat": "{{ns:project}}:ব্যুরোক্র্যাট",
-       "grouppage-suppress": "{{ns:project}}:à¦\93ভারসাà¦\87à¦\9f",
+       "grouppage-suppress": "{{ns:project}}:দমনà¦\95ারà§\80",
        "right-read": "পাতাসমূহ পড়ুন",
        "right-edit": "পাতা সম্পাদনা করুন",
        "right-createpage": "পাতা তৈরি করো (আলাপের পাতা নয়)",
        "upload-http-error": "একটি এইচটিটিপি ত্রুটি দেখা দিয়েছে: $1",
        "upload-copy-upload-invalid-domain": "এই ডোমেইন থেকে আপলোড সম্ভব নয়।",
        "upload-dialog-title": "ফাইল আপলোড করুন",
-       "upload-dialog-error": "একটি ত্রুটি দেখা দিয়েছে",
-       "upload-dialog-warning": "একটি সতর্কবার্তা দেখা দিয়েছে",
        "upload-dialog-button-cancel": "বাতিল",
        "upload-dialog-button-done": "সম্পন্ন",
        "upload-dialog-button-save": "সংরক্ষণ",
        "upload-dialog-button-upload": "আপলোড",
-       "upload-dialog-label-select-file": "ফাইল নির্বাচন করুন",
-       "upload-dialog-label-infoform-title": "বিস্তারিত",
-       "upload-dialog-label-infoform-name": "নাম",
-       "upload-dialog-label-infoform-description": "বিবরণ",
-       "upload-dialog-label-usage-title": "ব্যবহার",
-       "upload-dialog-label-usage-filename": "ফাইলের নাম",
+       "upload-process-error": "একটি ত্রুটি দেখা দিয়েছে",
+       "upload-process-warning": "একটি সতর্কবার্তা দেখা দিয়েছে",
+       "upload-form-label-select-file": "ফাইল নির্বাচন করুন",
+       "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": "ফাইলের নাম",
        "backend-fail-stream": "\"$1\" ফাইলের স্ট্রিম দেখানো যাচ্ছে না।",
        "backend-fail-backup": "\"$1\" ফাইলের ব্যাকআপ তৈরী সম্ভব নয়।",
        "backend-fail-notexists": "\"$1\" নামের কোনো ফাইল নেই।",
        "filerevert-legend": "ফাইল পূর্বাবস্থায় ফেরত নিন",
        "filerevert-intro": "আপনি '''[[Media:$1|$1]]''' ফাইলটিকে [$3, $2 সময়ের $4 সংস্করণে] ফিরিয়ে নিচ্ছেন।",
        "filerevert-comment": "কারণ:",
-       "filerevert-defaultcomment": "$2, $1 সংস্করণে ফেরত যাওয়া হল",
+       "filerevert-defaultcomment": "$2, $1 সংস্করণে ফেরত যাওয়া হল ($3)",
        "filerevert-submit": "ফেরত যাওয়া হোক",
        "filerevert-success": "'''[[Media:$1|$1]]''' ফাইলটি  [$3, $2-এর $4 সংস্করণে] ফেরত নেওয়া হয়েছে।",
        "filerevert-badversion": "প্রদত্ত তারিখ ও সময়ের জন্য এই ফাইলটির কোন স্থানীয় সংস্করণ নেই।",
        "nopagetext": "আপনার নির্ধারিত লক্ষ্য পাতাটি নাই।",
        "pager-newer-n": "{{PLURAL:$1|নতুনতর ১টি|নতুনতর $1টি}}",
        "pager-older-n": "{{PLURAL:$1|আরও পুরনো ১টি|আরও পুরনো $1টি}}",
-       "suppress": "à¦\93ভারসাà¦\87à¦\9f",
+       "suppress": "দমন",
        "querypage-disabled": "কারিগরি কারণে এই বিশেষ পাতাটি আপাতত বন্ধ রয়েছে।",
        "apihelp": "এপিআই সাহায্য",
        "apihelp-no-such-module": "মডিউল \"$1\" পাওয়া যায়নি।",
        "booksources-text": "নতুন ও পুরাতন ব্যবহৃত বই বিক্রি করে, এমন কতগুলি সাইটের সংযোগের তালিকা নিচে দেওয়া হল, যে সাইটগুলিতে আপনার অনুসন্ধানকৃত বইগুলির উপর আরও তথ্য থাকতে পারে:",
        "booksources-invalid-isbn": "উল্লেখিত ISBN সঠিক নয়; অনুগ্রহ করে মূল উৎস থেকে আবার পরীক্ষা করুন।",
        "specialloguserlabel": "সম্পাদক:",
-       "speciallogtitlelabel": "লà¦\95à§\8dষà§\8dয (শিরà§\8bনাম à¦\85থবা à¦¬à§\8dযবহারà¦\95ারà§\80):",
+       "speciallogtitlelabel": "লà¦\95à§\8dষà§\8dয (শিরà§\8bনাম à¦¬à¦¾ {{ns:user}}:বà§\8dযবহারà¦\95ারà§\80র à¦\9cনà§\8dয à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦®):",
        "log": "লগগুলি",
        "all-logs-page": "সব পাবলিক লগ",
        "alllogstext": "{{SITENAME}}-এর সবগুলো লগের সম্মিলিত প্রদর্শন।\nআপনি লগের ধরন, ব্যবহারকারীর নাম, বা পাতার নাম নির্বাচন করে প্রদর্শনটির আকার কমিয়ে আনতে পারেন।",
        "emailccsubject": "আপনার বার্তার অনুলিপি $1-কে: $2",
        "emailsent": "ই-মেইল প্রেরণ করা হয়েছে",
        "emailsenttext": "আপনার ই-মেইল বার্তা প্রেরণ করা হয়েছে।",
-       "emailuserfooter": "এই ইমেইলটি {{SITENAME}} সাইটের \"{{int:emailuser}}\" সুবিধা ব্যবহার করে $1-এর পক্ষ থেকে $2-এর নিকট পাঠানো হয়েছে।",
+       "emailuserfooter": "এই ইমেইলটি {{SITENAME}} সাইটের \"{{int:emailuser}}\" সুবিধা ব্যবহার করে $1-এর পক্ষ থেকে {{GENDER:$2|$2}}-এর নিকট {{GENDER:$1|পাঠানো হয়েছে}}।",
        "usermessage-summary": "বাদবাকি সিস্টেম বার্তা",
        "usermessage-editor": "সিস্টেম ম্যাসেঞ্জার",
        "watchlist": "নজর তালিকা",
        "ipb_already_blocked": "\"$1\" ইতিমধ্যে ব্লক",
        "ipb-needreblock": "$1 পূর্বেই ব্লক রয়েছেন। আপনি কি সেটিংস পরিবর্তন করতে চান?",
        "ipb-otherblocks-header": "অন্যান্য {{PLURAL:$1|বাধাঁ|বাধাঁসমূহ}}",
-       "unblock-hideuser": "à¦\86পনি à¦\8fà¦\87 à¦¬à§\8dযবহারà¦\95ারà§\80à¦\95à§\87 à¦\86নবà§\8dলà¦\95 à¦\95রতà§\87 à¦ªà¦¾à¦°à¦¬à§\87ন à¦¨à¦¾, à¦\95ারণ à¦\8fà¦\87 à¦¬à§\8dযবহারà¦\95ারà§\80দà§\87র à¦¬à§\8dযবহাকারী নাম লুকানো রয়েছে।",
+       "unblock-hideuser": "à¦\86পনি à¦\8fà¦\87 à¦¬à§\8dযবহারà¦\95ারà§\80à¦\95à§\87 à¦¬à¦¾à¦§à¦¾ à¦®à§\81à¦\95à§\8dত à¦\95রতà§\87 à¦ªà¦¾à¦°à¦¬à§\87ন à¦¨à¦¾, à¦\95ারণ à¦\8fà¦\87 à¦¬à§\8dযবহারà¦\95ারà§\80দà§\87র à¦¬à§\8dযবহারকারী নাম লুকানো রয়েছে।",
        "ipb_cant_unblock": "ত্রুটি: $1 ব্লক আইডি খুঁজে পাওয়া যায়নি। হয়ত ইতিমধ্যেই এটির উপর থেকে বাধা তুলে নেওয়া হয়েছে।",
        "ipb_blocked_as_range": "ত্রুটি: $1 আইপি ঠিকানাটিকে সরাসরি বাধা দেওয়া হয়নি এবং বাধা তুলে নেওয়া যাবে না। তবে ঠিকানাটি $2 সীমার অন্তর্ভুক্ত এবং সেটি থেকে বাধা তুলে নেওয়া সম্ভব।",
        "ip_range_invalid": "অবৈধ আইপি শ্রেণী",
        "databasenotlocked": "ডাটাবেজ বন্ধ নয়।",
        "lockedbyandtime": "({{GENDER:$1|$1}} $2 এর $3 সময়ে)",
        "move-page": "$1 স্থানান্তর",
-       "move-page-legend": "পাতাটি সরিয়ে ফেলুন",
+       "move-page-legend": "পাতা স্থানান্তর",
        "movepagetext": "নিচের ফর্মটি ব্যবহার করে একটি পাতার শিরোনাম পরিবর্তন করা যাবে, এবং সেই সাথে নতুন শিরোনামে এর সমগ্র ইতিহাস স্থানান্তর করা যাবে।\nপুরনো শিরোনামটি নতুন শিরোনামটির প্রতি একটি পুনর্নির্দেশনা ধারণ করবে।\nযেসমস্ত পুনর্নির্দেশনা পুরনো শিরোনামটির দিকে নির্দেশ করছিল, সেগুলি স্বয়ংক্রিয়ভাবে হালনাগাদ করতে পারবেন।\nযদি তা না চান, তবে [[Special:DoubleRedirects|দ্বি-পুনর্নির্দেশনা]] বা [[Special:BrokenRedirects|অচল পুনর্নির্দেশনাগুলি]] পরীক্ষা করে দেখতে ভুলবেন না।\nসংযোগগুলি যাতে তাদের লক্ষ্যে পৌঁছায়, তা নিশ্চিত করার দায়িত্ব আপনার।\n\nলক্ষ্য করুন যে যদি নতুন শিরোনামে ইতিমধ্যেই একটি পাতা থেকে থাকে, তবে উৎস পাতাটি সেই শিরোনামে স্থানান্তর করা হবে '''না''', যদি না নতুন শিরোনামের পাতাটি খালি থাকে বা একটি পুননির্দেশনা হয় এবং এর কোন অতীত সম্পাদনা ইতিহাস না থাকে।\nঅর্থাৎ আপনি ভুল করে নাম পরিবর্তন করলে সহজেই পুরনো নামে ফেরত যেতে পারবেন, কিন্তু ইতিমধ্যে বিদ্যমান কোন পাতার উপরে লিখতে পারবেন না।\n\n'''সতর্কীকরণ!'''\nকোন জনপ্রিয় পাতার ক্ষেত্রে এই পরিবর্তনটি খুবই আকস্মিক হতে পারে; অগ্রসর হবার আগে এই কাজটির ফলাফল কী হতে পারে, সে ব্যাপারে অনুগ্রহ করে নিশ্চিত হোন।",
        "movepagetext-noredirectfixer": "নিচের ফর্মটি ব্যবহার করে একটি পাতার শিরোনাম পরিবর্তন করা যাবে, এবং সেই সাথে নতুন শিরোনামে এর সমগ্র ইতিহাস স্থানান্তর করা যাবে।\nপুরনো শিরোনামটি নতুন শিরোনামটির প্রতি একটি পুনর্নির্দেশনা ধারণ করবে।\n[[Special:DoubleRedirects|দ্বি-পুনর্নির্দেশনা]] বা [[Special:BrokenRedirects|অচল পুনর্নির্দেশনাগুলি]] পরীক্ষা করে দেখতে ভুলবেন না।\nসংযোগগুলি যাতে তাদের লক্ষ্যে পৌঁছায়, তা নিশ্চিত করার দায়িত্ব আপনার।\n\nলক্ষ্য করুন যে যদি নতুন শিরোনামে ইতিমধ্যেই একটি পাতা থেকে থাকে, তবে উৎস পাতাটি সেই শিরোনামে স্থানান্তর করা হবে '''না''', যদি না নতুন শিরোনামের পাতাটি খালি থাকে বা একটি পুননির্দেশনা হয় এবং এর কোন অতীত সম্পাদনা ইতিহাস না থাকে। \nঅর্থাৎ আপনি ভুল করে নাম পরিবর্তন করলে সহজেই পুরনো নামে ফেরত যেতে পারবেন, কিন্তু ইতিমধ্যে বিদ্যমান কোন পাতার উপরে লিখতে পারবেন না।\n\n'''সতর্কীকরণ!'''\nকোন জনপ্রিয় পাতার ক্ষেত্রে এই পরিবর্তনটি খুবই আকস্মিক হতে পারে;\nঅগ্রসর হবার আগে এই কাজটির ফলাফল কী হতে পারে, সে ব্যাপারে অনুগ্রহ করে নিশ্চিত হোন।",
        "movepagetalktext": "পাতাটির সাথে সাথে সংশ্লিষ্ট আলোচনা পাতাটিও স্বয়ংক্রিয়ভাবে সরানো হবে '''যদি না:'''\n*খালি নয় এমন একটি আলাপ পাতা নতুন শিরোনামটির অধীনে ইতিমধ্যেই বিদ্যমান থাকে, অথবা\n*আপনি নিচের বাক্সটি থেকে টিক সরিয়ে নিতে পারেন।\n\nএসব ক্ষেত্রে আপনি চাইলে নিজের হাতে পাতাটিকে সরাতে বা একত্রীকরণ করতে পারেন।",
        "cant-move-to-category-page": "আপনার পাতাটিকে বিষয়শ্রেণী পাতায় স্থানান্তরের অনুমতি নেই।",
        "newtitle": "এই নতুন শিরোনামে",
        "move-watch": "এই পাতাটি নজরে রাখুন",
-       "movepagebtn": "পাতা à¦¸à¦°à¦¾ন",
+       "movepagebtn": "পাতা à¦¸à§\8dথানানà§\8dতর à¦\95রà§\81ন",
        "pagemovedsub": "সরিয়ে নেওয়া হয়েছে",
        "movepage-moved": "'''\"$1\"-কে \"$2\" শিরোনামে স্থানান্তর করা হয়েছে'''",
        "movepage-moved-redirect": "একটি পুনর্নির্দেশনা তৈরি হয়েছে।",
        "movepage-moved-noredirect": "পুনর্নির্দেশ তৈরীতে বাধা দেয়া হয়েছে।",
        "articleexists": "এই শিরোনামে একটি পাতা ইতোমধ্যে সৃষ্টি হয়ে গেছে, অথবা আপনি যে শিরোনামটি পছন্দ করেছেন তা গ্রহণযোগ্য নয়। দয়া করে অন্য একটি শিরোনাম দিয়ে চেষ্টা করুন।",
        "cantmove-titleprotected": "আপনি এই অবস্থানে পাতাটিকে স্থানান্তর করতে পারেন না, কারণ এই নতুন শিরোনামটি সৃষ্টি করা থেকে সুরক্ষিত।",
-       "movetalk": "সংশ্লিষ্ট আলাপের পাতা সরিয়ে নাও",
+       "movetalk": "সংশ্লিষ্ট আলাপ পাতা স্থানান্তর করো",
        "move-subpages": "উপপাতা স্থানান্তর ($1টি পর্যন্ত)",
        "move-talk-subpages": "উপপাতার আলাপ পাতা স্থানান্তর ($1টি পর্যন্ত)",
        "movepage-page-exists": "$1 পাতাটি ইতিমধ্যেই বিদ্যমান এবং স্বয়ংক্রিয়ভাবে পুনর্লিখন করা সম্ভব নয়।",
        "tooltip-ca-nstab-main": "বিষয়বস্তু পাতাটি দেখুন",
        "tooltip-ca-nstab-user": "ব্যহারকারী পাতাটি দেখুন",
        "tooltip-ca-nstab-media": "মিডিয়া পাতাটি দেখুন",
-       "tooltip-ca-nstab-special": "à¦\8fà¦\9fি à¦\8fà¦\95à¦\9fি à¦¬à¦¿à¦¶à§\87ষ à¦ªà¦¾à¦¤à¦¾, à¦\86পনি à¦\8fà¦\9fি à¦¸à¦®à§\8dপাদনা à¦\95রতà§\87 à¦ªà¦¾à¦°à¦¬à§\87ন না",
+       "tooltip-ca-nstab-special": "à¦\8fà¦\9fি à¦\8fà¦\95à¦\9fি à¦¬à¦¿à¦¶à§\87ষ à¦ªà¦¾à¦¤à¦¾, à¦\8fবà¦\82 à¦\8fà¦\9fি à¦¸à¦®à§\8dপাদনা à¦\95রা à¦¯à¦¾à¦¬à§\87 না",
        "tooltip-ca-nstab-project": "প্রকল্প পাতাটি দেখুন",
        "tooltip-ca-nstab-image": "ফাইলের পাতাটি দেখুন",
        "tooltip-ca-nstab-mediawiki": "সিস্টেম বার্তাটি দেখুন",
        "logentry-newusers-byemail": "$1, $3 ব্যবহারকরী অ্যাকাউন্টটি {{GENDER:$2|তৈরী করেছেন}} এবং পাসওয়ার্ড ইমেইলের মাধ্যমে পাঠানো হয়েছে",
        "logentry-newusers-autocreate": "$1 অ্যাকাউন্টটি স্বয়ংক্রিয়ভাবে {{GENDER:$2|তৈরি}} হয়েছে",
        "logentry-protect-move_prot": "$1 সুরক্ষা সেটিং $4 থেকে $3-এ {{GENDER:$2|সরিয়েছেন}}",
+       "logentry-protect-unprotect": "$1 $3 থেকে সুরক্ষা {{GENDER:$2|সরিয়ে নিয়েছেন}}",
+       "logentry-protect-protect": "$1 $3 {{GENDER:$2|সুরক্ষিত করেছেন}} $4",
+       "logentry-protect-protect-cascade": "$1 $3 {{GENDER:$2|সুরক্ষিত করেছেন}} $4 [প্রপাতাকার]",
+       "logentry-protect-modify": "$1 $3-এর জন্য সুরক্ষা স্তর {{GENDER:$2|পরিবর্তন করেছেন}} $4",
+       "logentry-protect-modify-cascade": "$1 $3-এর জন্য সুরক্ষা স্তর {{GENDER:$2|পরিবর্তন করেছেন}} $4 [প্রপাতাকার]",
        "logentry-rights-rights": "$1 ব্যবহারকারী, $3 এর দলগত সদস্যপদ $4 থেকে $5 এ {{GENDER:$2|পরিবর্তন}} করেছেন",
        "logentry-rights-rights-legacy": "$1 দলের সদস্যপদ পরিবর্তন করেছেন {{GENDER:$2|changed}} এর জন্য $3",
        "logentry-rights-autopromote": "$1 সয়ংক্রিয়ভাবে $4 থেকে $5 এ {{GENDER:$2|উন্নীত}} হয়েছে",
        "api-error-badaccess-groups": "আপনার এই উইকিতে ফাইল আপলোডের অনুমতি নেই।",
        "api-error-badtoken": "অভ্যন্তরীণ ত্রুটি: খারাপ টোকেন।",
        "api-error-copyuploaddisabled": "এই সার্ভারে ইউআরএল-এর মাধ্যমে আপলোড করার সুবিধা নিস্ক্রিয় রয়েছে।",
-       "api-error-duplicate": "à¦\87তà§\8bমধà§\8dযà§\87 à¦\8fà¦\87 à¦¸à¦¾à¦\87à¦\9fà§\87 à¦\8fà¦\95à¦\87 à¦°à¦\95মà§\87র à¦\95নà§\8dà¦\9fà§\87à¦\9f à¦¸à¦®à§\83দà§\8dধ {{PLURAL:$1|[$2 à¦\85নà§\8dয à¦«à¦¾à¦\87ল]|[$2 à¦\95িà¦\9bà§\81 à¦\85নà§\8dয à¦«à¦¾à¦\87ল]}} রয়েছে।",
+       "api-error-duplicate": "à¦\87তà§\8bমধà§\8dযà§\87 à¦\8fà¦\87 à¦¸à¦¾à¦\87à¦\9fà§\87 à¦\8fà¦\95à¦\87 à¦°à¦\95মà§\87র à¦¬à¦¿à¦·à¦¯à¦¼ à¦¸à¦®à§\83দà§\8dধ {{PLURAL:$1|à¦\85নà§\8dয à¦«à¦¾à¦\87ল|à¦\95িà¦\9bà§\81 à¦\85নà§\8dয à¦«à¦¾à¦\87ল}} রয়েছে।",
        "api-error-duplicate-archive": "একই নাম ও বিষয়বস্তু বিশিষ্ট {{PLURAL:$1|অপর একটি ফাইল|কয়েকটি ফাইল}} পূর্বে এই উইকিতে ছিলো, এবং {{PLURAL:$1|সেটিকে|সেগুলোকে}} অপসারণ করা হয়েছে।",
        "api-error-empty-file": "আপনার জমাকৃত ফাইলটি খালি।",
        "api-error-emptypage": "নতুন পাতা তৈরি হচ্ছে, খালি পাতা গ্রহণযোগ্য নয়।",
        "special-characters-title-emdash": "em ড্যাশ",
        "special-characters-title-minus": "বিয়োগ চিহ্ন",
        "mw-widgets-dateinput-no-date": "কোন তারিখ নির্বাচন করা হয়নি",
+       "mw-widgets-dateinput-placeholder-day": "বববব-মম-দদ",
+       "mw-widgets-dateinput-placeholder-month": "বববব-মম",
        "mw-widgets-titleinput-description-new-page": "পাতা এখনো বিদ্যমান নয়",
        "mw-widgets-titleinput-description-redirect": "$1-এ পুনঃনির্দেশিত"
 }
index ac591c9..5007e73 100644 (file)
        "upload-http-error": "Ha ocorregut un error HTTP: $1",
        "upload-copy-upload-invalid-domain": "Les càrregues de còpia no són disponibles des d'aquest domini.",
        "upload-dialog-title": "Carrega un fitxer",
-       "upload-dialog-error": "S’ha produït un error",
-       "upload-dialog-warning": "S'ha produït un avís",
        "upload-dialog-button-cancel": "Cancel·la",
        "upload-dialog-button-done": "Fet",
        "upload-dialog-button-save": "Desa",
        "upload-dialog-button-upload": "Carrega",
-       "upload-dialog-label-select-file": "Seleccioneu fitxer",
-       "upload-dialog-label-infoform-title": "Detalls",
-       "upload-dialog-label-infoform-name": "Nom",
-       "upload-dialog-label-infoform-description": "Descripció",
-       "upload-dialog-label-usage-title": "Ús",
-       "upload-dialog-label-usage-filename": "Nom del fitxer",
+       "upload-process-error": "S’ha produït un error",
+       "upload-process-warning": "S'ha produït un avís",
+       "upload-form-label-select-file": "Seleccioneu fitxer",
+       "upload-form-label-infoform-title": "Detalls",
+       "upload-form-label-infoform-name": "Nom",
+       "upload-form-label-infoform-description": "Descripció",
+       "upload-form-label-usage-title": "Ús",
+       "upload-form-label-usage-filename": "Nom del fitxer",
        "backend-fail-stream": "No s'ha pogut transmetre el fitxer $1.",
        "backend-fail-backup": "No s'ha pogut fer una còpia de seguretat del fitxer $1.",
        "backend-fail-notexists": "El fitxer $1 no existeix.",
index f2de5d0..795fd4a 100644 (file)
        "createacct-captcha": "Bezpečnostní kontrola",
        "createacct-imgcaptcha-ph": "Opište výše zobrazený text",
        "createacct-submit": "Vytvořit účet",
-       "createacct-another-submit": "Vytvořit jiný účet",
+       "createacct-another-submit": "Vytvořit účet",
        "createacct-benefit-heading": "{{grammar:4sg|{{SITENAME}}}} tvoří lidé jako vy.",
        "createacct-benefit-body1": "{{PLURAL:$1|editace|editace|editací}}",
        "createacct-benefit-body2": "{{PLURAL:$1|stránka|stránky|stránek}}",
        "permissionserrorstext-withaction": "Z {{PLURAL:$1|následujícího důvodu|následujících důvodů}} nemáte oprávnění $2:",
        "recreate-moveddeleted-warn": "'''Upozornění: Pokoušíte se znovuzaložit stránku, která byla v minulosti smazána.'''\n\nZvažte, zda je vhodné v editaci této stránky pokračovat.\nNíže vidíte soupis přesunů a smazání této stránky:",
        "moveddeleted-notice": "Tato stránka byla smazána.\nPodrobnosti si můžete prohlédnout v níže zobrazeném seznamu provedených přesunů a smazání této stránky.",
+       "moveddeleted-notice-recent": "Omlouváme se, ale tato stránka byla nedávno (v posledních 24 hodinách) smazána. Pro úplnost je níže zobrazen soupis přesunů a smazání této stránky.",
        "log-fulllog": "Zobrazit všechny záznamy",
        "edit-hook-aborted": "Editace byla bez bližšího vysvětlení zrušena přípojným bodem.",
        "edit-gone-missing": "Stránku se nepodařilo aktualizovat.\nZřejmě byla smazána.",
        "group-bot": "Boti",
        "group-sysop": "Správci",
        "group-bureaucrat": "Byrokraté",
-       "group-suppress": "Dohlížitelé",
+       "group-suppress": "Utajovatelé",
        "group-all": "(všichni)",
        "group-user-member": "{{GENDER:$1|uživatel|uživatelka|uživatel}}",
        "group-autoconfirmed-member": "automaticky {{GENDER:$1|schválený uživatel|schválená uživatelka|schválený uživatel}}",
        "group-bot-member": "{{GENDER:$1|bot|botka|bot}}",
        "group-sysop-member": "{{GENDER:$1|správce|správkyně|správce}}",
        "group-bureaucrat-member": "{{GENDER:$1|byrokrat|byrokratka|byrokrat}}",
-       "group-suppress-member": "{{GENDER:$1|dohlížitel|dohlížitelka|dohlížitel}}",
+       "group-suppress-member": "{{GENDER:$1|utajovatel|utajovatelka|utajovatel}}",
        "grouppage-user": "{{ns:project}}:Uživatelé",
        "grouppage-autoconfirmed": "{{ns:project}}:Automaticky schválení uživatelé",
        "grouppage-bot": "{{ns:project}}:Boti",
        "grouppage-sysop": "{{ns:project}}:Správci",
        "grouppage-bureaucrat": "{{ns:project}}:Byrokraté",
-       "grouppage-suppress": "{{ns:project}}:Dohlížitelé",
+       "grouppage-suppress": "{{ns:project}}:Utajovatelé",
        "right-read": "Čtení stránek",
        "right-edit": "Editace stránek",
        "right-createpage": "Zakládání stránek (které nejsou diskusní)",
        "upload-http-error": "Došlo k chybě HTTP: $1",
        "upload-copy-upload-invalid-domain": "Načítání kopírováním není dostupné z této domény.",
        "upload-dialog-title": "Načtení souboru",
-       "upload-dialog-error": "Došlo k chybě",
-       "upload-dialog-warning": "Objevilo se upozornění",
        "upload-dialog-button-cancel": "Storno",
        "upload-dialog-button-done": "Hotovo",
        "upload-dialog-button-save": "Uložit",
        "upload-dialog-button-upload": "Načíst",
-       "upload-dialog-label-select-file": "Výběr souboru",
-       "upload-dialog-label-infoform-title": "Podrobnosti",
-       "upload-dialog-label-infoform-name": "Název",
-       "upload-dialog-label-infoform-description": "Popis",
-       "upload-dialog-label-usage-title": "Použití",
-       "upload-dialog-label-usage-filename": "Jméno souboru",
+       "upload-process-error": "Došlo k chybě",
+       "upload-process-warning": "Objevilo se upozornění",
+       "upload-form-label-select-file": "Výběr souboru",
+       "upload-form-label-infoform-title": "Podrobnosti",
+       "upload-form-label-infoform-name": "Název",
+       "upload-form-label-infoform-description": "Popis",
+       "upload-form-label-usage-title": "Použití",
+       "upload-form-label-usage-filename": "Jméno souboru",
        "backend-fail-stream": "Soubor $1 nelze streamovat.",
        "backend-fail-backup": "Soubor $1 nelze zazálohovat.",
        "backend-fail-notexists": "Soubor $1 neexistuje.",
        "filerevert-legend": "Vrátit zpět soubor",
        "filerevert-intro": "Vracíte zpět '''[[Media:$1|$1]]''' na [$4 verzi z $3 $2].",
        "filerevert-comment": "Důvod:",
-       "filerevert-defaultcomment": "Navrácena verze nahraná v $2 dne $1.",
+       "filerevert-defaultcomment": "Návrat na verzi z $2, $1 ($3)",
        "filerevert-submit": "Vrátit zpět",
        "filerevert-success": "Soubor '''[[Media:$1|$1]]''' byl vrácen zpět na [$4 verzi z $3 $2].",
        "filerevert-badversion": "Není dostupná předchozí verze tohoto souboru s odpovídající časovou značkou.",
        "nopagetext": "Cílová stránka, kterou jste specifikovali, neexistuje.",
        "pager-newer-n": "{{PLURAL:$1|1 novější|$1 novější|$1 novějších}}",
        "pager-older-n": "{{PLURAL:$1|1 starší|$1 starší|$1 starších}}",
-       "suppress": "Dozor",
+       "suppress": "Utajit",
        "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.",
index 89fe6cd..5acb6a4 100644 (file)
        "group-bot": "Bots",
        "group-sysop": "Administratoren",
        "group-bureaucrat": "Bürokraten",
-       "group-suppress": "Oversighter",
+       "group-suppress": "Unterdrücker",
        "group-all": "(alle)",
        "group-user-member": "{{GENDER:$1|Benutzer|Benutzerin}}",
        "group-autoconfirmed-member": "{{GENDER:$1|Automatisch bestätigter Benutzer|Automatisch bestätigte Benutzerin}}",
        "group-bot-member": "Bot",
        "group-sysop-member": "{{GENDER:$1|Administrator|Administratorin}}",
        "group-bureaucrat-member": "{{GENDER:$1|Bürokrat|Bürokratin}}",
-       "group-suppress-member": "{{GENDER:$1|Oversighter|Oversighterin}}",
+       "group-suppress-member": "{{GENDER:$1|Unterdrücker|Unterdrückerin}}",
        "grouppage-user": "{{ns:project}}:Benutzer",
        "grouppage-autoconfirmed": "{{ns:project}}:Automatisch bestätigte Benutzer",
        "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Administratoren",
        "grouppage-bureaucrat": "{{ns:project}}:Bürokraten",
-       "grouppage-suppress": "{{ns:project}}:Oversighter",
+       "grouppage-suppress": "{{ns:project}}:Unterdrücker",
        "right-read": "Seiten lesen",
        "right-edit": "Seiten bearbeiten",
        "right-createpage": "Seiten erstellen (die keine Diskussionsseiten sind)",
        "upload-http-error": "Ein HTTP-Fehler ist aufgetreten: $1",
        "upload-copy-upload-invalid-domain": "Als Kopie hochladbare Dateien sind über diese Domain nicht verfügbar.",
        "upload-dialog-title": "Datei hochladen",
-       "upload-dialog-error": "Es ist ein Fehler aufgetreten",
-       "upload-dialog-warning": "Es ist eine Warnung aufgetreten",
        "upload-dialog-button-cancel": "Abbrechen",
        "upload-dialog-button-done": "Schließen",
        "upload-dialog-button-save": "Speichern",
        "upload-dialog-button-upload": "Hochladen",
-       "upload-dialog-label-select-file": "Datei auswählen",
-       "upload-dialog-label-infoform-title": "Einzelheiten",
-       "upload-dialog-label-infoform-name": "Name",
-       "upload-dialog-label-infoform-description": "Beschreibung",
-       "upload-dialog-label-usage-title": "Verwendung",
-       "upload-dialog-label-usage-filename": "Dateiname",
+       "upload-process-error": "Es ist ein Fehler aufgetreten",
+       "upload-process-warning": "Es ist eine Warnung aufgetreten",
+       "upload-form-label-select-file": "Datei auswählen",
+       "upload-form-label-infoform-title": "Einzelheiten",
+       "upload-form-label-infoform-name": "Name",
+       "upload-form-label-infoform-description": "Beschreibung",
+       "upload-form-label-usage-title": "Verwendung",
+       "upload-form-label-usage-filename": "Dateiname",
        "backend-fail-stream": "Die Datei $1 konnte nicht übertragen werden.",
        "backend-fail-backup": "Die Datei $1 konnte nicht gesichert werden.",
        "backend-fail-notexists": "Die Datei $1 ist nicht vorhanden.",
        "filerevert-legend": "Datei zurücksetzen",
        "filerevert-intro": "Du setzt die Datei '''[[Media:$1|$1]]''' auf die [$4 Version vom $2, $3 Uhr] zurück.",
        "filerevert-comment": "Grund:",
-       "filerevert-defaultcomment": "Zurückgesetzt auf die Version vom $1, $2 Uhr",
+       "filerevert-defaultcomment": "Zurückgesetzt auf die Version vom $1, $2 Uhr ($3)",
        "filerevert-submit": "Zurücksetzen",
        "filerevert-success": "'''[[Media:$1|$1]]''' wurde auf die [$4 Version vom $2, $3 Uhr] zurückgesetzt.",
        "filerevert-badversion": "Es gibt keine Version der Datei zu dem angegebenen Zeitpunkt.",
        "nopagetext": "Die angegebene Seite ist nicht vorhanden.",
        "pager-newer-n": "{{PLURAL:$1|nächster|nächste $1}}",
        "pager-older-n": "{{PLURAL:$1|vorheriger|vorherige $1}}",
-       "suppress": "Oversight",
+       "suppress": "Unterdrücken",
        "querypage-disabled": "Diese Spezialseite wurde aus Gründen der Leistungserhaltung deaktiviert.",
        "apihelp": "API-Hilfe",
        "apihelp-no-such-module": "Modul „$1“ nicht gefunden.",
        "emailccsubject": "Kopie deiner Nachricht an $1: $2",
        "emailsent": "E-Mail verschickt",
        "emailsenttext": "Deine E-Mail wurde verschickt.",
-       "emailuserfooter": "Diese E-Mail wurde von „$1“ an „$2“ durch die Funktion „{{int:emailuser}}“ bei {{SITENAME}} gesendet.",
+       "emailuserfooter": "Diese E-Mail wurde von „$1“ an „{{GENDER:$2|$2}}“ durch die Funktion „{{int:emailuser}}“ bei {{SITENAME}} {{GENDER:$1|gesendet}}.",
        "usermessage-summary": "Systemnachricht gespeichert.",
        "usermessage-editor": "System-Messenger",
        "usermessage-template": "MediaWiki:Benutzernachricht",
        "deletepage": "Seite löschen",
        "confirm": "Bestätigen",
        "excontent": "Inhalt war: „$1“",
-       "excontentauthor": "Inhalt war: „$1“ (einziger Bearbeiter: [[Special:Contributions/$2|$2]])",
+       "excontentauthor": "Inhalt war: „$1“. Einziger Bearbeiter: [[Special:Contributions/$2|$2]] ([[User talk:$2|Diskussion]])",
        "exbeforeblank": "Inhalt vor dem Leeren der Seite: „$1“",
        "delete-confirm": "Löschen von „$1“",
        "delete-legend": "Löschen",
        "logentry-newusers-byemail": "Benutzerkonto $3 wurde von $1 {{GENDER:$2|erstellt}} und das Passwort wurde per E-Mail zugesandt",
        "logentry-newusers-autocreate": "Benutzerkonto $1 wurde automatisch {{GENDER:$2|erstellt}}",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|verschob}} die Schutzeinstellungen von $4 nach $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|entfernte}} den Schutz der Seite $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|schützte}} die Seite $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|schützte}} die Seite $3 $4 [kaskadierend]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|änderte}} den Schutzstatus der Seite $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|änderte}} den Schutzstatus der Seite $3 $4 [kaskadierend]",
        "logentry-rights-rights": "$1 {{GENDER:$2|änderte}} die Gruppenzugehörigkeit für $3 von $4 zu $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|änderte}} die Gruppenzugehörigkeit für $3",
        "logentry-rights-autopromote": "$1 wurde automatisch von $4 zu $5 {{GENDER:$2|zugeordnet}}",
index 76c1aad..88a6a34 100644 (file)
        "fileexists": "यै नामको फाइल पैल्ली नैं छ, यदि तम परिवर्तन गद्या कुरडीमू सुनिश्चित छैनौ भण्या कृपया <strong>[[:$1]]</strong> जाँच गर।\n[[$1|thumb]]",
        "filewasdeleted": "यै नामको एक फाइल पहिली पनि अपलोड गरिबर पछि हटाई सकियाको छ।\nपुनः अपलोड गद्दु पूर्व तम $1 लाई निक्करी जाँच गर ।",
        "upload-dialog-title": "चित्र अपलोड गर",
-       "upload-dialog-error": "गल्ती भयो",
-       "upload-dialog-warning": "सूचना हुनु",
        "upload-dialog-button-cancel": "रद्द",
        "upload-dialog-button-done": "सकियो",
        "upload-dialog-button-save": "सङ्ग्रह गद्या",
        "upload-dialog-button-upload": "अपलोड",
-       "upload-dialog-label-select-file": "फाइल छान",
-       "upload-dialog-label-infoform-title": "विवरण",
-       "upload-dialog-label-infoform-name": "नाऊ",
-       "upload-dialog-label-infoform-description": "बेलिविस्तार",
-       "upload-dialog-label-usage-title": "रिती",
-       "upload-dialog-label-usage-filename": "फाइल नाउ",
+       "upload-process-error": "गल्ती भयो",
+       "upload-process-warning": "सूचना हुनु",
+       "upload-form-label-select-file": "फाइल छान",
+       "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": "फाइल नाउ",
        "uploadstash-nofiles": "तमरा कोइ पनि स्टाश गर्याका फाइलहरू नाइथिन् ।",
        "uploadstash-badtoken": "त्यो कार्य असफलभयो , सायद तमरो सम्पादन अधिकार समाप्त भयो । पुन: प्रयास गर ।",
        "uploadstash-refresh": "फाइलहरूको सूची ताजा गर्न्या",
index 9620918..76c46c3 100644 (file)
@@ -42,7 +42,8 @@
                        "Milicevic01",
                        "Ah3kal",
                        "Macofe",
-                       "Stam.nikos"
+                       "Stam.nikos",
+                       "Giorgos456"
                ]
        },
        "tog-underline": "Υπογράμμιση συνδέσμων:",
        "nstab-template": "Πρότυπο",
        "nstab-help": "Σελίδα βοήθειας",
        "nstab-category": "Κατηγορία",
+       "mainpage-nstab": "Αρχική σελίδα",
        "nosuchaction": "Δεν υπάρχει τέτοια ενέργεια.",
        "nosuchactiontext": "Η ενέργεια που καθορίστηκε από την διεύθυνση URL δεν είναι έγκυρη.\nΕνδέχεται να πληκτρολογήσατε λανθασμένα την διεύθυνση URL ή να ακολουθήσατε έναν μη έγκυρο σύνδεσμο.\nΜπορεί επίσης να είναι σημάδι κάποιου σφάλματος του λογισμικού που χρησιμοποιεί ο ιστότοπος {{SITENAME}}.",
        "nosuchspecialpage": "Δεν υπάρχει τέτοια ειδική σελίδα",
        "upload-http-error": "Εμφανίστηκε κάποιο σφάλμα HTTP: $1",
        "upload-copy-upload-invalid-domain": "Δεν υπάρχουν διαθέσιμα ανεβάσματα αντιγράφων από αυτό τον τομέα.",
        "upload-dialog-title": "Ανέβασμα αρχείου",
-       "upload-dialog-error": "Ένα σφάλμα συνέβη",
-       "upload-dialog-warning": "Προέκυψε μία προειδοποίηση",
        "upload-dialog-button-cancel": "Ακύρωση",
        "upload-dialog-button-done": "Ολοκληρώθηκε",
        "upload-dialog-button-save": "Αποθήκευση",
        "upload-dialog-button-upload": "Ανέβασμα",
-       "upload-dialog-label-select-file": "Επιλογή αρχείου",
-       "upload-dialog-label-infoform-title": "Λεπτομέρειες",
-       "upload-dialog-label-infoform-name": "Όνομα",
-       "upload-dialog-label-infoform-description": "Περιγραφή",
-       "upload-dialog-label-usage-title": "Χρήση",
-       "upload-dialog-label-usage-filename": "Όνομα αρχείου",
+       "upload-process-error": "Ένα σφάλμα συνέβη",
+       "upload-process-warning": "Προέκυψε μία προειδοποίηση",
+       "upload-form-label-select-file": "Επιλογή αρχείου",
+       "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": "Όνομα αρχείου",
        "backend-fail-stream": "Αδύνατη η μετάδοση του αρχείου $1.",
        "backend-fail-backup": "Αδύνατη η δημιουργία αντίγραφου ασφαλείας του αρχείου $1.",
        "backend-fail-notexists": "Το αρχείο $1 δεν υπάρχει.",
index 3fc297c..0b17c78 100644 (file)
        "deletepage": "Delete page",
        "confirm": "Confirm",
        "excontent": "content was: \"$1\"",
-       "excontentauthor": "content was: \"$1\" (and the only contributor was \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "content was: \"$1\", and the only contributor was \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]])",
        "exbeforeblank": "content before blanking was: \"$1\"",
        "delete-confirm": "Delete \"$1\"",
        "delete-legend": "Delete",
        "htmlform-title-not-exists": "[[:$1]] does not exist.",
        "htmlform-user-not-exists": "<strong>$1</strong> does not exist.",
        "htmlform-user-not-valid": "<strong>$1</strong> isn't a valid username.",
+       "rawmessage": "$1",
        "sqlite-has-fts": "$1 with full-text search support",
        "sqlite-no-fts": "$1 without full-text search support",
        "logentry-delete-delete": "$1 {{GENDER:$2|deleted}} page $3",
        "logentry-newusers-byemail": "User account $3 was {{GENDER:$2|created}} by $1 and password was sent by email",
        "logentry-newusers-autocreate": "User account $1 was {{GENDER:$2|created}} automatically",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|moved}} protection settings from $4 to $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|removed}} protection from $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|protected}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|protected}} $3 $4 [cascading]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|changed}} protection level for $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|changed}} protection level for $3 $4 [cascading]",
        "logentry-rights-rights": "$1 {{GENDER:$2|changed}} group membership for $3 from $4 to $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|changed}} group membership for $3",
        "logentry-rights-autopromote": "$1 was automatically {{GENDER:$2|promoted}} from $4 to $5",
index 2dd6ab0..283af64 100644 (file)
        "createacct-captcha": "Comprobación de seguridad",
        "createacct-imgcaptcha-ph": "Escribe el texto de arriba",
        "createacct-submit": "Crea tu cuenta",
-       "createacct-another-submit": "Crear otra cuenta",
+       "createacct-another-submit": "Crear cuenta",
        "createacct-benefit-heading": "Personas como tú son las que construyen {{SITENAME}}.",
        "createacct-benefit-body1": "{{PLURAL:$1|edición|ediciones}}",
        "createacct-benefit-body2": "{{PLURAL:$1|página|páginas}}",
        "upload-http-error": "Ha ocurrido un error HTTP: $1",
        "upload-copy-upload-invalid-domain": "No se pueden realizar subidas remotas desde este dominio.",
        "upload-dialog-title": "Subir archivo",
-       "upload-dialog-error": "Ha ocurrido un error",
-       "upload-dialog-warning": "Ha ocurrido una advertencia",
        "upload-dialog-button-cancel": "Cancelar",
        "upload-dialog-button-done": "Hecho",
        "upload-dialog-button-save": "Guardar",
        "upload-dialog-button-upload": "Subir",
-       "upload-dialog-label-select-file": "Seleccionar archivo",
-       "upload-dialog-label-infoform-title": "Detalles",
-       "upload-dialog-label-infoform-name": "Nombre",
-       "upload-dialog-label-infoform-description": "Descripción",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nombre del archivo",
+       "upload-process-error": "Ha ocurrido un error",
+       "upload-process-warning": "Ha ocurrido una advertencia",
+       "upload-form-label-select-file": "Seleccionar archivo",
+       "upload-form-label-infoform-title": "Detalles",
+       "upload-form-label-infoform-name": "Nombre",
+       "upload-form-label-infoform-description": "Descripción",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nombre del archivo",
        "backend-fail-stream": "No se pudo transmitir el archivo «$1».",
        "backend-fail-backup": "No se pudo hacer copia de seguridad del archivo «$1».",
        "backend-fail-notexists": "El archivo  $1  no existe.",
        "filerevert-legend": "Reversión de archivos",
        "filerevert-intro": "Estás por revertir <strong>[[Media:$1|$1]]</strong> a la [$4 versión del $2 a las $3].",
        "filerevert-comment": "Motivo:",
-       "filerevert-defaultcomment": "Revertido a la versión subida el $1 a las $2",
+       "filerevert-defaultcomment": "Revertido a la versión del $1 a las $2 ($3)",
        "filerevert-submit": "Revertir",
        "filerevert-success": "<strong>[[Media:$1|$1]]</strong> ha sido revertido a la [$4 versión del $2 a las $3].",
        "filerevert-badversion": "No existe versión local previa de este archivo con esa marca de tiempo.",
        "nopagetext": "La página destino que has especificado no existe.",
        "pager-newer-n": "{{PLURAL:$1|1 siguiente|$1 siguientes}}",
        "pager-older-n": "{{PLURAL:$1|1 anterior|$1 anteriores}}",
-       "suppress": "Supresor de ediciones",
+       "suppress": "Supresor",
        "querypage-disabled": "Esta página especial está deshabilitada por motivos de rendimiento.",
        "apihelp": "Ayuda de la API",
        "apihelp-no-such-module": "No se encontró el módulo \"$1\".",
        "emailccsubject": "Copia de tu mensaje a $1: $2",
        "emailsent": "Correo electrónico enviado",
        "emailsenttext": "Se ha enviado tu mensaje de correo electrónico.",
-       "emailuserfooter": "Este correo electrónico fue enviado por $1 a $2 a través de la función «Enviar un correo electrónico a este usuario» en {{SITENAME}}.",
+       "emailuserfooter": "Este correo electrónico fue {{GENDER:$1|enviado}} por $1 a {{GENDER:$2|$2}} a través de la función «{{int:emailuser}}» en {{SITENAME}}.",
        "usermessage-summary": "Dejando un mensaje de sistema.",
        "usermessage-editor": "Mensajero del sistema",
        "watchlist": "Lista de seguimiento",
        "deletepage": "Borrar esta página",
        "confirm": "Confirmar",
        "excontent": "el contenido era: «$1»",
-       "excontentauthor": "el contenido era: «$1» (y el único autor fue «[[Special:Contributions/$2|$2]]»)",
+       "excontentauthor": "el contenido era: «$1», y el único autor fue «[[Special:Contributions/$2|$2]]» ([[User talk:$2|discusión]])",
        "exbeforeblank": "El contenido antes de blanquear era: «$1»",
        "delete-confirm": "Borrar «$1»",
        "delete-legend": "Borrar",
        "logentry-newusers-byemail": "La cuenta de usuario $3 ha sido {{GENDER:$2|creada}} por $1 y la contraseña ha sido enviada por correo",
        "logentry-newusers-autocreate": "La cuenta $1 se {{GENDER:$2|creó}} automáticamente",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|trasladó}} las preferencias de protección de $4 a $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|eliminó}} la protección de $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|protegió}} a $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|protegió}} a $3 $4 [en cascada]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|cambió}} el nivel de protección de $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|cambió}} el nivel de protección de $3 $4 [en cascada]",
        "logentry-rights-rights": "$1 modificó los grupos a los que pertenece $3: de $4 a $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|modificó}} los grupos a los que pertenece $3",
        "logentry-rights-autopromote": "$1 ha sido {{GENDER:$2|promocionado|promocionada}} automáticamente de $4 a $5",
index 65dd24f..2bd637b 100644 (file)
        "nstab-template": "Mall",
        "nstab-help": "Juhend",
        "nstab-category": "Kategooria",
+       "mainpage-nstab": "Esileht",
        "nosuchaction": "Sellist toimingut pole.",
        "nosuchactiontext": "Viki ei tunne internetiaadressile vastavat tegevust.\nVõimalik, et sa sisestasid aadressi valesti või kasutasid vigast linki.\nSamuti ei ole välistatud, et tarkvaras, mida {{SITENAME}} kasutatab, on viga.",
        "nosuchspecialpage": "Sellist erilehekülge pole.",
        "createacct-captcha": "Turvakontroll",
        "createacct-imgcaptcha-ph": "Sisesta ülalnähtav tekst",
        "createacct-submit": "Loo konto",
-       "createacct-another-submit": "Loo teine konto",
+       "createacct-another-submit": "Loo konto",
        "createacct-benefit-heading": "{{SITENAME}} on sinusuguste inimeste tehtud.",
        "createacct-benefit-body1": "{{PLURAL:$1|muudatus|muudatust}}",
        "createacct-benefit-body2": "{{PLURAL:$1|lehekülg|lehekülge}}",
        "changeemail-password": "Sinu parool {{GRAMMAR:inessive|{{SITENAME}}}}:",
        "changeemail-submit": "Muuda e-posti aadress",
        "changeemail-throttled": "Oled proovinud liiga palju kordi sisse logida.\nPalun oota $1, enne kui uuesti proovid.",
+       "changeemail-nochange": "Palun sisesta teistsugune uus e-posti aadress.",
        "resettokens": "Lubade lähtestamine",
        "resettokens-text": "Saad lähtestada load, mida on vaja siin sinu kontoga seotud kindlatele eraandmetele ligipääsuks.\n\nPeaksid load lähtestama, kui jagasid neid kogemata või kui su konto on kellegi teise võimusesse sattunud.",
        "resettokens-no-tokens": "Lähtestatavad load puuduvad.",
        "permissionserrorstext-withaction": "Sul pole lubatud {{lcfirst:$2}} {{PLURAL:$1|järgmisel põhjusel|järgmistel põhjustel}}:",
        "recreate-moveddeleted-warn": "'''Hoiatus: Lood uuesti lehekülge, mis on varem kustutatud.'''\n\nKaalu, kas lehekülje uuesti loomine on kohane.\nLehekülje eelnevad kustutamised ja teisaldamised:",
        "moveddeleted-notice": "See lehekülg on kustutatud.\nAllpool on esitatud lehekülje kustutamis- ja teisaldamislogi.",
+       "moveddeleted-notice-recent": "Kahjuks on see lehekülg hiljuti kustutatud (viimase 24 tunni jooksul).\nAllpool on ära toodud selle lehekülje sissekanded teisaldamis- ja kustutamislogis.",
        "log-fulllog": "Vaata kogu logi",
        "edit-hook-aborted": "Laiendusliides katkestas muutmise täpsemat selgitust andmata.",
        "edit-gone-missing": "Polnud võimalik lehekülge uuendada.\nTundub, et see on kustutatud.",
        "upload-http-error": "HTTP-viga: $1",
        "upload-copy-upload-invalid-domain": "Sellest domeenist pole kopeerimise teel üleslaadimine võimalik.",
        "upload-dialog-title": "Faili üleslaadimine",
-       "upload-dialog-error": "Esines tõrge",
-       "upload-dialog-warning": "Esines hoiatus",
        "upload-dialog-button-cancel": "Loobu",
        "upload-dialog-button-done": "Valmis",
        "upload-dialog-button-save": "Salvesta",
        "upload-dialog-button-upload": "Laadi üles",
-       "upload-dialog-label-select-file": "Vali fail",
-       "upload-dialog-label-infoform-title": "Üksikasjad",
-       "upload-dialog-label-infoform-name": "Pealkiri",
-       "upload-dialog-label-infoform-description": "Kirjeldus",
-       "upload-dialog-label-usage-title": "Kasutus",
-       "upload-dialog-label-usage-filename": "Failinimi",
+       "upload-process-error": "Esines tõrge",
+       "upload-process-warning": "Esines hoiatus",
+       "upload-form-label-select-file": "Vali fail",
+       "upload-form-label-infoform-title": "Üksikasjad",
+       "upload-form-label-infoform-name": "Pealkiri",
+       "upload-form-label-infoform-description": "Kirjeldus",
+       "upload-form-label-usage-title": "Kasutus",
+       "upload-form-label-usage-filename": "Failinimi",
        "backend-fail-stream": "Faili $1 ei saanud edastada.",
        "backend-fail-backup": "Faili $1 ei saanud varundada.",
        "backend-fail-notexists": "Faili $1 pole olemas.",
        "filerevert-legend": "Faili taastamine",
        "filerevert-intro": "Sa taastad faili '''[[Media:$1|$1]]''' seisuga [$4 $3, $2] kasutusel olnud versiooni.",
        "filerevert-comment": "Põhjus:",
-       "filerevert-defaultcomment": "Ennistati versioon seisuga $1, kell $2",
+       "filerevert-defaultcomment": "Ennistati versioon seisuga $1, kell $2 ($3)",
        "filerevert-submit": "Taasta",
        "filerevert-success": "Faili '''[[Media:$1|$1]]''' seisuga [$4 $3, $2 kasutusel olnud versioon] on taastatud.",
        "filerevert-badversion": "Ette antud ajatempliga kohalik versioon sellest failist puudub.",
        "deletepage": "Kustuta lehekülg",
        "confirm": "Kinnita",
        "excontent": "sisu oli: '$1'",
-       "excontentauthor": "sisu oli: '$1' (ja ainuke kirjutaja oli '[[Special:Contributions/$2|$2]]')",
+       "excontentauthor": "sisu oli: \"$1\"; ainuke kirjutaja oli \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|arutelu]])",
        "exbeforeblank": "sisu enne lehekülje tühjendamist: '$1'",
        "delete-confirm": "Lehekülje \"$1\" kustutamine",
        "delete-legend": "Kustutamine",
        "logentry-newusers-byemail": "$1 {{GENDER:$2|lõi}} kasutajakonto $3 ja parool saadeti e-kirjatsi",
        "logentry-newusers-autocreate": "Konto $1 {{GENDER:$2|loodi}} automaatselt",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|teisaldas}} kaitsesätted leheküljelt $4 leheküljele $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|eemaldas}} lehekülje $3 kaitse",
+       "logentry-protect-protect": "$1 {{GENDER:$2|kaitses}} lehekülje $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|kaitses}} lehekülje $3 $4 [kaskaadkaitse]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|muutis}} lehekülje $3 kaitsetaset $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|muutis}} lehekülje $3 kaitsetaset $4 [kaskaadkaitse]",
        "logentry-rights-rights": "$1 {{GENDER:$2|muutis}} kasutaja $3 rühmaliikmesust; enne oli $4, nüüd on $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|muutis}} kasutaja $3 rühmaliikmesust",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|viidi}} automaatselt üle teise rühma; enne oli $4, nüüd on $5",
        "api-error-badaccess-groups": "Sul pole selles vikis üleslaadimisõigust.",
        "api-error-badtoken": "Sisemine tõrge: Sobimatu nimi.",
        "api-error-copyuploaddisabled": "URLi kaudu üleslaadimine on selles serveris keelatud.",
-       "api-error-duplicate": "Siin on {{PLURAL:$1|[$2 teine samasisuline fail]|[$2 mõned teised samasisulised failid]}} juba olemas.",
+       "api-error-duplicate": "Siin on {{PLURAL:$1|teine samasisuline fail|mõned teised samasisulised failid}} juba olemas.",
        "api-error-duplicate-archive": "Siin {{PLURAL:$1|on teine samasisuline fail|olid mõned teised samasisulised failid}} juba olemas, aga {{PLURAL:$1|see|need}} kustutati.",
        "api-error-empty-file": "Üleslaaditav fail on tühi.",
        "api-error-emptypage": "Uute tühjade lehekülgede loomine pole lubatud.",
index 79fbcbe..59ffe63 100644 (file)
        "nstab-help": "Laguntza orrialdea",
        "nstab-category": "Kategoria",
        "mainpage-nstab": "Azala",
-       "nosuchaction": "Ekintza hori ez da existitizen",
+       "nosuchaction": "Ekintza hori ez da existitzen",
        "nosuchactiontext": "URL bidez zehaztutako ekintza okerra da.\nURLa gaizki idatzi duzu, edo hautsitako lotura jarraitu duzu.\nHonek akatsa indikatzen du {{SITENAME}}-(e)n.",
-       "nosuchspecialpage": "Ez da aparteko orrialde hori existitzen",
+       "nosuchspecialpage": "Orri berezi hori ez existitzen",
        "nospecialpagetext": "<strong>Orri berezi baliogabe bat eskatu duzu.</strong>\n\nBada orri berezien zerrenda bat, [[Special:SpecialPages|{{int:specialpages}}]] orrian.",
        "error": "Errorea",
        "databaseerror": "Datu-base errorea",
        "createacct-captcha": "Segurtasun froga",
        "createacct-imgcaptcha-ph": "Sartu gainean ikusten duzun testua",
        "createacct-submit": "Kontua sortu",
-       "createacct-another-submit": "Beste kontu bat sortu",
+       "createacct-another-submit": "Kontu bat sortu",
        "createacct-benefit-heading": "{{SITENAME}} zu bezalako pertsonek egiten dute.",
        "createacct-benefit-body1": "{{PLURAL:$1|edizio bat|$1 edizio}}",
        "createacct-benefit-body2": "{{PLURAL:$1|Orrialde 1|$1 orrialde}}",
        "rev-deleted-text-permission": "Orrialdearen berrikuspen hau '''ezabatua''' izan da.\nXehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus daitezke.",
        "rev-deleted-text-unhide": "Orriaren bertsio hau '''ezabatu''' da.\nXehetasunak ikusgai daude [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabatze erregistroan].\nAdministratzailea zarenez, oraindik [$1 bertsio hau ikus dezakezu], nahi izanez gero.",
        "rev-suppressed-text-unhide": "Orriaren bertsio hau '''ezeztatu''' da.\nXehetasunak ikusgai daude [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ezeztatze erregistroan].\nAdministratzailea zarenez, oraindik [$1 bertsio hau ikus dezakezu], nahi izanez gero.",
-       "rev-deleted-text-view": "Orrialdearen berrikuspen hau '''ezabatua''' izan da.\nZuk ikusteko aukera daukazu; xehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus ditzakezu.",
+       "rev-deleted-text-view": "Orriaren berrikuspen hau '''ezabatua''' izan da.\nZuk ikusteko aukera daukazu; xehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus ditzakezu.",
        "rev-suppressed-text-view": "Berrikuspen hau '''ezabatua''' izan da.\nAdministratzaile bezala ikus dezakezu; xehetasun gehiagorako [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ezabapen erregistrora joan].",
        "rev-deleted-no-diff": "Ezin duzu ezberdintasun hau ikusi, berrikuspenetako bat '''ezabatua''' izan delako.\nXehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] aurki ditzakezu.",
        "rev-suppressed-no-diff": "Ezin duzu ezberdintasunik ikusi berrikuspenen bat '''ezabatua''' izan delako.",
        "upload-http-error": "HTTP errorea gertatu da: $1",
        "upload-copy-upload-invalid-domain": "Domeinu honetan ezin dira igoerak kopiatu.",
        "upload-dialog-title": "Igo fitxategia",
-       "upload-dialog-error": "Errore bat gertatu da",
        "upload-dialog-button-cancel": "Utzi",
        "upload-dialog-button-done": "Egina",
        "upload-dialog-button-save": "Gorde",
        "upload-dialog-button-upload": "Igo",
-       "upload-dialog-label-select-file": "Fitxategia Aukeratu",
-       "upload-dialog-label-infoform-title": "Xehetasunak",
-       "upload-dialog-label-infoform-name": "Izena",
-       "upload-dialog-label-infoform-description": "Deskribapena",
-       "upload-dialog-label-usage-title": "Erabilera",
-       "upload-dialog-label-usage-filename": "Fitxategiaren izena",
+       "upload-process-error": "Errore bat gertatu da",
+       "upload-form-label-select-file": "Fitxategia Aukeratu",
+       "upload-form-label-infoform-title": "Xehetasunak",
+       "upload-form-label-infoform-name": "Izena",
+       "upload-form-label-infoform-description": "Deskribapena",
+       "upload-form-label-usage-title": "Erabilera",
+       "upload-form-label-usage-filename": "Fitxategiaren izena",
        "backend-fail-stream": "Ezin izan da \"$1\" fitxategiaren stream egin.",
        "backend-fail-backup": "Ezin izan da \"$1\" fitxategiaren backup egin.",
        "backend-fail-notexists": "$1 fitxategia ez da existitzen.",
        "undeletedrevisions-files": "{{PLURAL:$1|berrikuspen|berrikuspen}} eta {{PLURAL:$2|fitxategi|fitxategi}} leheneratu dira",
        "undeletedfiles": "{{PLURAL:$1|fitxategi|fitxategi}} leheneratu dira",
        "cannotundelete": "Ezabatutako birgaitzean akatsa: $1",
-       "undeletedpage": "'''$1 leheneratu egin da'''\n\n[[Special:Log/delete|Ezabaketa erregistrora]] jo azken ezabaketa eta leheneraketak ikusteko.",
-       "undelete-header": "Berriki ezabatutako orrialdeak ikusteko [[Special:Log/delete|ezabaketa erregistrora]] jo.",
+       "undeletedpage": "'''«$1» leheneratu da'''\n\nAzken ezabatze eta leheneratzeak ikusteko, jo ezazu [[Special:Log/delete|ezabaketa erregistrora]].",
+       "undelete-header": "Berriki ezabatutako orriak ikusteko, jo ezazu [[Special:Log/delete|ezabaketa erregistrora]].",
        "undelete-search-title": "Ezabatutako orrialdeak bilatu",
        "undelete-search-box": "Ezabatutako orrialdeak bilatu",
        "undelete-search-prefix": "Honela hasten diren orrialdeak erakutsi:",
        "tooltip-ca-nstab-main": "Eduki orrialdea ikusi",
        "tooltip-ca-nstab-user": "Lankide orrialdea ikusi",
        "tooltip-ca-nstab-media": "Media orrialdea ikusi",
-       "tooltip-ca-nstab-special": "Hau aparteko orrialde bat da, ezin duzu orrialdea aldatu.",
+       "tooltip-ca-nstab-special": "Hau orri berezi bat da, ezin duzu orria aldatu.",
        "tooltip-ca-nstab-project": "Proiektuaren orrialdea ikusi",
        "tooltip-ca-nstab-image": "Irudiaren orrialdea ikusi",
        "tooltip-ca-nstab-mediawiki": "Sistemaren mezua ikusi",
        "compare-rev2": "2. berrikuspena",
        "compare-submit": "Alderatu",
        "compare-invalid-title": "Zehaztutako izenburua ez dago zuzen.",
-       "compare-title-not-exists": "Zehazturiko izenburua ez da existitzen.",
+       "compare-title-not-exists": "Adierazi duzun izenburua ez da existitzen.",
        "compare-revision-not-exists": "Zehazturiko berrikuspena ez da existitzen.",
        "dberr-problems": "Barkatu! Webgune honek zailtasun teknikoak jasaten ari da.",
        "dberr-again": "Saiatu pare bat minutu itxaroten edo kargatu ezazu orrialdea berriro.",
index 3529566..4bb6b81 100644 (file)
        "protectedpage": "Página protegia",
        "jumpto": "Sartal a:",
        "jumptonavigation": "Güiquipeandu",
-       "jumptosearch": "Landeal",
+       "jumptosearch": "landeal",
        "aboutsite": "Al tentu {{SITENAME}}",
        "aboutpage": "Project:Enjolmación",
        "copyright": "Continiu disponibri bahu $1.",
        "nstab-template": "Prantilla",
        "nstab-help": "Páhina d'ayua",
        "nstab-category": "Categoria",
+       "mainpage-nstab": "Página prencipal",
        "nosuchaction": "Nu desisti tal ación",
        "nosuchactiontext": "La URL nu es vália.\nEs possibri que aigas marrau escribiendu la direción, u aigas siguiu un atiju encorretu.\nTamién es possibri que se trati dun marru entelnu de {{SITENAME}}.\nespecificá ena URL",
        "nosuchspecialpage": "Nu desisti tal páhina especial",
        "group-sysop": "Çahorilis",
        "group-bureaucrat": "Alministraoris",
        "group-all": "(tó)",
-       "group-user-member": "{{GENDER:$1|Usuáriu}}",
-       "group-autoconfirmed-member": "Usuáriu autuconfirmau",
+       "group-user-member": "{{GENDER:$1|usuáriu|usuária}}",
+       "group-autoconfirmed-member": "{{GENDER:$1|usuáriu autuconfirmau|usuária autoconfirmada}}",
        "group-bot-member": "Bot",
        "group-sysop-member": "Çahoril",
        "group-bureaucrat-member": "Alministraol",
        "namespace": "Espáciu de nombris:",
        "invert": "Invertil seleción",
        "blanknamespace": "(Prencipal)",
-       "contributions": "Endirguis el usuáriu",
+       "contributions": "Endirguis {{GENDER:$1|el usuáriu|la usuária}}",
        "contributions-title": "Contribucionis del usuáriu a $1",
        "mycontris": "Los mis endirguis",
        "contribsub2": "Pa $1 ($2)",
        "iranian-calendar-m10": "10 mes Jalāli",
        "iranian-calendar-m11": "11 mes Jalāli",
        "iranian-calendar-m12": "12 mes Jalāli",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|caraba]])",
        "version": "Velsión",
        "version-extensions": "Estensionis istalás",
        "version-specialpages": "Páhinas especialis",
index e94a443..a163ddb 100644 (file)
        "upload-http-error": "یک خطای اچ‌تی‌تی‌پی رخ داد: $1",
        "upload-copy-upload-invalid-domain": "بارگذاری کپی پرونده‌ها از این دامنه امکان‌پذیر نیست.",
        "upload-dialog-title": "بارگذاری پرونده",
-       "upload-dialog-error": "يک خطا اتفاق افتاد",
-       "upload-dialog-warning": "یک هشدار رخ‌داد",
        "upload-dialog-button-cancel": "لغو",
        "upload-dialog-button-done": "انجام شد",
        "upload-dialog-button-save": "ذخیره",
        "upload-dialog-button-upload": "بارگذاری",
-       "upload-dialog-label-select-file": "یک فایل انتخاب کنید",
-       "upload-dialog-label-infoform-title": "جزئیات",
-       "upload-dialog-label-infoform-name": "نام",
-       "upload-dialog-label-infoform-description": "توضیحات",
-       "upload-dialog-label-usage-title": "کاربرد",
-       "upload-dialog-label-usage-filename": "نام پرونده",
+       "upload-process-error": "يک خطا اتفاق افتاد",
+       "upload-process-warning": "یک هشدار رخ‌داد",
+       "upload-form-label-select-file": "یک فایل انتخاب کنید",
+       "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": "نام پرونده",
        "backend-fail-stream": "نمی‌توان پروندهٔ $1 را ارسال کرد.",
        "backend-fail-backup": "نمی‌توان نسخهٔ پشتیبان برای پروندهٔ $1 ایجاد کرد.",
        "backend-fail-notexists": "پروندهٔ $1 وجود ندارد.",
index 3966983..3ffffd6 100644 (file)
        "nstab-template": "Malline",
        "nstab-help": "Ohjesivu",
        "nstab-category": "Luokka",
+       "mainpage-nstab": "Etusivu",
        "nosuchaction": "Toimintoa ei ole olemassa",
        "nosuchactiontext": "URL:ssä määritelty toiminto ei ole kelvollinen.\nOlet saattanut kirjoittaa URL:in väärin tai olet seurannut virheellistä linkkiä.\nKyseessä voi myös mahdollisesti olla virhe sivuston {{SITENAME}} käyttämässä ohjelmistossa.",
        "nosuchspecialpage": "Kyseistä toimintosivua ei ole",
        "createacct-captcha": "Turvatarkastus",
        "createacct-imgcaptcha-ph": "Kirjoita teksti, jonka näet edellä",
        "createacct-submit": "Luo tunnus",
-       "createacct-another-submit": "Luo toinen käyttäjätunnus",
+       "createacct-another-submit": "Luo käyttäjätunnus",
        "createacct-benefit-heading": "{{SITENAME}} on sinun kaltaistesi ihmisten tekemä.",
        "createacct-benefit-body1": "{{PLURAL:$1|muokkaus|muokkausta}}",
        "createacct-benefit-body2": "{{PLURAL:$1|sivu|sivua}}",
        "changeemail-password": "{{SITENAME}}-salasanasi:",
        "changeemail-submit": "Muuta sähköpostiosoite",
        "changeemail-throttled": "Olet tehnyt liian monta kirjautumisyritystä.\nOdota $1 ennen kuin yrität uudelleen.",
+       "changeemail-nochange": "Anna joku toinen sähköpostiosoite.",
        "resettokens": "Uudista avaimet",
        "resettokens-text": "Tällä sivulla voit uudistaa avaimesi (''eng.'' reset tokens), jotka mahdollistavat pääsyn käyttäjätunnukseesi liittyviin tiettyihin yksityisiin tietoihin.\n\nSinun pitäisi tehdä tämä, jos olet vahingossa jakanut avaimet jonkun kanssa tai jos käyttäjätunnuksesi on vaarannettu.",
        "resettokens-no-tokens": "Avaimia ei ole uudistettavaksi.",
        "permissionserrorstext-withaction": "Sinulla ei ole oikeutta {{lcfirst:$2}} {{PLURAL:$1|seuraavasta syystä|seuraavista syistä}}:",
        "recreate-moveddeleted-warn": "'''Varoitus: Olet luomassa sellaista sivua, joka on aikaisemmin poistettu.'''\n\nHarkitse, kannattaako tätä sivua luoda uudelleen. \nAlla on tämän sivun poisto- ja siirtohistoria:",
        "moveddeleted-notice": "Tämä sivu on poistettu. Alla on tämän sivun poisto- ja siirtohistoria.",
+       "moveddeleted-notice-recent": "Valitettavasti tämä sivu on poistettu aivan äskettäin (viimeisen 24 tunnin aikana).\nAlla näkyy sivun poisto- ja siirtolokin tietoja.",
        "log-fulllog": "Näytä loki kokonaan",
        "edit-hook-aborted": "Laajennuskoodi esti muokkauksen antamatta syytä.",
        "edit-gone-missing": "Sivun päivitys ei onnistunut.\nSe on ilmeisesti poistettu.",
        "upload-http-error": "HTTP-virhe: $1",
        "upload-copy-upload-invalid-domain": "Tiedostojen tallentamista tästä verkko-osoitteesta ei ole sallittu.",
        "upload-dialog-title": "Tiedoston tallennus",
-       "upload-dialog-error": "Tapahtui virhe",
-       "upload-dialog-warning": "Sisältää varoituksen",
        "upload-dialog-button-cancel": "Peru",
        "upload-dialog-button-done": "Valmis",
        "upload-dialog-button-save": "Tallenna",
        "upload-dialog-button-upload": "Tallenna",
-       "upload-dialog-label-select-file": "Valitse tiedosto",
-       "upload-dialog-label-infoform-title": "Yksityiskohdat",
-       "upload-dialog-label-infoform-name": "Nimi",
-       "upload-dialog-label-infoform-description": "Kuvaus",
-       "upload-dialog-label-usage-title": "Käyttö",
-       "upload-dialog-label-usage-filename": "Tiedostonimi",
+       "upload-process-error": "Tapahtui virhe",
+       "upload-process-warning": "Sisältää varoituksen",
+       "upload-form-label-select-file": "Valitse tiedosto",
+       "upload-form-label-infoform-title": "Yksityiskohdat",
+       "upload-form-label-infoform-name": "Nimi",
+       "upload-form-label-infoform-description": "Kuvaus",
+       "upload-form-label-usage-title": "Käyttö",
+       "upload-form-label-usage-filename": "Tiedostonimi",
        "backend-fail-stream": "Tiedoston $1 virtauttaminen epäonnistui.",
        "backend-fail-backup": "Tiedostoa $1 ei voitu varmuuskopioida.",
        "backend-fail-notexists": "Tiedostoa $1 ei ole olemassa.",
        "filerevert-legend": "Tiedoston palautus",
        "filerevert-intro": "Olet palauttamassa takaisin tiedostoa '''[[Media:$1|$1]]''' [$4 versioon, joka luotiin $2 kello $3].",
        "filerevert-comment": "Syy:",
-       "filerevert-defaultcomment": "Palautettiin takaisin versioon, joka luotiin $1 kello $2 (UTC)",
+       "filerevert-defaultcomment": "Palautettiin takaisin versioon, joka tehtiin $1 kello $2 ($3)",
        "filerevert-submit": "Suorita palauttaminen",
        "filerevert-success": "'''[[Media:$1|$1]]''' on palautettu takaisin [$4 versioon, joka luotiin $2 kello $3].",
        "filerevert-badversion": "Tiedostosta ei ole luotu versiota kyseisellä ajan hetkellä.",
        "emailccsubject": "Kopio lähettämästäsi viestistä osoitteeseen $1: $2",
        "emailsent": "Sähköposti lähetetty",
        "emailsenttext": "Sähköpostiviestisi on lähetetty.",
-       "emailuserfooter": "Tämän sähköpostin lähetti $1 vastaanottajalle $2 käyttämällä ”{{int:emailuser}}” -toimintoa {{GRAMMAR:inessive|{{SITENAME}}}}.",
+       "emailuserfooter": "Tämän sähköpostin {{GENDER:$1|lähetti}} $1 vastaanottajalle {{GENDER:$2|$2}} käyttämällä ”{{int:emailuser}}” -toimintoa {{GRAMMAR:inessive|{{SITENAME}}}}.",
        "usermessage-summary": "Jätetään järjestelmäviesti.",
        "usermessage-editor": "Järjestelmäviestittäjä",
        "watchlist": "Tarkkailulista",
        "deletepage": "Poista sivu",
        "confirm": "Toteuta",
        "excontent": "sisälsi: ”$1”",
-       "excontentauthor": "sisälsi: ”$1” (ainoa muokkaaja oli $2)",
+       "excontentauthor": "sisältö oli: \"$1\", ja ainoa muokkaaja oli \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|keskustelu]])",
        "exbeforeblank": "ennen tyhjentämistä sisälsi: ”$1”",
        "delete-confirm": "Poista ”$1”",
        "delete-legend": "Sivun poisto",
        "logentry-newusers-byemail": "$1 {{GENDER:$2|loi}} käyttäjätunnuksen $3 ja salasana lähetettiin sähköpostitse",
        "logentry-newusers-autocreate": "Käyttäjätunnus $1 {{GENDER:$2|luotiin}} automaattisesti",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|siirsi}} suojauksen asetukset sivulta $4 sivulle $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|otti pois}} suojauksen kohteesta $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|suojasi}} kohteen $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|suojasi}} kohteen $3 $4 [tarttuvasti]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|muutti}} suojauksen tasoa kohteessa $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|muutti}} suojauksen tasoa kohteessa $3 $4 [tarttuvasti]",
        "logentry-rights-rights": "$1 {{GENDER:$2|muutti}} käyttäjän $3 oikeudet ryhmistä $4 ryhmiin $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|muutti}} käyttäjän $3 jäsenyyttä ryhmässä",
        "logentry-rights-autopromote": "Käyttäjän $1 oikeudet {{GENDER:$2|muuttuivat}} automaattisesti ryhmistä $4 ryhmiin $5",
        "api-error-badaccess-groups": "Sinulla ei ole oikeutta tallentaa tiedostoja tähän wikiin.",
        "api-error-badtoken": "Sisäinen virhe: virheellinen tarkistussumma.",
        "api-error-copyuploaddisabled": "Tallentaminen URL-osoitteesta ei ole käytössä.",
-       "api-error-duplicate": "Samansisältöisiä tiedostoja löytyi {{PLURAL:$1|[$2 yksi kappale]|[$2 useampia kappaleita]}}.",
+       "api-error-duplicate": "Samansisältöisiä tiedostoja löytyi {{PLURAL:$1|[yksi kappale]|[useampia kappaleita]}}.",
        "api-error-duplicate-archive": "Sivustolla oli aiemmin {{PLURAL:$1|toinen samansisältöinen tiedosto|toisia samansisältöisiä tiedostoja}}, mutta {{PLURAL:$1|se|ne}} poistettiin.",
        "api-error-empty-file": "Määrittämäsi tiedosto on tyhjä.",
        "api-error-emptypage": "Ei ole sallittua luoda uutta, tyhjää sivua.",
index 7eb3b97..5a9ebd3 100644 (file)
        "createacct-captcha": "Contrôle de sécurité",
        "createacct-imgcaptcha-ph": "Entrez le texte que vous voyez ci-dessus",
        "createacct-submit": "Créez votre compte",
-       "createacct-another-submit": "Créer un autre compte",
+       "createacct-another-submit": "Créer le compte",
        "createacct-benefit-heading": "{{SITENAME}} est écrit par des gens comme vous.",
        "createacct-benefit-body1": "{{PLURAL:$1|modification|modifications}}",
        "createacct-benefit-body2": "{{PLURAL:$1|article|articles}}",
        "group-bot": "Robots",
        "group-sysop": "Administrateurs",
        "group-bureaucrat": "Bureaucrates",
-       "group-suppress": "Superviseurs",
+       "group-suppress": "Limitateurs",
        "group-all": "(tous)",
        "group-user-member": "{{GENDER:$1|utilisateur|utilisatrice}}",
        "group-autoconfirmed-member": "{{GENDER:$1|utilisateur enregistré|utilisatrice enregistrée}}",
        "group-bot-member": "{{GENDER:$1|robot}}",
        "group-sysop-member": "{{GENDER:$1|administrateur|administratrice}}",
        "group-bureaucrat-member": "{{GENDER:$1|bureaucrate}}",
-       "group-suppress-member": "{{GENDER:$1|superviseur|superviseuse}}",
+       "group-suppress-member": "{{GENDER:$1|limitateur|limitatrice}}",
        "grouppage-user": "{{ns:project}}:Utilisateurs",
        "grouppage-autoconfirmed": "{{ns:project}}:Utilisateurs enregistrés",
        "grouppage-bot": "{{ns:project}}:Robots",
        "grouppage-sysop": "{{ns:project}}:Administrateurs",
        "grouppage-bureaucrat": "{{ns:project}}:Bureaucrates",
-       "grouppage-suppress": "{{ns:project}}:Superviseurs",
+       "grouppage-suppress": "{{ns:project}}:Suppress",
        "right-read": "Lire les pages",
        "right-edit": "Modifier les pages",
        "right-createpage": "Créer des pages (qui ne sont pas des pages de discussion)",
        "upload-http-error": "Une erreur HTTP est survenue : $1",
        "upload-copy-upload-invalid-domain": "La copie des téléversements n’est pas disponible depuis ce domaine.",
        "upload-dialog-title": "Téléverser un fichier",
-       "upload-dialog-error": "Une erreur est survenue",
-       "upload-dialog-warning": "Un avertissement s’est produit",
        "upload-dialog-button-cancel": "Annuler",
        "upload-dialog-button-done": "Fait",
        "upload-dialog-button-save": "Enregistrer",
        "upload-dialog-button-upload": "Téléverser",
-       "upload-dialog-label-select-file": "Sélectionner un fichier",
-       "upload-dialog-label-infoform-title": "Détails",
-       "upload-dialog-label-infoform-name": "Nom",
-       "upload-dialog-label-infoform-description": "Description",
-       "upload-dialog-label-usage-title": "Utilisation",
-       "upload-dialog-label-usage-filename": "Nom du fichier",
+       "upload-process-error": "Une erreur est survenue",
+       "upload-process-warning": "Un avertissement s’est produit",
+       "upload-form-label-select-file": "Sélectionner un fichier",
+       "upload-form-label-infoform-title": "Détails",
+       "upload-form-label-infoform-name": "Nom",
+       "upload-form-label-infoform-description": "Description",
+       "upload-form-label-usage-title": "Utilisation",
+       "upload-form-label-usage-filename": "Nom du fichier",
        "backend-fail-stream": "Impossible de lire le fichier $1.",
        "backend-fail-backup": "Impossible de sauvegarder le fichier $1.",
        "backend-fail-notexists": "Le fichier $1 n’existe pas.",
        "filerevert-legend": "Rétablir le fichier",
        "filerevert-intro": "Vous êtes sur le point de rétablir le fichier '''[[Media:$1|$1]]''' à la [$4 version du $2 à $3].",
        "filerevert-comment": "Motif :",
-       "filerevert-defaultcomment": "Version du $1 à $2 rétablie",
+       "filerevert-defaultcomment": "Retour sur la version du $2, $1 ($3)",
        "filerevert-submit": "Rétablir",
        "filerevert-success": "'''[[Media:$1|$1]]''' a été rétabli à [$4 la version du $2 à $3].",
        "filerevert-badversion": "Il n'y a pas localement de version antérieure du fichier qui porte la date indiquée.",
        "nopagetext": "La page cible que vous avez indiquée n'existe pas.",
        "pager-newer-n": "{{PLURAL:$1|plus récente|$1 plus récentes}}",
        "pager-older-n": "{{PLURAL:$1|plus ancienne|$1 plus anciennes}}",
-       "suppress": "Superviser",
+       "suppress": "Supprimer",
        "querypage-disabled": "Cette page spéciale est désactivée pour des raisons de performances.",
        "apihelp": "Aide de l’API",
        "apihelp-no-such-module": "Le module « $1 » est introuvable.",
        "deletepage": "Supprimer la page",
        "confirm": "Confirmer",
        "excontent": "contenait « $1 »",
-       "excontentauthor": "contenait « $1 » (et son seul contributeur était [[Special:Contributions/$2|$2]])",
+       "excontentauthor": "contenait « $1 » et son seul contributeur était [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]])",
        "exbeforeblank": "contenait avant blanchiment « $1 »",
        "delete-confirm": "Supprimer « $1 »",
        "delete-legend": "Supprimer",
        "logentry-newusers-byemail": "Le compte utilisateur $3 {{GENDER:$2|a été créé}} par $1 et le mot de passe a été envoyé par courriel",
        "logentry-newusers-autocreate": "Le compte $1 {{GENDER:$2|a été créé}} automatiquement",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|a déplacé}} les paramètres de protection de $4 vers $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|a supprimé}} la protection de $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|a protégé}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|a protégé}} $3 $4 [protection en cascade]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|a modifié}} le niveau de protection de $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|a modifié}} le niveau de protection de $3 $4 [protection en cascade]",
        "logentry-rights-rights": "$1 {{GENDER:$2|a modifié}} l'appartenance au groupe pour $3 de $4 à $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|a modifié}} l'appartenance au groupe pour $3",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|a été promu}} automatiquement de $4 à $5",
index 5b6b18c..4d693bf 100644 (file)
        "upload-http-error": "Diar as en HTTP-feeler mä: $1",
        "upload-copy-upload-invalid-domain": "Kopiin faan datein kön faan detdiar domeen ei huuchschüürd wurd.",
        "upload-dialog-title": "Datei huuchschüür",
-       "upload-dialog-error": "Diar as wat skiaf gingen",
-       "upload-dialog-warning": "Diar as en wäärnang kimen",
        "upload-dialog-button-cancel": "Ufbreeg",
        "upload-dialog-button-done": "Klaar",
        "upload-dialog-button-save": "Seekre",
        "upload-dialog-button-upload": "Huuchschüür",
-       "upload-dialog-label-select-file": "Datei ütjschük",
-       "upload-dialog-label-infoform-title": "Enkelthaiden",
-       "upload-dialog-label-infoform-name": "Nööm",
-       "upload-dialog-label-infoform-description": "Beskriiwang",
-       "upload-dialog-label-usage-title": "Brük",
-       "upload-dialog-label-usage-filename": "Dateinööm",
+       "upload-process-error": "Diar as wat skiaf gingen",
+       "upload-process-warning": "Diar as en wäärnang kimen",
+       "upload-form-label-select-file": "Datei ütjschük",
+       "upload-form-label-infoform-title": "Enkelthaiden",
+       "upload-form-label-infoform-name": "Nööm",
+       "upload-form-label-infoform-description": "Beskriiwang",
+       "upload-form-label-usage-title": "Brük",
+       "upload-form-label-usage-filename": "Dateinööm",
        "backend-fail-stream": "Det datei $1 küd ei auerdraanj wurd.",
        "backend-fail-backup": "Det datei $1 küd ei seekert wurd.",
        "backend-fail-notexists": "Det datei $1 jaft at ei.",
index bb52e39..18d854f 100644 (file)
        "upload-http-error": "Produciuse un erro HTTP: $1",
        "upload-copy-upload-invalid-domain": "A copia de cargas non está dispoñible neste dominio.",
        "upload-dialog-title": "Subir un ficheiro",
-       "upload-dialog-error": "Houbo un erro",
-       "upload-dialog-warning": "Produciuse unha advertencia",
        "upload-dialog-button-cancel": "Cancelar",
        "upload-dialog-button-done": "Feito",
        "upload-dialog-button-save": "Gardar",
        "upload-dialog-button-upload": "Subir",
-       "upload-dialog-label-select-file": "Seleccionar un ficheiro",
-       "upload-dialog-label-infoform-title": "Detalles",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrición",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nome do ficheiro",
+       "upload-process-error": "Houbo un erro",
+       "upload-process-warning": "Produciuse unha advertencia",
+       "upload-form-label-select-file": "Seleccionar un ficheiro",
+       "upload-form-label-infoform-title": "Detalles",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrición",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nome do ficheiro",
        "backend-fail-stream": "Non se puido transmitir o ficheiro \"$1\".",
        "backend-fail-backup": "Non se puido facer unha copia de seguridade do ficheiro \"$1\".",
        "backend-fail-notexists": "O ficheiro \"$1\" non existe.",
index f0a9a4e..f1eea2e 100644 (file)
        "upload-http-error": "E HTTP-Fähler isch ufträtte: $1",
        "upload-copy-upload-invalid-domain": "As Kopi uffeladbari Dateie sin iber die Domain nit verfiegbar.",
        "upload-dialog-title": "Datei ufelade",
-       "upload-dialog-error": "Es het e Fähler ’gä",
-       "upload-dialog-warning": "Es het e Warnig ’gä",
        "upload-dialog-button-cancel": "Abbräche",
        "upload-dialog-button-done": "Fertig",
        "upload-dialog-button-save": "Spychere",
        "upload-dialog-button-upload": "Ufelade",
-       "upload-dialog-label-select-file": "Datei ussueche",
-       "upload-dialog-label-infoform-title": "Details",
-       "upload-dialog-label-infoform-name": "Name",
-       "upload-dialog-label-infoform-description": "Beschrybig",
-       "upload-dialog-label-usage-title": "Verwändig",
-       "upload-dialog-label-usage-filename": "Dateiname",
+       "upload-process-error": "Es het e Fähler ’gä",
+       "upload-process-warning": "Es het e Warnig ’gä",
+       "upload-form-label-select-file": "Datei ussueche",
+       "upload-form-label-infoform-title": "Details",
+       "upload-form-label-infoform-name": "Name",
+       "upload-form-label-infoform-description": "Beschrybig",
+       "upload-form-label-usage-title": "Verwändig",
+       "upload-form-label-usage-filename": "Dateiname",
        "backend-fail-stream": "D Datei $1 het nit chenne ibertrait wäre.",
        "backend-fail-backup": "D Datei $1 het nit chenne gsicheret wäre.",
        "backend-fail-notexists": "D Datei $1 git s nit.",
index d476e5a..0bd1984 100644 (file)
        "upload-dialog-button-done": "સંપન્ન",
        "upload-dialog-button-save": "સાચવો",
        "upload-dialog-button-upload": "ચઢાવો",
-       "upload-dialog-label-select-file": "ફાઈલ પસંદ કરો",
-       "upload-dialog-label-infoform-title": "વિગતો",
-       "upload-dialog-label-infoform-name": "નામ",
-       "upload-dialog-label-infoform-description": "વર્ણન",
-       "upload-dialog-label-usage-title": "વપરાશ",
-       "upload-dialog-label-usage-filename": "ફાઈલનું નામ",
+       "upload-form-label-select-file": "ફાઈલ પસંદ કરો",
+       "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": "ફાઈલનું નામ",
        "backend-fail-stream": "ફાઈલ $1 ને લાવી ન શકાઈ.",
        "backend-fail-backup": "ફાઈલ $1 ની પ્રત ન સાચવી શકાઈ.",
        "backend-fail-notexists": "ફાઈલ $1 ઉપલબ્ધ નથી.",
index 3a38c7a..ac6e0f2 100644 (file)
        "databaseerror-error": "שגיאה: $1",
        "laggedslavemode": "'''אזהרה:''' הדף עשוי שלא להכיל עדכונים אחרונים.",
        "readonly": "בסיס הנתונים נעול",
-       "enterlockreason": "×\99ש ×\9c×\94×\96×\99×\9f סיבה לנעילה, כולל הערכה למועד שחרור הנעילה",
+       "enterlockreason": "×\99ש ×\9c×\94ק×\9c×\99×\93 סיבה לנעילה, כולל הערכה למועד שחרור הנעילה",
        "readonlytext": "בסיס נתונים זה של האתר נעול ברגע זה לצורך הזנת נתונים ושינויים. ככל הנראה מדובר בתחזוקה שוטפת, שלאחריה יחזור האתר לפעולתו הרגילה.\n\nמנהל המערכת שנעל את בסיס הנתונים סיפק את ההסבר הבא: $1",
        "missing-article": "בסיס הנתונים לא מצא את הטקסט של הדף שהוא היה אמור למצוא, בשם \"$1\" $2.\n\nהדבר נגרם בדרך כלל על־ידי קישור ישן להשוואת גרסאות של דף שנמחק או לגרסה של דף כזה.\n\nאם זה אינו המקרה, זהו כנראה באג בתוכנה.\nאנא דווחו על כך ל[[Special:ListUsers/sysop|מפעיל מערכת]], תוך שמירת פרטי כתובת ה־URL.",
        "missingarticle-rev": "(מספר גרסה: $1)",
        "createacct-captcha": "בדיקת אבטחה",
        "createacct-imgcaptcha-ph": "יש להקליד את הטקסט המופיע למעלה",
        "createacct-submit": "יצירת החשבון שלך",
-       "createacct-another-submit": "יצירת חשבון אחר",
+       "createacct-another-submit": "יצירת חשבון",
        "createacct-benefit-heading": "אנשים כמוך יוצרים את {{SITENAME}}.",
        "createacct-benefit-body1": "{{PLURAL:$1|עריכה|עריכות}}",
        "createacct-benefit-body2": "{{PLURAL:$1|דף|דפים}}",
        "emailnotauthenticated": "כתובת הדוא\"ל שלכם עדיין לא אומתה.\nלא יישלח אליכם דוא\"ל עבור אף אחת מהתכונות הבאות.",
        "noemailprefs": "יש לציין כתובת דוא\"ל בהעדפות שלך כדי שתכונות אלה יעבדו.",
        "emailconfirmlink": "אישור כתובת הדוא\"ל שלך",
-       "invalidemailaddress": "×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ×\90×\99× ×\94 ×\9eתק×\91×\9cת ×\9b×\99×\95×\95×\9f ×©× ×¨×\90×\94 ×©×\94×\99×\90 ×\91פ×\95ר×\9e×\98 ×\9c×\90 ×\97×\95ק×\99.\n×\99ש ×\9c×\94×\96×\99×\9f כתובת תקינה או להשאיר את השדה ריק.",
+       "invalidemailaddress": "×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ×\90×\99× ×\94 ×\9eתק×\91×\9cת ×\9b×\99×\95×\95×\9f ×©× ×¨×\90×\94 ×©×\94×\99×\90 ×\91פ×\95ר×\9e×\98 ×\9c×\90 ×\97×\95ק×\99.\n×\99ש ×\9c×\94ק×\9c×\99×\93 כתובת תקינה או להשאיר את השדה ריק.",
        "cannotchangeemail": "לא ניתן לשנות את כתובות הדוא\"ל של חשבונות באתר ויקי זה.",
        "emaildisabled": "אתר זה לא יכול לשלוח דואר אלקטרוני.",
        "accountcreated": "החשבון נוצר",
        "changeemail-password": "סיסמה ב{{grammar:תחילית|{{SITENAME}}}}:",
        "changeemail-submit": "שינוי כתובת הדוא\"ל",
        "changeemail-throttled": "ביצעתם ניסיונות רבים מדי להיכנס לחשבון זה.\nאנא המתינו $1 לפני שתנסו שוב.",
-       "changeemail-nochange": "× ×\90 ×\9c×\94×\96×\99×\9f ×\9bת×\95×\91ת ×\93×\95×\90\"×\9c שונה.",
+       "changeemail-nochange": "×\99ש ×\9c×\94ק×\9c×\99×\93 ×\9bת×\95×\91ת ×\93×\95×\90\"×\9c ×\97×\93ש×\94 שונה.",
        "resettokens": "איפוס אסימונים",
        "resettokens-text": "בעמוד זה ניתן לאפס אסימונים שמאפשרים גישה לנתונים פרטיים של החשבון שלך.\n\nרצוי לעשות זאת אם שיתפת אותם בטעות עם אחרים או אם חשבונך נפרץ.",
        "resettokens-no-tokens": "אין אסימונים לאיפוס.",
        "template-protected": "(מוגנת)",
        "template-semiprotected": "(מוגנת חלקית)",
        "hiddencategories": "דף זה כלול ב{{PLURAL:$1|קטגוריה מוסתרת אחת|־$1 קטגוריות מוסתרות}}:",
-       "edittools": "<!-- הטקסט הנכתב כאן יוצג מתחת לטופסי עריכת דפים והעלאת קבצים, ולפיכך ניתן לכתוב להציג בו תווים קשים לכתיבה, קטעים מוכנים של טקסט ועוד. -->",
+       "edittools": "<!-- הטקסט הנכתב כאן יוצג מתחת לטופסי עריכת דפים והעלאת קבצים. -->",
        "nocreatetext": "ב{{grammar:תחילית|{{SITENAME}}}} קיימת הגבלה על יצירת דפים חדשים.\nבאפשרותך לחזור אחורה ולערוך דף קיים, או [[Special:UserLogin|להיכנס לחשבון או ליצור חשבון]].",
        "nocreate-loggedin": "אינך מורשה ליצור דפים חדשים.",
        "sectioneditnotsupported-title": "עריכת פסקאות אינה נתמכת",
        "permissionserrorstext-withaction": "אינך מורשה $2, מה{{PLURAL:$1|סיבה הבאה|סיבות הבאות}}:",
        "recreate-moveddeleted-warn": "'''אזהרה: הנכם יוצרים דף חדש שנמחק בעבר.'''\n\nכדאי לשקול אם יהיה זה נכון להמשיך לערוך את הדף.\nיומני המחיקות וההעברות של הדף מוצגים להלן:",
        "moveddeleted-notice": "דף זה נמחק.\nיומני המחיקות וההעברות של הדף מוצגים להלן.",
-       "moveddeleted-notice-recent": "ס×\9c×\99×\97×\94, הדף הזה נמחק לאחרונה (ב־24 השעות האחרונות).\nיומני המחיקה וההעברה של הדף מוצגים להלן לעיון.",
+       "moveddeleted-notice-recent": "×\9eצ×\98ער×\99×\9d, הדף הזה נמחק לאחרונה (ב־24 השעות האחרונות).\nיומני המחיקה וההעברה של הדף מוצגים להלן לעיון.",
        "log-fulllog": "הצגת היומן המלא",
        "edit-hook-aborted": "העריכה בוטלה על־ידי Hook.\nלא ניתן הסבר לביטול.",
        "edit-gone-missing": "לא ניתן לעדכן את הדף.\nנראה שהוא נמחק.",
        "upload-http-error": "התרחשה שגיאת HTTP‏: $1",
        "upload-copy-upload-invalid-domain": "העלאת קבצים משרת זה אינה אפשרית.",
        "upload-dialog-title": "העלאת קובץ",
-       "upload-dialog-error": "אירעה שגיאה",
-       "upload-dialog-warning": "אירעה אזהרה",
        "upload-dialog-button-cancel": "ביטול",
        "upload-dialog-button-done": "בוצע",
        "upload-dialog-button-save": "שמירה",
        "upload-dialog-button-upload": "העלאה",
-       "upload-dialog-label-select-file": "בחירת קובץ",
-       "upload-dialog-label-infoform-title": "פרטים",
-       "upload-dialog-label-infoform-name": "שם",
-       "upload-dialog-label-infoform-description": "תיאור",
-       "upload-dialog-label-usage-title": "שימושים",
-       "upload-dialog-label-usage-filename": "שם הקובץ",
+       "upload-process-error": "אירעה שגיאה",
+       "upload-process-warning": "אירעה אזהרה",
+       "upload-form-label-select-file": "בחירת קובץ",
+       "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": "שם הקובץ",
        "backend-fail-stream": "לא הייתה אפשרות להזרים את הקובץ \"$1\".",
        "backend-fail-backup": "לא הייתה אפשרות לגבות את הקובץ \"$1\".",
        "backend-fail-notexists": "הקובץ \"$1\" אינו קיים.",
        "filerevert-legend": "שחזור קובץ",
        "filerevert-intro": "אתם עומדים לשחזר את הקובץ '''[[Media:$1|$1]]''' ל[$4 גרסה מ־$3, $2].",
        "filerevert-comment": "סיבה:",
-       "filerevert-defaultcomment": "שוחזר לגרסה מ־$2, $1",
+       "filerevert-defaultcomment": "שוחזר לגרסה מ־$2, $1 ($3)",
        "filerevert-submit": "שחזור",
        "filerevert-success": "<strong>[[Media:$1|$1]]</strong> שוחזר ל[$4 גרסה מ־$3, $2].",
        "filerevert-badversion": "אין גרסה מקומית קודמת של הקובץ שהועלתה בתאריך המבוקש.",
        "noemailtext": "משתמש זה לא הזין כתובת דואר אלקטרוני תקינה.",
        "nowikiemailtext": "משתמש זה בחר שלא לקבל דואר אלקטרוני ממשתמשים אחרים.",
        "emailnotarget": "שם המשתמש של הנמען לא קיים או בלתי תקין.",
-       "emailtarget": "×\99ש ×\9c×\94×\96×\99×\9f את שם המשתמש של הנמען",
+       "emailtarget": "×\99ש ×\9c×\94ק×\9c×\99×\93 את שם המשתמש של הנמען",
        "emailusername": "שם משתמש:",
        "emailusernamesubmit": "שליחה",
        "email-legend": "שליחת דואר אלקטרוני למשתמש אחר של {{SITENAME}}",
        "emailccsubject": "העתק של הודעתך למשתמש $1: $2",
        "emailsent": "הדואר נשלח",
        "emailsenttext": "הודעת הדואר האלקטרוני שלך נשלחה.",
-       "emailuserfooter": "דואר זה נשלח על־ידי $1 ל{{GRAMMAR:תחילית|$2}} באמצעות פעולת \"{{int:emailuser}}\" ב{{GRAMMAR:תחילית|{{SITENAME}}}}.",
+       "emailuserfooter": "$1 {{GENDER:$1|שלח|שלחה}} את הדוא\"ל הזה ל{{GRAMMAR:תחילית|$2}} באמצעות פעולת \"{{int:emailuser}}\" ב{{GRAMMAR:תחילית|{{SITENAME}}}}.",
        "usermessage-summary": "השארת הודעת מערכת.",
        "usermessage-editor": "שולח הודעות המערכת",
        "watchlist": "רשימת המעקב",
        "deletepage": "מחיקה",
        "confirm": "אישור",
        "excontent": "התוכן היה: \"$1\"",
-       "excontentauthor": "התוכן היה: \"$1\" ({{GENDER:$2|והתורם היחיד היה|והתורמת היחידה הייתה}} \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "התוכן היה: \"$1\", {{GENDER:$2|והתורם היחיד היה|והתורמת היחידה הייתה}} \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|שיחה]])",
        "exbeforeblank": "התוכן לפני שרוקן היה: \"$1\"",
        "delete-confirm": "מחיקת \"$1\"",
        "delete-legend": "מחיקה",
        "logentry-newusers-byemail": "חשבון המשתמש $3 נוצר על־ידי $1 והסיסמה נשלחה בדוא\"ל",
        "logentry-newusers-autocreate": "חשבון המשתמש $1 {{GENDER:$2|נוצר}} אוטומטית",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|העביר|העבירה}} את הגדרות ההגנה מהדף $4 אל הדף $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|הסיר|הסירה}} את ההגנה מהדף $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|הגן|הגנה}} על הדף $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|הגן|הגנה}} על הדף $3 $4 [מדורג]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|שינה|שינתה}} את רמת ההגנה של הדף $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|שינה|שינתה}} את רמת ההגנה של הדף $3 $4 [מדורג]",
        "logentry-rights-rights": "$1 {{GENDER:$2|שינה|שינתה}} את ההרשאות של $3 מ{{GRAMMAR:תחילית|$4}} ל{{GRAMMAR:תחילית|$5}}&rlm;",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|שינה|שינתה}} את ההרשאות של $3&rlm;",
        "logentry-rights-autopromote": "$1 קודם אוטומטית מ{{GRAMMAR:תחילית|$4}} ל{{GRAMMAR:תחילית|$5}}",
index de0be0e..84040f4 100644 (file)
        "createacct-captcha": "Controlo de securitate",
        "createacct-imgcaptcha-ph": "Scribe le texto que tu vide hic supra",
        "createacct-submit": "Crear tu conto",
-       "createacct-another-submit": "Crear un altere conto",
+       "createacct-another-submit": "Crear conto",
        "createacct-benefit-heading": "{{SITENAME}} es facite per gente como tu.",
        "createacct-benefit-body1": "{{PLURAL:$1|modification|modificationes}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pagina|paginas}}",
        "group-bot": "Bots",
        "group-sysop": "Administratores",
        "group-bureaucrat": "Bureaucrates",
-       "group-suppress": "Supervisores",
+       "group-suppress": "Suppressores",
        "group-all": "(totes)",
        "group-user-member": "{{GENDER:$1|usator|usatrice|usator}}",
        "group-autoconfirmed-member": "{{GENDER:$1|usator|usatrice|usator}} autoconfirmate",
        "group-bot-member": "{{GENDER:$1|robot}}",
        "group-sysop-member": "{{GENDER:$1|administrator|administratrice|administrator}}",
        "group-bureaucrat-member": "{{GENDER:$1|bureaucrate}}",
-       "group-suppress-member": "{{GENDER:$1|supervisor|supervisora}}",
+       "group-suppress-member": "{{GENDER:$1|suppressor}}",
        "grouppage-user": "{{ns:project}}:Usatores",
        "grouppage-autoconfirmed": "{{ns:project}}:Usatores autoconfirmate",
        "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Administratores",
        "grouppage-bureaucrat": "{{ns:project}}:Bureaucrates",
-       "grouppage-suppress": "{{ns:project}}:Supervisores",
+       "grouppage-suppress": "{{ns:project}}:Suppressores",
        "right-read": "Leger paginas",
        "right-edit": "Modificar paginas",
        "right-createpage": "Crear paginas (non discussion)",
        "upload-http-error": "Un error HTTP occurreva: $1",
        "upload-copy-upload-invalid-domain": "Le incargamento de copias non es disponibile ab iste dominio.",
        "upload-dialog-title": "Incargar file",
-       "upload-dialog-error": "Un error ha occurrite",
-       "upload-dialog-warning": "Un advertimento se ha producite",
        "upload-dialog-button-cancel": "Cancellar",
        "upload-dialog-button-done": "Facite",
        "upload-dialog-button-save": "Salveguardar",
        "upload-dialog-button-upload": "Incargar",
-       "upload-dialog-label-select-file": "Seliger file",
-       "upload-dialog-label-infoform-title": "Detalios",
-       "upload-dialog-label-infoform-name": "Nomine",
-       "upload-dialog-label-infoform-description": "Description",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nomine del file",
+       "upload-process-error": "Un error ha occurrite",
+       "upload-process-warning": "Un advertimento se ha producite",
+       "upload-form-label-select-file": "Seliger file",
+       "upload-form-label-infoform-title": "Detalios",
+       "upload-form-label-infoform-name": "Nomine",
+       "upload-form-label-infoform-description": "Description",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nomine del file",
        "backend-fail-stream": "Non poteva transmitter le file $1.",
        "backend-fail-backup": "Non poteva facer un copia de reserva del file $1.",
        "backend-fail-notexists": "Le file $1 non existe.",
        "filerevert-legend": "Reverter file",
        "filerevert-intro": "Tu reverte '''[[Media:$1|$1]]''' al [$4 version del $3 a $2].",
        "filerevert-comment": "Motivo:",
-       "filerevert-defaultcomment": "Revertite al version del $2 a $1",
+       "filerevert-defaultcomment": "Revertite al version del $2, $1 ($3)",
        "filerevert-submit": "Reverter",
        "filerevert-success": "'''[[Media:$1|$1]]''' ha essite revertite al [$4 version del $3 a $2].",
        "filerevert-badversion": "Non existe un version local anterior de iste file con le data e hora providite.",
        "nopagetext": "Le pagina de destination que tu ha specificate non existe.",
        "pager-newer-n": "{{PLURAL:$1|1 plus recente|$1 plus recente}}",
        "pager-older-n": "{{PLURAL:$1|1 minus recente|$1 minus recente}}",
-       "suppress": "Supervisor",
+       "suppress": "Supprimer",
        "querypage-disabled": "Iste pagina special es disactivate pro evitar de supercargar le systema.",
        "apihelp": "Adjuta con le API",
        "apihelp-no-such-module": "Modulo \"$1\" non trovate.",
        "emailccsubject": "Copia de tu message a $1: $2",
        "emailsent": "E-mail inviate",
        "emailsenttext": "Tu message de e-mail ha essite inviate.",
-       "emailuserfooter": "Iste e-mail ha essite inviate per $1 a $2 con le function \"{{int:emailuser}}\" in {{SITENAME}}.",
+       "emailuserfooter": "Iste e-mail ha essite {{GENDER:$1|inviate}} per $1 a {{GENDER:$2|$2}} con le function \"{{int:emailuser}}\" in {{SITENAME}}.",
        "usermessage-summary": "Lassante un message de systema.",
        "usermessage-editor": "Messagero del systema",
        "watchlist": "Observatorio",
        "logentry-newusers-byemail": "Le conto de usator $3 ha essite {{GENDER:$2|create}} per $1 e le contrasigno ha essite inviate per e-mail",
        "logentry-newusers-autocreate": "Le conto $1 ha essite {{GENDER:$2|create}} automaticamente",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|displaciava}} le parametros de protection de $4 a $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|removeva}} le protection de $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|protegeva}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|protegeva}} $3 $4 [in cascada]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|cambiava}} le nivello de protection de $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|cambiava}} le nivello de protection de $3 $4 [in cascada]",
        "logentry-rights-rights": "$1 {{GENDER:$2|cambiava}} le appertinentia a gruppos pro $3 de $4 a $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|cambiava}} le appertinentia a gruppos pro $3",
        "logentry-rights-autopromote": "$1 ha essite automaticamente {{GENDER:$2|promovite}} de $4 a $5",
index a633533..49da7a9 100644 (file)
        "nstab-template": "Plantilia",
        "nstab-help": "Panid ti tulong",
        "nstab-category": "Kategoria",
+       "mainpage-nstab": "Umuna a Panid",
        "nosuchaction": "Awan ti kasta nga aramid",
        "nosuchactiontext": "Ti aramid a nainaganan babaen ti URL ket imbalido.\nMabalin a madi ti naimakiniliam nga URL, wenno sinurotmo ti saan a nasayaat a silpo.\nMabalinmo pay nga ibaga ti parikut ti sopwer nga us-usaren babaen ti {{SITENAME}}.",
        "nosuchspecialpage": "Awan ti kasta nga espesial a panid",
        "createacct-captcha": "Panagpatalged ti seguridad",
        "createacct-imgcaptcha-ph": "Ikabil ti teksto a makitam dita ngato",
        "createacct-submit": "Partuatem ti pakabilangam",
-       "createacct-another-submit": "Agpartuat iti sabali a pakabilangan",
+       "createacct-another-submit": "Agpartuat iti pakabilangan",
        "createacct-benefit-heading": "Ti {{SITENAME}} ket inar-aramid babaen ti tattao a kasla kenka.",
        "createacct-benefit-body1": "{{PLURAL:$1|nga inurnos|nga inur-urnos}}",
        "createacct-benefit-body2": "{{PLURAL:$1|a panid|a pampanid}}",
        "changeemail-password": "Ti bukodmo a kontrasenias ti {{SITENAME}}:",
        "changeemail-submit": "Sukatan ti esurat",
        "changeemail-throttled": "Adu unay ti panagpadasmo a sumrek.\nPangngaasi nga aguray ti $1 sakbay a padasen manen.",
+       "changeemail-nochange": "Pangngaasi nga agikabil iti sabali a baro nga adres ti esurat.",
        "resettokens": "Isaad manen dagiti tandaan",
        "resettokens-text": "Mabalinmo nga isaad manen dagiti tandaan a mangpalubos ti panagserrek ti naisangayan a pribado datos a mainaig ti pakabilangam ditoy.\n\nAramidem daytoy no aksidente nga inbingaymo dagitoy iti sabali wenno ti pakabilangam ket nakomprimiso.",
        "resettokens-no-tokens": "Awan dagiti maisaad manen a tandaan.",
        "group-bot": "Dagiti bot",
        "group-sysop": "Dagiti administrador",
        "group-bureaucrat": "Dagiti burokrata",
-       "group-suppress": "Pakapansin",
+       "group-suppress": "Dagiti agilaplapped",
        "group-all": "(amin)",
        "group-user-member": "{{GENDER:$1|agar-aramat}}",
        "group-autoconfirmed-member": "{{GENDER:$1|automatiko a napasingkedan nga agar-aramat}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|administrador}}",
        "group-bureaucrat-member": "{{GENDER:$1|burokrata}}",
-       "group-suppress-member": "{{GENDER:$1|pagpansin}}",
+       "group-suppress-member": "{{GENDER:$1|agilaplapped}}",
        "grouppage-user": "{{ns:project}}:Dagiti agar-aramat",
        "grouppage-autoconfirmed": "{{ns:project}}:Dagiti automatiko a napasingkedan nga agar-aramat",
        "grouppage-bot": "{{ns:project}}:Dagiti bot",
        "grouppage-sysop": "{{ns:project}}:Dagiti administrador",
        "grouppage-bureaucrat": "{{ns:project}}:Dagiti burokrata",
-       "grouppage-suppress": "{{ns:project}}:Pagpansin",
+       "grouppage-suppress": "{{ns:project}}:Ilapped",
        "right-read": "Basaen dagiti panid",
        "right-edit": "Agurnos kadagiti panid",
        "right-createpage": "Agpartuat kadagiti panid (saan a pagtutungtongan a pampanid)",
        "upload-http-error": "Adda napasamak a biddut ti HTTP: $1",
        "upload-copy-upload-invalid-domain": "Dagiti kopia a panagikarga ket saan a magun-od manipud iti daytoy a dominio.",
        "upload-dialog-title": "Agikarga iti papeles",
-       "upload-dialog-error": "Adda napasamak a biddut",
-       "upload-dialog-warning": "Adda napasamak a ballaag",
        "upload-dialog-button-cancel": "Ukasen",
        "upload-dialog-button-done": "Nalpasen",
        "upload-dialog-button-save": "Idulin",
        "upload-dialog-button-upload": "Agikarga",
-       "upload-dialog-label-select-file": "Pilien ti papeles",
-       "upload-dialog-label-infoform-title": "Dagiti salaysay",
-       "upload-dialog-label-infoform-name": "Nagan",
-       "upload-dialog-label-infoform-description": "Deskripsion",
-       "upload-dialog-label-usage-title": "Panagusar",
-       "upload-dialog-label-usage-filename": "Nagan ti papeles",
+       "upload-process-error": "Adda napasamak a biddut",
+       "upload-process-warning": "Adda napasamak a ballaag",
+       "upload-form-label-select-file": "Pilien ti papeles",
+       "upload-form-label-infoform-title": "Dagiti salaysay",
+       "upload-form-label-infoform-name": "Nagan",
+       "upload-form-label-infoform-description": "Deskripsion",
+       "upload-form-label-usage-title": "Panagusar",
+       "upload-form-label-usage-filename": "Nagan ti papeles",
        "backend-fail-stream": "Saan a maipan ti papeles $1.",
        "backend-fail-backup": "Saan a makaidulin ti kapada ti papeles ti $1.",
        "backend-fail-notexists": "Awan ti papeles ti $1.",
        "filerevert-legend": "Isubli ti papeles",
        "filerevert-intro": "Mangrugrugika nga agipasubli ti papeles ti <strong>[[Media:$1|$1]]</strong> iti [$4 bersion manipud idi $3, $2].",
        "filerevert-comment": "Rason:",
-       "filerevert-defaultcomment": "Naisubli iti bersion manipud idi $2, $1",
+       "filerevert-defaultcomment": "Naisubli iti bersion manipud idi $2, $1 ($3)",
        "filerevert-submit": "Isubli",
        "filerevert-success": "Ti <strong>[[Media:$1|$1]]</strong> ket naipasubli iti [$4 bersion manipud idi $3, $2].",
        "filerevert-badversion": "Awan ti dati a lokal a bersion iti daytoy a papeles a naited ti dayta nga oras ken petsa.",
        "nopagetext": "Awan ti puntaan a panid a nainaganam.",
        "pager-newer-n": "{{PLURAL:$1|nabarbaro a 1|nabarbaro a $1}}",
        "pager-older-n": "{{PLURAL:$1|nadadaan a 1|nadadaan a $1}}",
-       "suppress": "Pakapansin",
+       "suppress": "Ilapped",
        "querypage-disabled": "Daytoy nga espesial a panid ket nabaldado gapu kadagiti rason ti kasayaat ti panagpataray.",
        "apihelp": "Tulong ti API",
        "apihelp-no-such-module": "Saan a nabirukan ti modulo ti \"$1\".",
        "emailccsubject": "Kopia ti mensahem kenni $1: $2",
        "emailsent": "Naipatuloden ti esurat",
        "emailsenttext": "Naipatuloden ti esurat a mensahem.",
-       "emailuserfooter": "Daytoy nga esurat ket impatulod babaen ni $1 kenni $2 iti \"{{int:emailuser}}\" nga annong iti {{SITENAME}}",
+       "emailuserfooter": "Daytoy nga esurat ket {{GENDER:$1|impatulod}} babaen ni $1 kenni {{GENDER:$2|$2}} babaen ti \"{{int:emailuser}}\" nga annong iti {{SITENAME}}",
        "usermessage-summary": "Pumanpanaw iti mesahe ti sistema.",
        "usermessage-editor": "Mensahero ti sistema",
        "watchlist": "Bambantayan",
index 27bd8af..3eb3d2e 100644 (file)
        "createacct-captcha": "Controllo di sicurezza",
        "createacct-imgcaptcha-ph": "Inserisci il testo che vedi sopra",
        "createacct-submit": "Crea la tua utenza",
-       "createacct-another-submit": "Crea un'altra utenza",
+       "createacct-another-submit": "Crea utenza",
        "createacct-benefit-heading": "{{SITENAME}} cresce grazie a persone come te.",
        "createacct-benefit-body1": "{{PLURAL:$1|modifica|modifiche}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pagina|pagine}}",
        "group-bot": "Bot",
        "group-sysop": "Amministratori",
        "group-bureaucrat": "Burocrati",
-       "group-suppress": "Oversight",
+       "group-suppress": "Soppressori",
        "group-all": "(tutti)",
        "group-user-member": "{{GENDER:$1|utente}}",
        "group-autoconfirmed-member": "{{GENDER:$1|utente autoconvalidato|utente autoconvalidata|utente autoconvalidato/a}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|amministratore|amministratrice|amministratore/trice}}",
        "group-bureaucrat-member": "{{GENDER:$1|burocrate}}",
-       "group-suppress-member": "{{GENDER:$1|oversight}}",
+       "group-suppress-member": "{{GENDER:$1|soppressore|sopprimitrice}}",
        "grouppage-user": "{{ns:project}}:Utenti",
        "grouppage-autoconfirmed": "{{ns:project}}:Utenti autoconvalidati",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Amministratori",
        "grouppage-bureaucrat": "{{ns:project}}:Burocrati",
-       "grouppage-suppress": "{{ns:project}}:Oversight",
+       "grouppage-suppress": "{{ns:project}}:Soppressori",
        "right-read": "Legge pagine",
        "right-edit": "Modifica pagine",
        "right-createpage": "Crea pagine (escluse le pagine di discussione)",
        "upload-http-error": "Si è verificato un errore HTTP: $1",
        "upload-copy-upload-invalid-domain": "Non è consentito il caricamento di copie da questo dominio.",
        "upload-dialog-title": "Carica file",
-       "upload-dialog-error": "Si è verificato un errore",
-       "upload-dialog-warning": "Si è verificato un avviso",
        "upload-dialog-button-cancel": "Annulla",
        "upload-dialog-button-done": "Fatto",
        "upload-dialog-button-save": "Salva",
        "upload-dialog-button-upload": "Carica",
-       "upload-dialog-label-select-file": "Seleziona file",
-       "upload-dialog-label-infoform-title": "Dettagli",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrizione",
-       "upload-dialog-label-usage-title": "Utilizzo",
-       "upload-dialog-label-usage-filename": "Nome del file",
+       "upload-process-error": "Si è verificato un errore",
+       "upload-process-warning": "Si è verificato un avviso",
+       "upload-form-label-select-file": "Seleziona file",
+       "upload-form-label-infoform-title": "Dettagli",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrizione",
+       "upload-form-label-usage-title": "Utilizzo",
+       "upload-form-label-usage-filename": "Nome del file",
        "backend-fail-stream": "Impossibile trasmettere il file $1.",
        "backend-fail-backup": "Impossibile eseguire il backup del file $1 .",
        "backend-fail-notexists": "Il file $1 non esiste.",
        "filerevert-legend": "Ripristina file",
        "filerevert-intro": "Si sta per ripristinare il file '''[[Media:$1|$1]]''' alla [$4 versione del $2, $3].",
        "filerevert-comment": "Motivo:",
-       "filerevert-defaultcomment": "Ripristinata la versione del $2, $1",
+       "filerevert-defaultcomment": "Ripristinata la versione del $2, $1 ($3)",
        "filerevert-submit": "Ripristina",
        "filerevert-success": "'''Il file [[Media:$1|$1]]''' è stato ripristinato alla [$4 versione del $2, $3].",
        "filerevert-badversion": "Non esistono versioni locali precedenti del file con il timestamp richiesto.",
        "nopagetext": "La pagina richiesta non esiste.",
        "pager-newer-n": "{{PLURAL:$1|1 più recente|$1 più recenti}}",
        "pager-older-n": "{{PLURAL:$1|1 meno recente|$1 meno recenti}}",
-       "suppress": "Oversight",
+       "suppress": "Sopprimi",
        "querypage-disabled": "Questa pagina speciale è disattivata per motivi di prestazioni.",
        "apihelp": "Aiuto API",
        "apihelp-no-such-module": "Modulo \"$1\" non trovato.",
        "emailccsubject": "Copia del messaggio inviato a $1: $2",
        "emailsent": "Messaggio inviato",
        "emailsenttext": "Il messaggio e-mail è stato inviato.",
-       "emailuserfooter": "Questa email è stata inviata da $1 a $2 attraverso la funzione \"{{int:emailuser}}\" su {{SITENAME}}.",
+       "emailuserfooter": "Questa email è stata {{GENDER:$1|inviata}} da $1 a {{GENDER:$2|$2}} attraverso la funzione \"{{int:emailuser}}\" su {{SITENAME}}.",
        "usermessage-summary": "Messaggio di sistema",
        "usermessage-editor": "Messaggero di sistema",
        "usermessage-template": "MediaWiki:MessaggioUtente",
        "deletepage": "Cancella pagina",
        "confirm": "Conferma",
        "excontent": "il contenuto era: '$1'",
-       "excontentauthor": "il contenuto era: '$1' (e l'unico contributore era '[[Special:Contributions/$2|$2]]')",
+       "excontentauthor": "il contenuto era: '$1', e l'unico contributore era \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|msg]])",
        "exbeforeblank": "Il contenuto prima dello svuotamento era: '$1'",
        "delete-confirm": "Cancella \"$1\"",
        "delete-legend": "Cancella",
        "logentry-newusers-byemail": "L'utenza $3 è stata {{GENDER:$2|creata}} da $1 e la password è stata inviata via email",
        "logentry-newusers-autocreate": "L'utenza $1 è stata {{GENDER:$2|creata}} automaticamente",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|ha spostato}} le impostazioni di protezione da $4 a $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|ha rimosso}} la protezione da $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|ha protetto}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|ha protetto}} $3 $4 [ricorsiva]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|ha modificato}} il livello di protezione per $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|ha modificato}} il livello di protezione per $3 $4 [ricorsiva]",
        "logentry-rights-rights": "$1 {{GENDER:$2|ha modificato}} l'appartenenza di $3 dal gruppo $4 al gruppo $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|ha modificato}} l'appartenenza a gruppi di $3",
        "logentry-rights-autopromote": "$1 è {{GENDER:$2|stato promosso|stata promossa|stato/a promosso/a}} automaticamente da $4 a $5",
        "api-error-badaccess-groups": "Non sei autorizzato a caricare documenti su questa wiki.",
        "api-error-badtoken": "Errore interno: token errato.",
        "api-error-copyuploaddisabled": "Il caricamento tramite URL è disabilitato su questo server.",
-       "api-error-duplicate": "Sul sito {{PLURAL:$1|c'è già [$2 un altro documento]|ci sono già [$2 altri documenti]}} con lo stesso contenuto.",
+       "api-error-duplicate": "Sul sito {{PLURAL:$1|c'è già un altro documento|ci sono già altri documenti}} con lo stesso contenuto.",
        "api-error-duplicate-archive": "{{PLURAL:$1|C'era un altro file|C'erano altri file}} già nel sito con lo stesso contenuto, ma {{PLURAL:$1|è stato cancellato|sono stati cancellati}}.",
        "api-error-empty-file": "Il file selezionato era vuoto.",
        "api-error-emptypage": "La creazione di nuove pagine vuote non è consentita.",
index ead03df..e37ea90 100644 (file)
        "createacct-captcha": "自動作成防止チェック",
        "createacct-imgcaptcha-ph": "上に表示されている文字列を入力",
        "createacct-submit": "アカウントを作成",
-       "createacct-another-submit": "アカウントを作成",
+       "createacct-another-submit": "アカウントを作成",
        "createacct-benefit-heading": "{{SITENAME}}は、あなたのような人々が創っています。",
        "createacct-benefit-body1": "{{PLURAL:$1|編集}}",
        "createacct-benefit-body2": "{{PLURAL:$1|ページ}}",
        "grouppage-bot": "{{ns:project}}:ボット",
        "grouppage-sysop": "{{ns:project}}:管理者",
        "grouppage-bureaucrat": "{{ns:project}}:ビューロクラット",
-       "grouppage-suppress": "{{ns:project}}:秘匿",
+       "grouppage-suppress": "{{ns:project}}:秘匿",
        "right-read": "ページを閲覧",
        "right-edit": "ページを編集",
        "right-createpage": "ページ (議論ページ以外) を作成",
        "upload-http-error": "HTTP エラー発生: $1",
        "upload-copy-upload-invalid-domain": "このドメインからのアップロードは許可されていません。",
        "upload-dialog-title": "ファイルをアップロード",
-       "upload-dialog-error": "エラーが発生しました",
-       "upload-dialog-warning": "警告",
        "upload-dialog-button-cancel": "中止",
        "upload-dialog-button-done": "完了",
        "upload-dialog-button-save": "保存",
        "upload-dialog-button-upload": "アップロード",
-       "upload-dialog-label-select-file": "ファイル選択",
-       "upload-dialog-label-infoform-title": "詳細",
-       "upload-dialog-label-infoform-name": "名前",
-       "upload-dialog-label-infoform-description": "説明",
-       "upload-dialog-label-usage-title": "使用法",
-       "upload-dialog-label-usage-filename": "ファイル名",
+       "upload-process-error": "エラーが発生しました",
+       "upload-process-warning": "警告",
+       "upload-form-label-select-file": "ファイル選択",
+       "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": "ファイル名",
        "backend-fail-stream": "ファイル $1 をストリームできませんでした。",
        "backend-fail-backup": "ファイル $1 をバックアップできませんでした。",
        "backend-fail-notexists": "ファイル $1 は存在しません。",
        "filerevert-legend": "ファイルを差し戻す",
        "filerevert-intro": "ファイル<strong>[[Media:$1|$1]]</strong>を[$4 $2$3版]に差し戻そうとしています。",
        "filerevert-comment": "理由:",
-       "filerevert-defaultcomment": "$1$2の版へ差し戻し",
+       "filerevert-defaultcomment": "$1$2の版へ差し戻し ($3)",
        "filerevert-submit": "差し戻す",
        "filerevert-success": "<strong>[[Media:$1|$1]]</strong>は[$4 $2$3の版]に差し戻されました。",
        "filerevert-badversion": "このファイルに指定された時刻印を持つ過去の版はありません。",
        "emailccsubject": "$1 に送信したメールの控え: $2",
        "emailsent": "メールを送信しました",
        "emailsenttext": "メールを送信しました。",
-       "emailuserfooter": "このメールは$1から$2へ、{{SITENAME}}の「{{int:emailuser}}」機能で送信されました。",
+       "emailuserfooter": "このメールは$1から{{GENDER:$2|$2}}へ、{{SITENAME}}の「{{int:emailuser}}」機能で{{GENDER:$1|送信}}されました。",
        "usermessage-summary": "システムメッセージを残す。",
        "usermessage-editor": "システムメッセンジャー",
        "watchlist": "ウォッチリスト",
        "deletepage": "ページを削除",
        "confirm": "確認",
        "excontent": "内容:「$1」",
-       "excontentauthor": "内容:「$1」(投稿者は「[[Special:Contributions/$2|$2]]」のみ)",
+       "excontentauthor": "内容:「$1」、投稿者は「[[Special:Contributions/$2|$2]]」のみ ([[User talk:$2|talk]])",
        "exbeforeblank": "白紙化前の内容:「$1」",
        "delete-confirm": "「$1」の削除",
        "delete-legend": "削除",
        "logentry-newusers-byemail": "利用者アカウント $3 が $1 によって{{GENDER:$2|作成され}}、そのパスワードがメールで送信されました",
        "logentry-newusers-autocreate": "利用者アカウント $1 が自動的に{{GENDER:$2|作成されました}}",
        "logentry-protect-move_prot": "$1 が保護設定を $4 から $3 に{{GENDER:$2|移動しました}}",
+       "logentry-protect-unprotect": "$1 が $3 からの保護を{{GENDER:$2|削除}}しました",
+       "logentry-protect-protect": "$1 が $3 の $4 を{{GENDER:$2|保護}}しました",
+       "logentry-protect-protect-cascade": "$1 が $3 の $4 を{{GENDER:$2|保護}}しました [カスケード]",
+       "logentry-protect-modify": "$1 が $3 の $4 の保護レベルを{{GENDER:$2|変更}}しました",
+       "logentry-protect-modify-cascade": "$1 が $3 の $4 の保護レベルを{{GENDER:$2|変更}}しました [カスケード]",
        "logentry-rights-rights": "$1 が $3 の所属グループを $4 から $5 に{{GENDER:$2|変更しました}}",
        "logentry-rights-rights-legacy": "$1 が $3 の所属グループを{{GENDER:$2|変更しました}}",
        "logentry-rights-autopromote": "$1 が $4 から $5 に自動的に{{GENDER:$2|昇格しました}}",
index 575e43f..2fe06b6 100644 (file)
        "jumpto": "Skift te:",
        "jumptonavigation": "navigasjon",
        "jumptosearch": "Syegneng",
+       "view-pool-error": "Beklawe, men serveren ä i yeblikk öwebelasten. \nFor mång bruga forsyege å sietj siden.\nWentj e yeblikk, för du forsyege å besyeg siden idjen.\n\n$1",
+       "generic-pool-error": "Beklawe, men serveren ä i yeblikk öwebelasten.\nFor mång bruga forsyeg å sietj siden.\nWentj e yeblikk för du forsyege å besyeg siden idjen.",
+       "pool-timeout": "Timeout mens man wentje på låsnengen",
+       "pool-queuefull": "Pool-køen ä full",
+       "pool-errorunknown": "Utjentj fejl",
+       "pool-servererror": "Pool-counterservicen ä ett te rådihed ($1).",
+       "poolcounter-usage-error": "Brugsfejl: $1",
        "aboutsite": "Om {{SITENAME}}",
        "aboutpage": "Project:Om",
        "copyright": "Inholje ä utdjøwen unje $1 mämenna ånj ä åndjøwen.",
        "ok": "OK",
        "retrievedfrom": "Hentjen fra \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|Du hår}} $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|Du hår}} $1 fra {{PLURAL:$3|i ånj bruge| $3 bruga}} ($2).",
+       "youhavenewmessagesmanyusers": "Du hår $1 fra mång bruga ($2).",
+       "newmessageslinkplural": "{{PLURAL:$1|e ny besked|999=nyj beskede}}",
+       "newmessagesdifflinkplural": "siensti {{PLURAL:$1|øndreng|999=øndrenge}}",
        "youhavenewmessagesmulti": "Du hår nyj beskede på $1",
        "editsection": "redigiir",
        "editold": "redigiir",
        "page-rss-feed": "\"$1\" RSS-feed",
        "page-atom-feed": "\"$1\" Atom-feed",
        "red-link-title": "$1 (siden ä ett skrøwen ennu)",
+       "sort-descending": "Sortiir fallenje",
+       "sort-ascending": "Sortiir stigenje",
        "nstab-main": "Siid",
        "nstab-user": "Brugesiid",
        "nstab-media": "Mediesiid",
        "nstab-category": "Kategori",
        "mainpage-nstab": "Forsiid",
        "nosuchaction": "Funksjonen finjs ett",
-       "nosuchactiontext": "Funksje ångævet i'n URL ken ekke genkendes åf æ MediaWiki-softwær",
+       "nosuchactiontext": "Hånjlengen som ä åndjøwen i URL'i ä udjylji.\nDu kan ha skrøwen URL'i forkiertj, elle fuljtj en ukorrekt henwisneng.\nDä kan åsså skyljs en fejl i programmet som brugs å {{SITENAME}}.",
        "nosuchspecialpage": "En sån specialsiid finjs ett",
-       "nospecialpagetext": "Du harst bedt en sonstside'm, der ekke ken genkendes åf æ MediaWiki-softwær.",
+       "nospecialpagetext": "<strong>Du hår bien om en specialsiid, som ett kan djenkentjs å MediaWiki-softwari.</strong>\n\nEn list öwe djylji specialside finjs på [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Fejl",
        "databaseerror": "Databasefejl",
+       "databaseerror-text": "Där opstue fejl i en forspöyrgsel te databasi.\nDetj kan indikiir en fejl i softwari.",
+       "databaseerror-textcl": "Där opstue fejl i en forspöyrgsel te databasi.",
        "databaseerror-query": "Forspöyrgsel: $1",
        "databaseerror-function": "Funksjon: $1",
        "databaseerror-error": "Fejl: $1",
        "pt-createaccount": "Oprett konto",
        "pt-userlogout": "Logg å",
        "retypenew": "Djentast ny adgångskode",
+       "resetpass-submit-cancel": "Åbryd",
        "passwordreset": "Nullstell adgångskode",
        "bold_sample": "Fied tekst",
        "bold_tip": "Fied tekst",
        "editing": "Redigiire $1",
        "creating": "Oprette $1",
        "editingsection": "Redigiire $1 (åsnit)",
+       "editingcomment": "Redigiire $1 (ny åsnit)",
+       "editconflict": "Redigiirengskonflikt: $1",
        "copyrightwarning": "Bemærk wenlist å åll bidraw te {{SITENAME}} ä å betrakt som utdjøwen unje $2 (se $1 for detalje).\nHwes du ett onske å din tekst skal utsätts for nådesløs redigiirenge å å den kan blyw kopiiirtj ette forgodtbefinjenje, så skal du ett placiir den her.<br />\nDu låwe os åsså, å du siel hår forfatten teksten elle hår kopiiirtj den fra en public domain-tjelj elle en tilswarenje fri tjelj.\n'''Lägg åller material her som ä beskøttetj å anjas ophawsrett uen dæes tillædels!'''",
        "templatesused": "{{PLURAL:$1|Skabelon|Skabelone}} som ä brugtj på siden:",
        "templatesusedpreview": "Følgende skablåner bruges åf denne ertikelførhåndsvesnenge:",
        "histfirst": "älsti",
        "histlast": "nysti",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
+       "history-feed-title": "Versjonshistori",
        "history-feed-item-nocomment": "$1 mä $2",
        "rev-delundel": "ønda sijtbarhed",
        "history-title": "$1: Versjonshistorik",
        "search-redirect": "(omdirigiireng $1)",
        "search-section": "(åsnit $1)",
        "search-suggest": "Mientje du: $1",
+       "search-interwiki-caption": "Systeprojekte",
+       "search-interwiki-default": "Resultate fra $1:",
+       "search-interwiki-more": "(mier)",
+       "search-relatedarticle": "Relatiirtj",
+       "searchrelated": "relatiirtj",
        "searchall": "åll",
        "search-showingresults": "{{PLURAL:$4|Resultat <strong>$1</strong> å <strong>$3</strong>|Resultat <strong>$1 - $2</strong> å <strong>$3</strong>}}",
        "search-nonefound": "Syegnengen djij ien resultate.",
        "mypreferences": "Instellenge",
        "prefs-skin": "Utsienje",
        "skin-preview": "Forhånjswisneng",
+       "prefs-misc": "Forskelli",
+       "prefs-resetpass": "Skift adgångskode",
+       "prefs-changeemail": "Ønda e-mailadress",
+       "prefs-setemail": "Åndjie en e-mailadress",
+       "prefs-email": "Instellenge for e-mail",
        "prefs-rendering": "Utsienje",
+       "saveprefs": "Djiem instellenge",
+       "restoreprefs": "Djensätt åll standardinstellenge (i åll seksjone)",
+       "prefs-editing": "Redigiireng",
+       "rows": "Räkke:",
+       "columns": "Kolonne:",
+       "searchresultshead": "Syegresultate",
+       "stub-threshold": "Græns for stumplinkformatiireng ($1):",
+       "stub-threshold-sample-link": "eksempel",
+       "stub-threshold-disabled": "Deaktiviirtj",
+       "recentchangesdays": "Åntal daw som skal wises i siensti øndrenge:",
+       "recentchangesdays-max": "Maksimal $1 {{PLURAL:$1|daw}}",
+       "recentchangescount": "Åntal redigiirenge som skal wises som standard:",
+       "prefs-help-recentchangescount": "Dä djälje for siensti øndrenge, historike å logge.",
+       "prefs-help-watchlist-token2": "Detj ä hemmeli lygli te webfeed å din öwewågnengslist.\nHwes anjer tjenne den, will man wær istånj te å läs din öwewågnengslist, så diel den ett.\n[[Special:ResetTokens|Klikk her hwes du hår brug å nullstell den]].",
+       "savedprefs": "Din instellenge ä bløwen djiemen.",
+       "timezonelegend": "Tidszone:",
+       "localtime": "Lokaltiid:",
+       "timezoneuseserverdefault": "Brug wikiis standardinstelleng ($1)",
+       "timezoneuseoffset": "Ånj (åndjie forskell)",
+       "servertime": "Serveris tiid:",
+       "guesstimezone": "Hentj tidszone fra browseri",
+       "timezoneregion-africa": "Afrika",
+       "timezoneregion-america": "Amerika",
+       "timezoneregion-antarctica": "Antarktis",
+       "timezoneregion-arctic": "Arktis",
+       "timezoneregion-asia": "Asien",
+       "timezoneregion-atlantic": "Atlantjerhawe",
+       "timezoneregion-australia": "Australien",
+       "timezoneregion-europe": "Europa",
+       "timezoneregion-indian": "Indisk Ocean",
+       "timezoneregion-pacific": "Stillhawe",
+       "allowemail": "Tillæd e-mail fra anjer bruga",
+       "prefs-searchoptions": "Syeg",
+       "prefs-namespaces": "Naunrum",
+       "default": "standard",
+       "prefs-files": "File",
+       "prefs-custom-css": "Personli CSS",
+       "prefs-custom-js": "Personli JavaScript",
+       "prefs-common-css-js": "Fælls CSS/JS for åll utsienje:",
+       "prefs-reset-intro": "Du kan brug siden te å tebagstell åll din instellenge te standardinstellenger.\nDä kan ett djendjörs.",
+       "prefs-emailconfirm-label": "Bekräftels å e-mail:",
        "youremail": "E-mail:",
+       "username": "{{GENDER:$1|Brugenaun}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Mälemm}} å {{PLURAL:$1|gruppen|grupper}}:",
+       "prefs-registration": "Registriirengstidspuntj:",
        "yourrealname": "Det rijti naun:",
+       "yourlanguage": "Spraw:",
+       "yourvariant": "Sprawvariantj for inholj:",
+       "prefs-help-variant": "Sprawvaruabtheb elle rettskriiwneng, som du forträkke, å denn wikis inholjsside wises i.",
+       "yournick": "Ny signatur:",
+       "prefs-help-signature": "Kommentare på diskusjonsside bör signiirs mä \"<nowiki>~~~~</nowiki>\" som will blyw konvertiirtj te din signatur å e tidsstempel.",
+       "badsig": "Syntaksi i signaturen ä udjylji; kontrolliir wenlist den brugtje HTML.",
+       "badsiglength": "Din signatur ä for lång. Den ma hyest inholj $1 {{PLURAL:$1|tejn}}.",
+       "yourgender": "Hwant forträkke du å blyw beskriiwen?",
        "prefs-help-realname": "Åndjiels å rijti naun ä walgfritj.\nHwes du wælge å oplys det naun, wil dä blyw brugtj te å tilskriiw dej det arbejt.",
+       "prefs-editor": "Redigiirengsprogramme",
+       "prefs-preview": "Forhånjswisneng",
+       "prefs-advancedrc": "Avanciirtje instellinge",
+       "prefs-advancedrendering": "Avanciirtje instellinge",
+       "prefs-advancedsearchoptions": "Avanciirtje instellinge",
+       "prefs-advancedwatchlist": "Avanciirtje instellinge",
+       "prefs-displayrc": "Instellenge for wisneng",
+       "prefs-displaywatchlist": "Wisnengsmulihede",
+       "prefs-tokenwatchlist": "Märk",
+       "prefs-diffs": "Forskell",
        "grouppage-sysop": "{{ns:project}}:Administrore",
        "right-writeapi": "Brug redigiirengsdieli å API",
        "newuserlogpage": "Brugeoprettelslogg",
        "randompage": "Tefælji siid",
        "randomredirect": "Tefælji henwisnenge",
        "statistics": "Statistik",
+       "pageswithprop": "Side mä e side-ejnskåp",
+       "pageswithprop-legend": "Side mä e side-ejnskåp",
        "doubleredirects": "Doppelt omdirigiirenge",
        "brokenredirects": "Defekt omdirigiirenge",
        "withoutinterwiki": "Side uen henwisnenge te anjer spraw",
        "unusedimages": "Ubrugtje file",
        "wantedcategories": "Onske kategorie",
        "wantedpages": "Onske side",
-       "mostlinked": "Side mä fliest henwisnenge",
+       "wantedfiles": "Onske file",
+       "wantedtemplates": "Onske skabelone",
+       "mostlinked": "Side mä di fliesti henwisnenge",
        "mostlinkedcategories": "Miest-brugtje kategorie",
        "mostlinkedtemplates": "Miest-brugtje side",
        "mostcategories": "Side mä di fliesti kategorie",
        "mostimages": "Miest-brugtje file",
+       "mostinterwikis": "Side mä di fliesti interwikilinks",
        "mostrevisions": "Side mä di fliesti versjone",
        "prefixindex": "Åll side som bedjynne mä",
        "shortpages": "Kort side",
        "longpages": "Lång side",
        "deadendpages": "Blinjenjside",
        "protectedpages": "Skriiwbeskøttetj side",
+       "protectedtitles": "Beskøttetj sidenaun",
        "listusers": "Brugelist",
        "newpages": "Nysti side",
        "ancientpages": "Älsti side",
        "linksearch-text": "Wildcards som \"*.wikipedia.org\" kan benøtts.\nDär skal som minimum åndjies e topnivå-domæn som f. eks. \"*.org\".<br />\n{{PLURAL:$2|Unjestötten protokol|Unjestötten protokolle}}: $1 (bruge automatisk http:// hwes där ett ä åndjøwen no protokol).",
        "linksearch-line": "$2 linke te $1",
        "linksearch-error": "Wildcards ma kons benøtts i starti å hostnaune.",
+       "trackingcategories": "Spørengskategorie",
        "emailuser": "E-mail te bruge",
        "watchlist": "Öwewågnengslist",
        "mywatchlist": "Öwewågnengslist",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskusjon]])",
        "version": "Informasjon om MediaWiki",
        "specialpages": "Specialside",
+       "specialpages-group-maintenance": "Weliholjelsside",
+       "specialpages-group-pages": "Sideliste",
        "tag-filter": "[[Special:Tags|Tag]]filtjer:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
        "logentry-delete-delete": "$1 {{GENDER:$2|slettetj}} siden $3",
index 61a3382..8e1f092 100644 (file)
@@ -23,7 +23,8 @@
                        "გიორგიმელა",
                        "아라",
                        "Macofe",
-                       "SHOTHA"
+                       "SHOTHA",
+                       "Gi777ga"
                ]
        },
        "tog-underline": "ბმულების ხაზგასმა:",
        "nstab-template": "თარგი",
        "nstab-help": "დახმარება",
        "nstab-category": "კატეგორია",
+       "mainpage-nstab": "მთავარი გვერდი",
        "nosuchaction": "მოქმედება არ არსებობს",
        "nosuchactiontext": "URL-ის მიერ მითითებული მოქმედება მცდარია.\nშესაძლოა შეცდომით აკრიფეთ URL, ან არასწორ ბმულზე გადახვედით.\nაგრეთვე შესაძლოა, {{SITENAME}}-ს მიერ გამოყენებულ პროგრამულ უზრუნველყოფაში იყოს შეცდომა.",
        "nosuchspecialpage": "სპეციალური გვერდი არ არსებობს",
        "actionthrottled": "სიჩქარის შეზღუდვა.",
        "actionthrottledtext": "სპამთან ბრძოლასთან დაკავშირებით აკრძალულია შემდეგი მონაცემების მრავალჯერ გამეორება. გთხოვთ გაიმეოროთ იგი მოგვიანებით.",
        "protectedpagetext": "ეს გვერდი დაბლოკილია რედაქტირებისათვის ან სხვა მოქმედებისათვის.",
-       "viewsourcetext": "თქვენ შეგიძლიათ ნახოთ ამ გვერდის საწყისი ფაილი და მისი ასლი შექმნათ:",
-       "viewyourtext": "თქვენ შეგიძლიათ იხილოთ და დააკოპიროთ  '''თქვენი რედაქტირებების''' საწყისი ტექსტი ამ გვერდზე:",
+       "viewsourcetext": "თქვენ შეგიძლიათ ნახოთ ამ გვერდის საწყისი ფაილი და მისი ასლი შექმნათ.",
+       "viewyourtext": "თქვენ შეგიძლიათ იხილოთ და დააკოპიროთ  <strong>თქვენი რედაქტირებების</strong> საწყისი ტექსტი ამ გვერდზე:",
        "protectedinterface": "ეს გვერდი წარმოადგენს ტექსტურ ინტერფეისს პროგრამული უზრუნველყოფისათვის და დაცულია ვანდალიზმის აღკვეთის მიზნით.",
        "editinginterface": "'''ყურადღება:''' თქვენ არედაქტირებთ გვერდს, რომელიც პროგრამის ინტერფეისის ტექსტს შეიცავს. \nამ გვერდზე განხორციელებული რედაქტირება გამოიწვევს ამ ვიკის სხვა მომხმარებელთა სამუშაო ინტერფეისის შეცვლასაც. \nიმისათვის, რომ დაამატოთ ან შეცვალოთ თარგმანები ყველა ვიკიში, გთხოვთ, გამოიყენოთ მედიავიკის ლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
        "translateinterface": "თარგმანების ყველა ვიკიში დასამატებლად ან შესაცვლელად, გთხოვთ გამოიყენოთ მედიავიკებისლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
        "createacct-captcha": "უსაფრთხოების შემოწმება",
        "createacct-imgcaptcha-ph": "შეიყვანეთ ზემოთ მოცემული ტექსტი",
        "createacct-submit": "შექმენით თქვენი ანგარიში",
-       "createacct-another-submit": "á\83¡á\83®á\83\95á\83\90 á\83\90á\83\9cá\83\92á\83\90á\83 á\83\98á\83¨á\83\98á\83¡ á\83¨á\83\94á\83¥á\83\9bá\83\9cá\83\90",
+       "createacct-another-submit": "ანგარიშის შექმნა",
        "createacct-benefit-heading": "{{SITENAME}} შექმნილია თქვენნაირი ადამიანების მიერ.",
        "createacct-benefit-body1": "{{PLURAL:$1|რედაქტირება|რედაქტირება}}",
        "createacct-benefit-body2": "{{PLURAL:$1|გვერდი|გვერდი}}",
        "changeemail-password": "თქვენი პაროლი პროექტში {{SITENAME}}:",
        "changeemail-submit": "ელ-ფოსტის შეცვლა",
        "changeemail-throttled": "თქვენ უკვე ძალიან ბევრჯერ სცადეთ შესვლა.\nგთხოვთ, მოიცადოთ $1, სანამ კიდევ სცდიდეთ.",
+       "changeemail-nochange": "გთხოვთ, შეიყვანოთ ახალი, განსხვავებული ელექტრონული მისამართი.",
        "resettokens": "ტოკენების ჩამოყრა",
        "resettokens-text": "თქვენ შეგიძლიათ ჩამოყაროთ ტოკენები, რომლებიც შესაძლებლობას იძლევიან შესვლას განსაზღვრულ პირად მონაცემებში, დაკავშირებულს თქვენ ანგარიშთან აქ. \n\nთქვენ ეს აუცილებლად უნდა გააკეთოთ, თუ თქვენ ის შემთხვევით გააცანით სხვას ან თუკი თქვენი ანგარიში იქნა გატეხილი.",
        "resettokens-no-tokens": "არ არის ტოკენები ჩამოსაყრელად",
        "yourdiff": "განსხვავებები",
        "copyrightwarning": "ყურადღება მიაქციეთ: ნებისმიერი წვლილი გვერდზე {{SITENAME}} $2 ლიცენზიას ექვემდებარება (იხ. $1 დეტალებისთვის). თუ არ გსურთ თქვენი ნამუშევარი თავისუფლად გავრცელდეს და მისი დაუნდობელი რედაქტირება მოხდეს, მაშინ ნუ შეიყვანთ მას აქ.<br />\nთქვენ ასევე პირობას დებთ, რომ ეს თქვენი დაწერილია, ან გადმოღებულია საზოგადოებრივი დომენიდან, ან მსგავსი თავისუფალი წყაროდან.\n'''ნუ შემოიტანთ საავტორო უფლებებით დაცულ ნაშრომს ავტორის თანხმობის გარეშე!'''",
        "copyrightwarning2": "*გაითვალისწინეთ, რომ ნებისმიერი წვლილი {{SITENAME}}-ში შეიძლება ჩასწორდეს, შეიცვალოს ან წაიშალოს სხვა რედაქტორების მიერ.\n*თუ არ გსურთ, რომ თქვენი ნამუშევარი შეუზღუდავად იქნეს რედაქტირებული, მას აქ ნუ განათავსებთ.<br />\n*თქვენ აგრეთვე პირობას დებთ, რომ თქვენს მიერ განთავსებული ტექსტი თქვენი დაწერილია, ან გადმოწერილია საზოგადოებრივი დომენიდან ან მსგავსი თავისუფალი წყაროდან. (იხ. $1 დეტალებისთვის).\n*'''ნუ შემოიტანთ საავტორო უფლებებით დაცულ ნაშრომს ავტორის ნებართვის გარეშე!'''",
+       "editpage-cannot-use-custom-model": "ამ გვერდის მასალის მოდელი არ შეიძლება, რომ შეიცვალოს.",
        "longpageerror": "'''შეცდომა: თქვენს მიერ აკრეფილი ტექსტის ზომა {{PLURAL:$1|$1 კილობაიტია}}, რაც აღემატება, დადგენილ {{PLURAL:$2|$2 კილობაიტიან}} ზღვარს. გვერდის შენახვა შეუძლებელია.'''",
        "readonlywarning": "'''გაფრთხილება: მონაცემთა ბაზა დახურულია პერიოდული შემოწმებისთვის, შესაბამისად თქვენ ვერ შეძლებთ რედაქტირებას ამ მომენტში.'''\nსასურველია ტექსტის ასლი შეინახოთ ტექსტურ რედაქტორში და მოგვიანებით შემოიტანოთ.\n\nმონაცემთა ბაზის დამბლოკველმა ადმინისტრატორმა შემდეგი კომენტარი დატოვა: $1",
        "protectedpagewarning": "'''ყურადღება:  ეს გვერდი დაბლოკილია და მისი რედაქტირება შეუძლიათ მხოლოდ მომხმარებლებს ადმინისტრატორის უფლებებით'''\nიხილეთ დაცვის ჟურნალის ჩანაწერი",
        "columns": "სვეტები",
        "searchresultshead": "ძიება",
        "stub-threshold": "გაფორმების გასაუმჯობესებლად <a href=\"#\" class=\"stub\"> მოცემულია ესკიზების ბმულები</a> (ბაიტებში):",
+       "stub-threshold-sample-link": "მაგალითი",
        "stub-threshold-disabled": "გათიშულია",
        "recentchangesdays": "ბოლო ცვლილებებში საჩვენებელი დღეები:",
        "recentchangesdays-max": "მაქსიმუმ $1 {{PLURAL:$1|დღე}}",
        "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[$1 მომხმარებლის/ები კონტროლი]",
        "rc_categories": "მხოლოდ კატეგორიებიდან (განაცალკევეთ \"|\"-ის მიხედვით)",
-       "rc_categories_any": "ნებისმიერი",
+       "rc_categories_any": "á\83\90á\83 á\83©á\83\94á\83£á\83\9aá\83\98á\83\93á\83\90á\83\9c á\83\9cá\83\94á\83\91á\83\98á\83¡á\83\9bá\83\98á\83\94á\83 á\83\98",
        "rc-change-size": "$1",
        "rc-change-size-new": "ზომა ცვლილების შემდეგ არის: {{PLURAL:$1|ბაიტი|ბაიტი}}",
        "newsectionsummary": "/* $1 */ ახალი სექცია",
        "upload-too-many-redirects": "URL შეიცავს ძალიან ბევრ გადამისამართებებს",
        "upload-http-error": "მოხდა HTTP შეცდომა: $1",
        "upload-copy-upload-invalid-domain": "ამ დომენში ატვირთვების კოპირება არ არის ხელმისაწვდომი.",
+       "upload-dialog-title": "ფაილის ატვირთვა",
+       "upload-dialog-button-cancel": "გაუქმება",
+       "upload-dialog-button-done": "შესრულდა",
+       "upload-dialog-button-save": "შენახვა",
+       "upload-dialog-button-upload": "ატვირთვა",
+       "upload-process-error": "მოხდა შეცდომა",
+       "upload-process-warning": "გაჩნდა გაფრთხილება",
+       "upload-form-label-select-file": "ფაილის არჩევა",
+       "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": "ფაილის სახელი",
        "backend-fail-stream": "ფაილი $1 ტრანსლირება ვერ მოხერხდა.",
        "backend-fail-backup": "ფაილი $1 სარეზერვო ასლის გაკეთება ვერ მოხერხდა.",
        "backend-fail-notexists": "ფაილი $1 არ არსებობს.",
        "filerevert-legend": "დააბრუნე ფაილი",
        "filerevert-intro": "<span class=\"plainlinks\">თქვენ აბრუნებთ '''[[Media:$1|$1]]'''  [$4 ვერსიას $3, $2]-თან.</span>",
        "filerevert-comment": "მიზეზი:",
-       "filerevert-defaultcomment": "დაბრუნება ვერსიასთან $2, $1-დან.",
+       "filerevert-defaultcomment": "დაბრუნება ვერსიასთან $2, $1-დან ($3).",
        "filerevert-submit": "გაუქმება",
        "filerevert-success": "'''[[Media:$1|$1]]''' დაუბრუნდა ვერსიას [$4  $3, $2]-დან.",
        "filerevert-badversion": "არ არსებობს ფაილის წინა ლოკალური ვერსია მოთხოვნილი  თარიღითა და დროით",
        "nopagetext": "მოცემული სამიზნო გვერდი არ არის მიითებული.",
        "pager-newer-n": "{{PLURAL:$1|უახლესი 1|უახლესი $1}}",
        "pager-older-n": "{{PLURAL:$1|უფრო ძველი 1|უფრო ძველი $1}}",
-       "suppress": "á\83\93á\83\90á\83\9bá\83\90á\83\9aá\83\95ა",
+       "suppress": "á\83©á\83\90á\83®á\83¨á\83\9dá\83\91ა",
        "querypage-disabled": "ეს სპეცგვერდი გამორთულია წარმადობის გასაზრდელად.",
        "apihelp": "API დახმარება",
        "apihelp-no-such-module": "მოდული „$1“ ვერ მოიძებნა.",
        "booksources-text": "ქვემოთ არის ვებ გვერდების ბმულების სია სადაც იყიდება ახალი და ნახმარი წიგნები, და შესაძლოა შეიცავდნენ დამატებით ინფორმაციას წიგნების შესახებ, რომლებსაც ეძებთ:",
        "booksources-invalid-isbn": "თქვენს მიერ მითითებული ISBN, შეცდომას შეიცავს.  შეამოწმეთ, თუ თავდაპირველი წყარო სწორადაა აკრეფილი.",
        "specialloguserlabel": "შემსრულებელი:",
-       "speciallogtitlelabel": "მიზანი (სათაური, ან მომხმარებელი):",
+       "speciallogtitlelabel": "მიზანი (სათაური, ან {{ns:user}}:მომხმარებლის სახელი):",
        "log": "ჟურნალები",
        "all-logs-page": "ყველა საზოგადო ჟურნალი",
        "alllogstext": "{{SITENAME}}-ის ყველა არსებული ჩანაწერის კომბინირებული ჩვენება.\nშეგიძლიათ გაცხრილოთ იგი ჩანაწერის ტიპის, მომხმარებლის სახელის, ან დაკავშირებული გვერდის შერჩევით.",
        "rollback-success": "გაუქმდა რედაქტირება $1; დაბრუნება ვერსიაზე $2.",
        "sessionfailure-title": "სეანსის შეცდომა",
        "sessionfailure": "ჩანს, რომ პრობლემაა თქვენი რეგისტრაციის სესიისათვის;\nეს მოქმედება შეჩერდა თქვენი სესიაში შემოჭრის თავიდან ასაცილებლად.\nგთხოვთ, დააწკაპუნოთ ღილაკს „უკან“ და თავიდან ჩართოთ გვერდი, რომლიდანაც შემოხვედით და სცადოთ განმეორებით.",
+       "changecontentmodel-legend": "შინაარსის მოდელის შეცვლა",
+       "changecontentmodel-title-label": "გვერდის სათაური",
+       "changecontentmodel-model-label": "შინაარსის ახალი მოდელი",
+       "changecontentmodel-reason-label": "მიზეზი:",
+       "changecontentmodel-success-title": "შინაარსის მოდელი შეიცვალა",
+       "logentry-contentmodel-change-revertlink": "დაბრუნება",
+       "logentry-contentmodel-change-revert": "დაბრუნება",
        "protectlogpage": "დაცვის ისტორია",
        "protectlogtext": "ქვემოთ წარმოდგენილია გვერდის დაცვის დონის ცვლილებების სია. \nიხილეთ ასევე [[Special:ProtectedPages|დაცული გვერდების სია]] ამ მომენტისთვის.",
        "protectedarticle": "დაცულია გვერდი: „[[$1]]“",
        "variantname-zh-my": "my",
        "variantname-zh": "zh",
        "variantname-gan-hans": "hans",
+       "variantname-kk-kz": "kk-kz",
+       "variantname-kk-tr": "kk-tr",
+       "variantname-kk-cn": "kk-cn",
+       "variantname-kk-cyrl": "kk-cyrl",
+       "variantname-kk-latn": "kk-latn",
+       "variantname-kk-arab": "kk-arab",
+       "variantname-kk": "kk",
        "metadata": "მეტამონაცემები",
        "metadata-help": "ეს ფაილი შეიცავს დამატებით ინფორმაციას, სავარაუდოდ ციფრული კამერიდან ან სკანერიდან, რომელიც მის შესაქმნელად გამოიყენეს. თუ ფაილის ორიგინალი შეცვლილია, ზოგიერთი დეტალი შესაძლოა სრულად არ ასახავდეს ფაილში შეტანილ ცვლილებებს.",
        "metadata-expand": "დამატებითი ინფორმაციის ჩვენება",
        "version-libraries": "დაინსტალირებული ბიბლიოთეკები",
        "version-libraries-library": "ბიბლიოთეკა",
        "version-libraries-version": "ვერსია",
+       "version-libraries-license": "ლიცენზია",
+       "version-libraries-description": "აღწერა",
+       "version-libraries-authors": "ავტორები",
        "redirect": "გადამისამართება ფაილიდან, მომხმარებლიდან, გვერდიდან ან ვერსიის იდენტიფიკატორიდან",
        "redirect-legend": "გადამისამართება ფაილზე ან გვერდზე",
        "redirect-summary": "ეს დამხმარე გვერდი ამისამართებს ფაილის (ფაილის სახელიდან) გვერდზე, (გვერდის ან ვერსიის იდენტიფიკატორიდან) ან მომხმარებლის გვერდზე (მომხმარებლის რაოდენობრივი იდენტიფიკატორიდან). გამოყენება: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]] ან [[{{#Special:Redirect}}/user/101]].",
        "htmlform-cloner-create": "მეტის დამატება",
        "htmlform-cloner-delete": "წაშლა",
        "htmlform-cloner-required": "აუცილებელია სულ მცირე ერთი მნიშვნელობა.",
+       "htmlform-title-not-exists": "[[:$1]] არ არსებობს.",
+       "htmlform-user-not-exists": "<strong>$1</strong> არ არსებობს.",
+       "htmlform-user-not-valid": "<strong>$1</strong> არ არის სწორი მომხმარებლის სახელი.",
        "sqlite-has-fts": "$1 სრული ტექსტის ძიების მხარდაჭერით",
        "sqlite-no-fts": "$1 სრული ტექსტის ძიების მხარდაჭერის გარეშე",
        "logentry-delete-delete": "მომხმარებელმა $1 {{GENDER:$2|წაშალა}} გვერდი: „$3“",
        "special-characters-title-endash": "ტირე",
        "special-characters-title-emdash": "გრძელი ტირე",
        "special-characters-title-minus": "მინუსის ნიშანი",
+       "mw-widgets-dateinput-no-date": "თარიღი არ არის არჩეული",
        "mw-widgets-dateinput-placeholder-day": "წწწწ-თთ-დდ",
        "mw-widgets-dateinput-placeholder-month": "წწწწ-თთ",
        "mw-widgets-titleinput-description-new-page": "გვერდი ჯერ არ არსებობს",
index 5d881be..68d2c87 100644 (file)
        "upload-http-error": "HTTP қатесі кездесті: $1",
        "upload-copy-upload-invalid-domain": "Бұл домейннен еселеп жүктеу қолжетімді емес.",
        "upload-dialog-title": "Файл жүктеу",
-       "upload-dialog-error": "Белгісіз қате кездесті",
-       "upload-dialog-warning": "Ескерту кездесті",
        "upload-dialog-button-cancel": "Қажет емес",
        "upload-dialog-button-done": "Бітті",
        "upload-dialog-button-save": "Сақтау",
        "upload-dialog-button-upload": "Жүктеу",
-       "upload-dialog-label-select-file": "Файлды таңдау",
-       "upload-dialog-label-infoform-title": "Егжей-тегжейі",
-       "upload-dialog-label-infoform-name": "Атауы",
-       "upload-dialog-label-infoform-description": "Сипаттамасы",
-       "upload-dialog-label-usage-title": "Қолданылуы",
-       "upload-dialog-label-usage-filename": "Файл атауы",
+       "upload-process-error": "Белгісіз қате кездесті",
+       "upload-process-warning": "Ескерту кездесті",
+       "upload-form-label-select-file": "Файлды таңдау",
+       "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": "Файл атауы",
        "backend-fail-stream": "«$1» файлы ақпады.",
        "backend-fail-backup": "«$1» файлының сақтық есесі жасалмады.",
        "backend-fail-notexists": "$1 файлы бар емес.",
        "logentry-suppress-revision": "$1 $3 бетіндегі {{PLURAL:$5|нұсқаның|$5 нұсқаның}} көрінулігін құпия түрде {{GENDER:$2|өзгертті}}",
        "logentry-suppress-event-legacy": "$1 $3 бетіндегі журнал оқиғаларының көрінулігін құпия түрде {{GENDER:$2|өзгертті}}",
        "logentry-suppress-revision-legacy": "$1 $3 бетіндегі нұсқалардың көрінулігін құпия түрде {{GENDER:$2|өзгертті}}",
-       "revdelete-content-hid": "мағлұматын жасырыды",
+       "revdelete-content-hid": "мағлұматын жасырды",
        "revdelete-summary-hid": "өңдеу түйіндемесін жасырды",
        "revdelete-uname-hid": "қатысушы есімін жасырды",
        "revdelete-content-unhid": "мағлұматы жасырылмаған",
index 0cc83c4..816366b 100644 (file)
        "jumpto": "លោតទៅ៖",
        "jumptonavigation": "ការណែនាំ",
        "jumptosearch": "ស្វែងរក",
-       "view-pool-error": "សូមអភ័យទោស។ ប្រព័ន្ធបម្រើការមានការមមាញឹកខ្លាំងពេកនៅពេលនេះ។\n\nមានអ្នកប្រើប្រាស់ជាច្រើនកំពុងព្យាយាមចូលមើលទំព័រនេះ។\n\nសូមរង់ចាំមួយភ្លែតសិនរួចសាកល្បងចូលមកកាន់ទំព័រនេះឡើងវិញ។\n\n$1",
+       "view-pool-error": "សូមអភ័យទោស។ ប្រព័ន្ធបម្រើការមានការមមាញឹកខ្លាំងពេកនៅពេលនេះ។\nមានអ្នកប្រើប្រាស់ជាច្រើនកំពុងព្យាយាមចូលមើលទំព័រនេះ។\nសូមរង់ចាំមួយភ្លែតសិនរួចសាកល្បងចូលមកកាន់ទំព័រនេះឡើងវិញ។\n\n$1",
+       "generic-pool-error": "សូមអភ័យទោស។ ប្រព័ន្ធបម្រើការមានការមមាញឹកខ្លាំងពេកនៅពេលនេះ។\nមានអ្នកប្រើប្រាស់ជាច្រើនកំពុងព្យាយាមចូលមើលទំព័រនេះ។\nសូមរង់ចាំមួយភ្លែតសិនរួចសាកល្បងចូលមកកាន់ទំព័រនេះឡើងវិញ។",
        "pool-errorunknown": "កំហុសមិនស្គាល់",
        "aboutsite": "អំពី{{SITENAME}}",
        "aboutpage": "Project:អំពី",
        "nstab-template": "ទំព័រគំរូ",
        "nstab-help": "ទំព័រជំនួយ",
        "nstab-category": "ចំណាត់ថ្នាក់ក្រុម",
+       "mainpage-nstab": "ទំព័រដើម",
        "nosuchaction": "គ្មានសកម្មភាពបែបនេះទេ",
        "nosuchactiontext": "សកម្មភាព​បានបង្ហាញដោយ URL មិន​ត្រឹមត្រូវ​។\nអ្នក​ប្រហែលជាបាន​វាយ URL ខុស បើ​មិន​ដូច្នេះ​ទេ​មាន​តែ​តំណភ្ជាប់​មិន​ត្រឹមត្រូវ​។\nនេះ​ក៏​អាច​បញ្ជាក់​ប្រាប់​ពី​កំហុស​នៅ​ក្នុង​ផ្នែកទន់​ប្រើដោយ {{SITENAME}} ។",
        "nosuchspecialpage": "គ្មានទំព័រពិសេសបែបនេះទេ",
        "createacct-captcha": "ត្រួតពិនិត្យសុវត្ថិភាព",
        "createacct-imgcaptcha-ph": "បញ្ចូលឃ្លាដែលអ្នកឃើញខាងលើ",
        "createacct-submit": "បង្កើតគណនីរបស់អ្នក",
-       "createacct-another-submit": "បង្កើតគណនីមួយទៀត",
+       "createacct-another-submit": "បង្កើតគណនី",
        "createacct-benefit-heading": "{{SITENAME}} ត្រូវបង្កើតឡើងដោយបុគ្គលស្ម័គ្រចិត្តដូចជាអ្នកជាដើម។",
        "createacct-benefit-body1": "{{PLURAL:$1|កំណែ|កំណែ}}",
        "createacct-benefit-body2": "{{PLURAL:$1|ទំព័រ|ទំព័រ}}",
        "createacct-benefit-body3": "{{PLURAL:$1|អ្នករួមចំណែក|អ្នករួមចំណែក}}ថ្មីៗ",
        "badretype": "ពាក្យសម្ងាត់ដែលអ្នកបានវាយបញ្ចូលនោះ គឺមិនស៊ីគ្នាទេ។",
+       "usernameinprogress": "ការបង្កើតគណនីសម្រាប់អ្នកប្រើប្រាស់នេះកំពុងប្រព្រឹត្តទៅ។ សូមរង់ចាំបន្តិច។",
        "userexists": "អត្តនាមដែលអ្នកបានវាយបញ្ចូលមានគេប្រើហើយ។\nសូមជ្រើសរើសអត្តនាមផ្សេងពីនេះ។",
        "loginerror": "កំហុសនៃការកត់ឈ្មោះចូល",
        "createacct-error": "បញ្ហាក្នុងការបង្កើតគណនី",
        "changeemail-password": "ពាក្យសំងាត់{{SITENAME}}របស់អ្នក:",
        "changeemail-submit": "ផ្លាស់ប្ដូរអ៊ីមែល",
        "changeemail-throttled": "អ្នកបានព្យាយាមកត់ឈ្មោះចូលច្រើនដងពេកហើយ។​\nសូមរង់ចាំរយៈពេល$1 មុនពេលសាកល្បងម្ដងទៀត។",
+       "changeemail-nochange": "សូមវាយបញ្ចូលអាសយដ្ឋានអ៊ីមែលផ្សេងមួយទៀត។",
        "bold_sample": "អក្សរដិត",
        "bold_tip": "អក្សរដិត",
        "italic_sample": "អក្សរទ្រេត",
        "search-category": "(ចំណាត់ថ្នាក់ក្រុម $1)",
        "search-file-match": "(ខ្លឹមសារឯកសារត្រូវគ្នា)",
        "search-suggest": "ប្រហែលជាអ្នកចង់រក៖ $1",
+       "search-rewritten": "បង្ហាញលទ្ធផលពីការស្វែងរក $1។ ស្វែងរក $2 ជំនួសវិញ។",
        "search-interwiki-caption": "គម្រោងជាបងប្អូន",
        "search-interwiki-default": "លទ្ធផលពី$1៖",
        "search-interwiki-more": "(បន្ថែមទៀត)",
        "prefsnologintext2": "សូមកត់ឈ្មោះចូលដើម្បីផ្លាស់ប្ដូរចំណង់ចំណូលចិត្តរបស់អ្នក។",
        "prefs-skin": "សំបក",
        "skin-preview": "មើលជាមុន",
-       "datedefault": "គ្មានចំណូលចិត្ត",
-       "prefs-labs": "á\9e\98á\9e»á\9e\81á\9e\84á\9e¶á\9e\9aá\9e\96á\9e·á\9e\9fá\9f\81á\9e\9fá\9e\90á\9f\92á\9e\98á\9e¸á\9f\97á\9e\8aá\9f\82á\9e\9bá\9e\9fá\9f\92á\9e\90á\9e·á\9e\8fá\9e\80á\9f\92á\9e\9aá\9f\84á\9e\98á\9e\80á\9e¶á\9e\9aá\9e\96á\9e·á\9e\9fá\9f\84á\9e\92á\9e\93á\9f\8dá\9e\93á\9f\85á\9e¡á\9e¾á\9e\99",
+       "datedefault": "á\9e\82á\9f\92á\9e\98á\9e¶á\9e\93á\9e\85á\9f\86á\9e\8eá\9e\84á\9f\8bá\9e\85á\9f\86á\9e\8eá\9e¼á\9e\9bá\9e\85á\9e·á\9e\8fá\9f\92á\9e\8f",
+       "prefs-labs": "á\9e\98á\9e»á\9e\81á\9e\84á\9e¶á\9e\9aá\9e\96á\9e·á\9e\9fá\9f\81á\9e\9fá\9e\80á\9f\92á\9e\9aá\9f\84á\9e\98á\9e\80á\9e¶á\9e\9aá\9e\96á\9e·á\9e\9fá\9f\84á\9e\92á\9e\93á\9f\8d",
        "prefs-user-pages": "ទំព័រអ្នកប្រើប្រាស់",
        "prefs-personal": "ប្រវត្តិរូប",
        "prefs-rc": "បន្លាស់​ប្ដូរ​ថ្មីៗ",
        "prefs-resetpass": "ប្តូរពាក្យសម្ងាត់",
        "prefs-changeemail": "ផ្លាស់ប្ដូរអ៊ីមែល",
        "prefs-setemail": "ដាក់អាសយដ្ឋានអ៊ីមែលមួយ",
-       "prefs-email": "\nជំរើសទាក់ទិននឹងអ៊ីមែល",
+       "prefs-email": "ជម្រើសទាក់ទិននឹងអ៊ីមែល",
        "prefs-rendering": "ការរចនា",
        "saveprefs": "រក្សាទុក",
        "restoreprefs": "ស្ដារ​ការកំណត់​ទាំងអស់​ទៅ​លំនាំដើម (គ្រប់ផ្នែកទាំងអស់)",
        "rows": "ជួរដេក៖",
        "columns": "ជួរឈរ៖",
        "searchresultshead": "ស្វែងរក",
-       "stub-threshold": "ទំហំអប្បបរមាសំរាប់ដាក់ជាទំរង់<a href=\"#\" class=\"stub\">តំណភ្ជាប់ទៅទំព័រកំប៉ិចកំប៉ុក</a> (គិតជាបៃ)៖",
+       "stub-threshold": "ទំហំអប្បបរមាសម្រាប់ដាក់ជាទម្រង់ទំព័រកំប៉ិចកំប៉ុក($1)៖",
+       "stub-threshold-sample-link": "គំរូ",
        "stub-threshold-disabled": "មិនប្រើ",
        "recentchangesdays": "ចំនួនថ្ងៃបង្ហាញក្នុងទំព័របន្លាស់ប្តូរថ្មីៗ៖",
        "recentchangesdays-max": "(អតិបរមា $1 {{PLURAL:$1|ថ្ងៃ|ថ្ងៃ}})",
        "savedprefs": "ចំណង់ចំណូលចិត្តនានារបស់អ្នកត្រូវបានរក្សាទុកហើយ។",
        "timezonelegend": "ល្វែង​ម៉ោង:",
        "localtime": "ម៉ោងក្នុងស្រុក​៖",
-       "timezoneuseserverdefault": "á\9e\8fá\9e¶á\9e\98á\9e\80á\9e¶á\9e\9aá\9e\80á\9f\86á\9e\93ត់ដើមរបស់វិគី ($1)",
-       "timezoneuseoffset": "á\9e\95á\9f\92á\9e\9fá\9f\81á\9e\84á\9e\91á\9f\80á\9e\8f (á\9e\94á\9e\89á\9f\92á\9e\85á\9e¼á\9e\9bá\9e\98á\9f\89á\9f\84á\9e\84á\9e\8aá\9f\84á\9e\99á\9e\81á\9f\92á\9e\9bá\9e½á\9e\93á\9e¯ង)",
-       "servertime": "ម៉ោងម៉ាស៊ីនបម្រើ​៖",
+       "timezoneuseserverdefault": "á\9e\8fá\9e¶á\9e\98á\9e\80á\9e¶á\9e\9aá\9e\80á\9f\86á\9e\8eត់ដើមរបស់វិគី ($1)",
+       "timezoneuseoffset": "á\9e\95á\9f\92á\9e\9fá\9f\81á\9e\84á\9e\91á\9f\80á\9e\8f (á\9e\80á\9f\86á\9e\8eá\9e\8fá\9f\8bá\9e\82á\9e\98á\9f\92á\9e\9bá\9e¶á\9e\8fá\9e\98á\9f\89á\9f\84ង)",
+       "servertime": "á\9e\98á\9f\89á\9f\84á\9e\84á\9e\98á\9f\89á\9e¶á\9e\9fá\9f\8aá\9e¸á\9e\93á\9e\94á\9e\98á\9f\92á\9e\9aá\9e¾â\80\8bá\9e\80á\9e¶á\9e\9aá\9f\96",
        "guesstimezone": "បំពេញពីកម្មវិធីរាវរក",
        "timezoneregion-africa": "អាហ្វ្រិក",
        "timezoneregion-america": "អាមេរិក",
        "prefs-namespaces": "លំហឈ្មោះ",
        "default": "លំនាំដើម",
        "prefs-files": "ឯកសារ",
-       "prefs-custom-css": "កែតំរូវ CSS",
-       "prefs-custom-js": "កែតំរូវ JS",
+       "prefs-custom-css": "CSS កែសម្រួល",
+       "prefs-custom-js": "JavaScript កែសម្រួល",
        "prefs-common-css-js": "CSS/JavaScriptរួមសំរាប់សំបកទាំងអស់",
        "prefs-reset-intro": "អ្នក​អាច​ប្រើ​ទំព័រ​នេះ​ដើម្បី​កំណត់​ឡើង​វិញ​នូវ​ចំណូល​ចិត្ត​របស់​អ្នក​ដូច​លំនាំ​ដើម​របស់​តំបន់​វិញ​។\nសកម្មភាព​នេះ​មិន​អាច​ធ្វើ​ឡើង​វិញ​បាន​ទេ​។",
        "prefs-emailconfirm-label": "បញ្ជាក់ទទួលស្គាល់អ៊ីមែល៖",
        "upload-too-many-redirects": "URLនេះមានតំណភ្ជាប់បញ្ជូនបន្តច្រើនពេកហើយ",
        "upload-http-error": "មានកំហុសHTTPមួយបានកើតឡើង៖ $1",
        "upload-dialog-title": "ផ្ទុកឯកសារឡើង",
-       "upload-dialog-error": "មានបញ្ហាកើតឡើង",
-       "upload-dialog-warning": "មានការព្រមាន",
        "upload-dialog-button-cancel": "បោះបង់",
        "upload-dialog-button-done": "រួចរាល់",
        "upload-dialog-button-save": "រក្សាទុក",
        "upload-dialog-button-upload": "ផ្ទុកឡើង",
-       "upload-dialog-label-select-file": "ជ្រើសរើសឯកសារ",
-       "upload-dialog-label-infoform-title": "ព័ត៌មាន​លំអិត",
-       "upload-dialog-label-infoform-name": "ឈ្មោះ​",
-       "upload-dialog-label-infoform-description": "ការ​ពិពណ៌នា",
-       "upload-dialog-label-usage-title": "បម្រើបម្រាស់",
-       "upload-dialog-label-usage-filename": "ឈ្មោះឯកសារ",
+       "upload-process-error": "មានបញ្ហាកើតឡើង",
+       "upload-process-warning": "មានការព្រមាន",
+       "upload-form-label-select-file": "ជ្រើសរើសឯកសារ",
+       "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": "ឈ្មោះឯកសារ",
        "backend-fail-notexists": "គ្មានឯកសារ \"$1\" ទេ។",
        "backend-fail-notsame": "ឯកសារដែលមិនដូចគ្នាបេះបិទមួយមានរួចហើយនៅ \"$1\"។",
        "backend-fail-delete": "មិនអាចលុបឯកសារ \"$1\" បានទេ។",
        "filerevert-legend": "ត្រឡប់ឯកសារ",
        "filerevert-intro": "អ្នក​កំពុង​នឹង​ចាប់​ផ្ដើម​ត្រឡប់​ឯកសារ​'''[[Media:$1|$1]]''' ទៅ​កាន់​[កំណែ​ $4 ដែលមាន​កាល​បរិច្ឆេទ​ $3, $2]។",
        "filerevert-comment": "មូលហេតុ៖",
-       "filerevert-defaultcomment": "á\9e\94á\9e\98á\9f\92á\9e\9bá\9f\82á\9e\84á\9e\91á\9f\85á\9e\80á\9f\86á\9e\8eá\9f\82á\9e\94á\9f\92á\9e\9aá\9f\82á\9e\8aá\9e¾á\9e\98á\9e\87á\9e¶$2, $1",
+       "filerevert-defaultcomment": "á\9e\94á\9e¶á\9e\93á\9e\94á\9f\86á\9e\9bá\9f\82á\9e\84á\9e\8fá\9f\92á\9e\9aá\9e¡á\9e\94á\9f\8bá\9e\91á\9f\85á\9e\80á\9f\86á\9e\8eá\9f\82 $2, $1 ($3)",
        "filerevert-submit": "ត្រឡប់",
        "filerevert-success": "បានត្រឡប់ '''[[Media:$1|$1]]''' ទៅ [$4 កំណែកាលពី $3, $2]",
        "filerevert-badversion": "ឯកសារដែលមានកាលបរិច្ឆេទដូចដែលអ្នកផ្ដល់អោយ មិនមានកំណែពីមុននៅក្នុងវិគីនេះទេ។",
index b45065c..a68415a 100644 (file)
        "nstab-template": "틀",
        "nstab-help": "도움말",
        "nstab-category": "분류",
+       "mainpage-nstab": "대문",
        "nosuchaction": "이러한 명령이 없습니다",
        "nosuchactiontext": "URL에 지정한 명령이 올바르지 않습니다.\nURL을 잘못 입력했거나, 올바르지 않은 링크를 따라갔을 수 있습니다.\n{{SITENAME}}에 사용하는 소프트웨어의 버그가 있을 수 있습니다.",
        "nosuchspecialpage": "해당하는 특수 문서가 없습니다.",
        "createacct-captcha": "보안 검사",
        "createacct-imgcaptcha-ph": "위에 보이는 텍스트를 입력하세요",
        "createacct-submit": "계정 만들기",
-       "createacct-another-submit": "다른 계정 만들기",
+       "createacct-another-submit": "계정 만들기",
        "createacct-benefit-heading": "{{SITENAME}} 프로젝트는 여러분과 같은 사람들이 만듭니다.",
        "createacct-benefit-body1": "{{PLURAL:$1|편집}}",
        "createacct-benefit-body2": "{{PLURAL:$1|문서}}",
        "changeemail-password": "{{SITENAME}} 비밀번호:",
        "changeemail-submit": "이메일 주소 바꾸기",
        "changeemail-throttled": "로그인에 연속으로 너무 많이 실패하였습니다.\n$1 기다렸다가 다시 시도하세요.",
+       "changeemail-nochange": "다른 이메일 주소를 입력해 주세요.",
        "resettokens": "토큰 재설정",
        "resettokens-text": "여기에 당신의 계정과 관련된 특정 개인 데이터에 접근을 허용하는 토큰을 재설정합니다.\n\n토큰이 다른 사람에게 알려졌거나 계정이 침해되었을 때는 재설정해야 합니다.",
        "resettokens-no-tokens": "재설정할 토큰이 없습니다.",
        "rows": "줄 수:",
        "columns": "열 수:",
        "searchresultshead": "검색",
-       "stub-threshold": "링크를 <a href=\"#\" class=\"stub\">토막글</a> 형식으로 보여줄 문서 크기 (바이트 수):",
+       "stub-threshold": "링크를 토막글 형식으로 보여줄 문서 크기 ($1):",
+       "stub-threshold-sample-link": "샘플",
        "stub-threshold-disabled": "비활성화됨",
        "recentchangesdays": "최근 바뀜에 보여줄 날짜 수:",
        "recentchangesdays-max": "최대 $1{{PLURAL:$1|일}}",
        "upload-http-error": "HTTP 오류 발생: $1",
        "upload-copy-upload-invalid-domain": "이 도메인에 속하지 않는 웹사이트의 파일을 올릴 수 없습니다.",
        "upload-dialog-title": "파일 올리기",
-       "upload-dialog-error": "오류가 발생했습니다",
-       "upload-dialog-warning": "경고가 일어났습니다",
        "upload-dialog-button-cancel": "취소",
        "upload-dialog-button-done": "완료",
        "upload-dialog-button-save": "저장",
        "upload-dialog-button-upload": "올리기",
-       "upload-dialog-label-select-file": "파일을 선택해주세요.",
-       "upload-dialog-label-infoform-title": "자세한 사항",
-       "upload-dialog-label-infoform-name": "이름",
-       "upload-dialog-label-infoform-description": "설명",
-       "upload-dialog-label-usage-title": "사용",
-       "upload-dialog-label-usage-filename": "파일 이름",
+       "upload-process-error": "오류가 발생했습니다",
+       "upload-process-warning": "경고가 일어났습니다",
+       "upload-form-label-select-file": "파일을 선택해주세요.",
+       "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": "파일 이름",
        "backend-fail-stream": "\"$1\" 파일을 스트림할 수 없습니다.",
        "backend-fail-backup": "\"$1\" 파일을 백업할 수 없습니다.",
        "backend-fail-notexists": "$1 파일이 존재하지 않습니다.",
        "filerevert-legend": "파일 되돌리기",
        "filerevert-intro": "'''[[Media:$1|$1]]''' 파일을 [$4 $2 $3 버전]으로 되돌립니다.",
        "filerevert-comment": "이유:",
-       "filerevert-defaultcomment": "$1 $2 판으로 되돌림",
+       "filerevert-defaultcomment": "$1 $2 ($3) 판으로 되돌림",
        "filerevert-submit": "되돌리기",
        "filerevert-success": "'''[[Media:$1|$1]]''' 파일을 [$4 $2 $3 버전]으로 되돌렸습니다.",
        "filerevert-badversion": "입력된 시간 기록을 가진 파일의 로컬 버전이 없습니다.",
        "booksources-text": "아래의 목록은 새 책이나 중고 책을 판매하는 바깥 사이트로, 원하는 책의 정보를 얻을 수 있습니다.",
        "booksources-invalid-isbn": "입력한 ISBN이 올바르지 않은 것으로 보입니다. 원본과 대조해 문제가 있는지 확인해보세요.",
        "specialloguserlabel": "작업 수행자:",
-       "speciallogtitlelabel": "대상 (제목 또는 사용자):",
+       "speciallogtitlelabel": "대상 (제목 또는 {{ns:user}}:사용자_이름 으로사용자):",
        "log": "기록 목록",
        "all-logs-page": "모든 공개 기록",
        "alllogstext": "{{SITENAME}}에서의 기록이 모두 나와 있습니다.\n기록 종류, 사용자 이름, 문서 이름을 선택해서 볼 수 있습니다. (대소문자를 구별합니다.)",
        "sessionfailure-title": "세션 실패",
        "sessionfailure": "로그인 세션에 문제가 발생한 것 같습니다.\n세션 하이재킹을 막기 위해 동작이 취소되었습니다.\n브라우저의 뒤로 버튼을 누르고 문서를 새로 고침한 후에 다시 시도해 주세요.",
        "changecontentmodel-title-label": "문서 제목",
+       "changecontentmodel-model-label": "새 콘텐츠 모델",
        "changecontentmodel-reason-label": "이유:",
+       "changecontentmodel-success-title": "콘텐츠 모델이 변경되었습니다",
+       "changecontentmodel-success-text": "[[:$1]]의 콘텐츠 종류가 변경되었습니다.",
+       "changecontentmodel-cannot-convert": "[[:$1]]의 콘텐츠 모델이 $2의 모델로 전환될 수 없습니다.",
+       "changecontentmodel-nodirectediting": "$1 콘텐츠 모델은 직접 편집을 지원하지 않습니다",
+       "log-name-contentmodel": "콘텐츠 모델 변경 기록",
+       "log-description-contentmodel": "페이지의 콘텐츠 모델과 관련된 행위",
+       "logentry-contentmodel-change": "$1 사용자가 $3 의 콘텐츠 모델을 \"$4\"에서 \"$5\"로 {{GENDER:$2|변경하였습니다}}.",
        "logentry-contentmodel-change-revertlink": "되돌리기",
        "logentry-contentmodel-change-revert": "되돌리기",
        "protectlogpage": "문서 보호 기록",
        "lockedbyandtime": "({{GENDER:$1|$1}} 사용자가 $2 $3에 잠금)",
        "move-page": "$1 옮기기",
        "move-page-legend": "문서 옮기기",
-       "movepagetext": "ì\95\84ë\9e\98 ì\96\91ì\8b\9dì\9d\84 ì±\84ì\9b\8c ë¬¸ì\84\9cì\9d\98 ì\9d´ë¦\84ì\9d\84 ë°\94꾸고 ëª¨ë\93  ì\97­ì\82¬ë¥¼ ì\83\88 ì\9d´ë¦\84ì\9c¼ë¡\9c ë\90\9c ë¬¸ì\84\9cë¡\9c ì\98®ê¸¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9b\90ë\9e\98ì\9d\98 ë¬¸ì\84\9cë\8a\94 ì\83\88 ë¬¸ì\84\9cë¡\9c ë\84\98겨주ë\8a\94 ë§\81í\81¬ë¡\9cë§\8c ë\82¨ê²\8c ë\90\98ê³ ,\nì\9b\90ë\9e\98 ì\9d´ë¦\84ì\9d\84 ê°\80리í\82¤ë\8a\94 ë\84\98겨주기ë\8a\94 ì\9e\90ë\8f\99ì\9c¼ë¡\9c ê°±ì\8b ë\90©ë\8b\88ë\8b¤.\në§\8cì\95½ ì\9d´ ì\84¤ì \95ì\9d\84 ì\84 í\83\9dí\95\98ì§\80 ì\95\8aì\95\98ë\8b¤ë©´ [[Special:DoubleRedirects|ì\9d´ì¤\91 ë\84\98겨주기]]ì\99\80 [[Special:BrokenRedirects|ë\81\8a긴 ë\84\98겨주기]]를 í\99\95ì\9d¸í\95´ì£¼ì\84¸ì\9a\94.\në\8b¹ì\8b ì\9d\80 ë§\81í\81¬ì\99\80 ê°\80리í\82¤ë\8a\94 ë\8c\80ì\83\81ì\9d´ ì\84\9cë¡\9c ì\9d¼ì¹\98í\95\98ë\8f\84ë¡\9d í\95´ì\95¼ í\95\98ë\8a\94 ì±\85ì\9e\84ì\9d\84 ì§\91니다.\n\n만약 이미 있는 문서의 이름을 새 이름으로 입력했을 때는 그 문서가 넘겨주기 문서이고 문서 역사가 없어야만 이동이 됩니다. 그렇지 않을 경우에는 이동되지 <strong>않습니다</strong>.\n이것은 실수로 이동한 문서를 되돌릴 수는 있지만, 이미 존재하는 문서 위에 덮어씌울 수는 없다는 것을 의미합니다.\n\n<strong>주의!</strong>\n자주 사용하는 문서를 이동하면 해결하기 어려운 문제를 일으킬 수도 있습니다.\n이동하기 전에 반드시 이 문서를 이동해도 문제가 없는지 확인해주세요.",
-       "movepagetext-noredirectfixer": "ì\95\84ë\9e\98 ì\96\91ì\8b\9dì\9d\84 ì±\84ì\9b\8c ë¬¸ì\84\9cì\9d\98 ì\9d´ë¦\84ì\9d\84 ë°\94꾸고 ëª¨ë\93  ì\97­ì\82¬ë¥¼ ì\83\88 ì\9d´ë¦\84ì\9c¼ë¡\9c ë\90\9c ë¬¸ì\84\9cë¡\9c ì\98®ê¸¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9b\90ë\9e\98ì\9d\98 ë¬¸ì\84\9cë\8a\94 ì\83\88 ë¬¸ì\84\9cë¡\9c ë\84\98겨주ë\8a\94 ë§\81í\81¬ë¡\9cë§\8c ë\82¨ê²\8c ë\90©ë\8b\88ë\8b¤.\n[[Special:DoubleRedirects|ì\9d´ì¤\91 ë\84\98겨주기]]ì\99\80 [[Special:BrokenRedirects|ë\81\8a긴 ë\84\98겨주기]]를 í\99\95ì\9d¸í\95´ì£¼ì\84¸ì\9a\94.\në\8b¹ì\8b ì\9d\80 ë§\81í\81¬ì\99\80 ê°\80리í\82¤ë\8a\94 ë\8c\80ì\83\81ì\9d´ ì\84\9cë¡\9c ì\9d¼ì¹\98í\95\98ë\8f\84ë¡\9d í\95´ì\95¼ í\95\98ë\8a\94 ì±\85ì\9e\84ì\9d\84 ì§\91니다.\n\n만약 이미 있는 문서의 이름을 새 이름으로 입력했을 때는 그 문서가 넘겨주기 문서이고 문서 역사가 없어야만 이동이 됩니다. 그렇지 않을 경우에는 이동되지 <strong>않습니다</strong>.\n이것은 실수로 옮긴 문서를 되돌릴 수는 있지만, 이미 존재하는 문서 위에 덮어씌울 수는 없다는 것을 의미합니다.\n\n<strong>주의!</strong>\n자주 사용하는 문서를 이동하면 해결하기 어려운 문제를 일으킬 수도 있습니다.\n이동하기 전에 반드시 이 문서를 이동해도 문제가 없는지 확인해주세요.",
+       "movepagetext": "ì\95\84ë\9e\98 ì\96\91ì\8b\9dì\9d\84 ì±\84ì\9b\8c ë¬¸ì\84\9cì\9d\98 ì\9d´ë¦\84ì\9d\84 ë°\94꾸고 ëª¨ë\93  ì\97­ì\82¬ë¥¼ ì\83\88 ì\9d´ë¦\84ì\9c¼ë¡\9c ë\90\9c ë¬¸ì\84\9cë¡\9c ì\98®ê¸¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9b\90ë\9e\98ì\9d\98 ë¬¸ì\84\9cë\8a\94 ì\83\88 ë¬¸ì\84\9cë¡\9c ë\84\98겨주ë\8a\94 ë§\81í\81¬ë¡\9cë§\8c ë\82¨ê²\8c ë\90\98ê³ ,\nì\9b\90ë\9e\98 ì\9d´ë¦\84ì\9d\84 ê°\80리í\82¤ë\8a\94 ë\84\98겨주기ë\8a\94 ì\9e\90ë\8f\99ì\9c¼ë¡\9c ê°±ì\8b ë\90©ë\8b\88ë\8b¤.\në§\8cì\95½ ì\9d´ ì\84¤ì \95ì\9d\84 ì\84 í\83\9dí\95\98ì§\80 ì\95\8aì\95\98ë\8b¤ë©´ [[Special:DoubleRedirects|ì\9d´ì¤\91 ë\84\98겨주기]]ì\99\80 [[Special:BrokenRedirects|ë\81\8a긴 ë\84\98겨주기]]를 í\99\95ì\9d¸í\95´ì£¼ì\84¸ì\9a\94.\në\8b¹ì\8b ì\9d\80 ë§\81í\81¬ì\99\80 ê°\80리í\82¤ë\8a\94 ë\8c\80ì\83\81ì\9d´ ì\84\9cë¡\9c ì\9d¼ì¹\98í\95\98ë\8f\84ë¡\9d í\95´ì\95¼ í\95  ì±\85ì\9e\84ì\9d´ ì\9e\88ì\8aµ니다.\n\n만약 이미 있는 문서의 이름을 새 이름으로 입력했을 때는 그 문서가 넘겨주기 문서이고 문서 역사가 없어야만 이동이 됩니다. 그렇지 않을 경우에는 이동되지 <strong>않습니다</strong>.\n이것은 실수로 이동한 문서를 되돌릴 수는 있지만, 이미 존재하는 문서 위에 덮어씌울 수는 없다는 것을 의미합니다.\n\n<strong>주의!</strong>\n자주 사용하는 문서를 이동하면 해결하기 어려운 문제를 일으킬 수도 있습니다.\n이동하기 전에 반드시 이 문서를 이동해도 문제가 없는지 확인해주세요.",
+       "movepagetext-noredirectfixer": "ì\95\84ë\9e\98 ì\96\91ì\8b\9dì\9d\84 ì±\84ì\9b\8c ë¬¸ì\84\9cì\9d\98 ì\9d´ë¦\84ì\9d\84 ë°\94꾸고 ëª¨ë\93  ì\97­ì\82¬ë¥¼ ì\83\88 ì\9d´ë¦\84ì\9c¼ë¡\9c ë\90\9c ë¬¸ì\84\9cë¡\9c ì\98®ê¸¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9b\90ë\9e\98ì\9d\98 ë¬¸ì\84\9cë\8a\94 ì\83\88 ë¬¸ì\84\9cë¡\9c ë\84\98겨주ë\8a\94 ë§\81í\81¬ë¡\9cë§\8c ë\82¨ê²\8c ë\90©ë\8b\88ë\8b¤.\n[[Special:DoubleRedirects|ì\9d´ì¤\91 ë\84\98겨주기]]ì\99\80 [[Special:BrokenRedirects|ë\81\8a긴 ë\84\98겨주기]]를 í\99\95ì\9d¸í\95´ì£¼ì\84¸ì\9a\94.\në\8b¹ì\8b ì\9d\80 ë§\81í\81¬ì\99\80 ê°\80리í\82¤ë\8a\94 ë\8c\80ì\83\81ì\9d´ ì\84\9cë¡\9c ì\9d¼ì¹\98í\95\98ë\8f\84ë¡\9d í\95´ì\95¼ í\95  ì±\85ì\9e\84ì\9d´ ì\9e\88ì\8aµ니다.\n\n만약 이미 있는 문서의 이름을 새 이름으로 입력했을 때는 그 문서가 넘겨주기 문서이고 문서 역사가 없어야만 이동이 됩니다. 그렇지 않을 경우에는 이동되지 <strong>않습니다</strong>.\n이것은 실수로 옮긴 문서를 되돌릴 수는 있지만, 이미 존재하는 문서 위에 덮어씌울 수는 없다는 것을 의미합니다.\n\n<strong>주의!</strong>\n자주 사용하는 문서를 이동하면 해결하기 어려운 문제를 일으킬 수도 있습니다.\n이동하기 전에 반드시 이 문서를 이동해도 문제가 없는지 확인해주세요.",
        "movepagetalktext": "딸린 토론 문서도 자동으로 이동합니다. 하지만 다음의 경우는 '''이동하지 않습니다''':\n* 이동할 이름으로 된 문서가 이미 있는 경우\n* 아래의 선택을 해제하는 경우\n\n이 경우에는 문서를 직접 이동하거나 두 문서를 합쳐야 합니다.",
        "movearticle": "문서 옮기기:",
        "moveuserpage-warning": "<strong>경고:</strong> 사용자 문서를 옮기려 하고 있습니다. 사용자 문서만 이동되며 사용자 이름이 바뀌지 <strong>않는다</strong>는 점을 참고하세요.",
        "import-interwiki-history": "이 문서의 모든 역사를 가져오기",
        "import-interwiki-templates": "모든 틀을 포함하기",
        "import-interwiki-submit": "가져오기",
+       "import-mapping-default": "기본 위치로 들여오기",
+       "import-mapping-namespace": "이름공간으로 들여오기:",
+       "import-mapping-subpage": "이 문서의 하위문서로 들여오기:",
        "import-upload-filename": "파일 이름:",
        "import-comment": "요약:",
        "importtext": "원본 위키에서 [[Special:Export|내보내기]] 기능을 사용해 파일을 내려받으세요.\n그리고 당신의 컴퓨터에 저장해 둔 후 여기에 올려주세요.",
        "pageinfo-protect-cascading-yes": "예",
        "pageinfo-protect-cascading-from": "연쇄적 보호한 기점",
        "pageinfo-category-info": "분류 정보",
+       "pageinfo-category-total": "사용자 수",
        "pageinfo-category-pages": "문서 수",
        "pageinfo-category-subcats": "하위 분류 수",
        "pageinfo-category-files": "파일 수",
        "tags-deactivate-reason": "이유:",
        "tags-deactivate-not-allowed": "\"$1\" 태그를 비활성화할 수 없습니다.",
        "tags-deactivate-submit": "비활성화",
+       "tags-update-add-not-allowed-one": "\"$1\" 태그를 수동으로 추가하는 것은 허용되지 않습니다.",
+       "tags-update-add-not-allowed-multi": "다음 {{PLURAL:$2|태그는}} 수동으로 추가하는 것이 허용되지 않습니다: $1",
        "tags-update-remove-not-allowed-one": "\"$1\" 태그를 제거하는 것은 허용되지 않습니다.",
        "tags-edit-title": "태그 편집",
        "tags-edit-manage-link": "태그 관리",
        "api-error-badaccess-groups": "이 위키에 파일을 올릴 권한이 없습니다.",
        "api-error-badtoken": "내부 오류: 토큰이 잘못되었습니다.",
        "api-error-copyuploaddisabled": "이 서버에서 URL을 통해 파일 올리기가 비활성화되어 있습니다.",
-       "api-error-duplicate": "이 위키에 내용이 똑같은 {{PLURAL:$1|[$2 다른 파일]}}이 있습니다.",
+       "api-error-duplicate": "이 위키에 내용이 똑같은 {{PLURAL:$1|다른 파일}}이 있습니다.",
        "api-error-duplicate-archive": "같은 내용을 담고 있던 {{PLURAL:$1|다른 파일}}이 있었지만 이 {{PLURAL:$1|파일}}은 삭제되었습니다.",
        "api-error-empty-file": "올리려는 파일이 비어 있습니다.",
        "api-error-emptypage": "새 문서로 빈 문서를 만들 수 없습니다.",
index 8269b09..90f828b 100644 (file)
        "upload-http-error": "Ene <i lang=\"en\">HTTP</i>-Fäähler es opjetrodde: $1",
        "upload-copy-upload-invalid-domain": "Fun dä Domain künne mer nix noh heh huh laade. Di es nit zohjelohße.",
        "upload-dialog-title": "Dateij huhlahde",
-       "upload-dialog-error": "Ene Fähler es opjetrodde",
-       "upload-dialog-warning": "En Warnong wood ußjejovve.",
        "upload-dialog-button-cancel": "Ophühre!",
        "upload-dialog-button-done": "Jedonn",
        "upload-dialog-button-save": "Faßhalde",
        "upload-dialog-button-upload": "Lohß Jonn!",
-       "upload-dialog-label-select-file": "De ußjesöhk Dattei",
-       "upload-dialog-label-infoform-title": "Eijnzelheijte",
-       "upload-dialog-label-infoform-name": "Nahme",
-       "upload-dialog-label-infoform-description": "Äkliehrong",
-       "upload-dialog-label-usage-title": "Der Jebruch",
-       "upload-dialog-label-usage-filename": "Dä Dattei iehre Nahme",
+       "upload-process-error": "Ene Fähler es opjetrodde",
+       "upload-process-warning": "En Warnong wood ußjejovve.",
+       "upload-form-label-select-file": "De ußjesöhk Dattei",
+       "upload-form-label-infoform-title": "Eijnzelheijte",
+       "upload-form-label-infoform-name": "Nahme",
+       "upload-form-label-infoform-description": "Äkliehrong",
+       "upload-form-label-usage-title": "Der Jebruch",
+       "upload-form-label-usage-filename": "Dä Dattei iehre Nahme",
        "backend-fail-stream": "Mer kunnte di Dattei $1 nit övverdraare.",
        "backend-fail-backup": "Mer kunnte kein Sescherongskopih vun dä Dattei $1 maache.",
        "backend-fail-notexists": "En Dattei $1 jidd et nit.",
        "version-entrypoints": "<i lang=\"en\" xml:lang=\"en\">URL</i>s för enzeschteije",
        "version-entrypoints-header-entrypoint": "Enschteesch",
        "version-entrypoints-header-url": "<i lang=\"en\">URL</i>",
-       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Der Pad noh de Atikele]",
+       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Der Pahd noh de Atikele]",
        "version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath Der Pahd noh de Skrepte]",
        "version-libraries": "Enschtallehrte Projrammsammlonge",
        "version-libraries-library": "Projrammsammlong",
        "logentry-newusers-byemail": "{{GENDER:$4|Dä|Dat|Dä Metmaacher|De|Dat}} $1 wood {{GENDER:$4|als Metmaacher|als Metmaacher||als Metmaacher|als Metmaacher}} aanjelaat un {{GENDER:$4|sing|em sing|däm sing|dä iehr|däm sing}} Paßwoot met der <i lang=\"en>e-mail</i> verscheck.",
        "logentry-newusers-autocreate": "{{GENDER:$4|Dä|Dat|Dä Metmaacher|De|Dat}} $1 wood automattesch {{GENDER:$4|als Metmaacher|als Metmaacher||als Metmaacher|als Metmaacher}} {{GENDER:$2|vum|vum|vumm Metmaacher|vun dä|vum}} $1 aanjelaat.",
        "logentry-protect-move_prot": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät de Enschtällong vum schoz vun dä Sigg „$4“ noh dä Sigg „$3“ övvenumme",
+       "logentry-protect-unprotect": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät dä Schoz vun dä Sigg „$3“ opjehovve",
+       "logentry-protect-protect": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät di Sigg „$3“ jeschöz: $4",
+       "logentry-protect-protect-cascade": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät di Sigg „$3“ jeschöz: $4 met wiggerjävve",
+       "logentry-protect-modify": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät dä Schoz vun dä Sigg „$3“ verändert: $4",
+       "logentry-protect-modify-cascade": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} $1 hät dä Schoz vun dä Sigg „$3“ verändert: $4 met wiggerjävve",
        "logentry-rights-rights": "{{GENDER:$2|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät däm Metmaacher „$3“ sing Jroppe-Räächde vun „$4“ op „$5“ ömjestallt.",
        "logentry-rights-rights-legacy": "{{GENDER:$1|Dä|Et|Dä Metmaacher|De|Dat}} $1 hät däm Metmaacher $3 sing Räääschte-Jroppe verändert.",
        "logentry-rights-autopromote": "{{GENDER:$1|Dä|Et|Dä Metmaacher|De|Dat}} $1 wood automattesch vum $4 zom $5 jemaat.",
index b1a78f5..4815ec7 100644 (file)
        "createacct-captcha": "Sécherheets-Check",
        "createacct-imgcaptcha-ph": "Gitt den Text an deen Dir hei driwwer gesitt",
        "createacct-submit": "Äre Benotzerkont uleeën",
-       "createacct-another-submit": "Maacht een anere Benotzerkonnt op",
+       "createacct-another-submit": "Benotzerkont uleeën",
        "createacct-benefit-heading": "{{SITENAME}} gëtt vu Leit wéi Iech gemaach.",
        "createacct-benefit-body1": "{{PLURAL:$1|Ännerung|Ännerungen}}",
        "createacct-benefit-body2": "{{PLURAL:$1|Säit|Säiten}}",
        "group-bot": "Botten",
        "group-sysop": "Administrateuren",
        "group-bureaucrat": "Bürokraten",
-       "group-suppress": "Iwwersiicht",
+       "group-suppress": "Ënnerdrécker",
        "group-all": "(all)",
        "group-user-member": "{{GENDER:$1|Benotzer}}",
        "group-autoconfirmed-member": "{{GENDER:$1|automatesch confirméiert Benotzer}}",
        "grouppage-bot": "{{ns:project}}:Botten",
        "grouppage-sysop": "{{ns:project}}:Administrateuren",
        "grouppage-bureaucrat": "{{ns:project}}:Bürokraten",
-       "grouppage-suppress": "{{ns:project}}:Iwwersiicht",
+       "grouppage-suppress": "{{ns:project}}:Ënnerdrécken",
        "right-read": "Säite liesen",
        "right-edit": "Säiten änneren",
        "right-createpage": "Säiten uleeën (déi keng Diskussiounssäite sinn)",
        "upload-http-error": "Et ass en HTTP-Feeler geschitt: $1",
        "upload-copy-upload-invalid-domain": "Vun dësem Domain ass d'Eropluede vu Kopien net méiglech.",
        "upload-dialog-title": "Fichier eroplueden",
-       "upload-dialog-error": "Et ass e Feeler geschitt",
-       "upload-dialog-warning": "Eng Warnung gouf ausgeschwat",
        "upload-dialog-button-cancel": "Ofbriechen",
        "upload-dialog-button-done": "Fäerdeg",
        "upload-dialog-button-save": "Späicheren",
        "upload-dialog-button-upload": "Eroplueden",
-       "upload-dialog-label-select-file": "Fichier eraussichen",
-       "upload-dialog-label-infoform-title": "Detailer",
-       "upload-dialog-label-infoform-name": "Numm",
-       "upload-dialog-label-infoform-description": "Beschreiwung",
-       "upload-dialog-label-usage-title": "Benotzung",
-       "upload-dialog-label-usage-filename": "Numm vum Fichier",
+       "upload-process-error": "Et ass e Feeler geschitt",
+       "upload-process-warning": "Eng Warnung gouf ausgeschwat",
+       "upload-form-label-select-file": "Fichier eraussichen",
+       "upload-form-label-infoform-title": "Detailer",
+       "upload-form-label-infoform-name": "Numm",
+       "upload-form-label-infoform-description": "Beschreiwung",
+       "upload-form-label-usage-title": "Benotzung",
+       "upload-form-label-usage-filename": "Numm vum Fichier",
        "backend-fail-stream": "De Fichier $1 konnt net iwwerdroe ginn.",
        "backend-fail-backup": "De Fichier $1 konnt net geséchert ginn.",
        "backend-fail-notexists": "De Fichier $1 gëtt et net.",
        "filerevert-legend": "De Fichier zrécksetzen.",
        "filerevert-intro": "Dir setzt de Fichier '''[[Media:$1|$1]]''' op d'[$4 Versioun vum $2, $3 Auer] zréck.",
        "filerevert-comment": "Bemierkung:",
-       "filerevert-defaultcomment": "zréckgesat op d'Versioun vum $1, $2 Auer",
+       "filerevert-defaultcomment": "Zréckgesat op d'Versioun vum $1, $2 Auer ($3)",
        "filerevert-submit": "Zrécksetzen",
        "filerevert-success": "<strong>[[Media:$1|$1]]</strong> gouf op d'[$4 Versioun vum $2, $3 Auer] zréckgesat.",
        "filerevert-badversion": "Et gëtt keng vireg lokal Versioun vun deem Fichier mat der Zäitinformatioun déi Dir uginn hutt.",
        "nopagetext": "Déi Zilsäit déi dir uginn hutt gëtt et net.",
        "pager-newer-n": "{{PLURAL:$1|nächsten|nächst $1}}",
        "pager-older-n": "{{PLURAL:$1|vireg|vireg $1}}",
-       "suppress": "Iwwersiicht",
+       "suppress": "Ënnerdrécken",
        "querypage-disabled": "Dës Spezialsäit ass aus Performance-Grënn ausgeschalt.",
        "apihelp": "API-Hëllef",
        "apihelp-no-such-module": "Modul \"$1\" net fonnt.",
index 29dad5a..4152c6a 100644 (file)
                        "Aswanas",
                        "Pofka",
                        "Albertas",
-                       "Macofe"
+                       "Macofe",
+                       "Zygimantus"
                ]
        },
-       "tog-underline": "Pabraukti nuorodas:",
+       "tog-underline": "Nuorodos pabraukimas:",
        "tog-hideminor": "Slėpti smulkius pakeitimus naujausių keitimų sąraše",
        "tog-hidepatrolled": "Slėpti patikrintus keitimus paskutinių keitimų sąraše",
        "tog-newpageshidepatrolled": "Slėpti patikrintus puslapius iš naujausių straipsnių sąrašo",
        "thu": "Ket",
        "fri": "Pen",
        "sat": "Šeš",
-       "january": "sausio",
+       "january": "Sausis",
        "february": "vasario",
-       "march": "Kovo",
-       "april": "balandžio",
-       "may_long": "gegužės",
-       "june": "birželio",
-       "july": "liepos",
-       "august": "rugpjūčio",
-       "september": "Rugsėjo",
-       "october": "spalio",
-       "november": "lapkričio",
+       "march": "kovo",
+       "april": "Balandis",
+       "may_long": "Gegužė",
+       "june": "Birželis",
+       "july": "Liepa",
+       "august": "Rugpjūtis",
+       "september": "rugsėjo",
+       "october": "Spalis",
+       "november": "Lapkritis",
        "december": "gruodžio",
        "january-gen": "Sausio",
        "february-gen": "Vasario",
        "feb": "Vas",
        "mar": "Kov",
        "apr": "Bal",
-       "may": "gegužės",
-       "jun": "Birželis",
+       "may": "Geg",
+       "jun": "Bir",
        "jul": "Lie",
        "aug": "Rgp",
        "sep": "Rgs",
        "cancel": "Atšaukti",
        "moredotdotdot": "Daugiau...",
        "morenotlisted": "Šis sąrašas nėra išsamus.",
-       "mypage": "Naudotojo puslapis",
-       "mytalk": "Mano aptarimas",
+       "mypage": "Puslapis",
+       "mytalk": "Aptarimas",
        "anontalk": "Šio IP aptarimas",
        "navigation": "Naršymas",
        "and": "&#32;ir",
        "create-this-page": "Sukurti šį puslapį",
        "delete": "Trinti",
        "deletethispage": "Ištrinti šį puslapį",
-       "undeletethispage": "Attrinti šį puslapį",
+       "undeletethispage": "Atkurti šį puslapį",
        "undelete_short": "Atkurti $1 {{PLURAL:$1:redagavimą|redagavimus|redagavimų}}",
        "viewdeleted_short": "Peržiūrėti $1 {{PLURAL:$1|ištrintą keitimą|ištrintus keitimus|ištrintų keitimų}}",
        "protect": "Užrakinti",
        "viewcount": "Šis puslapis buvo atvertas $1 {{PLURAL:$1|kartą|kartus|kartų}}.",
        "protectedpage": "Užrakintas puslapis",
        "jumpto": "Peršokti į:",
-       "jumptonavigation": "navigaciją",
+       "jumptonavigation": "navigacija",
        "jumptosearch": "paiešką",
        "view-pool-error": "Atsiprašome, šiuo metu serveriai yra perkrauti.\nPernelyg daug naudotojų skaito šį puslapį.\nPrašome palaukti ir bandyti į šį puslapį patekti dar kartą.\n\n$1",
        "generic-pool-error": "Atsiprašome, šiuo metu serveriai yra perkrauti.\nPernelyg daug naudotojų skaito šį išteklį.\nPrašome palaukti ir bandyti prieiti prie šio išteklio dar kartą.",
        "pool-servererror": "Saugyklos skaitiklio paslauga negalima ($1).",
        "poolcounter-usage-error": "Naudojimo klaida: $1",
        "aboutsite": "Apie {{SITENAME}}",
-       "aboutpage": "Project:About",
+       "aboutpage": "Project:Apie",
        "copyright": "Turinys pateikiamas pagal  $1  jei nenurodyta kitaip.",
        "copyrightpage": "{{ns:project}}:Autorinės teisės",
        "currentevents": "Naujienos",
-       "currentevents-url": "Project:Current events",
+       "currentevents-url": "Project:Dabartiniai įvykiai",
        "disclaimers": "Atsakomybės apribojimas",
        "disclaimerpage": "Project:General disclaimer",
        "edithelp": "Kaip redaguoti",
        "databaseerror": "Duomenų bazės klaida",
        "databaseerror-text": "Įvyko duomenų bazės klaida.\nTai gali rodyti programinės įrangos sutrikimą.",
        "databaseerror-textcl": "Įvyko duomenų bazės klaida.",
-       "databaseerror-query": "Užklausa:$1",
+       "databaseerror-query": "Užklausa: $1",
        "databaseerror-function": "Paskirtis: $1",
        "databaseerror-error": "Klaida: $1",
        "laggedslavemode": "Dėmesio: Puslapyje gali nesimatyti naujausių pakeitimų.",
        "createacct-captcha": "Saugumo patikrinimas",
        "createacct-imgcaptcha-ph": "Įveskite tekstą, kurį matote aukščiau",
        "createacct-submit": "Sukurkite savo paskyrą",
-       "createacct-another-submit": "Sukurti kitą paskyrą",
+       "createacct-another-submit": "Sukurti paskyrą",
        "createacct-benefit-heading": "{{SITENAME}} sukurtas žmonių kaip jūs.",
        "createacct-benefit-body1": "{{PLURAL:$1|keitimas|keitimai|keitimų}}",
        "createacct-benefit-body2": "{{PLURAL:$1|puslapis|puslapiai}}",
        "permissionserrorstext-withaction": "Jūs neturite leidimo $2 dėl {{PLURAL:$1|šios priežasties|šių priežasčių}}:",
        "recreate-moveddeleted-warn": "'''Dėmesio: Jūs atkuriate puslapį, kuris anksčiau buvo ištrintas.'''\n\nTurėtumėte nuspręsti, ar reikėtų toliau redaguoti šį puslapį.\nJūsų patogumui čia pateikiamas šio puslapio šalinimų ir perkėlimų sąrašas:",
        "moveddeleted-notice": "Šis puslapis buvo ištrintas.\nŽemiau pateikiamas puslapio šalinimų ir pervadinimų sąrašas.",
+       "moveddeleted-notice-recent": "Atsiprašome, šis puslapis nesenai buvo ištrintas (per pastarąsias 24 valandas). Puslapio ištrynimo ir perkėlimo istorija yra pateikiama žemiau kaip nuoroda.",
        "log-fulllog": "Rodyti visą istoriją",
        "edit-hook-aborted": "Keitimas nutrauktas užlūžimo.\nTam nėra paaiškinimo.",
        "edit-gone-missing": "Negalima atnaujinti puslapio.\nGreičiausiai jis yra ištrintas.",
        "grouppage-bot": "{{ns:project}}:Robotai",
        "grouppage-sysop": "{{ns:project}}:Administratoriai",
        "grouppage-bureaucrat": "{{ns:project}}:Biurokratai",
-       "grouppage-suppress": "{{ns:project}}:Peržiūra",
+       "grouppage-suppress": "{{ns:project}}:Slopinti",
        "right-read": "Skaityti puslapius",
        "right-edit": "Redaguoti puslapius",
        "right-createpage": "Kurti puslapius (kurie nėra aptarimų puslapiai)",
        "upload-http-error": "Įvyko HTTP klaida: $1",
        "upload-copy-upload-invalid-domain": "Pakrovimų kopijos yra neleidžiamos iš šio domeno.",
        "upload-dialog-title": "Įkelti failą",
-       "upload-dialog-error": "Įvyko klaida",
-       "upload-dialog-warning": "Įvyko įspėjimas",
        "upload-dialog-button-cancel": "Atšaukti",
        "upload-dialog-button-done": "Atlikta",
        "upload-dialog-button-save": "Išsaugoti",
        "upload-dialog-button-upload": "Įkelti",
-       "upload-dialog-label-select-file": "Pasirinkti failą",
-       "upload-dialog-label-infoform-title": "Detalės",
-       "upload-dialog-label-infoform-name": "Pavadinimas",
-       "upload-dialog-label-infoform-description": "Aprašymas",
-       "upload-dialog-label-usage-title": "Naudojimas",
-       "upload-dialog-label-usage-filename": "Failo pavadinimas",
+       "upload-process-error": "Įvyko klaida",
+       "upload-process-warning": "Įvyko įspėjimas",
+       "upload-form-label-select-file": "Pasirinkti failą",
+       "upload-form-label-infoform-title": "Detalės",
+       "upload-form-label-infoform-name": "Pavadinimas",
+       "upload-form-label-infoform-description": "Aprašymas",
+       "upload-form-label-usage-title": "Naudojimas",
+       "upload-form-label-usage-filename": "Failo pavadinimas",
        "backend-fail-stream": "Negali būti apdorotas failas $1.",
        "backend-fail-backup": "Negali būti išsaugotas failas $1.",
        "backend-fail-notexists": "Failas $1 neegzistuoja.",
        "nopagetext": "Adresas, kurį nurodėte, neegzistuoja.",
        "pager-newer-n": "$1 {{PLURAL:$1|naujesnis|naujesni|naujesnių}}",
        "pager-older-n": "$1 {{PLURAL:$1|senesnis|senesni|senesnių}}",
-       "suppress": "Peržiūra",
+       "suppress": "Slopinti",
        "querypage-disabled": "Šiame specialiajame puslapyje yra išjungta dėl neefektyvumo.",
        "apihelp": "API pagalba",
        "apihelp-no-such-module": "Nerasta modulio $1.",
        "tooltip-whatlinkshere-invert": "Pažymėkite šį langelį jei norite slėpti nuorodas iš puslapių pasirinkto pavadinimo tarpe.",
        "namespace_association": "Susijusi vardų sritis",
        "tooltip-namespace_association": "Įjunkite šią parinktį, kad taip pat įtrauktumėte aptarimų arba temos sritį, susijusią su pasirinkta sritimi",
-       "blanknamespace": "(Pagrindinė)",
+       "blanknamespace": "(Pagrindinis)",
        "contributions": "{{GENDER:$1|Naudotojo}} indėlis",
        "contributions-title": "{{GENDER:$1|Naudotojo|Naudotojos}} $1 indėlis",
        "mycontris": "Įnašai",
        "blocklink": "blokuoti",
        "unblocklink": "atblokuoti",
        "change-blocklink": "keisti blokavimo nustatymus",
-       "contribslink": "įnašas",
+       "contribslink": "įnašai",
        "emaillink": "siųsti el. laišką",
        "autoblocker": "Jūs buvote automatiškai užblokuotas, nes jūsų IP adresą neseniai naudojo „[[User:$1|$1]]“. Nurodyta naudotojo $1 blokavimo priežastis: „$2“.",
        "blocklogpage": "Blokavimų sąrašas",
        "logentry-newusers-byemail": "Vartotojo paskyra $3 buvo {{GENDER:$2|sukurta}} $1 ir slaptažodis išsiųstas el. paštu",
        "logentry-newusers-autocreate": "Vartotojo paskyra $1 buvo {{GENDER:$2|sukurta}} automatiškai",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|perkėlė}} apsaugos nustatymus iš $4 į $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|pašalino}} apsaugą nuo $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|apsaugojo}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|apsaugojo}} $3 $4 [pakopinė]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|pakeitė}} apsaugos lygį $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|pakeitė}} apsaugos lygį $3 $4 [pakopinė]",
        "logentry-rights-rights": "$1 {{GENDER:$2|pakeitė}} grupės narystę $3 iš $4 į $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|pakeista}} narystė grupėje $3",
        "logentry-rights-autopromote": "$1 buvo automatiškai {{GENDER:$2|pervestas}} iš $4 į $5",
index 1d8f185..fbe61bb 100644 (file)
        "upload-dialog-button-done": "Gatavs",
        "upload-dialog-button-save": "Saglabāt",
        "upload-dialog-button-upload": "Augšupielādēt",
-       "upload-dialog-label-select-file": "Izvēlieties file",
-       "upload-dialog-label-infoform-title": "Papildinformācija",
-       "upload-dialog-label-infoform-description": "Apraksts",
-       "upload-dialog-label-usage-title": "Pielietojums",
-       "upload-dialog-label-usage-filename": "Faila nosaukums",
+       "upload-form-label-select-file": "Izvēlieties file",
+       "upload-form-label-infoform-title": "Papildinformācija",
+       "upload-form-label-infoform-description": "Apraksts",
+       "upload-form-label-usage-title": "Pielietojums",
+       "upload-form-label-usage-filename": "Faila nosaukums",
        "backend-fail-stream": "Nevar straumēt failu $1.",
        "backend-fail-backup": "Nevar dublēt failu $1.",
        "backend-fail-notexists": "Fails $1 nepastāv.",
index f427852..6487b45 100644 (file)
        "upload-http-error": "Nisy tsy fetezana HTTP nitranga : $1",
        "upload-copy-upload-invalid-domain": "Tsy misy eto amin'ity dômenina ity ny tahaky ny upload.",
        "upload-dialog-title": "Hanafatra rakitra",
-       "upload-dialog-error": "Nisy hadisoana nitranga",
-       "upload-dialog-warning": "Nisy fampitandremana nitranga",
        "upload-dialog-button-cancel": "Aoka",
        "upload-dialog-button-done": "Vita",
        "upload-dialog-button-save": "Tehirizina",
        "upload-dialog-button-upload": "Mampiditra",
-       "upload-dialog-label-select-file": "Hifidy rakitra",
-       "upload-dialog-label-infoform-title": "Antsipirihany",
-       "upload-dialog-label-infoform-name": "Anarana",
-       "upload-dialog-label-infoform-description": "Famisavisana",
-       "upload-dialog-label-usage-title": "Fampiasana",
-       "upload-dialog-label-usage-filename": "Anaran-drakitra",
+       "upload-process-error": "Nisy hadisoana nitranga",
+       "upload-process-warning": "Nisy fampitandremana nitranga",
+       "upload-form-label-select-file": "Hifidy rakitra",
+       "upload-form-label-infoform-title": "Antsipirihany",
+       "upload-form-label-infoform-name": "Anarana",
+       "upload-form-label-infoform-description": "Famisavisana",
+       "upload-form-label-usage-title": "Fampiasana",
+       "upload-form-label-usage-filename": "Anaran-drakitra",
        "backend-fail-stream": "Tsy afaka mamaky ilay rakitra $1.",
        "backend-fail-backup": "Tsy afaka mitahiry ilay rakitra $1.",
        "backend-fail-notexists": "Tsy misy ilay rakitra $1.",
index a7628ba..308fce4 100644 (file)
        "createacct-captcha": "Безбедносна проверка",
        "createacct-imgcaptcha-ph": "Внесете го гореприкажаниот текст",
        "createacct-submit": "Направи ја",
-       "createacct-another-submit": "Создајте друга сметка",
+       "createacct-another-submit": "Создај сметка",
        "createacct-benefit-heading": "{{SITENAME}} е дело на луѓе како вас.",
        "createacct-benefit-body1": "{{PLURAL:$1|уредување|уредувања}}",
        "createacct-benefit-body2": "{{PLURAL:$1|страница|страници}}",
        "group-bot": "Ботови",
        "group-sysop": "Администратори",
        "group-bureaucrat": "Бирократи",
-       "group-suppress": "СкÑ\80ивачи",
+       "group-suppress": "Ð\9fÑ\80иÑ\82аÑ\98Ñ\83вачи",
        "group-all": "(сите)",
        "group-user-member": "корисник",
        "group-autoconfirmed-member": "автопотврден корисник",
        "group-bot-member": "бот",
        "group-sysop-member": "администратор",
        "group-bureaucrat-member": "бирократ",
-       "group-suppress-member": "{{GENDER:$1|скривачи}}",
+       "group-suppress-member": "{{GENDER:$1|притајувач}}",
        "grouppage-user": "{{ns:project}}:Корисници",
        "grouppage-autoconfirmed": "{{ns:project}}:Автопотврдени корисници",
        "grouppage-bot": "{{ns:project}}:Ботови",
        "grouppage-sysop": "{{ns:project}}:Администратори",
        "grouppage-bureaucrat": "{{ns:project}}:Бирократи",
-       "grouppage-suppress": "{{ns:project}}:СкÑ\80ивање",
+       "grouppage-suppress": "{{ns:project}}:Ð\9fÑ\80иÑ\82аÑ\98Ñ\83вање",
        "right-read": "Читање страници",
        "right-edit": "Уредување страници",
        "right-createpage": "Создавање на страници (кои не се страници за разговор)",
        "upload-http-error": "Се појави грешка во HTTP: $1.",
        "upload-copy-upload-invalid-domain": "Примероци од подигањата не се достапни на овој домен.",
        "upload-dialog-title": "Подигни податотека",
-       "upload-dialog-error": "Се појави грешка",
-       "upload-dialog-warning": "Се јави предупредување",
        "upload-dialog-button-cancel": "Откажи",
        "upload-dialog-button-done": "Готово",
        "upload-dialog-button-save": "Зачувај",
        "upload-dialog-button-upload": "Подигни",
-       "upload-dialog-label-select-file": "Одберете податотека",
-       "upload-dialog-label-infoform-title": "Подробно",
-       "upload-dialog-label-infoform-name": "Назив",
-       "upload-dialog-label-infoform-description": "Опис",
-       "upload-dialog-label-usage-title": "Употреба",
-       "upload-dialog-label-usage-filename": "Назив на податотеката",
+       "upload-process-error": "Се појави грешка",
+       "upload-process-warning": "Се јави предупредување",
+       "upload-form-label-select-file": "Одберете податотека",
+       "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": "Назив на податотеката",
        "backend-fail-stream": "Не можев да ја емитувам податотеката $1.",
        "backend-fail-backup": "Не можев да направам резерва на податотеката $1.",
        "backend-fail-notexists": "Податотеката $1 не постои.",
        "filerevert-legend": "Врати податотека",
        "filerevert-intro": "Ја враќате '''[[Media:$1|$1]]''' на [$4 верзијата од $3, $2].",
        "filerevert-comment": "Причина:",
-       "filerevert-defaultcomment": "Вратена на верзија од $2, $1",
+       "filerevert-defaultcomment": "Вратена на верзија од $2, $1 ($3)",
        "filerevert-submit": "Врати",
        "filerevert-success": "'''[[Media:$1|$1]]''' е вратен на [$4 верзијата од $3, $2].",
        "filerevert-badversion": "Нема претходна месна верзија на оваа податотека со даденото време.",
        "nopagetext": "Целната страница која ја наведовте не постои.",
        "pager-newer-n": "{{PLURAL:$1|понова 1|понови $1}}",
        "pager-older-n": "{{PLURAL:$1|постара 1|постари $1}}",
-       "suppress": "СкÑ\80иваÑ\9aе",
+       "suppress": "Ð\9fÑ\80иÑ\82аи",
        "querypage-disabled": "Оваа службена страница е оневозможена за да не попречува на делотворноста.",
        "apihelp": "Помош со извршникот",
        "apihelp-no-such-module": "Модулот „$1“ не е пронајден.",
        "emailccsubject": "Копија од вашата порака до $1: $2",
        "emailsent": "Писмото е испратено",
        "emailsenttext": "Писмото е испратено.",
-       "emailuserfooter": "$1 го испрати писмово на $2 со помош на функцијата „{{int:emailuser}}“ на {{SITENAME}}.",
+       "emailuserfooter": "$1 го испрати писмово на {{GENDER:$2|$2}} со помош на функцијата „{{int:emailuser}}“ на {{SITENAME}}.",
        "usermessage-summary": "Оставете системска порака.",
        "usermessage-editor": "Системски гласник",
        "usermessage-template": "MediaWiki:КорисникПорака",
        "logentry-newusers-byemail": "$1 {{GENDER:$2|ја направи}} корисничката сметка $3. Лозинката ви ја испративме по е-пошта",
        "logentry-newusers-autocreate": "Автоматски {{GENDER:$2|создадена}} корисничката сметка $1",
        "logentry-protect-move_prot": "$1 ги {{GENDER:$2|премести}} заштитните поставки од $4 на $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|ја отстрани}} заштитата од $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|стави заштита}} на $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|стави заштита}} на $3 $4 [каскадно]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|го измени}} степенот на заштита на $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|го измени}} степенот на заштита на $3 $4 [каскадно]",
        "logentry-rights-rights": "$1 {{GENDER:$2|го измени}} групното членство на $3 од $4 во $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|го измени}} групното членство во $3",
        "logentry-rights-autopromote": "$1 автоматски {{GENDER:$2|унапреден|унапредена}} од $4 во $5",
index 791ce8b..79f988e 100644 (file)
        "nstab-template": "ഫലകം",
        "nstab-help": "സഹായ താൾ",
        "nstab-category": "വർഗ്ഗം",
+       "mainpage-nstab": "പ്രധാന താൾ",
        "nosuchaction": "ഈ പ്രവൃത്തി അസാധുവാണ്‌",
        "nosuchactiontext": "യു.ആർ.എൽ. വഴി നിർവചിച്ച പ്രവർത്തനം വിക്കി തിരിച്ചറിഞ്ഞില്ല. താങ്കൾ യു.ആർ.എൽ. തെറ്റായി നൽകിയിരിക്കാം അല്ലെങ്കിൽ ഒരു തെറ്റായ ലിങ്കുവഴി വന്നിരിക്കാം.\nഒരുപക്ഷേ, ഇത് {{SITENAME}} ഉപയോഗിക്കുന്ന സോഫ്റ്റ്‌വെയറിലെ ബഗ്ഗും ആകാം.",
        "nosuchspecialpage": "അത്തരമൊരു പ്രത്യേകതാൾ നിലവിലില്ല",
        "createacct-captcha": "സുരക്ഷാ പരിശോധന",
        "createacct-imgcaptcha-ph": "മുകളിൽ കാണുന്ന എഴുത്ത് ഇവിടെ നൽകുക",
        "createacct-submit": "താങ്കളുടെ അംഗത്വം സൃഷ്ടിക്കുക",
-       "createacct-another-submit": "മറàµ\8dà´±àµ\8aà´°àµ\81 à´\85à´\82à´\97à´¤àµ\8dവമàµ\86à´\9fàµ\81à´\95àµ\8dà´\95àµ\81à´\95",
+       "createacct-another-submit": "അംഗത്വമെടുക്കുക",
        "createacct-benefit-heading": "താങ്കളെപ്പോലെയുള്ളവരാണ്  {{SITENAME}}  പടുത്തുയർത്തിയിരിക്കുന്നത്.",
        "createacct-benefit-body1": "{{PLURAL:$1|തിരുത്ത്|തിരുത്തുകൾ}}",
        "createacct-benefit-body2": "{{PLURAL:$1|താൾ|താളുകൾ}}",
        "changeemail-password": "താങ്കളുടെ {{SITENAME}} രഹസ്യവാക്ക്:",
        "changeemail-submit": "ഇമെയിലിൽ മാറ്റംവരുത്തുക",
        "changeemail-throttled": "താങ്കൾ നിരവധി തവണ പ്രവേശിക്കാൻ ശ്രമിച്ചിരിക്കുന്നു.\nവീണ്ടും ശ്രമിക്കുന്നതിനു മുമ്പ് ദയവായി $1 കാത്തിരിക്കുക.",
+       "changeemail-nochange": "ദയവായി വേറെ ഒരു പുതിയ ഇമെയിൽ വിലാസം നൽകുക.",
        "resettokens": "ചീട്ടുകൾ പുനഃസജ്ജീകരിക്കുക",
        "resettokens-text": "താങ്കളുടെ അംഗത്വവുമായി ബന്ധപ്പെട്ടുള്ള ചില സ്വകാര്യവിവരങ്ങളിലേയ്ക്ക് ഇവിടെ ലഭ്യത സാദ്ധ്യമാക്കുന്ന ചീട്ടുകൾ താങ്കൾക്ക് പുനഃസജ്ജീകരിക്കാവുന്നതാണ്.\n\nതാങ്കളുടെ അംഗത്വവിവരങ്ങൾ മറ്റാർക്കെങ്കിലും അറിയാതെ കൈമാറിയിട്ടുണ്ടെങ്കിലോ താങ്കളുടെ അംഗത്വം അപഹരിക്കപ്പെട്ടുവെങ്കിലോ താങ്കളിത്  ചെയ്യേണ്ടതാണ്.",
        "resettokens-no-tokens": "ചീട്ടുകളൊന്നും പുനഃസജ്ജീകരിക്കാനില്ല.",
        "permissionserrorstext-withaction": "താങ്കൾക്ക് $2 എന്ന പ്രവൃത്തി ചെയ്യാൻ അനുമതി ഇല്ല, {{PLURAL:$1|കാരണം|കാരണങ്ങൾ}} താഴെ കൊടുത്തിരിക്കുന്നു:",
        "recreate-moveddeleted-warn": "'''മുന്നറിയിപ്പ്: മുമ്പ് മായ്ച്ചുകളഞ്ഞ താളാണ്‌ താങ്കൾ വീണ്ടും ചേർക്കാൻ ശ്രമിക്കുന്നത്'''\n\nതാങ്കൾ ചെയ്യുന്നത് ശരിയായ നടപടിയാണോ എന്നു പരിശോധിക്കുക. ഉറപ്പിനായി ഈ താളിന്റെ മായ്ക്കൽ രേഖയും മാറ്റൽ രേഖയും കൂടെ ചേർത്തിരിക്കുന്നു.",
        "moveddeleted-notice": "ഈ താൾ മായ്ക്കപ്പെട്ടിരിക്കുന്നു.\nഈ താളിന്റെ മായ്ക്കൽ രേഖ പരിശോധനയ്ക്കായി താഴെ കൊടുത്തിരിക്കുന്നു",
+       "moveddeleted-notice-recent": "ക്ഷമിക്കുക, ഈ താൾ ഈയടുത്ത് (കഴിഞ്ഞ 24 മണിക്കൂറിനുള്ളിൽ) മായ്ക്കപ്പെട്ടു.\nഅവലംബമായി മായ്ക്കലിന്റെയും താൾ നീക്കിയതിന്റെയും രേഖ താഴെ കൊടുത്തിരിക്കുന്നു.",
        "log-fulllog": "എല്ലാ രേഖകളും കാണുക",
        "edit-hook-aborted": "തിരുത്തൽ കൊളുത്തിനാൽ റദ്ദാക്കിയിരിക്കുന്നു.\nവിശദീകരണമൊന്നും നൽകിയിട്ടില്ല.",
        "edit-gone-missing": "ഈ താൾ പുതുക്കുവാൻ സാധിക്കുകയില്ല.\nഇത് മായ്ക്കപ്പെട്ടതായി കാണുന്നു.",
        "group-bot": "യന്ത്രങ്ങൾ",
        "group-sysop": "കാര്യനിർവാഹകർ",
        "group-bureaucrat": "ബ്യൂറോക്രാറ്റുകൾ",
-       "group-suppress": "à´®àµ\87ൽനàµ\8bà´\9fàµ\8dà´\9fà´\99àµ\8dà´\99ൾ",
+       "group-suppress": "à´\85മർà´\9aàµ\8dà´\9aà´\95ർ",
        "group-all": "(എല്ലാം)",
        "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|à´®àµ\87ൽനàµ\8bà´\9fàµ\8dà´\9fà´\82}}",
+       "group-suppress-member": "{{GENDER:$1|à´\85മർà´\9aàµ\8dà´\9aà´\95|à´\85മർà´\9aàµ\8dà´\9aà´\95ൻ}}",
        "grouppage-user": "{{ns:project}}:ഉപയോക്താക്കൾ",
        "grouppage-autoconfirmed": "{{ns:project}}:യാന്ത്രികമായി സ്ഥിരീകരിക്കപ്പെട്ട ഉപയോക്താക്കൾ",
        "grouppage-bot": "{{ns:project}}:യന്ത്രങ്ങൾ",
        "grouppage-sysop": "{{ns:project}}:കാര്യനിർവാഹകർ",
        "grouppage-bureaucrat": "{{ns:project}}:ബ്യൂറോക്രാറ്റ്",
-       "grouppage-suppress": "{{ns:project}}:à´®àµ\87ൽനàµ\8bà´\9fàµ\8dà´\9fà´\82",
+       "grouppage-suppress": "{{ns:project}}:à´\92à´¤àµ\81à´\95àµ\8dà´\95ൽ",
        "right-read": "\nതാളുകൾ വായിക്കുക",
        "right-edit": "താളുകൾ തിരുത്തുക",
        "right-createpage": "താളുകൾ സൃഷ്ടിക്കുക (സംവാദം താളുകൾ അല്ലാത്തവ)",
        "upload-http-error": "ഒരു എച്ച്.റ്റി.റ്റി.പി. പിഴവു സംഭവിച്ചിരിക്കുന്നു: $1",
        "upload-copy-upload-invalid-domain": "ഈ ഡൊമൈനിൽ നിന്നും പകർത്തി അപ്‌ലോഡ് ചെയ്യൽ ലഭ്യമല്ല.",
        "upload-dialog-title": "പ്രമാണം അപ്‌ലോഡ് ചെയ്യുക",
-       "upload-dialog-error": "ഒരു പിഴവുണ്ടായി",
-       "upload-dialog-warning": "ഒരു മുന്നറിയിപ്പുണ്ടായി",
        "upload-dialog-button-cancel": "റദ്ദാക്കുക",
        "upload-dialog-button-done": "ചെയ്തു കഴിഞ്ഞു",
        "upload-dialog-button-save": "സേവ് ചെയ്യുക",
        "upload-dialog-button-upload": "അപ്‌‌ലോഡ്",
-       "upload-dialog-label-select-file": "പ്രമാണം തിരഞ്ഞെടുക്കുക",
-       "upload-dialog-label-infoform-title": "വിശദാംശങ്ങൾ",
-       "upload-dialog-label-infoform-name": "പേര്‌",
-       "upload-dialog-label-infoform-description": "വിവരണം",
-       "upload-dialog-label-usage-title": "ഉപയോഗം",
-       "upload-dialog-label-usage-filename": "പ്രമാണത്തിന്റെ പേര്",
+       "upload-process-error": "ഒരു പിഴവുണ്ടായി",
+       "upload-process-warning": "ഒരു മുന്നറിയിപ്പുണ്ടായി",
+       "upload-form-label-select-file": "പ്രമാണം തിരഞ്ഞെടുക്കുക",
+       "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": "പ്രമാണത്തിന്റെ പേര്",
        "backend-fail-stream": "$1 എന്ന പ്രമാണം സ്ട്രീം ചെയ്യാൻ കഴിഞ്ഞില്ല.",
        "backend-fail-backup": "$1 എന്ന പ്രമാണത്തിന്റെ ബാക്ക്അപ് എടുക്കാൻ കഴിഞ്ഞില്ല.",
        "backend-fail-notexists": "$1 എന്ന പ്രമാണം നിലവിലില്ല.",
        "filerevert-legend": "പ്രമാണം തിരസ്ക്കരിക്കുക",
        "filerevert-intro": "താങ്കൾ '''[[Media:$1|$1]]''' എന്ന പ്രമാണത്തെ, [$4 $2, $3-ന് ഉണ്ടായിരുന്ന പതിപ്പിലേക്ക്] സേവ് ചെയ്യുകയാണ്‌.",
        "filerevert-comment": "കാരണം:",
-       "filerevert-defaultcomment": "$2 ൽ ഉണ്ടായിരുന്ന $1 പതിപ്പിലേക്കു സേവ് ചെയ്തിരിക്കുന്നു",
+       "filerevert-defaultcomment": "$1, $2 ($3)-നു ഉണ്ടായിരുന്ന പതിപ്പിലേക്കു സേവ് ചെയ്തിരിക്കുന്നു",
        "filerevert-submit": "പുനഃസ്ഥാപിക്കുക",
        "filerevert-success": "'''[[Media:$1|$1]]''' യെ,  [$3, $2 ഉണ്ടായിരുന്ന $4] പതിപ്പിലേക്കു സേവ് ചെയ്തിരിക്കുന്നു.",
        "filerevert-badversion": "താങ്കൾ തന്ന സമയവുമായി യോജിക്കുന്ന മുൻ പതിപ്പുകൾ ഒന്നും തന്നെ ഈ പ്രമാണത്തിനില്ല.",
        "nopagetext": "താങ്കൾ വ്യക്തമാക്കിയ ലക്ഷ്യതാൾ നിലവിലില്ല.",
        "pager-newer-n": "{{PLURAL:$1|പുതിയ 1|പുതിയ $1}}",
        "pager-older-n": "{{PLURAL:$1|പഴയ 1|പഴയ $1}}",
-       "suppress": "à´®àµ\87ൽനàµ\8bà´\9fàµ\8dà´\9fà´\82",
+       "suppress": "à´\92à´¤àµ\81à´\95àµ\8dà´\95àµ\81à´\95",
        "querypage-disabled": "പ്രവർത്തനമികവിനെ ബാധിക്കുന്ന കാരണങ്ങളാൽ ഈ പ്രത്യേക താൾ പ്രവർത്തന രഹിതമാക്കിയിരിക്കുന്നു.",
        "apihelp": "എ.പി.ഐ. സഹായം",
        "apihelp-no-such-module": "ഘടകം \"$1\" കണ്ടെത്താനായില്ല.",
        "emailccsubject": "$1 എന്ന ഉപയോക്താവിനയച്ച സന്ദേശത്തിന്റെ പകർപ്പ്: $2",
        "emailsent": "ഇമെയിൽ അയച്ചിരിക്കുന്നു",
        "emailsenttext": "താങ്കളുടെ ഇമെയിൽ അയച്ചു കഴിഞ്ഞിരിക്കുന്നു.",
-       "emailuserfooter": "ഈ ഇമെയിൽ, {{SITENAME}} സംരംഭത്തിലെ \"{{int:emailuser}}\" എന്ന സൗകര്യം ഉപയോഗിച്ച്, $1 എന്ന ഉപയോക്താവ് $2 എന്ന ഉപയോക്താവിന് അയച്ചതാണ്.",
+       "emailuserfooter": "ഈ ഇമെയിൽ, {{SITENAME}} സംരംഭത്തിലെ \"{{int:emailuser}}\" എന്ന സൗകര്യം ഉപയോഗിച്ച്, $1 എന്ന ഉപയോക്താവ് {{GENDER:$2|$2}} എന്ന ഉപയോക്താവിന് {{GENDER:$1|അയച്ചതാണ്}}.",
        "usermessage-summary": "വ്യവസ്ഥാസന്ദേശം ഉപേക്ഷിക്കുക.",
        "usermessage-editor": "വ്യവസ്ഥാസന്ദേശകൻ",
        "watchlist": "ശ്രദ്ധിക്കുന്നവ",
        "api-error-badaccess-groups": "ഈ വിക്കിയിൽ പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യാൻ താങ്കൾക്കനുവാദമില്ല.",
        "api-error-badtoken": "ആന്തരിക പിഴവ്: ഗുണകരമല്ലാത്ത ചീട്ട്.",
        "api-error-copyuploaddisabled": "യൂ.ആർ.എൽ. ഉപയോഗിച്ചുള്ള അപ്‌ലോഡ് ഈ സെർവറിൽ പ്രവർത്തനസജ്ജമാക്കിയിട്ടില്ല.",
-       "api-error-duplicate": "വിക്കിയിൽ ഇതേ ഉള്ളടക്കമുള്ള {{PLURAL:$1|[$2 മറ്റൊരു പ്രമാണം]|[$2 മറ്റ് പ്രമാണങ്ങൾ]}} മുമ്പേയുണ്ട്.",
+       "api-error-duplicate": "വിക്കിയിൽ ഇതേ ഉള്ളടക്കമുള്ള {{PLURAL:$1|മറ്റൊരു പ്രമാണം|മറ്റ് പ്രമാണങ്ങൾ}} മുമ്പേയുണ്ട്.",
        "api-error-duplicate-archive": "സൈറ്റിൽ ഇതേ ഉള്ളടക്കമുള്ള {{PLURAL:$1|മറ്റൊരു പ്രമാണം|മറ്റ് പ്രമാണങ്ങൾ}} ഉണ്ടായിരുന്നു, പക്ഷേ {{PLURAL:$1|അത്|അവ}} മായ്ക്കപ്പെട്ടിട്ടുണ്ട്.",
        "api-error-empty-file": "താങ്കൾ സമർപ്പിച്ച പ്രമാണം ശൂന്യമാണ്.",
        "api-error-emptypage": "ശൂന്യമായ പുതിയ താളുകൾ സൃഷ്ടിക്കുന്നത് അനുവദിക്കുന്നില്ല.",
index df571ba..0047452 100644 (file)
        "destfilename": "Tōcāhuīc:",
        "watchthisupload": "Tictlachiyāz inīn zāzanilli",
        "upload-success-subj": "Cualli quetzaliztli",
-       "upload-dialog-label-infoform-name": "Tōcāitl",
-       "upload-dialog-label-usage-filename": "Ihcuilōlli ītōcā",
+       "upload-form-label-infoform-name": "Tōcāitl",
+       "upload-form-label-usage-filename": "Ihcuilōlli ītōcā",
        "upload_source_file": " (cē tlahcuilōlli mochīuhpōhualhuazco)",
        "listfiles_search_for": "Tlatēmōz mēdiatl tōcācopa:",
        "imgfile": "īxiptli",
index 213135f..943922f 100644 (file)
        "createacct-captcha": "Cuntrollo 'e sicurezza",
        "createacct-imgcaptcha-ph": "Scrivite 'o testo ca vedite ncoppa",
        "createacct-submit": "Cria 'a toja utenza",
-       "createacct-another-submit": "Cria n'atu cunto",
+       "createacct-another-submit": "Cria nu cunto",
        "createacct-benefit-heading": "{{SITENAME}} è fatta 'e perzone comme te.",
        "createacct-benefit-body1": "{{PLURAL:$1|càgnamiento|càgnamiente}}",
        "createacct-benefit-body2": "{{PLURAL:$1|paggena|paggene}}",
        "group-bot": "Bot",
        "group-sysop": "Ammenistrature",
        "group-bureaucrat": "Burocrate",
-       "group-suppress": "Oversight",
+       "group-suppress": "Soppressure",
        "group-all": "(tutte)",
        "group-user-member": "{{GENDER:$1|utente}}",
        "group-autoconfirmed-member": "{{GENDER:$1|utente autocunfermato|utente autocunfermata|utente autocunfermato/a}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|ammenistratore|ammenistratrice|ammenistratore/trice}}",
        "group-bureaucrat-member": "{{GENDER:$1|burocrate}}",
-       "group-suppress-member": "{{GENDER:$1|oversight}}",
+       "group-suppress-member": "{{GENDER:$1|suppressure|supprimitrice}}",
        "grouppage-user": "{{ns:project}}:Utente",
        "grouppage-autoconfirmed": "{{ns:project}}:Utente autocunfermate",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Ammenistrature",
        "grouppage-bureaucrat": "{{ns:project}}:Burocrate",
-       "grouppage-suppress": "{{ns:project}}:Oversight",
+       "grouppage-suppress": "{{ns:project}}:Suppressure",
        "right-read": "Liegge paggene",
        "right-edit": "Cagna paggene",
        "right-createpage": "Crìa paggene (ca nun songo paggene 'e chiacchiera)",
        "upload-http-error": "N'errore HTTP è succiesso: $1",
        "upload-copy-upload-invalid-domain": "Nun è permessa 'a carreca 'e copie 'a chistu dumminio.",
        "upload-dialog-title": "Carreca file",
-       "upload-dialog-error": "N'errore cumparette",
-       "upload-dialog-warning": "N'avviso cumparette",
        "upload-dialog-button-cancel": "Canciella",
        "upload-dialog-button-done": "Fatto",
        "upload-dialog-button-save": "Sarva",
        "upload-dialog-button-upload": "Carreca",
-       "upload-dialog-label-select-file": "Sceglie file",
-       "upload-dialog-label-infoform-title": "Dettaglie",
-       "upload-dialog-label-infoform-name": "Nomme",
-       "upload-dialog-label-infoform-description": "Descrizzione",
-       "upload-dialog-label-usage-title": "Aúso",
-       "upload-dialog-label-usage-filename": "Nomme d' 'o file",
+       "upload-process-error": "N'errore cumparette",
+       "upload-process-warning": "N'avviso cumparette",
+       "upload-form-label-select-file": "Sceglie file",
+       "upload-form-label-infoform-title": "Dettaglie",
+       "upload-form-label-infoform-name": "Nomme",
+       "upload-form-label-infoform-description": "Descrizzione",
+       "upload-form-label-usage-title": "Aúso",
+       "upload-form-label-usage-filename": "Nomme d' 'o file",
        "backend-fail-stream": "Nun se può mannà 'o file \"$1\".",
        "backend-fail-backup": "Nun se può ffà 'o backup d' 'o file \"$1\".",
        "backend-fail-notexists": "'O file $1 nun esiste.",
        "filerevert-legend": "Arrepiglia 'o file",
        "filerevert-intro": "State arrepiglianno 'o file '''[[Media:$1|$1]]''' int' 'a [$4 verzione d' 'o $3, $2].",
        "filerevert-comment": "Mutive:",
-       "filerevert-defaultcomment": "Arripigliata 'a verzione d' 'o $2, $1",
+       "filerevert-defaultcomment": "Turnata 'a verzione comm' 'o $2, $1 ($3)",
        "filerevert-submit": "Arrepiglia",
        "filerevert-success": "'''[[Media:$1|$1]]''' è stat'arripigliato â verziona [$4 d' 'e $3 d' 'o $2].",
        "filerevert-badversion": "Nun ce sta na virziona lucale 'e stu file cu l'orario addimannato.",
        "nopagetext": "'A paggena 'e destinazione c'avite specificato nun esiste.",
        "pager-newer-n": "{{PLURAL:$1|1 cchiù nova|$1 cchiù nnove}}",
        "pager-older-n": "{{PLURAL:$1|1 cchiù viecchio|$1 cchiù viecchie}}",
-       "suppress": "Supervisione",
+       "suppress": "Supprime",
        "querypage-disabled": "Sta paggena speciale è stutata pe' mutive 'e prestaziune.",
        "apihelp": "Ajuto cu l'API",
        "apihelp-no-such-module": "'O modulo \"$1\" nun se trova.",
        "emailccsubject": "Copia d' 'a mmasciata tua 'a $1: $2",
        "emailsent": "Mmasciata e-mail mannata",
        "emailsenttext": "'A mmasciata d' 'a toja s'è mannata.",
-       "emailuserfooter": "Chista mmasciata e-mail è stata mannata 'a $1 a $2 p' 'a funziona \"{{int:emailuser}}\" 'e {{SITENAME}}.",
+       "emailuserfooter": "Chista mmasciata e-mail è stata {{GENDER:$1|mannata}} 'a $1 a {{GENDER:$2|$2}} p' 'a funziona \"{{int:emailuser}}\" 'e {{SITENAME}}.",
        "usermessage-summary": "Lassanno na mmasciata 'e sistema.",
        "usermessage-editor": "Mmasciatore d' 'o sistema",
        "watchlist": "Paggene cuntrullate",
        "logentry-newusers-byemail": "'O cunto utente $3 fuje {{GENDER:$2|criato|criata}} pe' $1 e 'a passuor è stata mannata pe' bbìa 'e na mmasciata e-mail",
        "logentry-newusers-autocreate": "'O cunto utente $1 fuje {{GENDER:$2|criato|criata}} automatecamente",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|spustaje}} mpustaziune 'e pruteziona 'a $4 a $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|luvata}} pruteziona 'a $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|pruteggette}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|pruteggette}} $3 $4 [cascading]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|cagnaje}} 'o livello 'e prutezione pe' $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|cagnaje}} 'o livello 'e prutezione pe' $3 $4 [cascading]",
        "logentry-rights-rights": "$1 {{GENDER:$2|cagnaje}} 'e gruppo pe' $3 'a $4 a $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|cagnaje}} 'e gruppo pe' $3",
        "logentry-rights-autopromote": "$1 è {{GENDER:$2|stato promosso|stata promossa}} automatecamente 'a $4 a $5",
index 6e3d661..b40191e 100644 (file)
        "nstab-template": "Sjabloon",
        "nstab-help": "Hulppagina",
        "nstab-category": "Categorie",
+       "mainpage-nstab": "Hoofdpagina",
        "nosuchaction": "Opgegeven handeling bestaat niet",
        "nosuchactiontext": "De opdracht in de URL is ongeldig.\nMogelijk heeft u een typefout gemaakt in de URL of een onjuiste koppeling gevolgd.\nHet kan ook wijzen op een fout in de software van {{SITENAME}}.",
        "nosuchspecialpage": "Deze speciale pagina bestaat niet",
        "columns": "Kolommen:",
        "searchresultshead": "Zoekresultaten",
        "stub-threshold": "Drempel voor markering als <a href=\"#\" class=\"stub\">beginnetje</a>:",
+       "stub-threshold-sample-link": "voorbeeld",
        "stub-threshold-disabled": "Uitgeschakeld",
        "recentchangesdays": "Aantal dagen weer te geven in de recente wijzigingen:",
        "recentchangesdays-max": "(maximaal $1 {{PLURAL:$1|dag|dagen}})",
        "group-bot": "bots",
        "group-sysop": "beheerders",
        "group-bureaucrat": "bureaucraten",
-       "group-suppress": "toezichthouders",
+       "group-suppress": "Toezichthouders",
        "group-all": "(iedereen)",
        "group-user-member": "{{GENDER:$1|gebruiker}}",
        "group-autoconfirmed-member": "{{GENDER:$1|autobevestigde gebruiker}}",
        "upload-http-error": "Er is een HTTP-fout opgetreden: $1",
        "upload-copy-upload-invalid-domain": "Uploaden per kopie is niet beschikbaar vanuit dit domein.",
        "upload-dialog-title": "Bestand uploaden",
-       "upload-dialog-error": "Er is een fout opgetreden",
-       "upload-dialog-warning": "Een waarschuwing is opgetreden",
        "upload-dialog-button-cancel": "Annuleren",
        "upload-dialog-button-done": "Afgerond",
        "upload-dialog-button-save": "Opslaan",
        "upload-dialog-button-upload": "Upload",
-       "upload-dialog-label-select-file": "Selecteer bestand",
-       "upload-dialog-label-infoform-title": "Details",
-       "upload-dialog-label-infoform-name": "Naam",
-       "upload-dialog-label-infoform-description": "Beschrijving",
-       "upload-dialog-label-usage-title": "Gebruik",
-       "upload-dialog-label-usage-filename": "Bestandsnaam",
+       "upload-process-error": "Er is een fout opgetreden",
+       "upload-process-warning": "Een waarschuwing is opgetreden",
+       "upload-form-label-select-file": "Selecteer bestand",
+       "upload-form-label-infoform-title": "Details",
+       "upload-form-label-infoform-name": "Naam",
+       "upload-form-label-infoform-description": "Beschrijving",
+       "upload-form-label-usage-title": "Gebruik",
+       "upload-form-label-usage-filename": "Bestandsnaam",
        "backend-fail-stream": "Het was niet mogelijk het bestand \"$1\" te streamen.",
        "backend-fail-backup": "Het was niet mogelijk een reservekopie van het bestand $1 te maken.",
        "backend-fail-notexists": "Het bestand $1 bestaat niet.",
index f593f3c..e411a97 100644 (file)
@@ -27,7 +27,7 @@
        "tog-norollbackdiff": "Älä ozuta eroloi, konzu olet ottanuh järilleh aijemban versien järilleh tuondu -toimindol",
        "underline-always": "Ainos",
        "underline-never": "Nikonzu",
-       "editfont-style": "Edituičendualovehen kirjainstiilu:",
+       "editfont-style": "Edituičendualovehen kirjainstiil'u:",
        "editfont-sansserif": "Sans-serif -fontu",
        "editfont-serif": "Serif-fontu",
        "sunday": "Pyhäpäivy",
        "listingcontinuesabbrev": "(jatko)",
        "index-category": "Indeksiruitut sivut",
        "noindex-category": "Indeksiruičemattomat sivut",
-       "broken-file-category": "Sivut, kudamil on ruadamattomii failulinkilöi",
+       "broken-file-category": "Sivut, kudamil on avuamattomii failulinkilöi",
        "about": "Tieduo sovellukses",
        "article": "Yhtevyssivu",
        "newwindow": "(avata uvves ikkunas)",
        "morenotlisted": "Tämä listu ei ole valmis.",
        "mypage": "Sivu",
        "mytalk": "Pagin",
-       "anontalk": "Paginsivutälle IP-adressile",
+       "anontalk": "Paginsivu tälle IP-adressile",
        "navigation": "Navigatsii",
        "and": "&#32;da",
        "qbfind": "Eči",
        "redirectedfrom": "(siirretty $1:späi)",
        "redirectpagesub": "uvvellehohjavussivu",
        "redirectto": "Uvvellehohjuau sivuh:",
-       "lastmodifiedat": "Tädä sivuu on muutettu jälgimäizen kerran $1, $2 aigah.",
+       "lastmodifiedat": "Tädä sivuu on muutettu jälgimäzen kerran $1, $2 aigah.",
        "protectedpage": "Suojattu sivu",
        "jumpto": "Siirry",
        "jumptonavigation": "navigatsii",
        "internalerror": "Syväindölline haireh",
        "internalerror_info": "Syväindölline haireh: $1",
        "filecopyerror": "Failua \"$1\" ei voitu kopiruija failakse \"$2\".",
-       "filerenameerror": "Ei voi uvvellehnimittoä \"$1\"-failua nimele \"$2\".",
+       "filerenameerror": "Ei voi uvvellehnimittiä \"$1\"-failua nimele \"$2\".",
        "filedeleteerror": "Failua \"$1\" ei voitu ottua iäre.",
        "directorycreateerror": "Ei voi luadie al'bomua \"$1\".",
        "directoryreadonlyerror": "Al'bom $1 on kirjutussuojattu.",
        "password-name-match": "Peittosana pidäy olla eri migu käyttäinimi.",
        "password-login-forbidden": "Tämän käyttäinimen da peittosanan käyttö on estetty.",
        "mailmypassword": "Azeta peittosana uvvelleh",
-       "passwordremindertitle": "Uusi väliaigaine peittosana {{SITENAME}}-sivuh niškoi",
-       "passwordremindertext": "Kentah IP-adressispäi $1 kyzyi työndämäh uuttu peittosanua saitale {{SITENAME}} ($4). Väliaigaine peittosana käyttäjäle $2 on nygöi $3. Kirjuttai da vaihta peittosana. Väliaigaine peittosana vahnenou {{PLURAL:$5|yhten päivän|$5 päivän}} jälles.\n\nOllou kentah toine työndänyh tämän pakičuksen, libo ku ollet mustanuh sinun peittosanan da et tahto vaihtua sidä, voit jättiä tämän viestin huomivottah dajatkua vahnan peittosanan käyttyö.",
+       "passwordremindertitle": "Uuzi väliaigaine peittosana {{SITENAME}}-sivuh niškoi",
+       "passwordremindertext": "Kentah IP-adressispäi $1 kyzyi työndämäh uuttu peittosanua saitale {{SITENAME}} ($4). Väliaigaine peittosana käyttäjäle $2 on nygöi $3. Kirjuttai da vaihta peittosana. Väliaigaine peittosana vahnenou {{PLURAL:$5|yhten päivän|$5 päivän}} jälles.\n\nOllou kentah toine työndänyh tämän pakičuksen, libo ku ollet mustanuh sinun peittosanan da et tahto vaihtua sidä, voit jättiä tämän viestin huomivottah da jatkua vahnan peittosanan käyttyö.",
        "mailerror": "Haireh työndäjes sähköpoštua: $1",
        "accountcreated": "Tili luajittu",
        "loginlanguagelabel": "Kieli: $1",
        "changeemail-none": "(niyhty)",
        "changeemail-password": "Sinun {{SITENAME}}-peittosana:",
        "changeemail-submit": "Vaihta sähköpoštu",
-       "changeemail-throttled": "Olet oppinuh kirjuttuakseh liijan moni kerdua. Ole hyvä, vuota $1 enne ku opit uvvelleh.",
+       "changeemail-throttled": "Olet oppinuh kirjuttuakseh liijan moni kerdua. Ole hyvä, vuota $1 enne ku opit uvvessah.",
        "resettokens-tokens": "Avaimet:",
        "bold_sample": "Lihavoitu tekstu",
        "bold_tip": "Lihavoitu tekstu",
        "watchthis": "Tarkaile tädä sivuu",
        "savearticle": "Tallenda sivu",
        "preview": "Ezikačo",
-       "showpreview": "Ezikaččo",
+       "showpreview": "Ezikačo",
        "showdiff": "Luajitut korjavukset",
        "anoneditwarning": "<strong>Varaitus:</strong> Et ole kirjutannuhes. Luadinet muutoksii syväindölöih, sinun Ip-adressu tulou nägövih kaikile. Ku <strong>[$1 kirjutannuttos]</strong> libo <strong>[$2 registriiruičettos]</strong>, sinun syväindömuutokset nävytäh sinun käyttäinimel, toizien eduloin ližäkse.",
        "blockedtitle": "Käyttäi on estetty",
        "filename-tooshort": "Failunimi on liijan lyhyt.",
        "watchthisupload": "Valvo tädä failua",
        "upload-dialog-button-save": "Tallenda",
-       "upload-dialog-label-infoform-title": "Tiijot",
-       "upload-dialog-label-infoform-name": "Nimi",
-       "upload-dialog-label-infoform-description": "Kuvavus",
-       "upload-dialog-label-usage-title": "Käyttö",
-       "upload-dialog-label-usage-filename": "Failunimi",
+       "upload-form-label-infoform-title": "Tiijot",
+       "upload-form-label-infoform-name": "Nimi",
+       "upload-form-label-infoform-description": "Kuvavus",
+       "upload-form-label-usage-title": "Käyttö",
+       "upload-form-label-usage-filename": "Failunimi",
        "license-header": "Licenzii",
        "imgfile": "tiijosto",
        "listfiles_name": "Nimi",
index 75388b1..11b3780 100644 (file)
        "nstab-template": "ଛାଞ୍ଚ",
        "nstab-help": "ସାହାଯ୍ୟ ପୃଷ୍ଠା",
        "nstab-category": "ଶ୍ରେଣୀ",
+       "mainpage-nstab": "ପ୍ରଧାନ ପୃଷ୍ଠା",
        "nosuchaction": "ସେହିଭଳି କିଛି କାମ ନାହିଁ",
        "nosuchactiontext": "URL ଟିରେ ଦିଆଯାଇଥିବା କାମଟି ଅଚଳ ଅଟେ ।\nଆପଣ ବୋଧ ହୁଏ URL ଟି ଭୁଲ ତାଇପ କରିଥିବେ, ଅଥବା ଲିଙ୍କଟି ଭୁଲ ଥିବ ।\nଏହା ମଧ୍ୟ {{SITENAME}}ରେ ବ୍ୟବହାର କରାଯାଇଥିବା ସଫ୍ଟବେରରେ ଥିବା କିଛି ଭୁଲକୁ ସୂଚାଇପାରେ ।",
        "nosuchspecialpage": "ସେହି ଭଳି କିଛି ବି ବିଶେଷ ପୃଷ୍ଠା ନାହିଁ",
        "createacct-another-username-ph": "ଆପଣଙ୍କ ଇଉଜର ନାମ ଟାଇପ କରନ୍ତୁ",
        "yourpassword": "ପାସୱାର୍ଡ଼",
        "userlogin-yourpassword": "ପାସୱାର୍ଡ଼",
-       "userlogin-yourpassword-ph": "à¬\86ପଣà¬\99à­\8dà¬\95 à¬ªà¬¾à¬¸à­±à¬¾à¬°à­\8dଡ଼ à¬¦à¬¿à¬\85ନ୍ତୁ",
+       "userlogin-yourpassword-ph": "à¬\86ପଣà¬\99à­\8dà¬\95 à¬ªà¬¾à¬¸à­±à¬¾à¬°à­\8dଡ଼ à¬²à­\87à¬\96ନ୍ତୁ",
        "createacct-yourpassword-ph": "ପାସୱର୍ଡ଼ ଦିଅନ୍ତୁ",
        "yourpasswordagain": "ପାସୱାର୍ଡ଼ ଆଉଥରେ:",
        "createacct-yourpasswordagain": "ପାସୱର୍ଡ଼ ନିଶ୍ଚିତ କରିବେ",
-       "createacct-yourpasswordagain-ph": "ଆଉଥରେ ପାସୱର୍ଡ଼ ଦିଅନ୍ତୁ",
+       "createacct-yourpasswordagain-ph": "à¬\86à¬\89ଥରà­\87 à¬ªà¬¾à¬¸à­±à¬¾à¬°à­\8dଡ଼ à¬¦à¬¿à¬\85ନà­\8dତà­\81",
        "remembermypassword": "ଏହି ବ୍ରାଉଜରରେ (ସବୁଠୁ ଅଧିକ ହେଲେ $1 {{PLURAL:$1|day|ଦିନ}}) ପାଇଁ ମୋ ଲଗଇନ ମନେ ରଖିଥିବେ",
        "userlogin-remembermypassword": "ମୋତେ ଲଗ-ଇନ କରି ରଖିଥାନ୍ତୁ",
        "userlogin-signwithsecure": "ନିରାପଦ କନେକସନ ବ୍ୟବ‌ହାର କରନ୍ତୁ",
        "gotaccount": "ଆଗରୁ ଖାତାଟିଏ ଅଛି କି? $1.",
        "gotaccountlink": "ଲଗ ଇନ (Log in)",
        "userlogin-resetlink": "ଲଗଇନ ତଥ୍ୟ ସବୁ ଭୁଲିଗେଲେକି?",
-       "userlogin-resetpassword-link": "ପାସୱାରà­\8dଡ଼ à¬­à­\81ଲିଯାà¬\87à¬\9bନà­\8dତି ?",
+       "userlogin-resetpassword-link": "ପାସୱାରà­\8dଡ଼ à¬®à¬¨à­\87ପଡà­\81ନାହିà¬\81?",
        "userlogin-helplink2": "ଲଗ ଇନ ପାଇଁ ସହଯୋଗ କରନ୍ତୁ",
        "userlogin-loggedin": "ଆପଣ {{GENDER:$1|$1}} ନାମରେ ଲଗ ଇନ କରିଛନ୍ତି । ତଳ ଫର୍ମଟି ବ୍ୟବହାର କରି ଆଉ ଜଣେ ସଭ୍ୟ ଭାବେ ଲଗ ଇନ କରନ୍ତୁ ।",
        "userlogin-createanother": "ଆଉ ଏକ ଖାତା ତିଆରି କରନ୍ତୁ",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ସଭ୍ୟ|ସଭ୍ୟଗଣା}}ଙ୍କୁ ଦେଖୁଅଛି]",
        "rc_categories": "ଶ୍ରେଣୀସମୂହ ପାଇଁ ସୀମା ( \"|\" ଦେଇ ଅଲଗା କରିବେ)",
        "rc_categories_any": "ଯେ କୌଣସି",
-       "rc-change-size-new": "ବଦଳପରେ $1 {{PLURAL:$1|byte|bytes}}",
+       "rc-change-size-new": "ବଦଳପରେ $1 {{PLURAL:$1|ବାଇଟ|ବାଇଟ}}",
        "newsectionsummary": "/* $1 */ ନୂଆ ଭାଗ",
        "rc-enhanced-expand": "ସବିଶେଷ ଦେଖାନ୍ତୁ",
        "rc-enhanced-hide": "ବେଶି କଥାସବୁ ଲୁଚାଇଦିଅ",
        "namespace_association": "ସମ୍ଭନ୍ଧିତ ନେମସ୍ପେସ",
        "tooltip-namespace_association": "ବଛାଯାଇଥିବା ନେମ୍ସସ୍ପେସ ସହ ଯୋଡ଼ା ଆଲୋଚନା ବା ବିଷୟ ନେମସ୍ପେସ ଏହା ଅନ୍ତଭୁକ୍ତ କରିବା ନିମନ୍ତେ ଏହି ଘରକୁ ବାଛନ୍ତୁ",
        "blanknamespace": "(ମୂଳ)",
-       "contributions": "{{GENDER:$1|User}}ଙ୍କ ଅବଦାନ",
+       "contributions": "{{GENDER:$1|ବ୍ୟବହାରକାରୀ}}ଙ୍କ ଅବଦାନ",
        "contributions-title": "$1 ପାଇଁ ବ୍ୟବହାରକାରୀଙ୍କ ଦାନ",
        "mycontris": "ଅବଦାନ",
        "contribsub2": "{{GENDER:$3|$1}} ପାଇଁ  ($2)",
        "allmessages-language": "ଭାଷା:",
        "allmessages-filter-submit": "ଯିବା",
        "allmessages-filter-translate": "ଅନୁବାଦ କରନ୍ତୁ",
-       "thumbnail-more": "ବିସà­\8dତାର",
+       "thumbnail-more": "ବଡ଼",
        "filemissing": "ଫାଇଲ ମିଳୁନାହିଁ",
        "thumbnail_error": "ନଖଦେଖଣା ତିଆରିବାରେ ଅସୁବିଧା: $1",
        "thumbnail_error_remote": "$1ରୁ ତ୍ରୁଟି ମେସେଜ:\n$2",
        "tooltip-pt-logout": "ଲଗଆଉଟ",
        "tooltip-pt-createaccount": "ଆପଣଙ୍କୁ ଗୋଟେ ଖାତା ଖୋଲି ଲଗ ଇନ କରିବା ପାଇଁ ପ୍ରୋତ୍ସାହିତ କରାଯାଉଛି, ଏମିତିବି ଏହା କରିବା ନିତାନ୍ତ ଆବଶ୍ୟକ ନୁହେଁ ।",
        "tooltip-ca-talk": "ଏହି ପୃଷ୍ଠାଟି ଉପରେ ଆଲୋଚନା",
-       "tooltip-ca-edit": "à¬\86ପଣ à¬\8fହି à¬ªà­\83ଷà­\8dଠାà¬\9fିରà­\87 à¬\85ଦଳ à¬¬à¬¦à¬³ à¬\95ରିପାରିବà­\87, à¬¤à­\87ବà­\87 à¬¸à¬¾à¬\87ତିବା à¬\86à¬\97ରà­\81 à¬¦à­\87à¬\96ଣା à¬¦à­\87à¬\96ନà­\8dତà­\81 à¥¤",
+       "tooltip-ca-edit": "à¬\8fହି à¬ªà­\83ଷà­\8dଠାà¬\9fି à¬¸à¬®à­\8dପାଦନ à¬\95ରନà­\8dତà­\81",
        "tooltip-ca-addsection": "ନୂଆ ବିଭାଗଟିଏ ଆରମ୍ଭ କରିବେ",
        "tooltip-ca-viewsource": "ଏହି ପୃଷ୍ଠାଟି କିଳାଯାଇଛି ।\nଆପଣ ଏହାର ମୂଳ ଦେଖିପାରିବେ",
        "tooltip-ca-history": "ଏହି ପୃଷ୍ଠାର ପୁରୁଣା ସଂସ୍କରଣ",
        "tooltip-ca-nstab-main": "ସୂଚୀ ପୃଷ୍ଠାଟି ଦେଖାଇବେ",
        "tooltip-ca-nstab-user": "ଫାଇଲ ପୃଷ୍ଠାଗୁଡ଼ିକ ଦେଖନ୍ତୁ",
        "tooltip-ca-nstab-media": "ମିଡ଼ିଆ ପୃଷ୍ଠାଟି ଦେଖିବେ",
-       "tooltip-ca-nstab-special": "à¬\8fହା à¬\97à­\8bà¬\9fିà¬\8f à¬¬à¬¿à¬¶à­\87ଷ à¬ªà­\83ଷà­\8dଠା, à¬\86ପଣ à¬\8fହାà¬\95à­\81 à¬¬à¬¦à¬³à¬¾à¬\87ପାରିବà­\87 ନାହିଁ",
+       "tooltip-ca-nstab-special": "à¬\8fହା à¬\8fà¬\95 à¬¬à¬¿à¬¶à­\87ଷ à¬ªà­\83ଷà­\8dଠା à¬¹à­\8bà¬\87ଥିବାରà­\81 à¬\8fହାà¬\95à­\81 à¬¬à¬¦à¬³à¬¾à¬¯à¬¾à¬\87ପାରିବ ନାହିଁ",
        "tooltip-ca-nstab-project": "ପ୍ରକଳ୍ପ ପୃଷ୍ଠାଟି ଦେଖାଇବେ",
        "tooltip-ca-nstab-image": "ଫାଇଲ ପୃଷ୍ଠାଗୁଡ଼ିକ ଦେଖନ୍ତୁ",
        "tooltip-ca-nstab-mediawiki": "ସିଷ୍ଟମ ମେସେଜ ଦେଖିବେ",
        "spam_reverting": "$1 ସହ ଯୋଡ଼ା ନଥିବା ଶେଷ ସଂସ୍କରଣକୁ ଲେଉଟାଇ ଦେଉଅଛୁଁ",
        "spam_blanking": "$1 ସହ ଯୋଡ଼ାଥିବା ସବୁଯାକ ସଂସ୍କରଣ ଖାଲି କରିଦିଆଗଲା",
        "spam_deleting": "$1 ସହ ଯୋଡ଼ାଥିବା ସବୁଯାକ ସଂସ୍କରଣ ଖାଲି କରିଦିଆଗଲା",
-       "simpleantispam-label": "à¬\86ଣà­\8dà¬\9fି-ସà­\8dପାମ à¬ªà¬°à¬\96 à¥¤\nà¬\8fହାà¬\95à­\81 à¬­à¬°ନ୍ତୁ <strong>ନାହିଁ</strong>!",
+       "simpleantispam-label": "ସà­\8dପାମରà­\8bଧà­\80 à¬ªà¬°à¬\96 à¥¤\nà¬\8fଥିରà­\87 à¬\95ିà¬\9bି à¬²à­\87à¬\96ନ୍ତୁ <strong>ନାହିଁ</strong>!",
        "pageinfo-title": "\"$1\"ର ବିବରଣୀ",
        "pageinfo-not-current": "ଦୁଖିତଃ, ପୁରୁଣା ସଂସ୍କରଣଗୁଡିକର ଏହି ତଥ୍ୟ ଦେବା ସମ୍ଭବ ନୁହେଁ ।",
        "pageinfo-header-basic": "ସାଧାରଣ ଜାଣିବା କଥା",
index 9a2588d..f02e0cd 100644 (file)
@@ -21,7 +21,8 @@
                        "Ævar Arnfjörð Bjarmason",
                        "לערי ריינהארט",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "ਪ੍ਰਚਾਰਕ"
                ]
        },
        "tog-underline": "ਲਿੰਕ ਹੇਠ-ਲਾਈਨ:",
@@ -38,6 +39,7 @@
        "tog-watchdefault": "ਮੇਰੇ ਵੱਲੋਂ ਸੋਧੇ ਗਏ ਸਫ਼ੇ ਅਤੇ ਫ਼ਾਈਲਾਂ ਮੇਰੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚ ਪਾਓ",
        "tog-watchmoves": "ਮੇਰੇ ਵੱਲੋਂ ਬਦਲੇ ਸਿਰਲੇਖਾਂ ਵਾਲ਼ੇ ਸਫ਼ੇ ਅਤੇ ਫ਼ਾਈਲਾਂ ਮੇਰੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚ ਪਾਓ",
        "tog-watchdeletion": "ਮੇਰੇ ਵਲੋਂ ਮਿਟਾਏ ਗਏ ਸਫ਼ੇ ਅਤੇ ਫ਼ਾਈਲਾਂ ਮੇਰੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚ ਪਾਓ",
+       "tog-watchrollback": "ਮੇਰੇ ਦੁਆਰਾ ਮੋੜੇ ਗਏ ਸਫ਼ਿਅਾਂ ਨੂੰ ਮੇਰੀ ਧਿਆਨਸੂਚੀ ਵਿੱਚ ਸ਼ਾਮਿਲ ਕਰੋ",
        "tog-minordefault": "ਸਾਰੀਆਂ ਸੋਧਾਂ ’ਤੇ ਮੂਲ ਰੂਪ ਵਿਚ ਛੋਟੇ ਹੋਣ ਦਾ ਨਿਸ਼ਾਨ ਲਾਓ",
        "tog-previewontop": "ਸੋਧ ਬਕਸੇ ਤੋਂ ਪਹਿਲਾਂ ਝਲਕ ਵਖਾਓ",
        "tog-previewonfirst": "ਪਹਿਲੀ ਸੋਧ ਉੱਤੇ ਝਲਕ ਵਖਾਓ",
@@ -48,7 +50,7 @@
        "tog-shownumberswatching": "ਨਜ਼ਰ ਰੱਖ ਰਹੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀ ਗਿਣਤੀ ਵਖਾਓ",
        "tog-oldsig": "ਮੌਜੂਦਾ ਦਸਤਖ਼ਤ:",
        "tog-fancysig": "ਦਸਤਖ਼ਤ ਨੂੰ ਬਤੌਰ ਵਿਕੀਲਿਖਤ ਮੰਨੋ (ਬਿਨਾਂ ਆਟੋਮੈਟਿਕ ਲਿੰਕ)",
-       "tog-uselivepreview": "ਸਿੱਧà©\80 à¨\9dਲà¨\95 à¨µà¨°à¨¤à©\8b (ਤà¨\9cਰਬà©\87-à¨\85ਧà©\80ਨ)",
+       "tog-uselivepreview": "ਮà©\8cà¨\9cà©\82ਦਾ à¨\9dਲà¨\95 à¨µà¨°à¨¤à©\8b",
        "tog-forceeditsummary": "ਜਦੋਂ ਮੈਂ ਖ਼ਾਲੀ ਸੋਧ ਸਾਰ ਦੇਵਾਂ ਤਾਂ ਮੈਨੂੰ ਆਗਾਹ ਕਰੋ",
        "tog-watchlisthideown": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚੋਂ ਮੇਰੀਆਂ ਸੋਧਾਂ ਲੁਕਾਓ",
        "tog-watchlisthidebots": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚੋਂ ਬੋਟਾਂ ਦੀਆਂ ਸੋਧਾਂ ਲੁਕਾਓ",
        "jumptonavigation": "ਨੇਵੀਗੇਸ਼ਨ",
        "jumptosearch": "ਖੋਜ",
        "view-pool-error": "ਅਫ਼ਸੋਸ, ਸਰਵਰ ਇਸ ਵੇਲੇ ਓਵਰਲੋਡ ਹੈ।\nਬਹੁਤ ਸਾਰੇ ਮੈਂਬਰ ਇਸ ਸਫ਼ੇ ਨੂੰ ਵੇਖਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਹੇ ਹਨ।\nਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਥੋੜੀ ਉਡੀਕ ਕਰੋ ਜੀ।\n$1",
+       "generic-pool-error": "ਮੁਆਫ਼ ਕਰੋ, ਇਸ ਵੇਲੇ ਸਰਵਰ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੇ।\nਇਸ ਚੀਜ਼ ਨੂੰ ਇਸ ਵੇਲੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵਰਤੋਂਕਾਰ ਵੇਖਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਹੇ ਹਨ।\nਇਸ ਚੀਜ਼ ਨੂੰ ਦੁਆਰਾ ਦੇਖਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਥੋੜ੍ਹੀ ਦੇਰ ਇੰਤਜ਼ਾਰ ਕਰੋ।",
        "pool-timeout": "ਲਾਕ ਲਈ ਉਡੀਕ ਦਾ ਵਕਤ ਖ਼ਤਮ ਹੋ ਗਿਆ ਹੈ",
        "pool-queuefull": "ਪੂਲ ਕਤਾਰ ਭਰੀ ਹੋਈ ਹੈ",
        "pool-errorunknown": "ਅਣਜਾਣ ਗਲਤੀ",
        "nstab-template": "ਫਰਮਾ",
        "nstab-help": "ਮਦਦ ਸਫ਼ਾ",
        "nstab-category": "ਸ਼੍ਰੇਣੀ",
+       "mainpage-nstab": "ਮੁੱਖ ਸਫ਼ਾ",
        "nosuchaction": "ਅਜਿਹੀ ਕੋਈ ਕਾਰਵਾਈ ਨਹੀਂ ਹੈ",
        "nosuchactiontext": "URL ਦੁਆਰਾ ਦੱਸਿਆ ਕੰਮ ਗ਼ਲਤ ਹੈ।\nਸ਼ਾਇਦ ਤੁਸੀਂ URL ਸਹੀ ਨਹੀਂ ਲਿਖਿਆ ਜਾਂ ਕਿਸੇ ਗ਼ਲਤ ਲਿੰਕ ਤੇ ਆਏ ਹੋ।\nਇਹ ਵੀ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ {{SITENAME}} ਦੁਆਰੇ ਵਰਤੇ ਜਾਂਦੇ ਸਾਫ਼ਟਵੇਅਰ ਵਿਚਲੀ ਗ਼ਲਤੀ ਵੱਲ ਇਸ਼ਾਰਾ ਹੋਵੇ।",
        "nosuchspecialpage": "ਅਜਿਹਾ ਕੋਈ ਖ਼ਾਸ ਸਫ਼ਾ ਨਹੀਂ ਹੈ",
        "filerenameerror": "ਫ਼ਾਈਲ ''$1'' ਦਾ ਨਾਂ ''$2'' ਨਹੀਂ ਸਾ ਸਕਿਆ।",
        "filedeleteerror": "''$1'' ਫ਼ਾਈਲ ਹਟਾਈ ਨਹੀਂ ਜਾ ਸਕੀ।",
        "directorycreateerror": "ਡਾਇਰੈਕਟਰੀ ''$1'' ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕੀ।",
+       "directoryreadonlyerror": "\"$1\" ਨਾਮਾਵਲੀ ਸਿਰਫ਼ ਪੜ੍ਹਣਯੋਗ ਹੈ।",
+       "directorynotreadableerror": "\"$1\" ਨਾਮਾਵਲੀ ਪੜ੍ਹਣਯੋਗ ਨਹੀਂ ਹੈ।",
        "filenotfound": "ਫ਼ਾਈਲ ''$1'' ਲੱਭੀ ਨਹੀਂ ਜਾ ਸਕੀ।",
        "unexpected": "ਅਣਉਮੀਦਿਆ ਮੁੱਲ: \"$1\"=\"$2\"।",
        "formerror": "ਗ਼ਲਤੀ: ਫ਼ਾਰਮ ਪੇਸ਼ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ",
        "createacct-captcha": "ਸੁਰੱਖਿਆ ਜਾਂਚ",
        "createacct-imgcaptcha-ph": "ਉੱਤੇ ਵੇਖਾਈ ਦੇ ਰਿਹਾ ਸ਼ਬਦ ਦਿਉ",
        "createacct-submit": "ਆਪਣਾ ਖਾਤਾ ਬਣਾਓ",
-       "createacct-another-submit": "ਹà©\8bਰ ਖਾਤਾ ਬਣਾਓ",
+       "createacct-another-submit": "ਨਵਾà¨\82 ਖਾਤਾ ਬਣਾਓ",
        "createacct-benefit-heading": "{{SITENAME}} ਨੂੰ ਤੁਹਾਡੇ ਵਰਗੇ ਲੋਕਾਂ ਵਲੋਂ ਹੀ ਬਣਾਇਆ ਗਿਆ ਹੈ।",
        "createacct-benefit-body1": "{{PLURAL:$1|ਸੋਧ|ਸੋਧਾਂ}}",
        "createacct-benefit-body2": "{{PLURAL:$1|ਸਫ਼ਾ|ਸਫ਼ੇ}}",
        "changeemail-password": "ਤੁਹਾਡਾ {{SITENAME}} ਪਾਸਵਰਡ:",
        "changeemail-submit": "ਈ-ਮੇਲ ਬਦਲੋ",
        "changeemail-throttled": "ਤੁਸੀਂ ਦਾਖ਼ਲ ਹੋਣ ਦੀਆਂ ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਕੀਤੀਆਂ ਹਨ।\nਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ $1 ਉਡੀਕ ਕਰੋ ਜੀ।",
+       "changeemail-nochange": "ਕਿਰਪਾ ਕਰਕੇ ਕੋਈ ਵੱਖਰਾ ਈਮੇਲ ਪਤਾ ਭਰੋ।",
        "resettokens": "ਟੋਕਨ ਮੁੜ-ਸੈੱਟ ਕਰੋ",
        "resettokens-text": "ਤੁਸੀਂ ਆਪਣੀਆਂ ਨਿਸ਼ਾਨੀਆਂ, ਜੋ ਤੁਹਾਡੇ ਖਾਤੇ ਨਾਲ਼ ਜੁੜੇ ਖ਼ਾਸ ਨਿੱਜੀ ਅੰਕੜਿਆਂ ਤੱਕ ਪੁੱਜਣ ਵਾਸਤੇ ਇਜਾਜ਼ਤ ਦਿੰਦੀਆਂ ਹਨ, ਨੂੰ ਇੱਥੇ ਮੁੜ-ਬਣਾ ਸਕਦੇ ਹੋ।\n\nਤੁਹਾਨੂੰ ਇਹ ਤਾਂ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ ਜੇਕਰ ਤੁਸੀਂ ਇਹਨਾਂ ਨੂੰ ਰੱਬ-ਸਬੱਬੀ ਕਿਸੇ ਨਾਲ਼ ਸਾਂਝਾ ਕਰ ਦਿੱਤਾ ਜਾਂ ਤੁਹਾਡਾ ਖਾਤਾ ਖ਼ਤਰੇ ਵਿੱਚ ਆ ਗਿਆ ਹੈ।",
        "resettokens-no-tokens": "ਨਵੀਆਂ ਬਣਾਉਣ ਵਾਸਤੇ ਕੋਈ ਨਿਸ਼ਾਨੀਆਂ ਨਹੀਂ ਹਨ।",
        "content-model-text": "ਆਮ ਲਿਖਤ",
        "content-model-javascript": "ਜਾਵਾਸਕਰਿਪਟ",
        "content-model-css": "ਸੀਐਸਐਸ",
+       "content-json-empty-object": "ਖਾਲੀ ਚੀਜ਼",
+       "content-json-empty-array": "ਖਾਲੀ ਤਰਤੀਬ",
        "post-expand-template-inclusion-warning": "'''ਖ਼ਬਰਦਾਰ:''' ਫਰਮੇ ਦਾ ਅਕਾਰ ਬਹੁਤ ਵੱਡਾ ਹੈ। ਕੁਝ ਫਰਮੇ ਸ਼ਾਮਲ ਨਹੀਂ ਹੋਣਗੇ।",
        "post-expand-template-inclusion-category": "ਉਹ ਸਫ਼ੇ ਜਿੱਥੇ ਫਰਮੇ ਸ਼ਾਮਲ ਕਰਨ ਦਾ ਅਕਾਰ ਹੱਦੋਂ ਵੱਧ ਗਿਆ ਹੈ",
        "post-expand-template-argument-warning": "'''ਚੇਤਾਵਨੀ:'''\nਇਸ ਪੰਨੇ ਤੇ ਘੱਟੋ ਘੱਟ ਇੱਕ ਐਸੀ ਸਾਂਚਾ ਬਹਿਸ ਹੈ ਜਿਸ ਦਾ ਅਕਾਰ ਬਹੁਤ ਵੱਡਾ ਹੈ। ਅਜਿਹੀਆਂ ਬਹਿਸਾਂ ਨੂੰ ਛੱਡ ਦਿੱਤਾ ਗਿਆ ਹੈ।",
        "parser-template-loop-warning": "ਫਰਮੇ ਦਾ ਲੂਪ ਲੱਭਿਆ: [[$1]]",
        "undo-success": "ਇਹ ਸੋਧ ਨਕਾਰੀ ਜਾ ਸਕਦੀ ਹੈ।\nਮਿਹਰਬਾਨੀ ਕਰਕੇ ਇਹ ਤਸਦੀਕ ਕਰਨ ਲਈ ਹੇਠਲੀ ਤੁਲਨਾ ਜਾਂਚੋ ਕਿ ਇਹ ਓਹੀ ਹੈ ਜੋ ਤੁਸੀਂ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ ਅਤੇ ਫਿਰ ਸੋਧ ਨਕਾਰਨ ਲਈ ਤਬਦੀਲੀਆਂ ਸਾਂਭ ਦਿਓ।",
        "undo-norev": "ਸੋਧ ਨਕਾਰੀ ਨਹੀਂ ਜਾ ਸਕਦੀ ਕਿਉਂਕਿ ਇਹ ਮੌਜੂਦ ਨਹੀਂ ਜਾਂ ਮਿਟਾ ਦਿੱਤੀ ਗਈ ਹੈ।",
+       "undo-nochange": "ਲਗਦਾ ਹੈ ਕਿ ਿਹ ਸੋਧ ਪਹਿਲਾਂ ਹੀ ਮੋੜ ਦਿੱਤੀ ਗਈ ਹੈ।",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|ਗੱਲ-ਬਾਤ]]) ਦੀ ਸੋਧ $1 ਨਕਾਰੀ",
        "undo-summary-username-hidden": "ਗੁਪਤ ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਕੀਤੀ $1 ਸੋਧ ਰੱਦ ਕਰੋ",
        "cantcreateaccounttitle": "ਖਾਤਾ ਬਣਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ",
        "rows": "ਕਤਾਰਾਂ:",
        "columns": "ਕਾਲਮ:",
        "searchresultshead": "ਖੋਜ",
+       "stub-threshold-sample-link": "ਨਮੂਨਾ",
        "stub-threshold-disabled": "ਬੰਦ ਹੈ",
        "recentchangesdays": "ਤਾਜ਼ਾ ਤਬਦੀਲੀਆਂ ਵਿਚ ਵਿਖਾਉਣ ਲਈ ਦਿਨ:",
        "recentchangesdays-max": "ਵੱਧ ਤੋਂ ਵੱਧ $1 {{PLURAL:$1|ਦਿਨ|ਦਿਨ}}",
        "right-editmyuserjs": "ਆਪਣੀਆਂ ਵਰਤੋਂਕਾਰ ਜਾਵਾਸਕਰਿਪਟ ਫ਼ਾਈਲਾਂ ਸੋਧੋ",
        "right-viewmywatchlist": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵੇਖੋ",
        "right-editmywatchlist": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਸੋਧੋ। ਧਿਆਨ ਦਿਓ ਕਿ ਕੁਝ ਸਫ਼ੇ ਇਸ ਹੱਕ ਤੋਂ ਬਿਨਾਂ ਵੀ ਜੁੜਨਗੇ।",
+       "right-viewmyprivateinfo": "ਆਪਣਾ ਨਿੱਜੀ ਡਾਟਾ ਵੇਖੋ (ਉਦਾਹਰਨ ਵਜੋਂ ਈਮੇਲ ਪਤਾ, ਅਸਲੀ ਨਾਂ)",
+       "right-editmyprivateinfo": "ਆਪਣਾ ਨਿੱਜੀ ਡਾਟਾ ਸੋਧੋ (ਉਦਾਹਰਨ ਵਜੋਂ ਈਮੇਲ ਪਤਾ, ਅਸਲੀ ਨਾਂ)",
        "right-editmyoptions": "ਆਪਣੀਆਂ ਤਰਜੀਹਾਂ ਸੋਧੋ",
+       "right-import": "ਹੋਰ ਵਿਕੀਅਾਂ ਤੋਂ ਸਫ਼ੇ ਦਰਾਮਦ ਕਰੋ",
+       "right-importupload": "ਕਿਸੇ ਫ਼ਾਈਲ ਅਪਲੋਡ ਤੋਂ ਸਫ਼ੇ ਦਰਾਮਦ ਕਰੋ",
        "right-unwatchedpages": "ਨਜ਼ਰ ਨਾ ਰੱਖੇ ਜਾ ਰਹੇ ਸਫ਼ਿਆਂ ਦੀ ਲਿਸਟ ਵੇਖਣੀ",
        "right-mergehistory": "ਸਫ਼ਿਆਂ ਦੇ ਅਤੀਤਾਂ ਨੂੰ ਰਲ਼ਾਉਣਾ",
        "right-userrights": "ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੇ ਹੱਕ ਬਦਲਣੇ",
        "action-viewmywatchlist": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵੇਖੋ",
        "action-viewmyprivateinfo": "ਆਪਣੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਵੇਖੋ",
        "action-editmyprivateinfo": "ਆਪਣੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸੋਧੋ",
+       "action-editcontentmodel": "ਕਿਸੇ ਸਫ਼ੇ ਦਾ ਸਮੱਗਰੀ ਮਾਡਲ ਸੋਧੋ",
        "nchanges": "$1 {{PLURAL:$1|ਤਬਦੀਲੀ|ਤਬਦੀਲੀਆਂ}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ਆਖ਼ਰੀ ਫੇਰੀ ਤੋਂ ਲੈ ਕੇ}}",
        "enhancedrc-history": "ਅਤੀਤ",
        "newpageletter": "ਨ",
        "boteditletter": "ਬੋਟ",
        "number_of_watching_users_pageview": "[$1 ਵੇਖ ਰਹੇ ਹਨ {{PLURAL:$1|ਯੂਜ਼ਰ}}]",
-       "rc_categories_any": "ਕੋਈ ਵੀ",
+       "rc_categories_any": "à¨\9aà©\81ਣà©\87 à¨¹à©\8bà¨\87à¨\85ਾà¨\82 à¨µà¨¿à©±à¨\9aà©\8bà¨\82 à¨\95à©\8bà¨\88 à¨µà©\80",
        "rc-change-size-new": "$1 {{PLURAL:$|ਬਾਈਟ|ਬਾਈਟਾਂ}} ਤਬਦੀਲੀ ਤੋਂ ਬਾਅਦ",
        "newsectionsummary": "/* $1 */ ਨਵਾਂ ਭਾਗ",
        "rc-enhanced-expand": "ਵੇਰਵੇ ਵੇਖਾਓ",
        "tmp-create-error": "ਆਰਜ਼ੀ ਫ਼ਾਈਲ ਬਣਾਈ ਨਾ ਜਾ ਸਕੀ।",
        "tmp-write-error": "ਆਰਜ਼ੀ ਫ਼ਾਈਲ ਲਿਖਣ ਲਈ ਗ਼ਲਤੀ ਆਈ।",
        "large-file": "ਫ਼ਾਈਲਾਂ $1 ਤੋਂ ਵੱਡੀਆਂ ਨਾ ਹੋਣ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ;\nਇਹ ਫ਼ਾਈਲ $2 ਦੀ ਹੈ।",
+       "largefileserver": "ਇਹ ਫ਼ਾਈਲ ਸਰਵਰ ਦੇ ਮੁਤਾਬਕ ਵੱਡੀ ਹੈ।",
        "windows-nonascii-filename": "ਵਿਕੀ ਖ਼ਾਸ ਚਿੰਨ੍ਹਾਂ ਵਾਲੇ ਫ਼ਾਈਲ ਨਾਮਾਂ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦਾ।",
-       "fileexists": "à¨\87ਹ à¨«à¨¼à¨¾à¨\88ਲ à¨¨à¨¾à¨\82 à¨ªà¨¹à¨¿à¨²à¨¾à¨\82 à¨¹à©\80 à¨®à©\8cà¨\9cà©\82ਦ à¨¹à©\88। à¨\9cà©\87 à¨¤à©\81ਸà©\80à¨\82 à¨\87ਹਨà©\82à©° à¨¬à¨¦à¨²à¨£ à¨¬à¨¾à¨°à©\87 à¨¦à©\8dਰਿà©\9c à¨¨à¨¹à©\80à¨\82 à¨¹à©\8b à¨¤à¨¾à¨\82  <strong>[[:$1]]</strong> à¨µà©\87à¨\96à©\8b à¨\9cà©\80। [[$1|thumb]]",
+       "fileexists": "à¨\87ਸ à¨¨à¨¾à¨\82 à¨¦à©\80 à¨«à¨¼à¨¾à¨\88ਲ à¨ªà¨¹à¨¿à¨²à¨¾à¨\82 à¨¹à©\80 à¨®à©\8cà¨\9cà©\82ਦ à¨¹à©\88। à¨\9cà©\87 {{GENDER:|ਤà©\81ਸà©\80à¨\82}} à¨\87ਸ à¨¨à©\82à©° à¨¬à¨¦à¨²à¨£ à¨¬à¨¾à¨°à©\87 à¨¦à©\8dਰਿà©\9c à¨¨à¨¹à©\80à¨\82 à¨¹à©\8b à¨¤à¨¾à¨\82  <strong>[[:$1]]</strong> à¨µà©\87à¨\96à©\8b à¨\9cà©\80।\n [[$1|thumb]]",
        "fileexists-extension": "ਇਸ ਨਾਂ ਨਾਲ਼ ਰਲਦੀ ਫ਼ਾਈਲ ਮੌਜੂਦ ਹੈ: [[$2|thumb]]\n* ਅੱਪਲੋਡ ਕੀਤੀ ਜਾਂਦੀ ਫ਼ਾਈਲ ਦਾ ਨਾਂ: <strong>[[:$1]]</strong>\n* ਮੌਜੂਦ ਫ਼ਾਈਲ ਦਾ ਨਾਂ: <strong>[[:$2]]</strong>\nਕੋਈ ਵੱਖਰਾ ਨਾਂ ਚੁਣੋ ਜੀ।",
        "file-exists-duplicate": "ਇਹ ਫ਼ਾਈਲ {{PLURAL:$1|ਇਸ ਫ਼ਾਈਲ|ਇਹਨਾਂ ਫ਼ਾਈਲਾਂ}} ਦੀ ਨਕਲ ਹੈ:",
        "uploadwarning": "ਅੱਪਲੋਡ ਚਿਤਾਵਨੀ",
index 0257dbf..5bf37b9 100644 (file)
        "personaltools": "Narzędzia osobiste",
        "articlepage": "Pokaż zawartość strony",
        "talk": "Dyskusja",
-       "views": "Wyświetleń",
+       "views": "Widok",
        "toolbox": "Narzędzia",
        "userpage": "Pokaż stronę użytkownika",
        "projectpage": "Pokaż stronę projektu",
        "createacct-captcha": "Kontrola bezpieczeństwa",
        "createacct-imgcaptcha-ph": "Wpisz tekst widoczny powyżej",
        "createacct-submit": "Utwórz konto",
-       "createacct-another-submit": "Utwórz kolejne konto",
+       "createacct-another-submit": "Utwórz konto",
        "createacct-benefit-heading": "{{grammar:B.lp|{{SITENAME}}}} tworzą ludzie tacy jak Ty.",
        "createacct-benefit-body1": "{{PLURAL:$1|edycja|edycje|edycji}}",
        "createacct-benefit-body2": "{{PLURAL:$1|strona|strony|stron}}",
        "upload-http-error": "Wystąpił błąd protokołu HTTP – $1",
        "upload-copy-upload-invalid-domain": "Przesyłanie kopii z tej domeny nie jest dostępne.",
        "upload-dialog-title": "Prześlij plik",
-       "upload-dialog-error": "Wystąpił błąd",
-       "upload-dialog-warning": "Pojawiło się ostrzeżenie",
        "upload-dialog-button-cancel": "Anuluj",
        "upload-dialog-button-done": "Gotowe",
        "upload-dialog-button-save": "Zapisz",
        "upload-dialog-button-upload": "Prześlij",
-       "upload-dialog-label-select-file": "Wybierz plik",
-       "upload-dialog-label-infoform-title": "Szczegóły",
-       "upload-dialog-label-infoform-name": "Nazwa",
-       "upload-dialog-label-infoform-description": "Opis",
-       "upload-dialog-label-usage-title": "Korzystanie",
-       "upload-dialog-label-usage-filename": "Nazwa pliku",
+       "upload-process-error": "Wystąpił błąd",
+       "upload-process-warning": "Pojawiło się ostrzeżenie",
+       "upload-form-label-select-file": "Wybierz plik",
+       "upload-form-label-infoform-title": "Szczegóły",
+       "upload-form-label-infoform-name": "Nazwa",
+       "upload-form-label-infoform-description": "Opis",
+       "upload-form-label-usage-title": "Korzystanie",
+       "upload-form-label-usage-filename": "Nazwa pliku",
        "backend-fail-stream": "Nie można odczytać pliku $1.",
        "backend-fail-backup": "Nie można utworzyć kopii zapasowej pliku  $1 .",
        "backend-fail-notexists": "Plik  $1  nie istnieje.",
        "filerevert-legend": "Przywracanie poprzedniej wersji pliku",
        "filerevert-intro": "Zamierzasz przywrócić '''[[Media:$1|$1]]''' do [$4 wersji z $3, $2].",
        "filerevert-comment": "Powód:",
-       "filerevert-defaultcomment": "Przywrócono wersję z $2, $1",
+       "filerevert-defaultcomment": "Przywrócono wersję z $1, $2 ($3)",
        "filerevert-submit": "Przywróć",
        "filerevert-success": "Plik '''[[Media:$1|$1]]''' został cofnięty do [$4 wersji z $3, $2].",
        "filerevert-badversion": "Brak poprzedniej lokalnej wersji tego pliku z podaną datą.",
        "logentry-newusers-byemail": "Konto $3 zostało utworzone przez użytkownika $1, hasło wysłano e-mailem",
        "logentry-newusers-autocreate": "$1 automatycznie {{GENDER:$2|utworzył|utworzyła|utworzył}} konto użytkownika",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|przeniósł|przeniosła}} ustawienia zabezpieczeń z $4 do $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|usunął|usunęła}} zabezpieczanie z $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|zabezpieczył|zabezpieczyła|zabezpieczył(a)}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|zabezpieczył|zabezpieczyła|zabezpieczył(a)}} $3 $4 [kaskadowo]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|zmienił|zmieniła|zmienił(a)}} poziom zabezpieczenia dla $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|zmienił|zmieniła|zmienił(a)}} poziom zabezpieczenia dla $3 $4 [kaskadowo]",
        "logentry-rights-rights": "$1 {{GENDER:$2|zmienił|zmieniła}} przynależność $3 do grup ($4 → $5)",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|zmienił|zmieniła}} przynależność $3 do grup",
        "logentry-rights-autopromote": "$1 automatycznie {{GENDER:$2|zmienił|zmieniła}} przynależność ($4 → $5)",
index 6383cfd..27e4889 100644 (file)
        "nstab-template": "کينډۍ",
        "nstab-help": "لارښود مخ",
        "nstab-category": "وېشنيزه",
+       "mainpage-nstab": "لومړی مخ",
        "nosuchaction": "هېڅ داسې کومه کړنه نشته",
        "nosuchactiontext": "کومه کړنه چې د URL لخوا ځانگړې شوې سمه نه ده.\nکېدای شي چې URL مو سم نه وي ټايپ کړی، او يا مو يوه ناسمه تړنه څارلې وي.\nدا د دې هم ښکارندويي کوي چې کېدای شي چې د {{SITENAME}} لخوا کارېدونکې ساوترې کې يوه تېروتنه وي.",
        "nosuchspecialpage": "داسې هېڅ کوم ځانگړی مخ نشته",
        "badtitletext": "ستاسې د غوښتل شوي مخ سرليک سم نه وو، يا مو د سرليک ځای تش وو او يا هم د ژبو خپلمنځي تړنې څخه يا د ويکي گانو خپلمنځي سرليکونو څخه يو ناسم توری مو پکې کارولی وي.\nکېدای شي چې ستاسې په ورکړ شوي سرليک کې يو يا څو داسې توري وي چې د سرليک په توگه بايد و نه کارېږي.",
        "title-invalid-interwiki": "په سرليک کې يوه ويکي خپلمنځي تړنه ده",
        "perfcached": "لاندينی اومتوک په حافظه کې ساتل شوی او کېدای شي اوسمهاله شوی نه وي.  اکثر بريد له مخې {{PLURAL:$1|يوه پايله|$1 پايلې}} په حافظه کې شته.",
+       "perfcachedts": "لاندې راغلی اومتوک په حافظه کې ساتل شوی او وروستی ځل په $1 هم مهاله شوی. په ساتلې حافظې کې ډېر تر ډېره {{PLURAL:$4|يوه پايله ده|$4 پايلې دي}}.",
        "querypage-no-updates": "د دې مخ اوسمهالېدنې ناچارن شوي.\nپه ښکاره توگه د دې ځای اومتوک به نه وي تازه شوي.",
        "viewsource": "سرچينه کتل",
        "viewsource-title": "د $1 سرچينه کتل",
        "welcomecreation-msg": "گڼون مو جوړ شو.\nد [[Special:Preferences|{{SITENAME}} غوره توبونه]] بدلول مو مه هېروۍ.",
        "yourname": "کارن-نوم:",
        "userlogin-yourname": "کارن-نوم",
-       "userlogin-yourname-ph": "کارن-نوم مو وليکۍ",
+       "userlogin-yourname-ph": "کارن-نوم مو وليکئ",
        "createacct-another-username-ph": "كارن نوم مو وركړۍ",
        "yourpassword": "پټنوم:",
        "userlogin-yourpassword": "پټنوم",
-       "userlogin-yourpassword-ph": "پټنوم مو وليکۍ",
-       "createacct-yourpassword-ph": "پټنوم مو وټاپۍ",
+       "userlogin-yourpassword-ph": "پټنوم مو وليکئ",
+       "createacct-yourpassword-ph": "پټنوم مو وټاپئ",
        "yourpasswordagain": "پټنوم بيا وليکه",
        "createacct-yourpasswordagain": "پټنوم مو تاييد کړۍ",
-       "createacct-yourpasswordagain-ph": "پټنوم مو بيا وټاپۍ",
+       "createacct-yourpasswordagain-ph": "پټنوم مو بيا وټاپئ",
        "remembermypassword": "زما پټنوم په دې کمپيوټر (تر $1 {{PLURAL:$1|ورځې|ورځو}}) په ياد وساته!",
        "userlogin-remembermypassword": "غونډال کې مې ننوتلی وساته",
        "userlogin-signwithsecure": "خوندي اړيکتيا کارول",
        "userlogin-createanother": "بل گڼون جوړول",
        "createacct-emailrequired": "برېښليک پته",
        "createacct-emailoptional": "برېښليک پته (اختياري)",
-       "createacct-email-ph": "برېښليک پته مو وټاپۍ",
+       "createacct-email-ph": "برېښليک پته مو وټاپئ",
        "createacct-another-email-ph": "برېښليک پته مو ورکړۍ",
        "createaccountmail": "يو لنډمهاله ناټاکلی پټنوم کارول او ځانگړې شوې برېښليک پتې ته ورلېږل",
        "createacct-realname": "آر نوم (اختياري)",
        "createacct-reason": "سبب",
        "createacct-reason-ph": "ولې تاسې بل گڼون جوړول غوااړۍ",
        "createacct-captcha": "امنيتي تدبير",
-       "createacct-imgcaptcha-ph": "پورته تاسې ته ښکاره شوی متن وټاپۍ",
+       "createacct-imgcaptcha-ph": "پورته ښکاره شوی متن دلته وټاپئ",
        "createacct-submit": "گڼون مو جوړ کړئ",
        "createacct-another-submit": "بل گڼون جوړول",
        "createacct-benefit-heading": "{{SITENAME}} ستاسې په شان خلکو لخوا جوړ شوی.",
        "nosuchusershort": "د \"$1\" په نوم هېڅ کوم گڼون نشته. لطفاً خپل د نوم ليکلې بڼې ته ځير شی چې پکې تېروتنه نه وي.",
        "nouserspecified": "تاسې ځان ته کوم کارن نوم نه دی ځانگړی کړی.",
        "login-userblocked": "په دې کارن بنديز لگېدلی. غونډال کې ننوتلو ته پرې نه ښودلی شو.",
-       "wrongpassword": "ناسم پټنوم مو ليکلی. لطفاً يو ځل بيا يې وليکۍ.",
+       "wrongpassword": "ناسم پټنوم مو ليکلی. لطفاً يو ځل بيا يې وليکئ.",
        "wrongpasswordempty": "تاسې پټنوم نه دی ليکلی. لطفاً سر له نوي يې وليکۍ.",
        "passwordtooshort": "بايد چې پټنوم مو لږ تر لږه {{PLURAL:$1|1 توری|$1 توري}} وي.",
        "passwordtoolong": "پټنوم مو بايد له {{PLURAL:$1|1 توري|$1 تورو}} څخه اوږد نه وي.",
        "prefs-namespaces": "نوم-تشيالونه",
        "default": "تلواليز",
        "prefs-files": "دوتنې",
-       "prefs-custom-css": "ځاني CSS",
+       "prefs-custom-css": "دوديزه سي اس اس",
        "prefs-custom-js": "ځاني جاواسکرېپټ",
        "prefs-common-css-js": "د ټولو پوښونو لپاره د CSS/جاواسکرېپټ دوتنه:",
        "prefs-emailconfirm-label": "د برېښليک باورتيا:",
        "prefs-registration": "د نومليکنې وخت:",
        "yourrealname": "اصلي نوم:",
        "yourlanguage": "ژبه:",
+       "yourvariant": "د ژبگړدود مېنځپانگه:",
        "yournick": "نوی لاسليک:",
        "badsiglength": "ستاسو لاسليک ډېر اوږد دی.\nبايد چې لاسليک مو له $1 {{PLURAL:$1|توري|تورو}} نه لږ وي.",
        "yourgender": "څنگه غواړۍ ځان څرگند کړۍ؟",
        "gender-unknown": "ناڅرگنده",
        "gender-male": "نارينه",
        "gender-female": "ښځينه",
+       "prefs-help-gender": "دا غوره توب اختياري دی.\nساوتری د خپلو ارزښتونو په کارولو سره تاسې ته مخاطب کېږي او د کره جنسيت او کره گرامري صيغې له مخې ستاسې يادونه کوي.\nدا مالومات به په عامه توگه ښکاري.",
        "email": "برېښليک",
        "prefs-help-realname": "آر نوم ورکول ستاسې د خوښې کار دی.\nکه تاسې خپل آر نوم ورکړۍ، نو ستاسې ټولې کړنې به ستاسې په نوم اړوندې شي.",
        "prefs-help-email": "د برېښليک ورکړه ستاسې په خوښه ده، خو په ورکړې سره به يې د يوه نوي پټنوم د لېږلو چار آسانه کړي هغه هم کله چې تاسې نه خپل پټنوم هېر شوی وي.",
        "boteditletter": "ر",
        "number_of_watching_users_pageview": "[$1  {{PLURAL:$1|کتونکی کارن|کتونکي کارنان}}]",
        "rc_categories": "د وېشنيزو بريدونه (په \"|\" بېلول)",
-       "rc_categories_any": "هر يو",
+       "rc_categories_any": "Ù\84Ù\87 Ù¼Ø§Ú©Ù\84 Ø´Ù\88Ù\8aÙ\88 Ù\87ر Ù\8aÙ\88",
        "rc-change-size-new": "$1 {{PLURAL:$1|بايټ|بايټونه}} د بدلون وروسته",
        "newsectionsummary": "/* $1 */ نوې برخه",
        "rc-enhanced-expand": "تفصيل ښکاره کول",
        "upload-misc-error": "د پورته کېدنې نامالومه تېروتنه",
        "upload-http-error": "د HTTP يوه ستونزه رامېنځ ته شوې: $1",
        "upload-dialog-title": "دوتنه پورته کول",
-       "upload-dialog-error": "يوه ستونزه پېښه شوې",
-       "upload-dialog-warning": "يوه گواښنه رامېنځ ته شوه",
        "upload-dialog-button-cancel": "ناگارل",
        "upload-dialog-button-done": "ترسره شو",
        "upload-dialog-button-save": "خوندي کول",
        "upload-dialog-button-upload": "پورته کول",
-       "upload-dialog-label-select-file": "دوتنه ټاکل",
-       "upload-dialog-label-infoform-title": "ځانگړنې",
-       "upload-dialog-label-infoform-name": "نوم",
-       "upload-dialog-label-infoform-description": "څرگندونه",
-       "upload-dialog-label-usage-title": "کارېدنې",
-       "upload-dialog-label-usage-filename": "د دوتنې نوم",
+       "upload-process-error": "يوه ستونزه پېښه شوې",
+       "upload-process-warning": "يوه گواښنه رامېنځ ته شوه",
+       "upload-form-label-select-file": "دوتنه ټاکل",
+       "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": "د دوتنې نوم",
        "backend-fail-notexists": "د $1 په نوم دوتنه نشته.",
        "backend-fail-delete": "د \"$1\" دوتنه ړنګه نه شوه.",
        "backend-fail-alreadyexists": "د $1 دوتنه له پخوا نه شته.",
        "pageswithprop-submit": "ورځه",
        "doubleredirects": "دوه ځلي ورگرځېدنې",
        "brokenredirects": "ماتې ورگرځېدنې",
+       "brokenredirectstext": "لاندينۍ مخ گرځونې ناموجوده مخونو سره تړنې لري:",
        "brokenredirects-edit": "سمول",
        "brokenredirects-delete": "ړنگول",
        "withoutinterwiki": "د ژبې د تړنو بې برخې مخونه",
        "nmembers": "$1 {{PLURAL:$1|غړی|غړي}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|غړی|غړي}}",
        "nrevisions": "$1 {{PLURAL:$1|بڼه|بڼې}}",
-       "nimagelinks": "په $1 {{PLURAL:$1|کارېدلی مخ|کارېدلي مخونه}}",
+       "nimagelinks": "په $1 {{PLURAL:$1|مخ|مخونو}} کارېدلی",
        "ntransclusions": "په $1 {{PLURAL:$1|مخ|مخونو}} کارېدلی",
        "specialpage-empty": "د دې راپور لپاره کومې پايلې نشته.",
        "lonelypages": "يتيم مخونه",
        "editcomment": "د سمون لنډيز دا و: \"''$1''\".",
        "changecontentmodel-title-label": "مخ سرليک",
        "changecontentmodel-reason-label": "سبب:",
+       "logentry-contentmodel-change-revertlink": "په څټ گرځول",
+       "logentry-contentmodel-change-revert": "په څټ گرځول",
        "protectlogpage": "د ژغورنې يادښت",
        "protectlogtext": "دلته لاندې د ژغورل شويو مخونو د بدلونونو لړليک راغلی.\nد دم گړۍ فعالو مخ ژغورنو لړليک لپاره د [[Special:ProtectedPages|ژغورل شويو مخونو لړليک]] وگورئ.",
        "protectedarticle": "\"[[$1]]\" وژغورل شو",
        "sp-contributions-search": "د ونډو پلټنه",
        "sp-contributions-username": "IP پته يا کارن-نوم:",
        "sp-contributions-toponly": "يوازې هغه سمونونه چې تر ټولو تازه بڼې لري ښکاره کول",
+       "sp-contributions-newonly": "يوازې د مخ جوړېدنې سمونونه ښکاره کول",
        "sp-contributions-submit": "پلټل",
        "whatlinkshere": "د دې مخ تړنې",
        "whatlinkshere-title": "هغه مخونه چې د \"$1\" سره تړنې لري",
        "expiringblock": "په $1 نېټه، $2 بجو پای ته رسېږي",
        "anononlyblock": "يواځې ورکنومی",
        "createaccountblock": "په گڼون جوړولو بنديز لگېدلی",
-       "emailblock": "پر Ø¨Ø±Û\90Ú\9aÙ\84Ù\8aÚ© Ø¨Ù\86دÙ\8aز Ù\88Ù\84Ú«ېد",
+       "emailblock": "پر Ø¨Ø±Û\90Ú\9aÙ\84Ù\8aÚ© Ø¨Ù\86دÙ\8aز Ù\88Ù\84Ú¯ېد",
        "blocklist-nousertalk": "د خبرواترو خپل مخ نه شی سمولای",
        "ipblocklist-empty": "د بنديز لړليک تش دی",
        "blocklink": "بنديز لگول",
        "ipb_already_blocked": "پر \"$1\" د پخوا نه بنديز دی",
        "ipb-needreblock": "پر $1 د پخوا نه بنديز لگېدلی.\nآيا تاسې د امستنو بدلول غواړۍ؟",
        "ipb-otherblocks-header": "{{PLURAL:$1|بل بنديز|نور بنديزونه}}",
+       "ip_range_invalid": "ناسم آی پي بريد.",
        "lockdb": "توکبنسټ تړل",
        "unlockdb": "توکبنسټ پرانيستل",
        "lockconfirm": "هو، زه د توکبنسټ تړل غواړم.",
        "exif-unknowndate": "ناڅرگنده نېټه",
        "exif-orientation-1": "نورمال",
        "exif-componentsconfiguration-0": "نشته دی",
+       "exif-exposureprogram-1": "لاسي",
        "exif-exposureprogram-2": "نورماله پروګرام",
        "exif-subjectdistance-value": "$1 متره",
        "exif-meteringmode-0": "ناجوت",
index 457e955..73926f4 100644 (file)
@@ -83,7 +83,8 @@
                        "TheEduGobi",
                        "Araceletorres",
                        "L",
-                       "Walesson"
+                       "Walesson",
+                       "Rhcastilhos"
                ]
        },
        "tog-underline": "Sublinhar links:",
        "nstab-template": "Predefinição",
        "nstab-help": "Página de ajuda",
        "nstab-category": "Categoria",
+       "mainpage-nstab": "Página principal",
        "nosuchaction": "Ação inexistente",
        "nosuchactiontext": "A ação especificada pela URL é inválida.\nVocê deve ter se enganado ao digitar a URL, ou acessou um link incorreto.\nIsso também pode indicar um erro no software usado no sítio {{SITENAME}}.",
        "nosuchspecialpage": "Esta página especial não existe",
        "createacct-captcha": "Verificação de segurança",
        "createacct-imgcaptcha-ph": "Digite o texto acima",
        "createacct-submit": "Crie sua conta",
-       "createacct-another-submit": "Criar outra conta",
+       "createacct-another-submit": "Criar conta",
        "createacct-benefit-heading": "{{SITENAME}} é feita por pessoas como você.",
        "createacct-benefit-body1": "{{PLURAL:$1|edição|edições}}",
        "createacct-benefit-body2": "{{PLURAL:$1|página|páginas}}",
        "changeemail-password": "Sua senha para o wiki {{SITENAME}}:",
        "changeemail-submit": "Alterar e-mail",
        "changeemail-throttled": "Você realizou demasiadas tentativas de se registrar.\nPor favor, aguarde $1 antes de tentar novamente.",
+       "changeemail-nochange": "Por favor insira um novo endereço de e-mail.",
        "resettokens": "Reiniciar os tokens",
        "resettokens-text": "Você pode reiniciar os tokens, que permitem o acesso a certos dados privados associados à sua conta, aqui.\n\nVocê só deve reiniciá-los se compartilhou-os com alguém ou se a sua conta foi comprometida.",
        "resettokens-no-tokens": "Não existem tokens para reiniciar.",
        "upload-too-many-redirects": "A URL contém redirecionamentos demais",
        "upload-http-error": "Ocorreu um erro HTTP: $1",
        "upload-copy-upload-invalid-domain": "Não é possível realizar envios remotos neste domínio.",
+       "upload-dialog-title": "Enviar arquivo",
        "upload-dialog-button-cancel": "Cancelar",
        "upload-dialog-button-done": "Feito",
        "upload-dialog-button-save": "Salvar",
        "upload-dialog-button-upload": "Enviar",
-       "upload-dialog-label-select-file": "Selecionar arquivo",
-       "upload-dialog-label-infoform-title": "Detalhes",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrição",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nome do arquivo",
+       "upload-process-error": "Ocorreu um erro",
+       "upload-process-warning": "Ocorreu um aviso",
+       "upload-form-label-select-file": "Selecionar arquivo",
+       "upload-form-label-infoform-title": "Detalhes",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrição",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nome do arquivo",
        "backend-fail-stream": "Não foi possível transmitir o arquivo  $1.",
        "backend-fail-backup": "Não foi possível fazer backup do arquivo  $1 .",
        "backend-fail-notexists": "O arquivo $1 não existe.",
        "filerevert-legend": "Reverter arquivo",
        "filerevert-intro": "<span class=\"plainlinks\">Você está revertendo '''[[Media:$1|$1]]''' para a [$4 versão de $2 - $3].</span>",
        "filerevert-comment": "Motivo:",
-       "filerevert-defaultcomment": "Revertido para a versão de $1 - $2",
+       "filerevert-defaultcomment": "Revertido para a versão de $2, $1 ($3)",
        "filerevert-submit": "Reverter",
        "filerevert-success": "<span class=\"plainlinks\">'''[[Media:$1|$1]]''' foi revertida para a [$4 versão de $2 - $3].</span>",
        "filerevert-badversion": "Não há uma versão local anterior deste arquivo no período de tempo especificado.",
        "nopagetext": "A página alvo especificada não existe.",
        "pager-newer-n": "{{PLURAL:$1|posterior|$1 posteriores}}",
        "pager-older-n": "{{PLURAL:$1|1 anterior|$1 anteriores}}",
-       "suppress": "Supervisor",
+       "suppress": "Suprimir",
        "querypage-disabled": "Esta página especial está desativada para não prejudicar o desempenho.",
        "apihelp": "Ajuda de API",
        "apihelp-no-such-module": "Modulo \"$1\" não foram achados.",
        "changecontentmodel-legend": "Alterar o modelo de conteúdo",
        "changecontentmodel-title-label": "Título da página",
        "changecontentmodel-reason-label": "Motivo:",
+       "changecontentmodel-success-title": "O modelo de conteúdo foi alterado",
+       "changecontentmodel-success-text": "O tipo de conteúdo de [[:$1]] foi alterado.",
        "logentry-contentmodel-change-revertlink": "reverter",
+       "logentry-contentmodel-change-revert": "reverter",
        "protectlogpage": "Registro de proteção",
        "protectlogtext": "Encontra-se abaixo o registro de proteção e desproteção de páginas.\nConsulte a [[Special:ProtectedPages|lista de páginas protegidas]] para ver as páginas que se encontram protegidas neste momento.",
        "protectedarticle": "protegeu \"[[$1]]\"",
        "pageinfo-robot-index": "Autorizado",
        "pageinfo-robot-noindex": "Desautorizado",
        "pageinfo-watchers": "Número de vigilantes da página",
+       "pageinfo-visiting-watchers": "Número de vigilantes que consultaram as edições recentes da página",
        "pageinfo-few-watchers": "Menos de  $1  {{PLURAL:$1|vigilante|vigilantes}}",
        "pageinfo-redirects-name": "Número de redirecionamentos para esta página",
        "pageinfo-subpages-name": "Subpáginas desta página",
        "htmlform-cloner-create": "Adicionar mais",
        "htmlform-cloner-delete": "Remover",
        "htmlform-cloner-required": "Pelo menos um valor é requerido",
+       "htmlform-title-not-creatable": "\"$1\" não é um título que possa ser atribuído a uma página",
+       "htmlform-title-not-exists": "[[:$1]] não existe.",
+       "htmlform-user-not-exists": "<strong>$1</strong> não existe.",
+       "htmlform-user-not-valid": "<strong>$1</strong> não é um nome de usuário válido.",
        "sqlite-has-fts": "$1 com suporte de pesquisa de texto completo",
        "sqlite-no-fts": "$1 sem suporte de pesquisa de texto completo",
        "logentry-delete-delete": "$1 apagou a página $3",
        "logentry-newusers-create2": "A conta de usuário $3 foi criada por $1",
        "logentry-newusers-byemail": "A conta de usuário $3 foi criada por $1, com a senha sendo enviada por e-mail",
        "logentry-newusers-autocreate": "A conta de usuário $1 foi criada automaticamente",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|removed}} proteção de $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|protected}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|protected}} $3 $4 [cascading]",
        "logentry-rights-rights": "$1 alterou os grupos de usuário de $3 de $4 para $5",
        "logentry-rights-rights-legacy": "$1 alterou os grupos de $3",
        "logentry-rights-autopromote": "$1 foi promovido automaticamente de $4 para $5",
        "special-characters-title-endash": "traço",
        "special-characters-title-emdash": "travessão",
        "special-characters-title-minus": "sinal de menos",
+       "mw-widgets-dateinput-no-date": "Nenhuma data selecionada",
        "mw-widgets-dateinput-placeholder-day": "AAAA-MM-DD",
        "mw-widgets-dateinput-placeholder-month": "AAAA-MM",
+       "mw-widgets-titleinput-description-new-page": "a página ainda não existe",
        "mw-widgets-titleinput-description-redirect": "redirecionar para $1"
 }
index 5c340e0..bfc64eb 100644 (file)
        "createacct-captcha": "Verificação de segurança",
        "createacct-imgcaptcha-ph": "Digite o texto que vê acima",
        "createacct-submit": "Crie a sua conta",
-       "createacct-another-submit": "Criar uma outra conta",
+       "createacct-another-submit": "Criar conta",
        "createacct-benefit-heading": "{{SITENAME}} é feito por pessoas como você.",
        "createacct-benefit-body1": "{{PLURAL:$1|edição|edições}}",
        "createacct-benefit-body2": "{{PLURAL:$1|página|páginas}}",
        "permissionserrorstext-withaction": "Não possui permissão para $2, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
        "recreate-moveddeleted-warn": "'''Aviso: Está a recriar uma página anteriormente eliminada.'''\n\nVerifique se é apropriado continuar a editar esta página.\nPara sua conveniência, é apresentado de seguida o registo de eliminação e de movimento da página:",
        "moveddeleted-notice": "Esta página foi eliminada.\nPara referência, é apresentado de seguida o registo de eliminações e de movimento da página.",
+       "moveddeleted-notice-recent": "Desculpe, esta página foi eliminada recentemente (nas últimas 24 horas).\nA exclusão e registo de movimentação para a página são fornecidos abaixo para referência.",
        "log-fulllog": "Ver registo detalhado",
        "edit-hook-aborted": "A edição foi abortada por um hook.\nNão foi dada nenhuma explicação.",
        "edit-gone-missing": "Não foi possível atualizar a página.\nEla parece ter sido eliminada.",
        "group-bot": "Robôs",
        "group-sysop": "Administradores",
        "group-bureaucrat": "Burocratas",
-       "group-suppress": "Supervisores",
+       "group-suppress": "Supressores",
        "group-all": "(todos)",
        "group-user-member": "{{GENDER:$1|utilizador|utilizadora}}",
        "group-autoconfirmed-member": "{{GENDER:$1|utilizador autoconfirmado|utilizadora autoconfirmada}}",
        "grouppage-bot": "{{ns:project}}:Robôs",
        "grouppage-sysop": "{{ns:project}}:Administradores",
        "grouppage-bureaucrat": "{{ns:project}}:Burocratas",
-       "grouppage-suppress": "{{ns:project}}:Supervisores",
+       "grouppage-suppress": "{{ns:project}}:Suprimir",
        "right-read": "Ler páginas",
        "right-edit": "Editar páginas",
        "right-createpage": "Criar páginas (que não sejam páginas de discussão)",
        "uploaddisabledtext": "O carregamento de ficheiros está desativado.",
        "php-uploaddisabledtext": "O carregamento de ficheiros está desativado no PHP.\nVerifique a configuração file_uploads, por favor.",
        "uploadscripted": "Este ficheiro contém HTML ou código que pode ser erradamente interpretado por um navegador.",
+       "upload-scripted-pi-callback": "Não se podem carregar arquivos que contenham instruções de processamento de páginas de estilo XML",
+       "uploaded-script-svg": "Encontrou um elemento scriptable no ficheiro \"$1\" SVG carregado.",
+       "uploaded-hostile-svg": "Encontrou-se um código CSS não seguro no elemento de estilo do arquivo SVG carregado.",
+       "uploaded-event-handler-on-svg": "Não está permitido configurar atributos controladores de eventos <code>$1=\"$2\"</code> nos arquivos SVG.",
+       "uploaded-href-attribute-svg": "Não se permite que os arquivos SVG contenham os atributos de <code>&lt;$1 $2=\"$3\"&gt;</code> apontando a recursos não locais (p.ex. http://, javascript:,etc)",
        "uploadscriptednamespace": "Este ficheiro SVG contém um domínio que não é permitido \"$1\".",
        "uploadinvalidxml": "Erro detectado na análise do XML do ficheiro carregado.",
        "uploadvirus": "O ficheiro contém um vírus! \nDetalhes: $1",
        "upload-http-error": "Ocorreu um erro HTTP: $1",
        "upload-copy-upload-invalid-domain": "Não é possível realizar carregamentos remotos neste domínio.",
        "upload-dialog-title": "Carregar ficheiro",
-       "upload-dialog-error": "Ocorreu um erro",
-       "upload-dialog-warning": "Ocorreu um aviso",
        "upload-dialog-button-cancel": "Cancelar",
        "upload-dialog-button-done": "Feito",
        "upload-dialog-button-save": "Gravar",
        "upload-dialog-button-upload": "Carregar",
-       "upload-dialog-label-select-file": "Selecionar ficheiro",
-       "upload-dialog-label-infoform-title": "Detalhes",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrição",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nome do ficheiro",
+       "upload-process-error": "Ocorreu um erro",
+       "upload-process-warning": "Ocorreu um aviso",
+       "upload-form-label-select-file": "Selecionar ficheiro",
+       "upload-form-label-infoform-title": "Detalhes",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrição",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nome do ficheiro",
        "backend-fail-stream": "Não foi possível transmitir o ficheiro \"$1\".",
        "backend-fail-backup": "Não foi possível fazer cópia de segurança do ficheiro \"$1\".",
        "backend-fail-notexists": "O ficheiro $1 não existe.",
        "filerevert-legend": "Reverter ficheiro",
        "filerevert-intro": "Está prestes a reverter o ficheiro '''[[Media:$1|$1]]''' para a [$4 versão de $2 às $3].",
        "filerevert-comment": "Motivo:",
-       "filerevert-defaultcomment": "Revertido para a versão de $1 - $2",
+       "filerevert-defaultcomment": "Revertido para a versão de $2, $1 ($3)",
        "filerevert-submit": "Reverter",
        "filerevert-success": "'''[[Media:$1|$1]]''' foi revertida para a [$4 versão das $3 de $2].",
        "filerevert-badversion": "Não há uma versão local anterior deste ficheiro no período de tempo especificado.",
        "emailccsubject": "Cópia da sua mensagem para $1: $2",
        "emailsent": "Mensagem enviada",
        "emailsenttext": "A sua mensagem foi enviada.",
-       "emailuserfooter": "Esta mensagem foi enviada por $1 para $2 através da opção \"{{int:emailuser}}\" em {{SITENAME}}.",
+       "emailuserfooter": "Esta mensagem foi {{GENDER:$1|enviada}} por $1 para {{GENDER:$2|$2}} através da opção \"{{int:emailuser}}\" em {{SITENAME}}.",
        "usermessage-summary": "Deixar mensagem de sistema.",
        "usermessage-editor": "Editor de mensagens de sistema",
        "watchlist": "Páginas vigiadas",
        "deletepage": "Eliminar página",
        "confirm": "Confirmar",
        "excontent": "o conteúdo era: \"$1\"",
-       "excontentauthor": "o conteúdo era: \"$1\" (e o único editor era [[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "o conteúdo era: \"$1\", e o único editor foi \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]])",
        "exbeforeblank": "o conteúdo antes de esvaziar era: \"$1\"",
        "delete-confirm": "Eliminar \"$1\"",
        "delete-legend": "Eliminar",
        "logentry-newusers-byemail": "A conta de utilizador $3 foi criada por $1 e a palavra-passe foi enviada por correio eletrónico",
        "logentry-newusers-autocreate": "A conta de utilizador $1 foi criada automaticamente",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|moveu}} as preferências de proteção de $4 para $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|removido}} proteção de $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|protegidas}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|protegido}} $3 $4 [cascading]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|alterado}} nível de proteção para $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|alterado}} nível de proteção para us$3 $4 [cascading]",
        "logentry-rights-rights": "$1 modificou os privilégios do utilizador $3 de $4 para $5",
        "logentry-rights-rights-legacy": "$1 alterou os grupos de $3",
        "logentry-rights-autopromote": "$1 foi automaticamente {{GENDER:$2|promovido|promovida}} de $4 a $5",
index 79d8a69..5657549 100644 (file)
        "deletepage": "Used as Submit button text.\n{{Identical|Delete page}}",
        "confirm": "Submit button text for protection confirmation\n\n{{Identical|Confirm}}",
        "excontent": "Automated deletion reason when deleting a page for admins. Parameters:\n* $1 - content before deletion",
-       "excontentauthor": "Automated deletion reason when deleting a page for admins providing that the page has one author only.\n\nParameters:\n* $1 - content before deletion\n* $2 - username",
+       "excontentauthor": "Automated deletion reason when deleting a page for admins providing that the page has one author only.\n\nParameters:\n* $1 - content before deletion\n* $2 - username\n\nThe label of the link to the talk page should be consistent with {{msg-mw|Talkpagelinktext}}.",
        "exbeforeblank": "Automated deletion reason when deleting a page for admins providing that the page was blanked before deletion.\n\nParameters:\n* $1 - content before blanking",
        "delete-confirm": "Used as page title. Parameters:\n* $1 - the page title\n{{Identical|Delete}}",
        "delete-legend": "{{Identical|Delete}}",
        "logentry-contentmodel-change-revert": "Prefilled edit summary when reverting a content model change. {{identical|revertmove}}",
        "protectlogpage": "{{doc-logpage}}\n\nTitle of [[Special:Log/protect]].",
        "protectlogtext": "Text in [[Special:Log/protect]].",
-       "protectedarticle": "Text describing an action on [[Special:Log]]. $1 is a page title.",
-       "modifiedarticleprotection": "Text describing an action on [[Special:Log]]. $1 is a page title.",
-       "unprotectedarticle": "Used as action in the log. Parameters:\n* $1 - target page title",
+       "protectedarticle": "This is a ''logentry'' message only used on IRC.\nText describing an action. $1 is a page title.",
+       "modifiedarticleprotection": "This is a ''logentry'' message only used on IRC.\nText describing an action. $1 is a page title.",
+       "unprotectedarticle": "This is a ''logentry'' message only used on IRC.\nUsed as action. Parameters:\n* $1 - target page title",
        "movedarticleprotection": "This is a ''logentry'' message only used on IRC. It appears in the log if a protected page is renamed.\n\nExample:\n<code>00:51, 16 September 2010 Siebrand +(Talk • contribs • block) moved protection settings from \"User:Siebrand/prot-move\" to \"User:Siebrand/prot-moved\" ‎ (User:Siebrand/prot-move moved to User:Siebrand/prot-moved: prot_move test.)</code>\n\nParameters:\n* $1 - target page title\n* $2 - source page title",
        "protect-title": "Title for the protection form. $1 is the title of the page to be (un)protected.",
        "protect-title-notallowed": "Same as {{msg-mw|Protect-title}}, but when the user does not have the right to change protection levels.\n\nParameters:\n* $1 - page title",
        "protect-fallback": "This message is used as an option in the protection form on wikis were extra protection levels have been configured.\n\nParameters:\n* $1 - undefined protection level (not localized). Defined protection levels are: \"sysop\" and \"autoconfirmed\"\n\nSee also:\n* {{msg-mw|Protect-level-sysop}}\n* {{msg-mw|Protect-level-autoconfirmed}}",
        "protect-level-autoconfirmed": "Used as protect level.\n\nSee example: {{canonicalurl:Main_Page|action=info}}",
        "protect-level-sysop": "Used as protect level.\n\nSee example: {{canonicalurl:Main_Page|action=info}}",
-       "protect-summary-desc": "{{Optional}}\nUsed in edit summary for description of a protecting restriction.\n* $1 is action, taken from restriction-*\n* $2 is restriction, taken from protect-level-*\n* $3 is {{msg-mw|protect-expiring}} or {{msg-mw|protect-expiry-indefinite}}",
+       "protect-summary-desc": "{{Optional}}\nUsed in edit summary for description of a protecting restriction.\n* $1 is action, taken from restriction-*\n* $2 is restriction, taken from protect-level-*\n* $3 is {{msg-mw|protect-expiring}}, {{msg-mw|protect-expiring-local}} or {{msg-mw|protect-expiry-indefinite}}",
        "protect-summary-cascade": "Used in edit summary when cascade protecting a page. Appears in protection log. See [[Special:Log]] and [[m:Special:Log]].\n\nAlso used in [[Special:ProtectedPages]] when a page is cascade protected. See example: [[m:Special:ProtectedPages]].<br />\nSee also:\n*{{msg-mw|Restriction-level-sysop}}\n*{{msg-mw|Restriction-level-autoconfirmed}}",
-       "protect-expiring": "Used as expiry text in page history, and in [[Special:Protectedtitles]], [[Special:Protectedpages]], and extension FlaggedRevs.\n* $1 - a date and time\n* $2 - a date (optional)\n* $3 - a time (optional)\nIf the expiry is indefinite, {{msg-mw|protect-expiry-indefinite}} is used.\n{{Identical|Expires $1 (UTC)}}",
-       "protect-expiring-local": "Parameter:\n* $1 - a timestamp like \"22:51, 23 July 2011 (UTC)\" depending on the wiki content language.\n{{Identical|Expire}}",
+       "protect-expiring": "Used as expiry text in page history, and in [[Special:Protectedtitles]], [[Special:Protectedpages]], and extension FlaggedRevs.\n* $1 - a date and time\n* $2 - a date (optional)\n* $3 - a time (optional)\nIf the expiry is indefinite, {{msg-mw|protect-expiry-indefinite}} is used.\n{{Identical|Expires $1 (UTC)}}\n\n\nSimilar to {{msg-mw|protect-expiring-local}}",
+       "protect-expiring-local": "Parameter:\n* $1 - a timestamp like \"22:51, 23 July 2011 (UTC)\" depending on the wiki content language.\n* $2 - a date (optional)\n* $3 - a time (optional)\n{{Identical|Expire}}\n\nSimilar to {{msg-mw|protect-expiring}}",
        "protect-expiry-indefinite": "Used as expiry text in page history, and in [[Special:Protectedtitles]], [[Special:Protectedpages]], and extension FlaggedRevs.\n\nIf the expiry is definite, {{msg-mw|protect-expiring}} is used.\n{{Identical|Indefinite}}",
        "protect-cascade": "See [[meta:Protect]] for more information.",
        "protect-cantedit": "Used as error message when changing the protection levels of the page.",
        "htmlform-title-not-exists": "Error message shown if the page title provided by the user does not exist. $1 is the page title.",
        "htmlform-user-not-exists": "Error message shown if a user with the name provided by the user does not exist. $1 is the username.",
        "htmlform-user-not-valid": "Error message shown if the name provided by the user isn't a valid username. $1 is the username.",
+       "rawmessage": "{{notranslate}} Used to pass arbitrary text as a message specifier array",
        "sqlite-has-fts": "Shown on [[Special:Version]].\nParameters:\n* $1 - version",
        "sqlite-no-fts": "Shown on [[Special:Version]].\nParameters:\n* $1 - version",
        "logentry-delete-delete": "{{Logentry|[[Special:Log/delete]]}}",
        "logentry-newusers-byemail": "{{Logentry|[[Special:Log/newusers]]}}\n\n$4 is the name of the user that was created.",
        "logentry-newusers-autocreate": "{{Logentry|[[Special:Log/newusers]]}}\n\n$4 is the gender of the target user.",
        "logentry-protect-move_prot": "{{Logentry|[[Special:Log/protect]]}}\n* $4 - the old title",
+       "logentry-protect-unprotect": "{{Logentry|[[Special:Log/protect]]}}",
+       "logentry-protect-protect": "{{Logentry|[[Special:Log/protect]]}}\n\n* $4 - protect expiry (formatted with {{msg-mw|protect-summary-desc}}, multiple possible)",
+       "logentry-protect-protect-cascade": "{{Logentry|[[Special:Log/protect]]}}\n\n* $4 - protect expiry (formatted with {{msg-mw|protect-summary-desc}}, multiple possible)\nFor word \"cascading\" see {{msg-mw|protect-summary-cascade}}",
+       "logentry-protect-modify": "{{Logentry|[[Special:Log/protect]]}}\n\n* $4 - protect expiry (formatted with {{msg-mw|protect-summary-desc}}, multiple possible)",
+       "logentry-protect-modify-cascade": "{{Logentry|[[Special:Log/protect]]}}\n\n* $4 - protect expiry (formatted with {{msg-mw|protect-summary-desc}}, multiple possible)\nFor word \"cascading\" see {{msg-mw|protect-summary-cascade}}",
        "logentry-rights-rights": "* $1 - username\n* $2 - (see below)\n* $3 - username\n* $4 - list of user groups or {{msg-mw|Rightsnone}}\n* $5 - list of user groups or {{msg-mw|Rightsnone}}\n----\n{{Logentry|[[Special:Log/rights]]}}",
        "logentry-rights-rights-legacy": "* $1 - username\n* $2 - (see below)\n* $3 - username\n----\n{{Logentry|[[Special:Log/rights]]}}",
        "logentry-rights-autopromote": "* $1 - username\n* $2 - (see below)\n* $3 - (see below)\n* $4 - comma separated list of old user groups or {{msg-mw|Rightsnone}}\n* $5 - comma separated list of new user groups\n----\n{{Logentry|[[Special:Log/rights]]}}",
index 284ebe0..5892565 100644 (file)
        "createacct-captcha": "Verificare de securitate",
        "createacct-imgcaptcha-ph": "Introduceți textul pe care îl vedeți deasupra",
        "createacct-submit": "Creați-vă contul",
-       "createacct-another-submit": "Creează un alt cont",
+       "createacct-another-submit": "Creează contul",
        "createacct-benefit-heading": "{{SITENAME}} este un proiect clădit de oameni ca dumneavoastră.",
        "createacct-benefit-body1": "{{PLURAL:$1|modificare|modificări|de modificări}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pagină|pagini|de pagini}}",
        "upload-http-error": "A avut loc o eroare HTTP: $1",
        "upload-copy-upload-invalid-domain": "Încărcarea copiilor nu este disponibilă pentru acest domeniu.",
        "upload-dialog-title": "Încărcare fișier",
-       "upload-dialog-error": "A apărut o eroare",
-       "upload-dialog-warning": "A apărut o atenționare",
        "upload-dialog-button-cancel": "Revocare",
        "upload-dialog-button-done": "Realizat",
        "upload-dialog-button-save": "Salvare",
        "upload-dialog-button-upload": "Încarcă",
-       "upload-dialog-label-select-file": "Selectează fișier",
-       "upload-dialog-label-infoform-title": "Detalii",
-       "upload-dialog-label-infoform-name": "Nume",
-       "upload-dialog-label-infoform-description": "Descriere",
-       "upload-dialog-label-usage-title": "Utilizare",
-       "upload-dialog-label-usage-filename": "Numele fișierului",
+       "upload-process-error": "A apărut o eroare",
+       "upload-process-warning": "A apărut o atenționare",
+       "upload-form-label-select-file": "Selectează fișier",
+       "upload-form-label-infoform-title": "Detalii",
+       "upload-form-label-infoform-name": "Nume",
+       "upload-form-label-infoform-description": "Descriere",
+       "upload-form-label-usage-title": "Utilizare",
+       "upload-form-label-usage-filename": "Numele fișierului",
        "backend-fail-stream": "Imposibil de citit fișierul $1.",
        "backend-fail-backup": "Imposibil de efectuat o copie de rezervă a fișierului $1.",
        "backend-fail-notexists": "Fișierul $1 nu există.",
        "emailccsubject": "O copie a mesajului la $1: $2",
        "emailsent": "E-mail trimis",
        "emailsenttext": "E-mailul dumneavoastră a fost trimis.",
-       "emailuserfooter": "Acest mesaj a fost trimis de $1 către $2 prin intermediul funcției „{{int:emailuser}}” de la {{SITENAME}}.",
+       "emailuserfooter": "Acest mesaj a fost {{GENDER:$1|trimis}} de $1 către {{GENDER:$2|$2}} prin intermediul funcției „{{int:emailuser}}” de la {{SITENAME}}.",
        "usermessage-summary": "a lăsat un mesaj de sistem",
        "usermessage-editor": "Mesager de sistem",
        "watchlist": "Pagini urmărite",
        "deletepage": "Șterge pagina",
        "confirm": "Confirmă",
        "excontent": "conținutul era: '$1'",
-       "excontentauthor": "conținutul era: „$1” (unicul contribuitor: [[Special:Contributions/$2|$2]])",
+       "excontentauthor": "conținutul era: „$1”, iar unicul contribuitor a fost „[[Special:Contributions/$2|$2]]” ([[User talk:$2|discuție]])",
        "exbeforeblank": "conținutul înainte de golire era: '$1'",
        "delete-confirm": "Şterge \"$1\"",
        "delete-legend": "Şterge",
        "logentry-newusers-byemail": "Contul de utilizator $3 a fost {{GENDER:$2|creat}} de către $1, iar parola a fost trimisă prin e-mail",
        "logentry-newusers-autocreate": "Contul de utilizator $1 a fost {{GENDER:$2|creat}} în mod automat",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|a mutat}} setările de protecție de la $4 la $3",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|a eliminat}} protecția pentru $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|a protejat}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|a protejat}} $3 $4 [protecție în cascadă]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|a modificat}} nivelul protecției pentru $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|a modificat}} nivelul protecției pentru $3 $4 [protecție în cascadă]",
        "logentry-rights-rights": "$1 {{GENDER:$2|a schimbat}} apartenența la grup pentru $3 de la $4 la $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|a schimbat}} apartenența la grup pentru $3",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|a fost promovat|a fost promovată}} în mod automat de la $4 la $5",
index ad04743..dc73d20 100644 (file)
        "nstab-template": "Template",
        "nstab-help": "Pàgene d'ajute",
        "nstab-category": "Categorije",
+       "mainpage-nstab": "Pàgena Prengepàle",
        "nosuchaction": "Non ge stonne otre azione",
        "nosuchactiontext": "L'aziona specifichete da l'URL non g'è canusciute da Uicchi.\nTu puè avè scritte male 'a URL, o quidde ca è scritte jè 'nu collegamende sbagliete.\nPò essere pure ca quiste jè 'nu bochere jndr'à 'u software de {{SITENAME}}.",
        "nosuchspecialpage": "Non ge stonne pàggene speciele",
        "createacct-captcha": "Verifiche de securezze",
        "createacct-imgcaptcha-ph": "Mitte 'u teste tune aqquà sus",
        "createacct-submit": "Ccreje 'u cunde utende tune",
-       "createacct-another-submit": "Ccreje 'n'otre cunde",
+       "createacct-another-submit": "Ccreje 'nu cunde utende",
        "createacct-benefit-heading": "{{SITENAME}} jè fatte da crestiane cumme a te.",
        "createacct-benefit-body1": "{{PLURAL:$1|cangiamende|cangiaminde}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pàgene|pàggene}}",
        "createacct-benefit-body3": "{{PLURAL:$1|condrebbutore}} recende",
        "badretype": "Le passuord ca è scritte non ge sonde uguale.",
+       "usernameinprogress": "'Na ccrejazzione de 'nu cunde pe stu nome utende ste già in esecuzione.\nPe piacere, aspitte.",
        "userexists": "'U nome de l'utende ca è scritte jè già ausate.\nPe piacere scacchiane n'otre.",
        "loginerror": "Errore de collegamende",
        "createacct-error": "Errore sus 'a ccrejazione d'u cunde",
        "group-bot": "Bot",
        "group-sysop": "Sysop",
        "group-bureaucrat": "Burocrate",
-       "group-suppress": "Supervisionature",
+       "group-suppress": "Suppressore",
        "group-all": "(tutte)",
        "group-user-member": "{{GENDER:$1|utende}}",
        "group-autoconfirmed-member": "{{GENDER:$1|utende autoconfermate}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|amministratore}}",
        "group-bureaucrat-member": "{{GENDER:$1|burocrate}}",
-       "group-suppress-member": "{{GENDER:$1|supervisionatore}}",
+       "group-suppress-member": "{{GENDER:$1|soppressore}}",
        "grouppage-user": "{{ns:project}}:Utinde",
        "grouppage-autoconfirmed": "{{ns:project}}:Utinde Autoconfermete",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Amministratore",
        "grouppage-bureaucrat": "{{ns:project}}:Burocrate",
-       "grouppage-suppress": "{{ns:project}}:Supervisionatore",
+       "grouppage-suppress": "{{ns:project}}:Soppresse",
        "right-read": "Ligge le pàggene",
        "right-edit": "Cange le pàggene",
        "right-createpage": "Ccreje le pàggene (ca non ge tènene le pàggene de le 'ngazzaminde)",
        "upload-http-error": "S'a verificate 'n'errore HTTP: $1",
        "upload-copy-upload-invalid-domain": "'A copie de le carecaminde non g'è disponibbile da stu dominie.",
        "upload-dialog-title": "Careche 'u file",
-       "upload-dialog-error": "Ave assute 'n'errore",
-       "upload-dialog-warning": "Ha assute 'n'avvise",
        "upload-dialog-button-cancel": "Annulle",
        "upload-dialog-button-done": "Fatte",
        "upload-dialog-button-save": "Reggìstre",
        "upload-dialog-button-upload": "Careche",
-       "upload-dialog-label-select-file": "Scacchie 'u file",
-       "upload-dialog-label-infoform-title": "Dettaglie",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrizione",
-       "upload-dialog-label-usage-title": "Ause",
-       "upload-dialog-label-usage-filename": "Nome d'u file",
+       "upload-process-error": "Ave assute 'n'errore",
+       "upload-process-warning": "Ha assute 'n'avvise",
+       "upload-form-label-select-file": "Scacchie 'u file",
+       "upload-form-label-infoform-title": "Dettaglie",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrizione",
+       "upload-form-label-usage-title": "Ause",
+       "upload-form-label-usage-filename": "Nome d'u file",
        "backend-fail-stream": "Non ge pozze trasmettere 'u file $1.",
        "backend-fail-backup": "Non ge pozze cupià 'u file $1.",
        "backend-fail-notexists": "'U file $1 non g'esiste.",
        "filerevert-legend": "'Nvirte 'u file",
        "filerevert-intro": "Tu ste converte 'u file '''[[Media:$1|$1]]''' jndr'à [$4 versione cumme $3, $2].",
        "filerevert-comment": "Mutive:",
-       "filerevert-defaultcomment": "Convertite a 'a versione a le $2 d'u $1",
+       "filerevert-defaultcomment": "Repristinate a 'a versione a le $2 d'u $1 ($3)",
        "filerevert-submit": "'Nvirte",
        "filerevert-success": "'''[[Media:$1|$1]]''' ha state convertite a 'a versiona [$4 de le $3 d'u $2].",
        "filerevert-badversion": "Non ge stè 'na versiona locale precedende de stu file cu l'orarie richieste.",
        "nopagetext": "'A pàgene de destinazione ca tu è specificate non g'esiste.",
        "pager-newer-n": "{{PLURAL:$1|cchiù nueve 1|cchiù nueve $1}}",
        "pager-older-n": "{{PLURAL:$1|cchiù vecchie 1|cchiù vicchie $1}}",
-       "suppress": "Supervisione",
+       "suppress": "Sopprime",
        "querypage-disabled": "Sta pàgena speciale jè desabbilitate pe mutive de prestaziune.",
        "apihelp": "Aijute de l'API",
        "apihelp-no-such-module": "Module \"$1\" none acchiate.",
        "emailccsubject": "Copie de le messàgge tue a $1: $2",
        "emailsent": "E-mail mannete",
        "emailsenttext": "'U messagge email tue ha state mannete.",
-       "emailuserfooter": "Sta e-mail ha state mannate da $1 a $2 da 'a funziona \"{{int:emailuser}}\" de {{SITENAME}}.",
+       "emailuserfooter": "Sta e-mail ha state {{GENDER:$1|mannate}} da $1 a {{GENDER:$2|$2}} da 'a funziona \"{{int:emailuser}}\" de {{SITENAME}}.",
        "usermessage-summary": "Lassanne 'nu messagge de sisteme.",
        "usermessage-editor": "Messaggiatore de sisteme",
        "usermessage-template": "MediaWiki:UserMessage",
        "api-error-badaccess-groups": "Tu non ge puè carecà file sus a sta Uicchi.",
        "api-error-badtoken": "Errore inderne: Gettone errate.",
        "api-error-copyuploaddisabled": "'U carecamende da URL jè disabbilitate sus a stu server.",
-       "api-error-duplicate": "{{PLURAL:$1|Stè [$2 'n'otre file]|Stonne [$2 otre file]}} sus a 'u site cu 'u stesse condenute.",
+       "api-error-duplicate": "{{PLURAL:$1|Stè 'n'otre file|Stonne otre file}} sus a 'u site cu 'u stesse condenute.",
        "api-error-duplicate-archive": "{{PLURAL:$1|Stave 'n'otre file|Stavane otre file}} già sus a 'u site cu 'u stesse condenute, ma {{PLURAL:$1|ha state|onne state}} scangellate.",
        "api-error-empty-file": "'U file ca tu è confermate ere vacande.",
        "api-error-emptypage": "Quanne se ne ccreje une, le pàggene vacande non ge sò permesse.",
index 97a111a..4b180f7 100644 (file)
@@ -83,7 +83,8 @@
                        "Marina Melik-Adamyan",
                        "Normalex",
                        "WindEwriX",
-                       "Nzeemin"
+                       "Nzeemin",
+                       "INS Pirat"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "nstab-template": "Шаблон",
        "nstab-help": "Справка",
        "nstab-category": "Категория",
+       "mainpage-nstab": "Заглавная",
        "nosuchaction": "Такого действия нет",
        "nosuchactiontext": "Указанное в URL действие ошибочно.\nВозможно, вы допустили опечатку при наборе URL или перешли по ошибочной ссылке.\nЭто может также указывать на ошибку в проекте {{SITENAME}}.",
        "nosuchspecialpage": "Нет такой служебной страницы",
        "no-null-revision": "Не удалось создать новую нулевую правку для страницы «$1»",
        "badtitle": "Недопустимое название",
        "badtitletext": "Запрашиваемое название страницы неправильно, пусто, либо неверно указано межъязыковое или интервики название. Возможно, в названии используются недопустимые символы.",
-       "title-invalid-empty": " Заголовок запрошенной страницы пуст или является названием пространства имен.",
+       "title-invalid-empty": "Заголовок запрошенной страницы пуст или содержит только название пространства имён.",
        "title-invalid-utf8": "Запрашиваемое название страницы содержит некорректную последовательность символов UTF-8.",
        "title-invalid-interwiki": "Запрашиваемое название страницы содержит интервики-ссылку, которая не может быть использована в названиях.",
        "title-invalid-talk-namespace": "Запрашиваемое название страницы ссылается на страницу обсуждения, которая не может существовать.",
        "createacct-captcha": "Проверка безопасности",
        "createacct-imgcaptcha-ph": "Введите текст, который вы видите выше",
        "createacct-submit": "Создать учётную запись",
-       "createacct-another-submit": "Создать ещё одну запись",
+       "createacct-another-submit": "Создать учётную запись",
        "createacct-benefit-heading": "{{SITENAME}} — совместный труд таких же людей, как вы.",
        "createacct-benefit-body1": "{{PLURAL:$1|правка|правки|правок}}",
        "createacct-benefit-body2": "{{PLURAL:$1|статья|статьи|статей}}",
        "file-thumbnail-no": "Название файла начинается с <strong>$1</strong>.\nВероятно, это уменьшенная копия изображения ''(миниатюра)''.\nЕсли у вас есть данное изображение в полном размере, пожалуйста, загрузите его или измените имя файла.",
        "fileexists-forbidden": "Файл с этим именем уже существует и не может быть перезаписан.\nЕсли всё равно хотите загрузить данный файл, пожалуйста, вернитесь назад и загрузите его под другим именем. [[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Файл с этим именем уже существует в общем хранилище файлов.\nЕсли вы всё-таки хотите загрузить этот файл, пожалуйста, вернитесь назад и измените имя файла. [[File:$1|thumb|center|$1]]",
-       "file-exists-duplicate": "Этот файл является дубликатом {{PLURAL:$1|1=следующего файла|следующих файлов}}:",
+       "file-exists-duplicate": "Этот файл — дубликат {{PLURAL:$1|1=следующего файла|следующих файлов}}:",
        "file-deleted-duplicate": "Подобный файл ([[:$1]]) уже удалялся. Пожалуйста, ознакомьтесь с историей удаления файла, прежде чем загружать его снова.",
        "file-deleted-duplicate-notitle": "Файл, идентичный этому файлу, был ранее удалён, а имя файла было запрещено.\nВам следует попросить кого-нибудь с правами просмотра данных по запрещённым файлам, чтобы он проанализировал ситуацию перед тем, как загружать файл снова.",
        "uploadwarning": "Предупреждение",
        "upload-options": "Параметры загрузки",
        "watchthisupload": "Следить за этим файлом",
        "filewasdeleted": "Файл с таким именем уже существовал ранее, но был удалён. Пожалуйста, проверьте $1 перед повторной загрузкой.",
-       "filename-bad-prefix": "Имя загружаемого файла начинается с «'''$1'''» и, вероятно, является одним из шаблонных имён, которые цифровые фотокамеры дают снимкам. Пожалуйста, выберите имя, лучше описывающее содержание файла.",
+       "filename-bad-prefix": "Имя загружаемого файла начинается с «<strong>$1</strong>» и, вероятно, представляет собой одно из шаблонных имён, генерируемых цифровыми фотокамерами. Пожалуйста, выберите имя, лучше описывающее содержание файла.",
        "filename-prefix-blacklist": " #<!-- оставьте эту строчку как есть --> <pre>\n# Синтаксис следующий:\n#   * Всё, что начинается с символа «#», считается комментарием (до конца строки)\n#   * Каждая непустая строка — префикс стандартного названия файла, которое обычно даёт цифровая камера\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # некоторые мобильные телефоны\nIMG # общее\nJD # Jenoptik\nMGP # Pentax\nPICT # различные\n #</pre> <!-- оставьте эту строчку как есть -->",
        "upload-success-subj": "Загрузка успешно завершена",
        "upload-success-msg": "Ваша загрузка [$2] прошла успешно. Вы можете посмотреть результат здесь: [[:{{ns:file}}:$1]]",
        "upload-http-error": "Произошла ошибка HTTP: $1",
        "upload-copy-upload-invalid-domain": "Копирование загрузок не доступно в этом домене.",
        "upload-dialog-title": "Загрузить файл",
-       "upload-dialog-error": "Произошла ошибка",
-       "upload-dialog-warning": "Появилось предупреждение",
        "upload-dialog-button-cancel": "Отменить",
        "upload-dialog-button-done": "Готово",
        "upload-dialog-button-save": "Сохранить",
        "upload-dialog-button-upload": "Загрузить",
-       "upload-dialog-label-select-file": "Выбрать файл",
-       "upload-dialog-label-infoform-title": "Подробности",
-       "upload-dialog-label-infoform-name": "Имя",
-       "upload-dialog-label-infoform-description": "Описание",
-       "upload-dialog-label-usage-title": "Использование",
-       "upload-dialog-label-usage-filename": "Имя файла",
+       "upload-process-error": "Произошла ошибка",
+       "upload-process-warning": "Появилось предупреждение",
+       "upload-form-label-select-file": "Выбрать файл",
+       "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": "Имя файла",
        "backend-fail-stream": "Не удалось транслировать файл $1.",
        "backend-fail-backup": "Невозможно сделать резервную копию файла $1.",
        "backend-fail-notexists": "Файл $1 не существует.",
        "img-auth-nofile": "Файл «$1» не существует.",
        "img-auth-isdir": "Вы пытаетесь получить доступ к каталогу «$1».\nРазрешён только доступ к файлам.",
        "img-auth-streaming": "Потоковая передача «$1».",
-       "img-auth-public": "Назначением img_auth.php является вывод файлов из закрытой вики.\nЭта вики настроена как общедоступная.\nДля оптимизации безопасности img_auth.php отключена.",
+       "img-auth-public": "Назначение img_auth.php — вывод файлов из закрытой вики.\nЭта вики настроена как общедоступная.\nДля оптимизации безопасности img_auth.php отключена.",
        "img-auth-noread": "Участник не имеет доступа на чтение «$1».",
        "http-invalid-url": "Ошибочный URL: $1",
        "http-invalid-scheme": "Не поддерживаются адреса со схемой «$1»",
        "version-poweredby-others": "другие",
        "version-poweredby-translators": "переводчики translatewiki.net",
        "version-credits-summary": "Хотим поблагодарить следующих участников за их вклад в развитие [[Special:Version|MediaWiki]].",
-       "version-license-info": "MediaWiki является свободным программным обеспечением, которое вы можете распространять и/или изменять в соответствии с условиями лицензии GNU General Public License, опубликованной фондом свободного программного обеспечения; второй версии, либо любой более поздней версии.\n\nMediaWiki распространяется в надежде, что она будет полезной, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, даже без подразумеваемых гарантий КОММЕРЧЕСКОЙ ЦЕННОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См. лицензию GNU General Public License для более подробной информации.\n\nВы должны были получить [{{SERVER}}{{SCRIPTPATH}}/COPYING копию GNU General Public License] вместе с этой программой, если нет, то напишите Free Software Foundation, Inc., по адресу: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA или [//www.gnu.org/licenses/old-licenses/gpl-2.0.html прочтите её онлайн].",
+       "version-license-info": "MediaWiki — свободное программное обеспечение, которое вы можете распространять и/или изменять в соответствии с условиями опубликованной Фондом свободного программного обеспечения лицензии GNU General Public License второй или любой более поздней версии (по вашему выбору).\n\nMediaWiki распространяется в надежде, что она будет полезной, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, даже без подразумеваемых гарантий КОММЕРЧЕСКОЙ ЦЕННОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННОЙ ЦЕЛИ. См. лицензию GNU General Public License для более подробной информации.\n\nВы должны были получить [{{SERVER}}{{SCRIPTPATH}}/COPYING копию GNU General Public License] вместе с этой программой, если нет, то напишите Free Software Foundation, Inc., по адресу: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA или [//www.gnu.org/licenses/old-licenses/gpl-2.0.html прочтите её онлайн].",
        "version-software": "Установленное программное обеспечение",
        "version-software-product": "Продукт",
        "version-software-version": "Версия",
        "api-error-badaccess-groups": "Вам не разрешено загружать файлы в эту вики.",
        "api-error-badtoken": "Внутренняя ошибка:  некорректный токен.",
        "api-error-copyuploaddisabled": "Загрузка по URL-адресу отключена на этом сервере.",
-       "api-error-duplicate": "Уже {{PLURAL:$1|1=существует [$2 другой файл]|существуют [$2 другие файлы]}} с таким же содержимым",
+       "api-error-duplicate": "Уже {{PLURAL:$1|существует другой файл|существуют другие файлы}} с таким же содержимым.",
        "api-error-duplicate-archive": "Раньше на сайте {{PLURAL:$1|1=уже был файл|были файлы}} с точно таким же содержанием, но {{PLURAL:$1|1=он был удалён|они были удалены}}.",
        "api-error-empty-file": "Отправленный вами файл пуст.",
        "api-error-emptypage": "Не допускается создание новых пустых страниц.",
index 3fc1ed3..3e0c9f0 100644 (file)
        "upload-dialog-button-done": "Оҥоһулунна",
        "upload-dialog-button-save": "Бигэргэт",
        "upload-dialog-button-upload": "Киллэрии",
-       "upload-dialog-label-select-file": "Билэни тал",
-       "upload-dialog-label-infoform-title": "Сиһилии",
-       "upload-dialog-label-infoform-name": "Аата",
-       "upload-dialog-label-infoform-description": "Быһаарыыта",
-       "upload-dialog-label-usage-title": "Туһаныы",
-       "upload-dialog-label-usage-filename": "Билэ аата",
+       "upload-process-error": "Алҕас таҕыста",
+       "upload-process-warning": "Сэрэтии үөскээтэ",
+       "upload-form-label-select-file": "Билэни тал",
+       "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": "Билэ аата",
        "backend-fail-stream": "$1 билэни ыытар табыллыбата.",
        "backend-fail-backup": "Бу билэ $1 резервнэй куопуйатын оҥорор табыллыбата.",
        "backend-fail-notexists": "Маннык $1 билэ суох эбит.",
        "booksources-text": "Манна кинигэ туһунан атын саайтарга ыйынньыктар хомулуннулар, онно баҕар эбии информация көстүөҕэ.",
        "booksources-invalid-isbn": "ISBN, арааһа, сыыһалаах. Нүөмэр көһөрөргө алҕас тахсыбатаҕын хат көр эрэ.",
        "specialloguserlabel": "Толорооччу:",
-       "speciallogtitlelabel": "Сорук (тиэкис эбэтэр киһи аата)",
+       "speciallogtitlelabel": "Сыал (тиэкис эбэтэр {{ns:user}}:кыттааччы аата):",
        "log": "Сурунааллар",
        "all-logs-page": "Көстөр сурунааллар барыта",
        "alllogstext": "{{SITENAME}} сурунаалларын уопсай испииһэгэ.\nСурунаал көрүҥүнэн, кыттааччы аатынан (улахан-кыра буукубата учуоттанар) эбэтэр сирэй аатынан (эмиэ улахана-кырата учуоттанар) наардыаххытын сөп.",
index 01b8a38..77556dc 100644 (file)
        "versionrequiredtext": "P'usari sta pàggina ci voli la virsioni $1 dû software MediaWiki. Talìa [[Special:Version|sta pàggina]]",
        "ok": "Va bonu",
        "retrievedfrom": "Estrattu di \"$1\"",
-       "youhavenewmessages": "Arricivisti $1 ($2).",
-       "youhavenewmessagesfromusers": "Arricivisti $1 di {{PLURAL:$3|n'àutru utenti|$3 utenti}} ($2).",
+       "youhavenewmessages": "{{PLURAL:$3|Arricivisti}} $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|Arricivisti}} $1 di {{PLURAL:$3|n'àutru utenti|$3 utenti}} ($2).",
        "youhavenewmessagesmanyusers": "Arricivisti $1 di tanti utenti ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|nu missaggiu novu|999=missaggi novi}}",
        "newmessagesdifflinkplural": "{{PLURAL:$1|ùrtimu canciamentu|999=ùrtimi canciamenti}}",
        "createacct-captcha": "Cuntrollu di sicurizza",
        "createacct-imgcaptcha-ph": "Nzirìsci lu testu ca vidi ccassupra",
        "createacct-submit": "Crea lu tò cuntu",
-       "createacct-another-submit": "Crea n'àutru cuntu",
+       "createacct-another-submit": "Crea un cuntu",
        "createacct-benefit-heading": "{{SITENAME}} è fatta di pirsuni comu a tìa.",
        "createacct-benefit-body1": "{{PLURAL:$1|cuntribbutu|cuntribbuti}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pàggina|pàggini}}",
        "changeemail-password": "La tò password di {{SITENAME}}:",
        "changeemail-submit": "Cancia nnirizzu",
        "changeemail-throttled": "Facisti troppi tintativi di trasuta.\nPi favuri aspetta $1 prima di pruvari n'àutra vota.",
+       "changeemail-nochange": "Pi favuri metti nu nnirizzu di posta elittrònica diffirenti di chiddu ca già c'è.",
        "resettokens": "Azziramentu dî token",
        "resettokens-text": "Ccà poi azzirari li ''token'' chi dùnanu accessu a certi dati risirvati assuciati ô tò cuntu.\n\nSta cosa s'avissi a fari si pi sbagghiu li facisti sapiri a quarchidunu o si lu tò cuntu fu cumprumisu.",
        "resettokens-no-tokens": "Nun ci sunnu token d'azzirari.",
        "newarticle": "(Novu)",
        "newarticletext": "Siguisti na lijami a na pàggina c'ancora nun esisti.\nPi criari sta pàggina, accumenza a scrìviri ccassutta (talìa la [$1 pàggina d'aiutu] p'aviri maiuri nfurmazzioni).\nSi agghicasti ccà pi sbagghiu, carca lu buttuni <strong>n arreri</strong> dû tò browser.",
        "anontalkpagetext": "----''Chista è la pàggina di discussioni di n’utenti anònimu, ca nun criau ancora n’accessu o ca nun l’usa.\nP’idintificàrilu è pirciò nicissariu usari lu nùmmiru di lu sò nnirizzu IP.\nLi nnirizzi IP ponnu pirò èssiri spartuti di cchiù utenti.\nSiddu sî n’utenti anònimu e riteni ca li cummenti prisenti nta sta pàggina nun si rifirìscinu a tia, [[Special:UserLogin/signup|crea n’accessu novu]] o [[Special:UserLogin|trasi]] cu chiddu ca già hai p’evitari d’èssiri cunfusu cu àutri utenti anònimi ‘n futuru.''",
-       "noarticletext": "Nta stu mumentu la pàggina addumannata è vacanti. È pussìbbili [[Special:Search/{{PAGENAME}}|circari stu tìtulu]] nta l'àutri pàggini dû situ oppuru <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|action=edit}} circari ntê riggistra culligati] oppuru [{{fullurl:{{FULLPAGENAME}}|action=edit}} canciari la pàggina ora]</span>.",
-       "noarticletext-nopermission": "Nta stu mumentu la pàggina addumannata è vacanti. È pussibbili [[Special:Search/{{PAGENAME}}|circari stu titulu]] nti àutri pàggini dû situ o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} circari ntê riggistra culligati]</span>, ma nun hai li pirmissa pi criari sta pàggina.",
+       "noarticletext": "Nta stu mumentu la pàggina addumannata è vacanti. È pussìbbili [[Special:Search/{{PAGENAME}}|circari stu tìtulu]] nta l'àutri pàggini dû situ oppuru <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|action=edit}} circari ntê riggistri culligati] oppuru [{{fullurl:{{FULLPAGENAME}}|action=edit}} canciari la pàggina ora]</span>.",
+       "noarticletext-nopermission": "Nta stu mumentu la pàggina addumannata è vacanti. È pussìbbili [[Special:Search/{{PAGENAME}}|circari stu tìtulu]] nti àutri pàggini dû situ o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} circari ntê riggistri culligati]</span>, ma nun hai li pirmissi pi criari sta pàggina.",
        "missing-revision": "La virsioni #$1 dâ paggina ntitulata \"{{FULLPAGENAME}}\" nun esisti.\n\nStu fattu di sòlitu succedi quannu si segui nu lijami di crunuluggìa versu na pàggina chi fu cancillata.\nSi ponnu vìdiri li dittagghî ntô [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} riggistru dî cancillazzioni].",
        "userpage-userdoesnotexist": "L'account \"<nowiki>$1</nowiki>\" nun currispunni a n'utenti riggistratu. Virificari si si voli criari o canciari sta pàggina.",
        "userpage-userdoesnotexist-view": "Lu cuntu utenti \"$1\" nun è riggistratu.",
        "permissionserrorstext-withaction": "Nun hai lu pirmissu di $2, pi {{PLURAL:$1|stu mutivu|sti mutivi}}:",
        "recreate-moveddeleted-warn": "'''Accura: stai pi criari na pàggina chi fu cancillata 'n passatu.'''\n\nAccuràtivi ch'è uppurtunu cuntinuari a canciari sta pàggina.\nL'alencu dî cancillazzioni e spustamenti rilativi veni ripurtatu ccà pi cummudità:",
        "moveddeleted-notice": "Sta pàggina fu scancillata. La lista di li scancillazzioni e spustamenti veni ammustrata di sècutu pi nfurmazzioni.",
+       "moveddeleted-notice-recent": "Ni dispiaci, ma sta pàggina ricentimenti fu scancillata (nta l'ùrtimi 24 uri).\nComu rifirimentu, ccassutta ci sunnu li riggistri dî scancillazzioni e dî spustamenti rilativi a sta pàggina.",
        "log-fulllog": "Talìa lu riggistru cumpletu",
        "edit-hook-aborted": "Canciamentu annullatu di n'hook.\nNun desi nudda spigazzioni.",
        "edit-gone-missing": "Nun si pò aggiurnari la pàggina.\nPari ca fu cancillata.",
        "mergehistory-empty": "Nudda virsioni di jùnciri.",
        "mergehistory-success": "$3 {{PLURAL:$3|virsioni di [[:$1]] fu junciuta|$3 virsioni di [[:$1]] foru junciuti}} â crunuluggìa di [[:$2]].",
        "mergehistory-fail": "Nun fu pussìbbili jùnciri li crunuluggìi, pi favuri cuntrolla n'àutra vota li paràmitri chi spicìficanu li pàggini e li dati.",
-       "mergehistory-fail-toobig": "Nun fu pussìbbili jùnciri li crunuluggìi pirchì s'avìssiru a spustari cchiossai virsioni dû lìmiti chi è $1.",
+       "mergehistory-fail-toobig": "Nun fu pussìbbili jùnciri li crunuluggìi pirchì s'avìssiru a spustari cchiossai virsioni dû lìmiti chi è {{PLURAL:$1|$1}}.",
        "mergehistory-no-source": "La pàggina d'orìggini $1 nun esisti.",
        "mergehistory-no-destination": "La pàggina di distinazzioni $1 nun esisti.",
        "mergehistory-invalid-source": "La pàggina d'orìggini havi a aviri nu tìtulu vàlidu.",
        "search-section": "(sizzioni $1)",
        "search-category": "(catigurìa $1)",
        "search-file-match": "(currispunnenza ntô cuntinutu dûn file)",
-       "search-suggest": "Forsi circavutu: $1",
+       "search-suggest": "Forsi circàvitu: $1",
        "search-rewritten": "Sunnu ammustrati li risurtati pi $1. Mmeci cerca $2.",
        "search-interwiki-caption": "Pruggetti frati",
        "search-interwiki-default": "Risurtati di $1:",
        "yournick": "Firma nova:",
        "prefs-help-signature": "Li cummenti ntê pàggini di discussioni s'avìssiru a firmari cu \"<nowiki>~~~~</nowiki>\", ca veni cunvirtutu ntâ tò firma cu appressu la data.",
        "badsig": "Firma grezza nun vàlida.\nCuntrolla l'etichetti HTML.",
-       "badsiglength": "La tò firma è troppu longa.\nNun havi a èssiri cchiù longa di $1 {{PLURAL:$1|caràttiri|caràttiri}}.",
+       "badsiglength": "La tò firma è troppu longa.\nNun havi a èssiri cchiù longa di $1 {{PLURAL:$1|caràttiri}}.",
        "yourgender": "Comu prifirisci èssiri discrivutu?",
        "gender-unknown": "Quannu t'ammintua, si pò, lu prugramma adòpira lu gèniri grammaticali nèutru",
        "gender-male": "È riggistratu supra {{SITENAME}}",
        "upload-http-error": "Ammattìu n'erruri HTTP: $1",
        "upload-copy-upload-invalid-domain": "Lu carricamentu di copî nun è cunzintutu di stu duminiu.",
        "upload-dialog-title": "Carricamentu dûn file",
-       "upload-dialog-error": "Ammattìu n'erruri",
-       "upload-dialog-warning": "Ammattìu n'avvisu",
        "upload-dialog-button-cancel": "Annulla",
        "upload-dialog-button-done": "Finutu",
        "upload-dialog-button-save": "Sarva",
        "upload-dialog-button-upload": "Càrrica",
-       "upload-dialog-label-select-file": "Scegghi lu file",
-       "upload-dialog-label-infoform-title": "Dittagghî",
-       "upload-dialog-label-infoform-name": "Nomu",
-       "upload-dialog-label-infoform-description": "Discrizzioni",
-       "upload-dialog-label-usage-title": "Usu",
-       "upload-dialog-label-usage-filename": "Nomu dû file",
+       "upload-process-error": "Ammattìu n'erruri",
+       "upload-process-warning": "Ammattìu n'avvisu",
+       "upload-form-label-select-file": "Scegghi lu file",
+       "upload-form-label-infoform-title": "Dittagghî",
+       "upload-form-label-infoform-name": "Nomu",
+       "upload-form-label-infoform-description": "Discrizzioni",
+       "upload-form-label-usage-title": "Usu",
+       "upload-form-label-usage-filename": "Nomu dû file",
        "backend-fail-stream": "Nun fu pussìbbili trasmèttiri lu file \"$1\".",
        "backend-fail-backup": "Nun fu pussìbbili fari na copia di riserva dû file \"$1\".",
        "backend-fail-notexists": "Lu file $1 nun esisti.",
        "filerevert-legend": "Riprìstina file",
        "filerevert-intro": "Stai pi ripristinari lu file '''[[Media:$1|$1]]''' â [virsioni $4 dô $2, $3].",
        "filerevert-comment": "Mutivu:",
-       "filerevert-defaultcomment": "Ripristinata la virsioni dô $1, $2",
+       "filerevert-defaultcomment": "Ripristinata la virsioni dô $1, $2 ($3)",
        "filerevert-submit": "Riprìstina",
        "filerevert-success": "'''Lu file [[Media:$1|$1]]''' hà statu ripristinatu â [$4 virsioni dô $2, $3].",
        "filerevert-badversion": "Nun esistanu virsiona locali pricidenti dô file cû timestamp richiestu.",
        "suppress": "Supravisuri",
        "querypage-disabled": "Sta pàggina spiciali fu disattivata pi mutivi di pristazzioni.",
        "apihelp": "Guida a l'API",
-       "apihelp-no-such-module": "Mòdulu \"$\" nun attruvatu.",
+       "apihelp-no-such-module": "Mòdulu «$1» nun attruvatu.",
        "booksources": "Fonti libbrarî",
        "booksources-search-legend": "Arricerca di fonti libbrarî",
        "booksources-isbn": "Còdici ISBN:",
        "listusers-blocked": "(bluccatu)",
        "activeusers": "Lista di l'utenti attivi",
        "activeusers-intro": "Chista è na lista di l'utenti chi fìciru na quarchi attività {{PLURAL:$1|nta l'ùrtimu jornu|nta l'ùrtimi $1 jorna}}.",
-       "activeusers-count": "$1 {{PLURAL:$1|azzioni|azzioni}} nta {{PLURAL:$3|l'ùrtimu jornu|l'ùrtimi $3 jorna}}",
+       "activeusers-count": "$1 {{PLURAL:$1|azzioni}} nta {{PLURAL:$3|l'ùrtimu jornu|l'ùrtimi $3 jorna}}",
        "activeusers-from": "Ammustra l'utenti a pàrtiri di:",
        "activeusers-hidebots": "Ammuccia li bot",
        "activeusers-hidesysops": "Ammuccia l'amministratura",
        "emailccsubject": "Copia dû missaggiu ca mannasti a $1: $2",
        "emailsent": "Missaggiu di posta elittrònica mannatu",
        "emailsenttext": "Lu tò missaggiu di posta elittrònica fu mannatu.",
-       "emailuserfooter": "Stu missaggiu fu mannatu di $1 a $2 pi menzu dâ funzioni \"{{int:emailuser}}\" supra a {{SITENAME}}.",
+       "emailuserfooter": "Stu missaggiu fu mannatu di {{GENDER:$1|$1}} a {{GENDER:$2|$2}} pi menzu dâ funzioni «{{int:emailuser}}» supra a {{SITENAME}}.",
        "usermessage-summary": "Lassatu nu missaggiu di sistema.",
        "usermessage-editor": "Missaggeri di sistema",
        "watchlist": "Lista taliata",
        "exbeforeblank": "lu cuntinutu prima dû svacantamentu era: \"$1\"",
        "delete-confirm": "Cancella \"$1\"",
        "delete-legend": "Cancella",
-       "historywarning": "<strong>Accura:</strong> La pàggina ca stai pi cancillari havi na crunuluggìa cu $1 virsioni:",
+       "historywarning": "<strong>Accura:</strong> La pàggina ca stai pi cancillari havi na crunuluggìa cu $1 {{PLURAL:$1|virsioni}}:",
        "confirmdeletetext": "Stai cancillannu na pàggina cu tutta la sò crunuluggìa.\nPi favuri, cunferma ca ntenni fari sta cosa, ca capisti li cunziguenzi, e chi lu fai secunnu [[{{MediaWiki:Policy-url}}|li lìnii guida]].",
        "actioncomplete": "Azzioni cumpritata",
        "actionfailed": "Azioni fallita",
        "deletereasonotherlist": "Àutru mutivu",
        "deletereason-dropdown": "* Mutivi cchiù cumuni pâ cancillazzioni\n** Spam\n** Vannalismu\n** Viulazzioni di lu drittu d'auturi\n** Dumanna di l'auturi\n** Rimannu scassatu",
        "delete-edit-reasonlist": "Cancia li mutivi dâ cancillazzioni",
-       "delete-toobig": "Sta pàggina havi na crunuluggìa dî canciamenti assai longa, cchiossai di $1 {{PLURAL:$1|virsioni|virsioni}}).\nLa cancillazzioni dî pàggini comu a chista è risirvata, pi scanzari la pussibbilitati di pruvucari senza vulìrilu prubblemi a {{SITENAME}}.",
-       "delete-warning-toobig": "Sta pàggina havi na crunuluggìa dî canciamenti assai longa, cchiossai di $1 {{PLURAL:$1|virsioni|virsioni}}).\nLa sò cancillazzioni pò disturbari lu funziunamentu di  {{SITENAME}}; prucedi cu cautela.",
+       "delete-toobig": "Sta pàggina havi na crunuluggìa dî canciamenti assai longa, cchiossai di $1 {{PLURAL:$1|virsioni}}.\nLa cancillazzioni dî pàggini comu a chista è risirvata, pi scanzari la pussibbilitati di pruvucari senza vulìrilu prubblemi a {{SITENAME}}.",
+       "delete-warning-toobig": "Sta pàggina havi na crunuluggìa dî canciamenti assai longa, cchiossai di $1 {{PLURAL:$1|virsioni}}.\nLa sò cancillazzioni pò disturbari lu funziunamentu di  {{SITENAME}}; prucedi cu cautela.",
        "deleteprotected": "Nun poi cancillari sta pàggina pirchì fu prutiggiuta.",
        "deleting-backlinks-warning": "'''Accura:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Àutri pàggini]] sunnu culligati o nclùdinu la pàggina chi stai cancillannu.",
        "rollback": "Annullamentu di canciamenti",
        "api-error-badaccess-groups": "Nun hai lu pirmissu di carricari file nta sta wiki.",
        "api-error-badtoken": "Erruri nternu: Token sbagghiatu",
        "api-error-copyuploaddisabled": "Lu carricamentu a pàrtiri d'URL è disattivatu nta stu server.",
-       "api-error-duplicate": "Già {{PLURAL:$1|c'è [$2 n'àutru file]|ci sunnu [$2 àutri file]}} supra ô situ chi {{PLURAL:$1|havi|hannu}} lu stissu cuntinutu.",
+       "api-error-duplicate": "Già {{PLURAL:$1|c'è n'àutru file]|ci sunnu àutri file]}} supra ô situ chi {{PLURAL:$1|havi|hannu}} lu stissu cuntinutu.",
        "api-error-duplicate-archive": "{{PLURAL:$1|C'era n'àutru file|C'èranu àutri file}} supra ô situ c'{{PLURAL:$1|avìa|avìanu}} lu stissu cuntinutu, ma {{PLURAL:$1|fu cancillatu|foru cancillati}}.",
        "api-error-empty-file": "Lu file chi mannasti era vacanti.",
        "api-error-emptypage": "Criari pàggini novi e vacanti nun è cunzintutu.",
index be35f72..4f8042b 100644 (file)
        "createacct-captcha": "Varnostno preverjanje",
        "createacct-imgcaptcha-ph": "Vnesite zgornje besedilo",
        "createacct-submit": "Ustvarite svoj račun",
-       "createacct-another-submit": "Ustvarite še en račun",
+       "createacct-another-submit": "Ustvarite račun",
        "createacct-benefit-heading": "{{GRAMMAR:tožilnik|{{SITENAME}}}} ustvarjajo ljudje, kot ste vi.",
        "createacct-benefit-body1": "{{PLURAL:$1|urejanje|urejanji|urejanja|urejanj}}",
        "createacct-benefit-body2": "{{PLURAL:$1|stran|strani}}",
        "group-bot": "Boti",
        "group-sysop": "Administratorji",
        "group-bureaucrat": "Birokrati",
-       "group-suppress": "Nadzorniki",
+       "group-suppress": "Zatiralci",
        "group-all": "(vsi)",
        "group-user-member": "{{GENDER:$1|uporabnik|uporabnica}}",
        "group-autoconfirmed-member": "{{GENDER:$1|samodejno potrjen uporabnik|samodejno potrjena uporabnica}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|administrator|administratorka}}",
        "group-bureaucrat-member": "{{GENDER:$1|birokrat|birokratinja}}",
-       "group-suppress-member": "{{GENDER:$1|nadzornik|nadzornica}}",
+       "group-suppress-member": "{{GENDER:$1|zatiralec|zatiralka}}",
        "grouppage-user": "{{ns:project}}:Uporabniki",
        "grouppage-autoconfirmed": "{{ns:project}}:Samodejno potrjeni uporabniki",
        "grouppage-bot": "{{ns:project}}:Boti",
        "grouppage-sysop": "{{ns:project}}:Administratorji",
        "grouppage-bureaucrat": "{{ns:project}}:Birokrati",
-       "grouppage-suppress": "{{ns:project}}:Nadzorniki",
+       "grouppage-suppress": "{{ns:project}}:Zatiralci",
        "right-read": "Branje strani",
        "right-edit": "Urejanje strani",
        "right-createpage": "Ustvarjanje strani (ki niso pogovorne)",
        "upload-http-error": "Prišlo je do napake HTTP: $1",
        "upload-copy-upload-invalid-domain": "Nalaganje kopij s te domene ni možno.",
        "upload-dialog-title": "Naloži datoteko",
-       "upload-dialog-error": "Prišlo je do napake",
-       "upload-dialog-warning": "Pojavilo se je opozorilo",
        "upload-dialog-button-cancel": "Prekliči",
        "upload-dialog-button-done": "Končano",
        "upload-dialog-button-save": "Shrani",
        "upload-dialog-button-upload": "Naloži",
-       "upload-dialog-label-select-file": "Izberi datoteko",
-       "upload-dialog-label-infoform-title": "Podrobnosti",
-       "upload-dialog-label-infoform-name": "Ime",
-       "upload-dialog-label-infoform-description": "Opis",
-       "upload-dialog-label-usage-title": "Uporaba",
-       "upload-dialog-label-usage-filename": "Ime datoteke",
+       "upload-process-error": "Prišlo je do napake",
+       "upload-process-warning": "Pojavilo se je opozorilo",
+       "upload-form-label-select-file": "Izberi datoteko",
+       "upload-form-label-infoform-title": "Podrobnosti",
+       "upload-form-label-infoform-name": "Ime",
+       "upload-form-label-infoform-description": "Opis",
+       "upload-form-label-usage-title": "Uporaba",
+       "upload-form-label-usage-filename": "Ime datoteke",
        "backend-fail-stream": "Ne morem pretakati datoteke $1.",
        "backend-fail-backup": "Ne morem varnostno kopirati datoteke $1.",
        "backend-fail-notexists": "Datoteka $1 ne obstaja.",
        "filerevert-legend": "Vrni datoteko",
        "filerevert-intro": "Vračate datoteko '''[[Media:$1|$1]]''' na [$4 različico $3, $2].",
        "filerevert-comment": "Razlog:",
-       "filerevert-defaultcomment": "Vrnjeno na različico $2, $1.",
+       "filerevert-defaultcomment": "Vrnjeno na različico $2, $1 ($3)",
        "filerevert-submit": "Vrni",
        "filerevert-success": "Datoteka '''[[Media:$1|$1]]''' je bila vrnjena na [$4 različico $3, $2].",
        "filerevert-badversion": "Ne najdem preteklih lokalnih verzij datoteke s podanim časovnim žigom.",
        "nopagetext": "Ciljna stran, ki ste jo navedli, ne obstaja.",
        "pager-newer-n": "{{PLURAL:$1|novejši|novejša|novejši|novejših}} $1",
        "pager-older-n": "{{PLURAL:$1|starejši|starejša|starejši|starejših}} $1",
-       "suppress": "Nadzor",
+       "suppress": "Zatri",
        "querypage-disabled": "Ta posebna stran je onemogočena iz zmogljivostnih razlogov.",
        "apihelp": "Pomoč za API",
        "apihelp-no-such-module": "Modula »$1« nismo našli.",
        "emailccsubject": "Kopija tvojega sporočila iz $1: $2",
        "emailsent": "E-pismo je poslano!",
        "emailsenttext": "E-pismo je poslano.",
-       "emailuserfooter": "To e-poštno sporočilo je bilo poslal(-a) $1 uporabniku $2 s funkcijo »{{int:emailuser}}« na {{GRAMMAR:dative|{{SITENAME}}}}.",
+       "emailuserfooter": "To e-poštno sporočilo je {{GENDER:$1|poslal|poslala|poslal(-a)}} $1 uporabniku {{GENDER:$2|$2}} s funkcijo »{{int:emailuser}}« na {{GRAMMAR:dative|{{SITENAME}}}}.",
        "usermessage-summary": "Pusti sistemsko sporočilo.",
        "usermessage-editor": "Sistemski sporočevalec",
        "watchlist": "Spisek nadzorov",
        "deletepage": "Briši stran",
        "confirm": "Potrdi",
        "excontent": "vsebina: '$1'",
-       "excontentauthor": "vsebina: '$1' (edini urejevalec pa '$2')",
+       "excontentauthor": "vsebina je bila: »$1«, edini urejevalec pa »[[Special:Contributions/$2|$2]]« ([[User talk:$2|pogovor]])",
        "exbeforeblank": "vsebina pred brisanjem: '$1'",
        "delete-confirm": "Brisanje »$1«",
        "delete-legend": "Izbriši",
        "logentry-newusers-byemail": "$1 je {{GENDER:$2|ustvaril|ustvarila|ustvaril(-a)}} uporabniški račun $3; geslo je bilo poslano po e-pošti",
        "logentry-newusers-autocreate": "Račun $1 je bil samodejno {{GENDER:$2|ustvarjen}}",
        "logentry-protect-move_prot": "$1 je {{GENDER:$2|prestavil|prestavila|prestavil(-a)}} nastavitve zaščite s strani $4 na $3",
+       "logentry-protect-unprotect": "$1 je {{GENDER:$2|odstranil|odstranila|odstranil(-a)}} zaščito $3",
+       "logentry-protect-protect": "$1 je {{GENDER:$2|zaščitil|zaščitila|zaščitil(-a)}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 je {{GENDER:$2|zaščitil|zaščitila|zaščitil(-a)}} $3 $4 [kaskadno]",
+       "logentry-protect-modify": "$1 je {{GENDER:$2|spremenil|spremenila|spremenil(-a)}} stopnjo zaščite $3 $4",
+       "logentry-protect-modify-cascade": "$1 je {{GENDER:$2|spremenil|spremenila|spremenil(-a)}} stopnjo zaščite $3 $4 [kaskadno]",
        "logentry-rights-rights": "$1 je {{GENDER:$2|spremenil|spremenila|spremenil(-a)}} uporabniške pravice uporabnika $3 z $4 na $5",
        "logentry-rights-rights-legacy": "$1 je {{GENDER:$2|spremenil|spremenila|spremenil(-a)}} uporabniške pravice uporabnika $3",
        "logentry-rights-autopromote": "$1 je {{GENDER:$2|bil samodejno povišan|bila samodejno povišana|bil(-a) samodejno povišan(-a)}} z $4 na $5",
index 30acb93..639f6b5 100644 (file)
@@ -52,7 +52,7 @@
        "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-enotifusertalkpages": "Më njofto me e-mail kur faqja ime e dikutimeve të përdoruesit ndryshohet",
+       "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",
        "tog-shownumberswatching": "Trego numrin e përdoruesve që vëzhgojnë këtë faqe",
        "talk": "Diskutimet",
        "views": "Shikime",
        "toolbox": "Mjete",
-       "userpage": "Shiko faqen e përdoruesit",
-       "projectpage": "Shiko projekt-faqen",
-       "imagepage": "Shikoni faqen e skedës",
+       "userpage": "Shfaq faqen e përdoruesit",
+       "projectpage": "Shfaq faqen e projektit",
+       "imagepage": "Shfaq faqen e skedës",
        "mediawikipage": "Shiko faqen e mesazhit",
        "templatepage": "Shiko faqen e shabllonit",
        "viewhelppage": "Shiko faqen për ndihmë",
-       "categorypage": "Shiko faqen e kategorive",
+       "categorypage": "Shfaq faqen e kategorisë",
        "viewtalkpage": "Shiko diskutimet",
        "otherlanguages": "Në gjuhë të tjera",
        "redirectedfrom": "(Përcjellë nga $1)",
        "policy-url": "Project:Politika e rregullave",
        "portal": "Portali i komunitetit",
        "portal-url": "Project:Portali i komunitetit",
-       "privacy": "Politika e anonimitetit",
-       "privacypage": "Project:Politika e anonimitetit",
+       "privacy": "Mbrojtja e privatësisë",
+       "privacypage": "Project: Mbrojtja e privatësisë",
        "badaccess": "Leje: gabim",
        "badaccess-group0": "Nuk ju lejohet veprimi i kërkuar",
        "badaccess-groups": "Veprimi që kërkuat lejohet vetëm nga përdorues të {{PLURAL:$2|grupit|grupeve}}: $1.",
        "protectedinterface": "Kjo faqe përmban tekstin e dritares së programit, për këtë arsye mbrohet për të shmangur abuzimet.",
        "editinginterface": "'''Kujdes:''' Po redaktoni një faqe që përdoret për tekstin dritares së programit. \nNdryshimet në këtë faqe do të ndikojnë pamjen e dritares për përdoruesit e tjerë.\nPër përkthime, ju lutem konsideroni përdorimin e [//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net], projektin e lokalizimit MediaWiki.",
        "translateinterface": "Të shtoni ose të ndryshojë përkthime për të gjitha wikis, ju lutem përdorimin e [//translatewiki.net/ translatewiki.net], MediaWiki lokalizimin e projektit.",
-       "cascadeprotected": "Kjo faqe është mbrojtur nga redaktimi pasi është përfshirë në {{PLURAL:$1|faqen|faqet}} e mëposhtme që {{PLURAL:$1|është|janë}} mbrojtur sipas metodës \"cascading\":\n$2",
+       "cascadeprotected": "Kjo faqe është mbrojtur nga redaktimi pasi që është përfshirë në {{PLURAL:$1|faqen|faqet}} e mëposhtme që {{PLURAL:$1|është|janë}} mbrojtur sipas metodës \"cascading\":\n$2",
        "namespaceprotected": "Nuk ju lejohet redaktimi i faqeve në hapsirën '''$1'''.",
        "customcssprotected": "Ju nuk keni leje për të redaktuar këtë faqe CSS, sepse ai përmban cilësimet personale tjetër user's.",
        "customjsprotected": "Ju nuk keni leje për të redaktuar këtë faqe JavaScript, sepse ai përmban cilësimet personale tjetër user's.",
        "mycustomcssprotected": "Ju nuk keni leje për të redaktuar këtë faqe CSS.",
        "mycustomjsprotected": "Ju nuk keni leje për të redaktuar këtë   faqe JavaScript .",
-       "myprivateinfoprotected": "Ju nuk keni leje për të redaktuar të dhënat tuaja private.",
-       "mypreferencesprotected": "Ju nuk keni leje për të ndryshuar preferencat tuaja.",
+       "myprivateinfoprotected": "Ti nuk ke leje për të redaktuar të dhënat e tua private.",
+       "mypreferencesprotected": "Ti nuk ke leje për të ndryshuar preferencat e tua.",
        "ns-specialprotected": "Faqet speciale nuk mund të redaktohen.",
        "titleprotected": "Ky titull është mbrojtur nga [[User:$1|$1]] dhe nuk mund të krijohet.\nArsyeja e dhënë është ''$2''.",
        "filereadonlyerror": "Nuk është në gjendje që të ndryshojë skedarin \"$1\" sepse depoja e skedarit \"$2\" është në formën vetëm-lexim.\n\nAdministratori i cili e mbylli atë e dha këtë shpjegim: \"$3\".",
        "exception-nologin-text": "Ju lutem [[Special:Userlogin|hyni brënda]] për të qenë  në gjendje të hyni në këtë faqe ose veprim.",
        "exception-nologin-text-manual": "Ju lutem <span class=\"notranslate\" translate=\"asnjë\">$1</span> që të jeni në gjendje për të hyrë në këtë faqe ose të veproni.",
        "virus-badscanner": "Konfiguracion i parregullt: Skaner i panjohur virusesh: ''$1''",
-       "virus-scanfailed": "skani dështoi (code $1)",
+       "virus-scanfailed": "skanimi dështoi (code $1)",
        "virus-unknownscanner": "antivirus i pa njohur:",
        "logouttext": "'''Ju keni dalë jashtë.''' \n \n Kini parasysh që disa faqe mund të shfaqen sikur të ishit i identifikuar derisa të fshini ''cache''-in e shfletuesit tuaj.",
        "welcomeuser": "Mirë se vini, $1!",
-       "welcomecreation-msg": "Llogaria juaj u krijua. \nMos harroni të ndryshoni [[Special:Preferences|{{SITENAME}} preferencat]] tuaja.",
+       "welcomecreation-msg": "Llogaria e jote u krijua. \nMos harro të ndryshosh [[Special:Preferences|{{SITENAME}} parapëlqimet]] e tua.",
        "yourname": "Fusni nofkën tuaj",
        "userlogin-yourname": "Emri i përdoruesit",
-       "userlogin-yourname-ph": "Shtypni emrin tuaj të përdoruesit",
+       "userlogin-yourname-ph": "Fut emrin tënd të përdoruesit",
        "createacct-another-username-ph": "Shtypni emrin e përdoruesit",
        "yourpassword": "Fusni fjalëkalimin tuaj",
        "userlogin-yourpassword": "Fjalëkalimi",
        "createaccount": "Hap një llogari",
        "gotaccount": "Keni një llogari? '''$1'''.",
        "gotaccountlink": "Identifikohuni",
-       "userlogin-resetlink": "Keni harruar të dhënat tuaja të identifikimit?",
+       "userlogin-resetlink": "Ke harruar të dhënat e tua të identifikimit?",
        "userlogin-resetpassword-link": "Keni harruar fjalëkalimin?",
        "userlogin-helplink2": "Ndihmë rreth identifikimit",
        "userlogin-loggedin": "Ju tashmë janë të regjistruar si <span class=\"notranslate\" translate=\"asnjë\">{{GJINIA:$1|</span><span class=\"notranslate\" translate=\"asnjë\">$1</span>}}.\nPërdorim formularin më poshtë që të hyni në si një përdorues tjetër.",
        "createacct-captcha": "kontroll sigurie",
        "createacct-imgcaptcha-ph": "Shkruaj tekstin që ju shihni më lartë",
        "createacct-submit": "Krijoni llogarinë tuaj",
-       "createacct-another-submit": "Krijo një llogari tjeter",
+       "createacct-another-submit": "Krijo një llogari",
        "createacct-benefit-heading": "{{SITENAME}} është bërë nga njerëz si ju.",
        "createacct-benefit-body1": "{{PLURAL:$1|redaktim|redaktime}}",
        "createacct-benefit-body2": "{{PLURAL:$1|faqe|faqe}}",
        "createacct-benefit-body3": "{{PLURAL:$1|kontribuesi i|kontribuesit e}} fundit",
        "badretype": "Fjalëkalimet nuk janë njësoj.",
+       "usernameinprogress": "Një krijim i llogarisë me këtë emër përdoruesi tashmë është në progres.\nTë lutem prit.",
        "userexists": "Emri i përdoruesit që kërkuat është në përdorim. \nZgjidhni një emër tjetër.",
        "loginerror": "Gabim gjatë identifikimit",
        "createacct-error": "krijim gabim llogarie",
        "createaccounterror": "I pamundur krijimi i llogarisë: $1",
-       "nocookiesnew": "Llogaria e përdoruesit u krijua por ju nuk jeni identifikuar ende.\n{{SITENAME}} shfrytëzon \"cookies\" për të identifikuar përdoruesit.\nJu nuk mundësoni lejimin e \"cookies\".\nJu lutemi, mundësojini ato, pastaj identifikohuni me anë të të dhënave tuaja të reja: emri i përdoruesit dhe fjalëkalimi.",
+       "nocookiesnew": "Llogaria e përdoruesit u krijua por ti nuk je identifikuar akoma.\n{{SITENAME}} shfrytëzon \"cookies\" për të identifikuar përdoruesit.\nTi ke çaktivizuar e \"cookies\".\nTë lutem, avktizo ato, pastaj identifikohu emrin e ri të përdoruesit dhe fjalëkalimin.",
        "nocookieslogin": "{{SITENAME}} shfrytëzon \"cookies\" për identifikimin e përdoruesve.\nYou nuk lejoni shfrytëzimin e \"cookies\".\nJu lutemi, lejoni shfrytëzimin e \"cookies\" dhe provojeni përsëri.",
        "nocookiesfornew": "Llogaria e përdoruesit nuk u krijua, pasi ne nuk mund të konfirmojmë burimin e tij.\nSigurohuni që ju lejoni shfrytëzimin e \"cookies\", rifreskoni këtë faqe dhe provojen përsëri.",
        "noname": "Nuk keni dhënë një emër përdoruesi të pranueshëm.",
        "changeemail-password": "Fjalëkalimi juaj i {{SITENAME}}:",
        "changeemail-submit": "Ndrysho postën elektronike",
        "changeemail-throttled": "Ju keni bërë shumë tentativa hyrjeje.\nJu lutemi prisni $1 përpara se të provoni sërish.",
+       "changeemail-nochange": "Të lutem shkruaj një tjetër adresë emaili.",
+       "resettokens": "Rivendos tokens",
        "resettokens-token-label": "$1 (vlera aktuale: $2)",
        "bold_sample": "Stil i theksuar i tekstit",
        "bold_tip": "Stil i theksuar i tekstit",
        "accmailtitle": "Fjalëkalimi u dërgua.",
        "accmailtext": "Një fjalëkalim i krijuar në mënyrë të rastësishme për [[User talk:$1|$1]] u dërgua në $2.\n\nFjalëkalimi për këtë llogari mund të ndryshohet në faqen ''[[Special:ChangePassword|ndrysho fjalëkalimin]]'' pasi të jeni identifikuar.",
        "newarticle": "(I ri)",
-       "newarticletext": "Ju keni ndjekur nje lidhje drejt një faqeje që nuk ekziston.\nPër ta krijuar këtë faqe ju mund të shkruani në kutinë e mëposhtme (shih [$1 faqen e ndihmës] për më shumë informacion).\nNëse ju keni mbërritur këtu gabimisht, atëherë klikoni butonin '''pas''' të shfletuesit tuaj.",
+       "newarticletext": "Ti ke ndjekur nje lidhje drejt një faqeje që nuk ekziston.\nPër ta krijuar këtë faqe, fillo të shkruash në kutinë e mëposhtme (shih [$1 faqen e ndihmës] për më shumë informacion).\nNëse ti ke mbërritur këtu gabimisht, atëherë kliko butonin '''pas''' të shfletuesit tënd.",
        "anontalkpagetext": "----'' Kjo është një faqe diskutimi për një përdorues anonim i cili nuk ka krijuar akoma një llogari, ose qe nuk e përdor atë. \n Prandaj, ne duhet të përdorim adresën IP numerike për identifikimin e tij. \nKjo adresë IP mund të përdoret nga disa përdorues.\n Në qoftë se jeni një përdorues anonim dhe mendoni se ndaj jush janë bërë komente të parëndësishme, ju lutem [[Special:UserLogin/signup|krijoni një llogari]] ose [[Special:UserLogin|identifikohuni]] për të shmangur konfuzionin në të ardhmen me përdorues të tjerë anonim .''",
        "noarticletext": "Momentalisht nuk ka tekst në këtë faqe.\nJu mund [[Special:Search/{{PAGENAME}}|ta kërkoni këtë titull]] në faqe tjera,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} të kërkoni ngjarjet e ngjashme në regjistër],\nose [{{fullurl:{{FULLPAGENAME}}|action=edit}} të redaktoni këtë faqe]</span>.",
        "noarticletext-nopermission": "Për momentin faqja e kërkuar është bosh.\nJu mund të [[Special:Search/{{PAGENAME}}|kërkoni këtë titiull]] në faqet e tjera, ose të <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} këtkoni regjistrat e ngjashëm]</span>, por ju nuk mundeni ta krijoni këtë faqe.",
        "userinvalidcssjstitle": "'''Kujdes:''' Nuk ka pamje të quajtur \"$1\". Vini re se faqet .css dhe .js përdorin titull me gërma të vogla, p.sh. {{ns:user}}:Foo/vector.css, jo {{ns:user}}:Foo/Vector.css.",
        "updated": "(E ndryshuar)",
        "note": "'''Shënim:'''",
-       "previewnote": "'''Vini re! Kjo faqe është vetëm për shqyrtim.'''\nNdryshimet tuaja nuk janë ruajtur ende!",
+       "previewnote": "'''Mos harro që kjo është vetëm një parapamje.'''\nNdryshimet e tua nuk janë ruajtur ende!",
        "continue-editing": "Shko në pjesën për redaktim",
        "previewconflict": "Kjo parapamje reflekton tekstin sipër kutisë së redaktimit siç do të duket kur të kryeni ndryshimin.",
        "session_fail_preview": "'''Ju kërkojmë ndjesë! Redaktimi juaj nuk mund të perpunohej për shkak të humbjes së të dhënave të seancës.'''\nJu lutemi, provojeni përsëri.\nNëse përsëri nuk punon, provoni të [[Special:UserLogout|dilni nga faqja]] dhe të identifikoheni serish.",
        "copyrightwarning": "Ju lutemi, vini re! Të gjitha kontributet në {{SITENAME}} jepen për publikim sipas $2 (shiko $1 për më shumë detaje).\nNëse ju nuk dëshironi që shkrimet tuaja të redaktohen pa mëshirë dhe të shpërndahen sipas dëshirës, atëherë mos i vendosni këtu.<br />\nGjithashtu, ju po na premtoni ne që gjithçka e keni shkruar vetë, ose e keni kopjuar nga një domain publik ose nga burime të tjera  te hapura.\n'''Mos vendosni material të mbrojtur nga e drejta e autorit pa leje!'''",
        "copyrightwarning2": "Ju lutemi, vini re! Të gjitha kontributet në {{SITENAME}} mund të redaktohen, ndryshohen ose hiqen nga përdorues të tjerë  (shiko $1 për më shumë detaje). \nNëse ju nuk dëshironi që shkrimet tuaja të redaktohen pa mëshirë dhe të shpërndahen sipas dëshirës, atëherë mos i vendosni këtu<br />\nGjithashtu, ju po na premtoni ne që gjithçka e keni shkruar vetë, ose e keni kopjuar nga një domain publik ose nga burime të tjera  te hapura.\n'''Mos vendosni material të mbrojtur nga e drejta e autorit pa leje!'''",
        "longpageerror": "'''Gabim: Teksti që shkruat është  {{PLURAL:$1|një kilobajt|$1 kilobajt}} i gjatë, që është mëtepër se maksimumi i lejuar prej  {{PLURAL:$2|një kilobajt|$2 kilobajtësh}} .'''\nNuk mund të ruhet.",
-       "readonlywarning": "'''Kujdes: Baza e të dhënave është mbyllur për mirëmbajtje, prandaj ju nuk do të mund të ruani redaktimin tuaj për momentin.'''\nJu mund të kopjoni tekstin dhe ta ruani për më vonë në një dokument tjetër.'''\n\nAdministruesi që e bllokoi ka dhënë këtë sqarim: $1.",
+       "readonlywarning": "<strong>Kujdes: Baza e të dhënave është mbyllur për mirëmbajtje, prandaj për momentin nuk do të mund të ruash redaktimin tënd.</strong>\nTi mund ta kopjosh/ngjitësh tekstin dhe ta ruash në një dokument tjetër për ta përdorur më vonë .\n\nAdministratori që e bllokoi ka dhënë këtë sqarim: $1.",
        "protectedpagewarning": "'''KUJDES: Kjo faqe është e mbrotjur dhe mund të redaktohet nga përdorues me të drejta administratori.'''\nShënimi i fundit në regjistër është paraqitur më poshtë për reference:",
        "semiprotectedpagewarning": "'''Shënim:''' Kjo faqe është e mbrojtur dhe mund të redaktohet vetëm nga përdorues të regjistruar.\nShënimi i fundit në regjistër është paraqitur më poshtë për reference:",
        "cascadeprotectedwarning": "'''Vini re:''' Kjo faqe është e mbrojtur dhe vetëm përdoruesit me privilegje administrative mund ta redaktojnë pasi është përfshirë në mbrotjen \"ujëvarë\" të {{PLURAL:$1|faqes së|faqeve të}} mëposhtme:",
        "editwarning-warning": "Duke e lënë këtë faqe mund të shkaktojë ju për të humbur të gjitha ndryshimet që keni bërë ju.\nNëse ju jeni regjistruar, ju mund të çaktivizoni këtë paralajmërim në \"{{int:prefs-editing}}\" seksionin e preferencave tuaja.",
        "content-model-text": "tekst i thejshtë",
        "content-model-javascript": "JavaScript",
+       "content-json-empty-object": "Objekt bosh",
+       "content-json-empty-array": "Fushë boshe",
        "expensive-parserfunction-warning": "Kujdes: Kjo faqe ka shumë kërkesa që kërkojnë analizë gramatikore të kushtueshme për sistemin.\n\nDuhet të ketë më pakë se $2, {{PLURAL:$2|kërkesë|kërkesa}}, kurse tani {{PLURAL:$1|është $1 kërkesë|janë $1 kërkesa}}.",
        "expensive-parserfunction-category": "Faqe me shumë shprehje të kushtueshmë për analizë gramatikore",
        "post-expand-template-inclusion-warning": "'''Kujdes''': Numri i shablloneve që perfshihen është shumë i madh.\nDisa shabllone nuk do të përfshihen.",
        "viewpagelogs": "Shiko regjistrat për këtë faqe",
        "nohistory": "Nuk ka histori redaktimesh për këtë faqe.",
        "currentrev": "Versioni i tanishëm",
-       "currentrev-asof": "Versioni momental që nga $1",
-       "revisionasof": "Versioni i $1",
+       "currentrev-asof": "Versioni aktual i datës $1",
+       "revisionasof": "Versioni i datës $1",
        "revision-info": "Versioni i datës $1 nga {{GENDER:$6|$2}}$7",
        "previousrevision": "← Version më i vjetër",
        "nextrevision": "Version më i ri →",
        "prefs-edits": "Numri i redaktimeve:",
        "prefs-skin": "Pamja",
        "skin-preview": "Parapamje",
-       "datedefault": "Parazgjedhje",
+       "datedefault": "E parazgjedhur",
        "prefs-labs": "Karakteristikat laboratorik",
        "prefs-user-pages": "Faqet e përdoruesit",
        "prefs-personal": "Përdoruesi",
-       "prefs-rc": "Ndryshime së fundmi",
+       "prefs-rc": "Ndryshimet e fundit",
        "prefs-watchlist": "Lista mbikqyrëse",
        "prefs-editwatchlist": "Redakto listën mbikqyrëse",
+       "prefs-editwatchlist-clear": "Boshatis listën tënde mbikqyrëse",
        "prefs-watchlist-days": "Numri i ditëve të treguara tek lista mbikqyrëse:",
        "prefs-watchlist-days-max": "Maksimumi $1 ditë",
        "prefs-watchlist-edits": "Numri i redaktimeve të treguara tek lista mbikqyrëse e zgjeruar:",
        "prefs-resetpass": "Ndrysho fjalëkalimin",
        "prefs-changeemail": "Ndrysho postën elektronike",
        "prefs-setemail": "Vendos adresën e postës elektronike",
-       "prefs-email": "Opsionet E-mail",
-       "prefs-rendering": "Dukja",
+       "prefs-email": "Opsionet e emailit",
+       "prefs-rendering": "Pamja",
        "saveprefs": "Ruaj parapëlqimet",
        "restoreprefs": "Rikthe të gjitha të dhënat e mëparshme",
        "prefs-editing": "Redaktimi",
        "recentchangesdays-max": "(maksimum $1 {{PLURAL:$1|dit|ditë}})",
        "recentchangescount": "Numri i redaktimeve për të treguar:",
        "prefs-help-recentchangescount": "Kjo përfshin ndryshimet e freskëta, historikun e faqes dhe regjistrat.",
-       "savedprefs": "Parapëlqimet tuaja janë ruajtur.",
+       "savedprefs": "Parapëlqimet e tua janë ruajtur.",
        "timezonelegend": "Zona kohore:",
        "localtime": "Ora lokale:",
        "timezoneuseserverdefault": "wiki default Përdorimi ( $1 )",
        "allowemail": "Lejo përdoruesit të më dërgojnë email",
        "prefs-searchoptions": "Kërko",
        "prefs-namespaces": "Hapësirat",
-       "default": "parazgjedhje",
+       "default": "e parazgjedhur",
        "prefs-files": "Figura",
        "prefs-custom-css": "CSS i përpunuem",
        "prefs-custom-js": "JavaScripti i përpunuar",
        "prefs-info": "Informatat bazike",
        "prefs-i18n": "Internacionalizimi",
        "prefs-signature": "Firma",
-       "prefs-dateformat": "Data i formatit",
-       "prefs-timeoffset": "Kohë të kompensuar",
+       "prefs-dateformat": "Formati i datës",
+       "prefs-timeoffset": "Diferenca kohore",
        "prefs-advancedediting": "Opsionet e avancuar",
        "prefs-editor": "redaktor",
        "prefs-preview": "Parapamje",
-       "prefs-advancedrc": "Opsionet e avancuar",
-       "prefs-advancedrendering": "Opsionet e avancuar",
-       "prefs-advancedsearchoptions": "Opsionet e avancuar",
-       "prefs-advancedwatchlist": "Opsionet e avancuar",
+       "prefs-advancedrc": "Opsione të avancuara",
+       "prefs-advancedrendering": "Opsione të avancuara",
+       "prefs-advancedsearchoptions": "Opsione të avancuara",
+       "prefs-advancedwatchlist": "Opsione të avancuara",
        "prefs-displayrc": "Shfaq opsionet",
        "prefs-displaywatchlist": "Shfaq opsionet",
        "prefs-diffs": "Ndryshimet",
        "email-address-validity-invalid": "Futni një e-mali adresë të vlefshme.",
        "userrights": "Ndrysho privilegjet e përdoruesve",
        "userrights-lookup-user": "Ndrysho grupet e përdoruesit",
-       "userrights-user-editname": "Fusni emrin e përdoruesit:",
+       "userrights-user-editname": "Fut emrin e përdoruesit:",
        "editusergroup": "Redakto grupet e përdoruesve",
        "editinguser": "Duke ndryshuar privilegjet e {{GENDER:$1|përdoruesit|përdorueses}} <strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Anëtarësimi tek grupet",
        "userrights-notallowed": "Ju nuk keni leje për të shtuar ose hequr privilegjet e përdoruesve.",
        "userrights-changeable-col": "Grupe që mund të ndryshoni",
        "userrights-unchangeable-col": "Grupe që s'mund të ndryshoni",
-       "userrights-conflict": "Konflikt në ndryshimin e të drejtave të përdoruesit! Ju lutemi të rishikoni dhe konfirmomi ndryshimet tuaja.",
+       "userrights-conflict": "Konflikt në ndryshimin e të drejtave të përdoruesit! Të lutem të rishiko dhe konfirmo ndryshimet e tua.",
        "group": "Grupi:",
        "group-user": "Përdorues",
        "group-autoconfirmed": "Përdorues të vërtetuar automatikisht",
        "group-bot": "Robot",
        "group-sysop": "Administrues",
        "group-bureaucrat": "Burokrat",
-       "group-suppress": "Kujdestari",
+       "group-suppress": "Shtypësit",
        "group-all": "(të gjitha)",
        "group-user-member": "{{GENDER:$1|përdorues|përdoruese}}",
        "group-autoconfirmed-member": "{{GENDER:$1|përdorues i vërtetuar automatikisht|përdoruese e vërtetuar automatikisht}}",
        "grouppage-bot": "{{ns:project}}:Robotë",
        "grouppage-sysop": "{{ns:project}}:Administruesit",
        "grouppage-bureaucrat": "{{ns:project}}:Burokratë",
-       "grouppage-suppress": "{{ns:project}}:Kujdestari",
+       "grouppage-suppress": "{{ns:project}}:Shtypur",
        "right-read": "Lexo faqe",
        "right-edit": "Redakto faqet",
        "right-createpage": "Hap faqe (që nuk janë faqe diskutimi)",
        "right-unblockself": "Zhblloko veten",
        "right-protect": "Ndrysho nivelin mbrojtës dhe redakto faqet e mbrojtura",
        "right-editprotected": "Redakto faqet e mbrojtura (pa ndryshuar mbrojtjen)",
+       "right-editsemiprotected": "Redakto faqet e mbrojtura, si \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Redakto modelin e përmbajtjes së një faqeje",
        "right-editinterface": "Ndrysho parapamjen e përdoruesit",
        "right-editusercssjs": "Redakto skedat CSS dhe JS të përdoruesve tjerë",
        "right-editusercss": "Redakto skedat CSS të përdoruesve tjerë",
        "right-edituserjs": "Redakto skedat JS të përdoruesve tjerë",
+       "right-editmyusercss": "Redakto CSS - skedat e tua të përdoruesit",
+       "right-editmyuserjs": "Redakto JavaScript - skedat e tua të përdoruesit",
+       "right-viewmywatchlist": "Shfaq listën time mbikqyrëse",
+       "right-editmyoptions": "Redakto parapëlqimet e tua",
        "right-rollback": "Rikthen shpejt redaktimet  e pedaktuesit të fundit",
        "right-markbotedits": "Shëno rikthimet si redaktime robotësh",
        "right-noratelimit": "Mos u prek nga kufizimet e vlerësimit",
        "action-import": "importo faqe nga një wiki tjetër",
        "action-importupload": "Importo faqe nga një ngarkim skede",
        "action-patrol": "shëno redaktimin e tjerëve si të patrulluar",
-       "action-autopatrol": "shëno redaktimet tua si të patrulluara",
+       "action-autopatrol": "shëno redaktimet tua si të patrulluara",
        "action-unwatchedpages": "shiko listën e faqeve të pa vrojtuara",
        "action-mergehistory": "bashko historikun e kësaj faqeje",
        "action-userrights": "ndrysho të gjitha të drejtat e përdoruesit",
        "enhancedrc-history": "historia",
        "recentchanges": "Ndryshimet e fundit",
        "recentchanges-legend": "Zgjedhjet e ndryshimeve momentale",
-       "recentchanges-summary": "Ndiqni ndryshime së fundmi tek kjo faqe.",
+       "recentchanges-summary": "Ndiq ndryshimet më të fundit të Wiktionary në këtë faqe.",
        "recentchanges-noresult": "Nuk ka ndryshime gjatë periudhës së dhënë që plotësojnë këto kritere.",
        "recentchanges-feed-description": "Ndjek ndryshimet më të fundit në wiki tek kjo fushë.",
        "recentchanges-label-newpage": "Ky redaktim krijoi një faqe të re",
        "upload-too-many-redirects": "Adresa URL përmbante shumë përcjellime.",
        "upload-http-error": "Ndodhi një gabim HTTP: $1",
        "upload-copy-upload-invalid-domain": "Ngarkesat e kopjimit nuk janë në dispozicion nga ky domein.",
+       "upload-dialog-title": "Ngarko skedën",
+       "upload-dialog-button-cancel": "Anulo",
+       "upload-dialog-button-done": "Mbyll",
+       "upload-dialog-button-save": "Ruaj",
+       "upload-dialog-button-upload": "Ngarko",
+       "upload-process-error": "Një gabim ka ndodhur",
        "backend-fail-stream": "Nuk mund të kalojë skedën $1.",
        "backend-fail-backup": "Nuk mund të rezervojë skedën $1.",
        "backend-fail-notexists": "Skeda $1 nuk ekziston.",
        "uploadstash-summary": "Kjo faqe ofron qasje tek skedat të cilat janë ngarkuar (ose janë në proçes ngarkimi) por që nuk janë publikuat akoma në wiki. Këto skeda nuk janë të dukshme për këdo përveç për përdoruesin që i ka ngarkuar ato.",
        "uploadstash-clear": "Spastro skedat e fshehura",
        "uploadstash-nofiles": "Ju nuk keni skeda të fshehura.",
-       "uploadstash-badtoken": "Kryerja e këtij veprimi ishte e pasuksesshme, ndoshta sepse kredencialet redaktuese tuaja kanë skaduar. Provoni përsëri.",
+       "uploadstash-badtoken": "Kryerja e këtij veprimi ishte e pasuksesshme, ndoshta sepse kredencialet e tua redaktuese kanë skaduar. Provo përsëri.",
        "uploadstash-errclear": "Spastrimi i skedave ishte i pasuksesshëm.",
        "uploadstash-refresh": "Rifreskoni listën e skedave",
        "invalid-chunk-offset": "Kompensim cope i pavlefshëm",
        "img-auth-nologinnWL": "Ju nuk jeni i regjistruar dhe \"$1\" nuk është në listën e bardhë.",
        "img-auth-nofile": "Skeda \"$1\" nuk ekziston.",
        "img-auth-isdir": "Ju po përpiqeni të hyni në një drejtori \"$1\".\nVetëm  qasja e skedës është e lejuar.",
-       "img-auth-streaming": "Duke rrejdhur \"$1\"",
+       "img-auth-streaming": "Duke ngarkuar \"$1\"",
        "img-auth-public": "Funksioni i img_auth.php është për të larguar skedat nga një wiki privat.\nKy wiki është i konfiguruar si një wiki publik.\nPër siguri optimale, img_auth.php është çaktivizuar.",
        "img-auth-noread": "Përdoruesi nuk ka qasje për të lexuar \"$1\".",
        "http-invalid-url": "Adresë URL e pavlefshme: $1",
        "listfiles_size": "Madhësia (bytes)",
        "listfiles_description": "Përshkrimi",
        "listfiles_count": "Versionet",
+       "listfiles-latestversion": "Versioni aktual",
+       "listfiles-latestversion-yes": "Po",
+       "listfiles-latestversion-no": "Jo",
        "file-anchor-link": "Figura",
        "filehist": "Historiku i dosjes",
        "filehist-help": "Shtypni një datë/kohë për ta parë skedën ashtu si dukej në atë kohë.",
        "filerevert-legend": "Rikthe skedën",
        "filerevert-intro": "Po ktheni '''[[Media:$1|$1]]''' tek [versioni $4 i $3, $2].",
        "filerevert-comment": "Arsyeja:",
-       "filerevert-defaultcomment": "U rikthye tek versioni i $2, $1",
+       "filerevert-defaultcomment": "Rikthyer në versionin e datës $2, ora $1 ($3)",
        "filerevert-submit": "Riktheje",
        "filerevert-success": "'''[[Media:$1|$1]]''' është kthyer tek [versioni $4 i $3, $2].",
        "filerevert-badversion": "Nuk ka version vendor tjetër të kësaj skede në kohën e dhënë.",
        "filedelete-comment": "Arsyeja:",
        "filedelete-submit": "Grise",
        "filedelete-success": "'''$1''' është grisur.",
-       "filedelete-success-old": "Versioni i '''[[Media:$1|$1]]''' që nga $3, $2 është grisur.",
+       "filedelete-success-old": "Versioni i '''[[Media:$1|$1]]''' i datës $3, ora $2 është fshirë.",
        "filedelete-nofile": "'''$1''' nuk ekziston.",
        "filedelete-nofile-old": "Nuk ka version të arkivuar të '''$1''' me të dhënat e kërkuara.",
        "filedelete-otherreason": "Arsye tjetër / shtesë:",
        "nopagetext": "Faqja e kërkuar nuk ekziston.",
        "pager-newer-n": "{{PLURAL:$1|1 më i reja|$1 më të reja}}",
        "pager-older-n": "{{PLURAL:$1|1 më i vjetër|$1 më të vjetra}}",
-       "suppress": "Kujdestari",
+       "suppress": "Shtypur",
        "querypage-disabled": "Kjo faqe speciale është çaktivizuar për arsye të performancës.",
        "apihelp-no-such-module": "Moduli \"$1\" nuk u gjet.",
        "booksources": "Burime librash",
        "log-title-wildcard": "Kërko tituj që fillojnë me këtë tekst",
        "showhideselectedlogentries": "Paraqit/fshih shënimet e përzgjedhura të regjistruara.",
        "allpages": "Të gjitha faqet",
-       "nextpage": "Faqja më pas ($1)",
-       "prevpage": "Faqja më parë ($1)",
+       "nextpage": "Faqja tjetër ($1)",
+       "prevpage": "Faqja e mëparshme ($1)",
        "allpagesfrom": "Trego faqet duke filluar nga:",
        "allpagesto": "Shfaq faqet që mbarojnë në:",
        "allarticles": "Të gjithë artikujt",
        "mailnologin": "S'ka adresë dërgimi",
        "mailnologintext": "Duhet të keni [[Special:UserLogin|hyrë brenda]] dhe të keni një adresë të saktë në [[Special:Preferences|parapëlqimet]] tuaja për tu dërguar email përdoruesve të tjerë.",
        "emailuser": "Email {{GENDER:{{PAGENAME}}|përdoruesit|përdorueses}}",
+       "emailuser-title-notarget": "Email për përdoruesin",
        "emailpagetext": "Mund të përdorni formularin e mëposhtëm për të dërguar e-mail tek ky përdorues.\nAdresa e email-it që shkruat tek [[Special:Preferences|preferencat tuaja]] do të duket si \"Nga\" adresa e email-it, pra marrësi do të ketë mundësinë t'ju përgjigjet direkt.",
        "defemailsubject": "{{SITENAME}} posta elektronike nga përdoruesi \"$1\"",
        "usermaildisabled": "Email-i i përdoruesit çaktivizua",
        "wlshowlast": "Trego $1 orët $2 ditët",
        "watchlist-options": "Mundësitë e listës mbikqyrëse",
        "watching": "Duke mbikqyrur...",
-       "unwatching": "Duke çmbikqyrur...",
+       "unwatching": "Mos e mbikqyr më...",
        "watcherrortext": "Është paraqitur një gabim përderisa ndryshuat parametrat e listës suaj mbikqyrëse për \"$1\".",
        "enotif_reset": "Shëno të gjitha faqet e vizituara",
        "enotif_impersonal_salutation": "Përdorues i {{SITENAME}}",
        "delete-warning-toobig": "Kjo faqe ka një historik të madh redaktimesh, më shumë se $1 {{PLURAL:$1|version|versione}}.\nGrisja e saj mund të ndërpresë operacionet e bazës së të dhënave të {{SITENAME}};\nvazhdoni me kujdes.",
        "rollback": "Riktheji mbrapsh redaktimet",
        "rollbacklink": "riktheje",
-       "rollbacklinkcount": "riktheni $1 {{PLURAL:$1|ndryshim|ndryshime}}",
+       "rollbacklinkcount": "rikthe $1 {{PLURAL:$1|ndryshim|ndryshime}}",
        "rollbacklinkcount-morethan": "riktheni më tepër $1 {{PLURAL:$1|ndryshim|ndryshime}}",
        "rollbackfailed": "Rikthimi dështoi",
        "cantrollback": "Redaktimi nuk mund të kthehej;\nredaktori i fundit është i vetmi autor i këtij artikulli.",
        "rollback-success": "Ndryshimet e $1 u kthyen mbrapsh; artikulli ndodhet tek verzioni i $2.",
        "sessionfailure-title": "Dështim sesioni",
        "sessionfailure": "Duket se ka një problem me seancën tuaj hyrëse; ky veprim është anuluar për tu mbrojtur nga ndonjë veprim dashakeq kundrejt shfletimit tuaj. Ju lutemi kthehuni mbrapsh, rifreskoni faqen prej nga erdhët dhe provojeni përsëri veprimin.",
+       "changecontentmodel-title-label": "Titulli i faqes",
        "changecontentmodel-reason-label": "Arsyeja:",
        "protectlogpage": "Regjistri i mbrojtjeve",
        "protectlogtext": "Më poshtë është lista e kyçjeve dhe çkyçjeve të faqes.\nShih listën e [[Special:ProtectedPages|faqeve të mbrojtura]] nga lista e mbrojtjeve të faqeve tani në veprim.",
        "protect-existing-expiry": "Koha ekzistuese e skadimit: $3, $2",
        "protect-otherreason": "Arsye tjera/shtesë:",
        "protect-otherreason-op": "Arsyeja tjetër",
-       "protect-dropdown": "*Arsye të zakonshme të mbrojtjes\n**Vandalizëm i tepërt\n**Spam i tepërt\n**Paralajmërim i redaktimeve joprodukive\n**Faqe e trafikut të lartë",
+       "protect-dropdown": "*Arsye të përgjithshme të mbrojtjes\n**Vandalizëm i tepërt\n**Spam i tepërt\n**Paralajmërim i redaktimeve joprodukive\n**Faqe me trafik të lartë",
        "protect-edit-reasonlist": "Redakto arsyet e mbrojtjes",
        "protect-expiry-options": "1 Orë:1 hour,1 Ditë:1 day,1 Javë:1 week,2 Javë:2 weeks,1 Muaj:1 month,3 Muaj:3 months,6 Muaj:6 months,1 Vjet:1 year,Pa kufi:infinite",
        "restriction-type": "Lejet:",
        "blocklog-showsuppresslog": "Ky përdorues ka qenë i bllokuar dhe i fshehur më parë.\nRegjistri i bllokimeve është poshtë për referncë:",
        "blocklogentry": "bllokoi [[$1]] për një kohë prej: $2 $3",
        "reblock-logentry": "ndryshoi parametrat e bllokimit për [[$1]] me një kohë prej $2 $3",
-       "blocklogtext": "Ky është një regjistër i veprimeve bllokuese dhe zhbllokuese të përdoruesit.\n\nAdresat I të bllokuara automatikisht nuk janë të paraqitura. \n\nShikoni dhe [[Special:BlockList|listën e të bllokuarve]] për një listë të bllokimeve dhe ndalimeve vepruese të tanishme.",
+       "blocklogtext": "Ky është një regjistër i veprimeve bllokuese dhe zhbllokuese të përdoruesit.\n\nAdresat e IP-ve të bllokuara automatikisht nuk janë të paraqitura. \n\nShih [[Special:BlockList|listën e IP-ve të bllokuara]] të bllokimeve të tanishme.",
        "unblocklogentry": "çbllokoi \"$1\"",
        "block-log-flags-anononly": "vetëm anonimët",
        "block-log-flags-nocreate": "krijimi i llogarive është pamundësuar",
        "ipb_already_blocked": "\"$1\" është i bllokuar",
        "ipb-needreblock": "$1 është i bllokuar.\nDëshironi t'i ndryshoni parametrat?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Bllokim tjetër|Bllokime të tjera}}",
-       "unblock-hideuser": "Ju nuk mund të zhbllokoni këtë përdorues, përderisa nofka e tij është e fshehur.",
-       "ipb_cant_unblock": "Gabim: Bllokimi ID $1 nuk u gjet.\n\nMund të jetë zhbllokuar deri tani.",
+       "unblock-hideuser": "Nuk mund ta zhbllokosh këtë përdorues, përderisa nofka e tij është e fshehur.",
+       "ipb_cant_unblock": "Gabim: ID $1 e bllokuar nuk u gjet. Mund të jetë zhbllokuar deri tani.",
        "ipb_blocked_as_range": "Gabim: Adresa IP $1 nuk është bllokuar direkt dhe nuk mund të zhbllokohet.\nAjo është, megjithatë, e bllokuar si pjesë e rangut $2, që nuk mund të zhbllokohet.",
        "ip_range_invalid": "Shtrirje IP gabim.",
        "ip_range_toolarge": "Radhitja e bllokimeve më të mëdha se /$1 nuk lejohet.",
        "sorbsreason": "Adresa IP e juaj është radhitur si ndërmjetëse e hapur tek lista DNSBL.",
        "sorbs_create_account_reason": "Adresa IP e juaj është radhitur si ndërmjetëse e hapur tek lista DNSBL që përdoret nga {{SITENAME}}. Nuk ju lejohet të hapni një llogari.",
        "cant-see-hidden-user": "Përdoruesi që po përpiqeni të bllokoni është i bllokuar dhe i fshehur.\nPërderisa ju nuk keni të drejtën e fshehjes së përdoruesve, ju nuk mund të shikoni ose redaktoni bllokimet e përdoruesit.",
-       "ipbblocked": "Ju nuk mund të bllokoni ose zhbllokoni përdoruesit e tjerë, sepse jeni për vete i bllokuar",
+       "ipbblocked": "Ti nuk mund t'i bllokosh ose zhbllokosh përdoruesit e tjerë, sepse je vet i bllokuar",
        "ipbnounblockself": "Ju nuk mund të zhbllokoni veten tuaj",
        "lockdb": "Blloko regjistrin",
        "unlockdb": "Çblloko regjistrin",
        "lockdbsuccesssub": "Regjistri u bllokua me sukses",
        "unlockdbsuccesssub": "Regjistri u zhbllokua me sukses",
        "lockdbsuccesstext": "Regjistri është bllokuar.<br />\nKujtohuni ta [[Special:UnlockDB|çbllokoni]] pasi të keni mbaruar mirëmbajtjen.",
-       "unlockdbsuccesstext": "Regjistri i {{SITENAME}} është zhbllokuar.",
+       "unlockdbsuccesstext": "Baza e të dhënave {{SITENAME}} është zhbllokuar.",
        "lockfilenotwritable": "Skeda për bllokimin e regjistrit s'mund të shkruhet.\nShërbyesi i rrjetit duhet të jetë në gjendje të shkruaj këtë skedë për të bllokuar ose çbllokuar regjistrin.",
        "databasenotlocked": "Regjistri nuk është bllokuar.",
        "lockedbyandtime": "(nga {{GENDER:$1|$1}} më $2 në $3)",
        "revertmove": "ktheje",
        "delete_and_move": "Grise dhe zhvendose",
        "delete_and_move_text": "==Nevojitet grisje==\n\nFaqja \"[[:$1]]\" ekziston, dëshironi ta grisni për të mundësuar zhvendosjen?",
-       "delete_and_move_confirm": "Po, grise faqen",
+       "delete_and_move_confirm": "Po, fshi këtë faqe",
        "delete_and_move_reason": "U gris për të liruar vendin për përcjellim të \"[[$1]]\"",
        "selfmove": "Nuk munda ta zhvendos faqen sepse titulli i ri është i njëjtë me të vjetrin.",
        "immobile-source-namespace": "Nuk mund të lëvizet faqja tek \"$1\"",
        "move-leave-redirect": "Lini një përcjellim prapa",
        "protectedpagemovewarning": "'''Kujdes''': Kjo faqe është mbrojtur, kështu që vetëm përdoruesit me privilegje administratorësh mund ta zhvendosin atë.\nVeprimi i fundit mbi këtë faqe është poshtë për referncë:",
        "semiprotectedpagemovewarning": "'''Kujdes''': Kjo faqe është mbrojtur, kështu që vetëm përdoruesit e regjistruar mund ta zhvendosin atë.\nVeprimi i fundit mbi këtë faqe është poshtë për referncë:",
-       "move-over-sharedrepo": "== Skeda ekziston ==\n[[:$1]] ekziston në një magazinë të përbashkët. Zhvendosja e një skede tek ky titull do të prishë skedën e përbashkët.",
+       "move-over-sharedrepo": "== Skeda ekziston ==\n[[:$1]] ekziston në një magazinë të përbashkët. Zhvendosja e një skede tek ky titull do të mbishkruajë skedën e përbashkët.",
        "file-exists-sharedrepo": "Emri i zgjedhur i skedës është në përdorim në një magazinë të përbashkët.\nJu lutemi zgjidhni në emët tjetër.",
        "export": "Eksportoni faqe",
        "exporttext": "Mund të eksportoni tekstin dhe historinë e redaktimit e një faqeje ose disa faqesh të mbështjesha në XML; kjo mund të importohet në një wiki tjetër që përdor softuerin MediaWiki (tani për tani, ky opsion nuk është përfshirë tek {{SITENAME}}).\n\nPër të eksportuar faqe, thjesht shtypni një emër për çdo rresht, ose krijoni lidhje të tipit [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] si [[{{MediaWiki:Mainpage}}]].",
        "allmessages-prefix": "Filtroni nga parashtesat:",
        "allmessages-language": "Gjuha:",
        "allmessages-filter-submit": "Shko",
+       "allmessages-filter-translate": "Përkthe",
        "thumbnail-more": "Zmadho",
        "filemissing": "Mungon skeda",
        "thumbnail_error": "Gabim gjatë krijimit të figurës përmbledhëse: $1",
+       "thumbnail_error_remote": "Mesazh gabimi nga $1:\n$2",
        "djvu_page_error": "Faqja DjVu jashtë renditjes",
        "djvu_no_xml": "Nuk mund të gjendet XML për skedën DjVu",
        "thumbnail-temp-create": "Nuk mund të krijohej parapamja e përkohshme e skedës",
        "import": "Importoni faqe",
        "importinterwiki": "Import ndër-wiki",
        "import-interwiki-text": "Zgjidhni një wiki dhe titull faqeje për të importuar.\nDatat e versioneve dhe emrat e redaktuesve do të ruhen.\nTë gjitha veprimet e importit transwiki janë të regjistruara tek [[Special:Log/import|registri i importimeve]].",
+       "import-interwiki-sourcewiki": "Burimi wiki:",
+       "import-interwiki-sourcepage": "Burimi i faqes:",
        "import-interwiki-history": "Kopjo të gjitha versionet e historisë për këtë faqe",
        "import-interwiki-templates": "Përfshini të gjitha stampat",
        "import-interwiki-submit": "Importo",
        "javascripttest-pagetext-frameworks": "Ju lutemi zgjidhni njërën nga kornizat vijuese punuese të testimit: $1",
        "javascripttest-pagetext-skins": "Zgjidhni një mostër për t'i kryer testimet:",
        "javascripttest-qunit-intro": "Shiko [$1 dokumentacionin e testimit] në mediawiki.org.",
-       "tooltip-pt-userpage": "Faqja juaj e përdoruesit",
+       "tooltip-pt-userpage": "Faqja jote e përdoruesit",
        "tooltip-pt-anonuserpage": "Faqja e përdoruesve anonim nga kjo adresë IP",
-       "tooltip-pt-mytalk": "Faqja juaj e diskutimeve",
+       "tooltip-pt-mytalk": "Faqja jote e diskutimeve",
        "tooltip-pt-anontalk": "Faqja e diskutimeve të përdoruesve anonim për këtë adresë IP",
-       "tooltip-pt-preferences": "Parapëlqimet tuaja",
+       "tooltip-pt-preferences": "Parapëlqimet e tua",
        "tooltip-pt-watchlist": "Lista e faqeve nën mbikqyrjen tuaj.",
-       "tooltip-pt-mycontris": "Lista e kontributeve tuaja",
+       "tooltip-pt-mycontris": "Lista e kontributeve tua",
        "tooltip-pt-login": "Identifikimi nuk është i detyrueshëm, megjithatë ne jua rekomandojmë.",
        "tooltip-pt-logout": "Dalje",
        "tooltip-pt-createaccount": "Ju rekomandojmë të krijoni një llogari dhe të kyqeni; megjithatë,  nuk është e detyrueshme",
        "tooltip-search-go": "Shko tek faqja me këtë emër nëse ekziston",
        "tooltip-search-fulltext": "Kërko faqet për këtë tekst",
        "tooltip-p-logo": "Vizito faqen kryesore",
-       "tooltip-n-mainpage": "Vizitoni Faqen kryesore",
+       "tooltip-n-mainpage": "Vizito faqen kryesore",
        "tooltip-n-mainpage-description": "Vizito faqen kryesore",
        "tooltip-n-portal": "Rreth projektit, çfarë mund të bëni dhe ku gjenden gjërat",
        "tooltip-n-currentevents": "Kërko informacion të mëparshëm për ngjarjet aktuale.",
        "tooltip-t-print": "Version i shtypshëm i kësaj faqeje",
        "tooltip-t-permalink": "Lidhja e përhershme tek ky version i faqes",
        "tooltip-ca-nstab-main": "Shikoni përmbajtjen e atikullit.",
-       "tooltip-ca-nstab-user": "Shikoni faqen e përdoruesit",
-       "tooltip-ca-nstab-media": "Shikoni faqen e skedës",
+       "tooltip-ca-nstab-user": "Shfaq faqen e përdoruesit",
+       "tooltip-ca-nstab-media": "Shfaq faqen e medias",
        "tooltip-ca-nstab-special": "Kjo është një faqe speciale. Ju nuk mundeni ta redaktoni këtë faqe",
-       "tooltip-ca-nstab-project": "Shikoni faqen e projektit",
+       "tooltip-ca-nstab-project": "Shfaq faqen e projektit",
        "tooltip-ca-nstab-image": "Shikoni faqen e figurës",
        "tooltip-ca-nstab-mediawiki": "Shikoni mesazhet e sistemit",
        "tooltip-ca-nstab-template": "Shikoni stampën",
        "spam_deleting": "Të gjitha inspektimet përmbanin lidhje në $1, duke fshirë",
        "simpleantispam-label": "Kontrolli anti-spam.\n<strong>Mos</strong> e plotëso këtë!",
        "pageinfo-title": "Informacion për \" $1 \"",
+       "pageinfo-header-basic": "Informatat bazike",
        "pageinfo-header-edits": "Historiku i redaktimeve",
+       "pageinfo-header-restrictions": "Mbrojtja e faqes",
+       "pageinfo-header-properties": "Tiparet e faqes",
+       "pageinfo-display-title": "Shfaq titullin",
+       "pageinfo-length": "Gjatësia e faqes (në bajt)",
+       "pageinfo-article-id": "ID-ja e faqes",
+       "pageinfo-language": "Gjuha e përmbajtjes së faqes",
        "pageinfo-watchers": "Numri i mbikqyrësve të faqes",
+       "pageinfo-firstuser": "Krijuesi i faqes",
+       "pageinfo-firsttime": "Data e krijimit të faqes",
+       "pageinfo-lastuser": "Redaktori i fundit",
+       "pageinfo-lasttime": "Data e redaktimit të fundit",
        "pageinfo-edits": "Numri total i redaktimeve",
        "pageinfo-authors": "Numri i përgjithshëm i autorëve të veçantë",
+       "pageinfo-recent-edits": "Numri i redaktimeve më të fundit (gjatë $1 ditëve të kaluara)",
        "pageinfo-toolboxlink": "Informacioni i faqes",
+       "pageinfo-redirectsto-info": "info",
+       "pageinfo-contentpage": "Llogaritet si një përmbajtje e faqes",
+       "pageinfo-contentpage-yes": "Po",
+       "pageinfo-protect-cascading-yes": "Po",
+       "pageinfo-category-info": "Informacioni i kategorisë",
        "pageinfo-category-total": "Numri i përgjithshëm i anëtarëve",
+       "pageinfo-category-pages": "Numri i faqeve",
+       "pageinfo-category-subcats": "Numri i nënkategorive",
+       "pageinfo-category-files": "Numri i skedave",
        "markaspatrolleddiff": "Shënoje si të patrulluar",
        "markaspatrolledtext": "Shënoje këtë artikull të patrulluar",
        "markedaspatrolled": "Shënoje të patrulluar",
        "filedeleteerror-short": "Gabim gjatë grisjes së skedës: $1",
        "filedeleteerror-long": "U hasën gabime gjatë grisjes së skedës:\n\n$1",
        "filedelete-missing": "Skeda \"$1\" nuk mund të griset pasi nuk ekziston.",
-       "filedelete-old-unregistered": "Versioni i skedës që keni zgjedhur \"$1\" nuk ndodhet në regjistër.",
+       "filedelete-old-unregistered": "Versioni i skedës së zgjedhur \"$1\" nuk ndodhet në bazën e të dhënave.",
        "filedelete-current-unregistered": "Skeda e zgjedhur \"$1\" nuk ndodhet në regjistër.",
        "filedelete-archive-read-only": "Skedari i arkivimit \"$1\" nuk mund të ndryshohet nga shëbyesi.",
        "previousdiff": "← Ndryshimi më para",
        "hours": "{{PLURAL:$1|$1 orë|$1 orë}}",
        "days": "{{PLURAL:$1|$1 ditë|$1 ditë}}",
        "ago": "$1 më parë",
+       "just-now": "mu tani",
+       "hours-ago": "$1 {{PLURAL:$1|orë|orë}} më parë",
+       "minutes-ago": "$1 {{PLURAL:$1|minutë|minuta}} më parë",
+       "seconds-ago": "$1 {{PLURAL:$1|sekond|sekonda}} më parë",
        "monday-at": "Të hënën në $1",
        "tuesday-at": "Të martën në $1",
        "wednesday-at": "Të mërkurën në $1",
        "exif-compressedbitsperpixel": "Lloji i ngjeshjes së figurës",
        "exif-pixelydimension": "Gjerësia Image",
        "exif-pixelxdimension": "lartësi Image",
-       "exif-usercomment": "Vërejtjet e përdoruesit",
+       "exif-usercomment": "Komentet e përdoruesit",
        "exif-relatedsoundfile": "Skeda audio shoqëruese",
        "exif-datetimeoriginal": "Data dhe koha e prodhimit të të dhënave",
        "exif-datetimedigitized": "Data dhe ora e digjitalizimit",
        "exif-gpslongitude-w": "Gjatësi perëndimore",
        "exif-gpsaltitude-above-sealevel": "$1 {{PLURAL:$1|metër|metra}} mbi nivelin detar",
        "exif-gpsaltitude-below-sealevel": "$1 {{PLURAL:$1|metër|metra}} nën nivelin detar",
-       "exif-gpsstatus-a": "Duke bërë matje",
+       "exif-gpsstatus-a": "Matja është në progres",
        "exif-gpsstatus-v": "Matja e nderveprimit",
        "exif-gpsmeasuremode-2": "matje në 2 madhësi",
        "exif-gpsmeasuremode-3": "matje në 3 madhësi",
        "confirm-watch-top": "Shto këtë faqe në listën mbikqyrëse tuajen?",
        "confirm-unwatch-button": "Në rregull",
        "confirm-unwatch-top": "Largo këtë faqe nga lista juaj mbikqyrëse ?",
-       "imgmultipageprev": "← faqja e kaluar",
+       "quotation-marks": "\"$1\"",
+       "imgmultipageprev": "← faqja e mëparshme",
        "imgmultipagenext": "faqja tjetër →",
        "imgmultigo": "Shko!",
        "imgmultigoto": "Shko tek faqja $1",
+       "img-lang-default": "(gjuha e parazgjedhur)",
        "ascending_abbrev": "ngritje",
        "descending_abbrev": "zbritje",
-       "table_pager_next": "Faqja më pas",
-       "table_pager_prev": "Faqja më parë",
+       "table_pager_next": "Faqja tjetër",
+       "table_pager_prev": "Faqja e mëparshme",
        "table_pager_first": "Faqja e parë",
        "table_pager_last": "Faqja e fundit",
        "table_pager_limit": "Trego $1 rreshta për faqe",
        "specialpages-group-maintenance": "Përmbledhje mirëmbajtjeje",
        "specialpages-group-other": "Faqe speciale të tjera",
        "specialpages-group-login": "Hyrje dhe hapje llogarie",
-       "specialpages-group-changes": "Ndryshime së fundmi dhe regjistra",
+       "specialpages-group-changes": "Ndryshimet më të fundit dhe regjistrat",
        "specialpages-group-media": "Përmbledhje media dhe ngarkime",
        "specialpages-group-users": "Përdoruesit dhe privilegjet",
        "specialpages-group-highuse": "Faqe të shumëpërdorura",
        "tags-title": "Etiketat",
        "tags-intro": "Kjo faqe liston etiketat që softueri mund t'i shënojë me një redaktim, dhe kuptimin e tyre.",
        "tags-tag": "Emri i etiketës",
-       "tags-display-header": "Dukja në listat e ndryshimeve",
+       "tags-display-header": "Pamja në listat e ndryshimeve",
        "tags-description-header": "Përshkrimi i plotë i kuptimit",
        "tags-hitcount-header": "Ndrzshimet e etikuara",
        "tags-edit": "redakto",
        "dberr-usegoogle": "Ju mund të provoni të kërkoni përmes Googles në ndërkohë.",
        "dberr-outofdate": "Vini re se indekset e tyre të përmbajtjes tona mund të jetë e vjetëruar.",
        "dberr-cachederror": "Kjo është një kopje e faqes së kërkuar dhe mund të jetë e vjetëruar.",
-       "htmlform-invalid-input": "Ka probleme me disa kontribute tuaja",
+       "htmlform-invalid-input": "Ka probleme me disa nga kontributet e tua",
        "htmlform-select-badoption": "Vlera që ju e specifikuat nuk është një alternativë e vlefshme.",
        "htmlform-int-invalid": "Vlera që ju e specifikuat nuk është numër i plotë.",
        "htmlform-float-invalid": "Vlera që ju e specifikuat nuk është numër.",
        "logentry-delete-delete": "$1 {{GENDER:$2|grisi}} faqen $3",
        "logentry-delete-restore": "$1 {{GENDER:$2|riktheu}} faqen $3",
        "logentry-delete-event": "$1 {{GENDER:$2|ndryshoi}} dukshmërinë e {{PLURAL:$5|e një ngjarjeje regjistri|$5 ngjarjeve regjistri}} në $3: $4",
-       "logentry-delete-revision": "$1 {{GENDER:$2|ndryshoi}} dukshmërinë e {{PLURAL:$5|një rishikimi|$5 rishikimeve}} në faqen $3: $4",
+       "logentry-delete-revision": "$1 {{GENDER:$2|ka dryshuar}} dukshmërinë e {{PLURAL:$5|një rishikimi|$5 rishikimeve}} në faqen $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|ndryshoi}} dukshmërinë e ngjarjeve të regjistit në $3",
        "logentry-delete-revision-legacy": "$1 {{GENDER:$2|ndryshoi}} dukshmërinë e rishikimeve në faqen $3",
        "logentry-suppress-delete": "$1 {{GENDER:$2|shtypi}} faqen $3",
        "logentry-newusers-create": "Llogaria e {{GENDER:$2|përdoruesit|përdorueses}} $1 u krijua.",
        "logentry-newusers-create2": "Llogaria e përdoruesit $3 është {{GENDER:$2|krijuar}} nga $1",
        "logentry-newusers-autocreate": "Llogaria e {{GENDER:$2|përdoruesit|përdorueses}} $1 u {{GENDER:$2|krijua}} automatikisht",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|ka hequr}} mbrojtjen nga faqja $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|ka mbrojtur}} faqen $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|ka mbrojtur}} faqen $3 $4 [cascading]",
+       "logentry-protect-modify": "$1 {{GENDER:$2|ka ndryshuar}} nivelin e mbrojtjes për $3 $4",
+       "logentry-protect-modify-cascade": "$1 {{GENDER:$2|ka ndryshuar}} nivelin e mbrojtjes për $3 $4 [cascading]",
        "logentry-rights-rights": "$1 {{GENDER:$2|ndërroi}} anëtarësinë e grupit për $3 nga $4 në $5",
        "logentry-rights-autopromote": "$1 është {{GENDER:$2|promovuar}} automatikisht nga $4 në $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|ngarkoi}} $3",
        "api-error-badtoken": "Gabim i brendshëm: Shenjë e keqe.",
        "api-error-copyuploaddisabled": "Ngarkimi nga URL-ja është çaktivizuar në këtë server.",
        "api-error-duplicate": "{{PLURAL:$1|Ekziston [$2 një skedë tjetër]|Ekzistojnë [$2 disa skeda të tjera]}} me të njëjtën përmbajtje.",
-       "api-error-duplicate-archive": "{{Ekzistonte një skedë tjetër|Ekzistonin disa skeda të tjera}} me të njëjtën përmbajtje, por {{PLURAL:$1|u gris|u grisën}}.",
+       "api-error-duplicate-archive": "{{Ekzistonte një skedë tjetër|Ekzistonin disa skeda të tjera}} me të njëjtën përmbajtje, por {{PLURAL:$1|ajo është|ato janë}} fshirë.",
        "api-error-empty-file": "Skeda që paraqitët ishte bosh.",
        "api-error-emptypage": "Nuk lejohet krijimi i faqeve të reja bosh.",
        "api-error-fetchfileerror": "Gabim i brendshëm: Diçka shkoi keq gjatë marrjes së skedës.",
index 9f9ebe9..a3920ba 100644 (file)
        "youhavenewmessagesfromusers": "Имате $1 од {{PLURAL:$3|другог корисника|$3 корисника|$3 корисника}} ($2).",
        "youhavenewmessagesmanyusers": "Имате $1 од много корисника ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|нову поруку|999=нове поруке}}",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|последњу измену|999=последње измене}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|последња измена|999=последње измене}}",
        "youhavenewmessagesmulti": "Имате нових порука на $1",
        "editsection": "уреди",
        "editold": "уреди",
        "noarticletext": "На овој страници тренутно нема садржаја.\nМожете [[Special:Search/{{PAGENAME}}|потражити овај наслов]] на другим страницама,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} претражити сродне извештаје] или [{{fullurl:{{FULLPAGENAME}}|action=edit}} уредити страницу]</span>.",
        "noarticletext-nopermission": "На овој страници тренутно нема садржаја.\nМожете [[Special:Search/{{PAGENAME}}|потражити овај наслов]] на другим страницама или <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} претражити сродне дневнике]</span>, али немате дозволу да направите ову страницу.",
        "missing-revision": "Не могу да пронађем измену бр. $1 на страници под називом „{{FULLPAGENAME}}“.\n\nОво се обично дешава када пратите застарелу везу до странице која је обрисана.\nВише информација можете пронаћи у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
-       "userpage-userdoesnotexist": "Кориснички налог „<nowiki>$1</nowiki>“ није отворен.\nРазмислите да ли заиста желите да направите или уредите ову страницу.",
+       "userpage-userdoesnotexist": "Кориснички налог „<nowiki>$1</nowiki>“ није отворен.\nРазмислите да ли заиста желите да направите/уредите ову страницу.",
        "userpage-userdoesnotexist-view": "Кориснички налог „$1“ није отворен.",
        "blocked-notice-logextract": "Овај корисник је тренутно блокиран.\nИзвештај о последњем блокирању можете погледати испод:",
        "clearyourcache": "'''Напомена:''' након чувања, можда ћете морати да очистите кеш прегледача.\n*'''Фајерфокс и Сафари:''' држите ''Shift'' и кликните на ''Освежи'', или притисните ''Ctrl-F5'' или Ctrl-R (''⌘-R'' на Макинтошу)\n*'''Гугл кроум:''' притисните ''Ctrl-Shift-R'' (''⌘-Shift-R'' на Макинтошу)\n*'''Интернет експлорер: '''држите ''Ctrl'' и кликните на ''Освежи'', или притисните ''Ctrl-F5''\n*'''Опера:''' очистите привремену меморију преко менија ''Алатке → Поставке''.",
        "upload-dialog-button-done": "Готово",
        "upload-dialog-button-save": "Сачувај",
        "upload-dialog-button-upload": "Пошаљи",
-       "upload-dialog-label-select-file": "Изабери датотеку",
-       "upload-dialog-label-infoform-title": "Детаљи",
-       "upload-dialog-label-infoform-name": "Назив",
-       "upload-dialog-label-infoform-description": "Опис",
-       "upload-dialog-label-usage-filename": "Назив датотеке",
+       "upload-form-label-select-file": "Изабери датотеку",
+       "upload-form-label-infoform-title": "Детаљи",
+       "upload-form-label-infoform-name": "Назив",
+       "upload-form-label-infoform-description": "Опис",
+       "upload-form-label-usage-filename": "Назив датотеке",
        "backend-fail-stream": "Не могу да емитујем датотеку $1.",
        "backend-fail-backup": "Не могу да направим резерву датотеке $1.",
        "backend-fail-notexists": "Датотека $1 не постоји.",
        "listgrouprights-members": "(списак чланова)",
        "listgrouprights-right-display": "<span class=\"listgrouprights-granted\">$1 <code>($2)</code></span>",
        "listgrouprights-right-revoked": "<span class=\"listgrouprights-revoked\">$1 <code>($2)</code></span>",
-       "listgrouprights-addgroup": "додаје {{PLURAL:$2|следећу групу|следеће групе}}: $1",
-       "listgrouprights-removegroup": "брише {{PLURAL:$2|следећу групу|следеће групе}}: $1",
+       "listgrouprights-addgroup": "додавање {{PLURAL:$2|следећих група}}: $1",
+       "listgrouprights-removegroup": "уклањање {{PLURAL:$2|следећих група}}: $1",
        "listgrouprights-addgroup-all": "додавање свих група",
        "listgrouprights-removegroup-all": "брисање свих група",
        "listgrouprights-addgroup-self": "додавање {{PLURAL:$2|групе|група}} на свој налог: $1",
        "sp-contributions-logs": "дневници",
        "sp-contributions-talk": "разговор",
        "sp-contributions-userrights": "управљање корисничким правима",
-       "sp-contributions-blocked-notice": "Овај корисник је блокиран. Испод су наведени последњи записи у дневнику блокирања:",
-       "sp-contributions-blocked-notice-anon": "Ð\9eвоÑ\98 Ð\98Ð\9f Ð°Ð´Ñ\80еÑ\81и Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð·Ð°Ð±Ñ\80аÑ\9aен Ð¿Ñ\80иÑ\81Ñ\82Ñ\83п.\nÐ\98звеÑ\88Ñ\82аÑ\98 Ð¾ Ð±Ð»Ð¾ÐºÐ¸Ñ\80аним ÐºÐ¾Ñ\80иÑ\81ниÑ\86има Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ð¸Ñ\81под:",
+       "sp-contributions-blocked-notice": "Овај корисник је тренутно блокиран. \nИспод су наведени последњи записи у дневнику блокирања:",
+       "sp-contributions-blocked-notice-anon": "Ð\9eва Ð\98Ð\9f Ð°Ð´Ñ\80еÑ\81а Ñ\98е Ñ\82Ñ\80енÑ\83Ñ\82но Ð±Ð»Ð¾ÐºÐ¸Ñ\80ана.\nÐ\98Ñ\81под Ñ\81Ñ\83 Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¸ Ð¿Ð¾Ñ\81ледÑ\9aи Ð·Ð°Ð¿Ð¸Ñ\81и Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83 Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа:",
        "sp-contributions-search": "Претрага доприноса",
        "sp-contributions-username": "ИП адреса или корисничко име:",
        "sp-contributions-toponly": "Само најновије измене",
        "ipbexpiry": "Истиче:",
        "ipbreason": "Разлог:",
        "ipbreason-dropdown": "*Најчешћи разлози за блокирање\n** Уношење лажних информација\n** Уклањање садржаја са страница\n** Постављање веза до спољашњих сајтова\n** Уношење бесмислица у странице\n** Непристојно понашање\n** Употреба више налога\n** Неприхватљиво корисничко име",
-       "ipb-hardblock": "Ð\97абÑ\80ани пријављеним корисницима да уређују с ове ИП адресе",
+       "ipb-hardblock": "Ð\9eнемогÑ\83Ñ\9bи пријављеним корисницима да уређују с ове ИП адресе",
        "ipbcreateaccount": "Онемогући отварање налога",
        "ipbemailban": "Онемогући кориснику да шаље е-поруке",
        "ipbenableautoblock": "Аутоматски блокирај последњу ИП адресу овог корисника и све даљње адресе с којих покуша да уређује",
index 4d58a29..d9eec57 100644 (file)
        "youhavenewmessagesfromusers": "Imate $1 od {{PLURAL:$3|drugog korisnika|$3 korisnika|$3 korisnika}} ($2).",
        "youhavenewmessagesmanyusers": "Imate $1 od mnogo korisnika ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|novu poruku|999=nove poruke}}",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|poslednju izmenu|999=poslednje izmene}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|poslednja izmena|999=poslednje izmene}}",
        "youhavenewmessagesmulti": "Imate novih poruka na $1",
        "editsection": "uredi",
        "editold": "uredi",
        "noarticletext": "Na ovoj stranici trenutno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne izveštaje] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} urediti stranicu]</span>.",
        "noarticletext-nopermission": "Na ovoj stranici trenutno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne dnevnike]</span>, ali nemate dozvolu da napravite ovu stranicu.",
        "missing-revision": "Ne mogu da pronađem izmenu br. $1 na stranici pod nazivom „{{FULLPAGENAME}}“.\n\nOvo se obično dešava kada pratite zastarelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
-       "userpage-userdoesnotexist": "Korisnički nalog „<nowiki>$1</nowiki>“ nije otvoren.\nRazmislite da li zaista želite da napravite ili uredite ovu stranicu.",
+       "userpage-userdoesnotexist": "Korisnički nalog „<nowiki>$1</nowiki>“ nije otvoren.\nRazmislite da li zaista želite da napravite/uredite ovu stranicu.",
        "userpage-userdoesnotexist-view": "Korisnički nalog „$1“ nije otvoren.",
        "blocked-notice-logextract": "Ovaj korisnik je trenutno blokiran.\nIzveštaj o poslednjem blokiranju možete pogledati ispod:",
        "clearyourcache": "'''Napomena:''' nakon čuvanja, možda ćete morati da očistite keš pregledača.\n*'''Fajerfoks i Safari:''' držite ''Shift'' i kliknite na ''Osveži'', ili pritisnite ''Ctrl-F5'' ili Ctrl-R (''⌘-R'' na Makintošu)\n*'''Gugl kroum:''' pritisnite ''Ctrl-Shift-R'' (''⌘-Shift-R'' na Makintošu)\n*'''Internet eksplorer: '''držite ''Ctrl'' i kliknite na ''Osveži'', ili pritisnite ''Ctrl-F5''\n*'''Opera:''' očistite privremenu memoriju preko menija ''Alatke → Postavke''.",
        "listgrouprights-members": "(spisak članova)",
        "listgrouprights-right-display": "<span class=\"listgrouprights-granted\">$1 <code>($2)</code></span>",
        "listgrouprights-right-revoked": "<span class=\"listgrouprights-revoked\">$1 <code>($2)</code></span>",
-       "listgrouprights-addgroup": "dodaje {{PLURAL:$2|sledeću grupu|sledeće grupe}}: $1",
-       "listgrouprights-removegroup": "briše {{PLURAL:$2|sledeću grupu|sledeće grupe}}: $1",
+       "listgrouprights-addgroup": "dodavanje {{PLURAL:$2|sledećih grupa}}: $1",
+       "listgrouprights-removegroup": "uklanjanje {{PLURAL:$2|sledećih grupa}}: $1",
        "listgrouprights-addgroup-all": "dodavanje svih grupa",
        "listgrouprights-removegroup-all": "brisanje svih grupa",
        "listgrouprights-addgroup-self": "dodavanje {{PLURAL:$2|grupe|grupa}} na svoj nalog: $1",
        "sp-contributions-logs": "dnevnici",
        "sp-contributions-talk": "razgovor",
        "sp-contributions-userrights": "upravljanje korisničkim pravima",
-       "sp-contributions-blocked-notice": "Ovaj korisnik je blokiran. Ispod su navedeni poslednji zapisi u dnevniku blokiranja:",
-       "sp-contributions-blocked-notice-anon": "Ovoj IP adresi je trenutno zabranjen pristup.\nIzveštaj o blokiranim korisnicima se nalazi ispod:",
+       "sp-contributions-blocked-notice": "Ovaj korisnik je trenutno blokiran. \nIspod su navedeni poslednji zapisi u dnevniku blokiranja:",
+       "sp-contributions-blocked-notice-anon": "Ova IP adresa je trenutno blokirana.\nIspod su navedeni poslednji zapisi u dnevniku blokiranja:",
        "sp-contributions-search": "Pretraga doprinosa",
        "sp-contributions-username": "IP adresa ili korisničko ime:",
        "sp-contributions-toponly": "Samo najnovije izmene",
        "ipbexpiry": "Ističe:",
        "ipbreason": "Razlog:",
        "ipbreason-dropdown": "*Najčešći razlozi za blokiranje\n** Unošenje lažnih informacija\n** Uklanjanje sadržaja sa stranica\n** Postavljanje veza do spoljašnjih sajtova\n** Unošenje besmislica u stranice\n** Nepristojno ponašanje\n** Upotreba više naloga\n** Neprihvatljivo korisničko ime",
-       "ipb-hardblock": "Zabrani prijavljenim korisnicima da uređuju s ove IP adrese",
+       "ipb-hardblock": "Onemogući prijavljenim korisnicima da uređuju s ove IP adrese",
        "ipbcreateaccount": "Onemogući otvaranje naloga",
        "ipbemailban": "Onemogući korisniku da šalje e-poruke",
        "ipbenableautoblock": "Automatski blokiraj poslednju IP adresu ovog korisnika i sve daljnje adrese s kojih pokuša da uređuje",
index a045c12..8ae161a 100644 (file)
        "nstab-template": "Mall",
        "nstab-help": "Hjälpsida",
        "nstab-category": "Kategori",
+       "mainpage-nstab": "Huvudsida",
        "nosuchaction": "Funktionen finns inte",
        "nosuchactiontext": "Den handling som specificerats av webbadressen är ogiltig.\nDu kan ha stavat webbadressen fel, eller följt en felaktig länk.\nDet kan även bero på en bugg i mjukvaran som används på {{SITENAME}}.",
        "nosuchspecialpage": "Någon sådan specialsida finns inte",
        "createacct-captcha": "Säkerhetskontroll",
        "createacct-imgcaptcha-ph": "Fyll i texten du ser ovan",
        "createacct-submit": "Skapa ditt konto",
-       "createacct-another-submit": "Skapa ett till konto",
+       "createacct-another-submit": "Skapa konto",
        "createacct-benefit-heading": "{{SITENAME}} är skapad av människor som dig.",
        "createacct-benefit-body1": "{{PLURAL:$1|redigering|redigeringar}}",
        "createacct-benefit-body2": "{{PLURAL:$1|sida|sidor}}",
        "permissionserrorstext-withaction": "Du har inte behörighet att $2, av följande {{PLURAL:$1|anledning|anledningar}}:",
        "recreate-moveddeleted-warn": "'''Varning: Du återskapar en sida som tidigare raderats.'''\n\nDu bör överväga om det är lämpligt att fortsätta redigera den här sidan.\nRaderings- och sidflyttningsloggen för den här sidan visas här som hjälp:",
        "moveddeleted-notice": "Den här sidan har raderats.\nRaderings- och sidflyttningsloggen för sidan visas nedan som referens.",
+       "moveddeleted-notice-recent": "Tyvärr, denna sida raderades nyligen (inom de senaste 24 timmarna).\nLoggen för radering och flyttning av sidan visas nedan som referens.",
        "log-fulllog": "Visa fullständig logg",
        "edit-hook-aborted": "Redigering avbruten av hook.\nDen gav ingen förklaring.",
        "edit-gone-missing": "Kunde inte uppdatera sidan.\nDet verkar som att den har raderats.",
        "upload-http-error": "Ett HTTP-fel uppstod: $1",
        "upload-copy-upload-invalid-domain": "Uppladdning av kopior är inte tillgängligt från denna domän.",
        "upload-dialog-title": "Ladda upp fil",
-       "upload-dialog-error": "Ett fel uppstod",
-       "upload-dialog-warning": "En varning uppstod",
        "upload-dialog-button-cancel": "Avbryt",
        "upload-dialog-button-done": "Klar",
        "upload-dialog-button-save": "Spara",
        "upload-dialog-button-upload": "Ladda upp",
-       "upload-dialog-label-select-file": "Välj fil",
-       "upload-dialog-label-infoform-title": "Detaljer",
-       "upload-dialog-label-infoform-name": "Namn",
-       "upload-dialog-label-infoform-description": "Beskrivning",
-       "upload-dialog-label-usage-title": "Användning",
-       "upload-dialog-label-usage-filename": "Filnamn",
+       "upload-process-error": "Ett fel uppstod",
+       "upload-process-warning": "En varning uppstod",
+       "upload-form-label-select-file": "Välj fil",
+       "upload-form-label-infoform-title": "Detaljer",
+       "upload-form-label-infoform-name": "Namn",
+       "upload-form-label-infoform-description": "Beskrivning",
+       "upload-form-label-usage-title": "Användning",
+       "upload-form-label-usage-filename": "Filnamn",
        "backend-fail-stream": "Kunde inte strömma filen $1.",
        "backend-fail-backup": "Kunde inte säkerhetskopiera filen ''$1''.",
        "backend-fail-notexists": "Filen $1 finns inte.",
        "filerevert-legend": "Återställ fil",
        "filerevert-intro": "Du återställer '''[[Media:$1|$1]]''' till [$4 versionen från $2 kl. $3].",
        "filerevert-comment": "Anledning:",
-       "filerevert-defaultcomment": "Återställer till versionen från $1 kl. $2.",
+       "filerevert-defaultcomment": "Återställer till versionen från $1 kl. $2 ($3)",
        "filerevert-submit": "Återställ",
        "filerevert-success": "'''[[Media:$1|$1]]''' har återställts till [$4 versionen från $2 kl. $3].",
        "filerevert-badversion": "Det finns ingen tidigare version av filen från den angivna tidpunkten.",
        "emailccsubject": "Kopia av ditt meddelande till $1: $2",
        "emailsent": "E-post har nu skickats",
        "emailsenttext": "Ditt e-postmeddelande har skickats",
-       "emailuserfooter": "Detta e-postmeddelande skickades av $1 till $2 med funktionen \"{{int:emailuser}}\" på {{SITENAME}}.",
+       "emailuserfooter": "Detta e-postmeddelande {{GENDER:$1|skickades}} av $1 till {{GENDER:$2|$2}} med funktionen \"{{int:emailuser}}\" på {{SITENAME}}.",
        "usermessage-summary": "Lämnar systemmeddelande.",
        "usermessage-editor": "Systemmeddelare",
        "watchlist": "Bevakningslista",
        "api-error-badaccess-groups": "Du får inte ladda upp filer till denna wiki.",
        "api-error-badtoken": "Internt fel: felaktig nyckel.",
        "api-error-copyuploaddisabled": "Uppladdning via URL är inaktiverad på den här servern.",
-       "api-error-duplicate": "Det finns redan {{PLURAL:$1|[$2 en annan fil]|[$2 andra filer]}} på webbplatsen med samma innehåll.",
+       "api-error-duplicate": "Det finns redan {{PLURAL:$1|en annan fil|andra filer}} på webbplatsen med samma innehåll.",
        "api-error-duplicate-archive": "Det fanns redan {{PLURAL:$1|en annan fil|några andra filer}} på webbplatsen med samma innehåll, men {{PLURAL:$1|den har|de har}} raderats.",
        "api-error-empty-file": "Filen du skickade var tom.",
        "api-error-emptypage": "Det är inte tillåtet att skapa nya, tomma sidor.",
index b0ce154..1f35812 100644 (file)
        "nstab-template": "แม่แบบ",
        "nstab-help": "หน้าวิธีใช้",
        "nstab-category": "หมวดหมู่",
+       "mainpage-nstab": "หน้าหลัก",
        "nosuchaction": "ไม่มีปฏิบัติการดังกล่าว",
        "nosuchactiontext": "การกระทำที่กำหนดผ่านยูอาร์แอลดังกล่าวไม่สามารถใช้ได้\nคุณอาจกรอกยูอาร์แอลผิด หรือมาตามลิงก์ที่ไม่ถูกต้อง\nหรืออาจเกิดจากข้อผิดพลาดในซอฟต์แวร์ซึ่ง {{SITENAME}} ใช้อยู่",
        "nosuchspecialpage": "ไม่มีหน้าพิเศษดังกล่าว",
        "actionthrottled": "ปฏิบัติการถูกจำกัด",
        "actionthrottledtext": "เพื่อเป็นมาตรการป้องกันสแปม คุณจึงถูกจำกัดมิให้กระทำสิ่งนี้ไม่ให้ติดต่อกันหลายครั้งเกินไปในช่วงระยะเวลาสั้น ๆ ซึ่งขณะนี้คุณเลยขีดจำกัดนี้แล้ว \nกรุณารอสักครู่แล้วลองอีกครั้ง",
        "protectedpagetext": "หน้านี้ถูกล็อกเพื่อป้องกันการแก้ไขหรือปฏิบัติการอื่น",
-       "viewsourcetext": "คุณสามารถดูและคัดลอกโค้ดของหน้านี้:",
+       "viewsourcetext": "คุณสามารถดูและคัดลอกโค้ดของหน้านี้",
        "viewyourtext": "คุณสามารถดูและคัดลอกต้นฉบับ<strong>การแก้ไขของคุณ</strong>มาหน้านี้ได้",
        "protectedinterface": "หน้านี้เป็นข้อความส่วนต่อประสานสำหรับซอฟต์แวร์บนวิกินี้ และถูกล็อกเพื่อป้องกันการกระทำผิด\nในการเพิ่มหรือเปลี่ยนแปลงการแปลสำหรับทุกวิกิ โปรดใช้ [//translatewiki.net/ translatewiki.net] โครงการแปลมีเดียวิกิเป็นภาษาถิ่น",
        "editinginterface": "<strong>คำเตือน:</strong> คุณกำลังแก้ไขหน้าที่ใช้จัดหาข้อความอินเตอร์เฟซให้ซอฟต์แวร์\nการเปลี่ยนแปลงหน้านี้จะมีผลต่อสภาพปรากฏของส่วนต่อประสานผู้ใช้แก่ผู้ใช้อื่นบนวิกินี้",
        "createacct-captcha": "ตรวจสอบความปลอดภัย",
        "createacct-imgcaptcha-ph": "กรอกข้อความที่คุณเห็นด้านบน",
        "createacct-submit": "สร้างบัญชีของคุณ",
-       "createacct-another-submit": "สรà¹\89าà¸\87อีà¸\81à¸\9aัà¸\8dà¸\8aี",
+       "createacct-another-submit": "สร้างบัญชี",
        "createacct-benefit-heading": "{{SITENAME}}สร้างจากคนเช่นคุณ",
        "createacct-benefit-body1": "$1 การแก้ไข",
        "createacct-benefit-body2": "$1 หน้า",
        "changeemail-password": "รหัสผ่าน {{SITENAME}} ของคุณ:",
        "changeemail-submit": "เปลี่ยนอีเมล",
        "changeemail-throttled": "คุณได้พยายามล็อกอินหลายครั้งเกินไป\nกรุณารอ $1 ก่อนลองอีกครั้ง",
+       "changeemail-nochange": "กรุณากรอกที่อยู่อีเมลอื่น",
        "resettokens": "ตั้งโทเค็นใหม่",
        "resettokens-text": "คุณสามารถตั้งโทเค็นใหม่ ซึ่งให้การเข้าถึงข้อมูลส่วนตัวบางอย่างที่เกี่ยวข้องกับบัญชีของคุณที่นี่\n\nคุณควรตั้งโทเค็นใหม่ หากคุณบอกผู้อื่นโดยมิได้ตั้งใจหรือบัญชีของคุณถูกเจาะ",
        "resettokens-no-tokens": "ไม่มีโทเค็นให้ตั้งใหม่",
        "permissionserrorstext-withaction": "คุณไม่มีสิทธิ$2 ด้วย{{PLURAL:$1|เหตุ|เหตุ}}ต่อไปนี้:",
        "recreate-moveddeleted-warn": "<strong>คำเตือน: คุณกำลังสร้างหน้าซึ่งได้ถูกลบไปก่อนหน้านี้แล้วอีกครั้ง</strong>\n\nคุณควรพิจารณาว่าการแก้ไขหน้านี้ต่อไปเหมาะสมหรือไม่\nปูมการลบและเปลี่ยนชื่อหน้านี้จัดไว้ด้านล่างเพื่อความสะดวก:",
        "moveddeleted-notice": "หน้านี้ถูกลบแล้ว\nปูมการลบและเปลี่ยนชื่อของหน้านี้แสดงไว้ด้านล่างเพื่ออ้างอิง",
+       "moveddeleted-notice-recent": "ขออภัย หน้านี้เพิ่งถูกลบ (ใน 24 ชั่วโมงล่าสุด)\nปูมการลบและย้ายสำหรับหน้านี้อยู่ด้านล่างเพื่อการอ้างอิง",
        "log-fulllog": "ดูปูมแบบเต็ม",
        "edit-hook-aborted": "การแก้ไขถูกฮุกยกเลิก\nไม่ได้ให้คำอธิบาย",
        "edit-gone-missing": "ไม่สามารถปรับหน้าดังกล่าวได้\nดูเหมือนถูกลบแล้ว",
        "upload-http-error": "เกิดข้อผิดพลาดเอชทีทีพี: $1",
        "upload-copy-upload-invalid-domain": "ไม่สามารถคัดลอกการอัปโหลดจากโดเมนนี้",
        "upload-dialog-title": "อัปโหลดไฟล์",
-       "upload-dialog-error": "เกิดข้อผิดพลาด",
-       "upload-dialog-warning": "เกิดคำเตือน",
        "upload-dialog-button-cancel": "ยกเลิก",
        "upload-dialog-button-done": "เสร็จสิ้น",
        "upload-dialog-button-save": "บันทึก",
        "upload-dialog-button-upload": "อัปโหลด",
-       "upload-dialog-label-select-file": "เลือกไฟล์",
-       "upload-dialog-label-infoform-title": "รายละเอียด",
-       "upload-dialog-label-infoform-name": "ชื่อ",
-       "upload-dialog-label-infoform-description": "คำอธิบาย",
-       "upload-dialog-label-usage-title": "การใช้",
-       "upload-dialog-label-usage-filename": "ชื่อไฟล์",
+       "upload-process-error": "เกิดข้อผิดพลาด",
+       "upload-process-warning": "เกิดคำเตือน",
+       "upload-form-label-select-file": "เลือกไฟล์",
+       "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": "ชื่อไฟล์",
        "backend-fail-backup": "ไม่สามารถสำรองไฟล์ \"$1\"",
        "backend-fail-notexists": "ไม่มีไฟล์ $1",
        "backend-fail-delete": "ไม่สามารถลบไฟล์ \"$1\"",
index a92a1b0..18d874e 100644 (file)
@@ -78,7 +78,8 @@
                        "Uğurkent",
                        "Kincki",
                        "McAang",
-                       "Captantrips"
+                       "Captantrips",
+                       "Diyapazon"
                ]
        },
        "tog-underline": "Bağlantıların altını çiz:",
        "newarticletext": "Henüz varolmayan bir sayfaya konulmuş bir bağlantıya tıkladınız.\nSayfayı oluşturmak için aşağıdaki metin kutusunu kullanın. ([$1 yardım sayfasına] bakınız).\nBuraya yanlışlıkla geldiyseniz tarayıcınızın  <strong>geri </strong> tuşuna tıklayın.",
        "anontalkpagetext": "----''Bu sayfa henüz bir kullanıcı hesabı oluşturmamış veya hesabını kullanmayan bir anonim kullanıcının mesaj sayfasıdır. Bu nedenle bu kişiyi belirtmek için rakamsal IP adresini kullanmak zorundayız. Bu gibi IP adresleri birçok kullanıcı tarafından paylaşılabilir. Eğer siz de bir anonim kullanıcıysanız ve size sizin ilginiz olmayan iletiler geliyorsa, lütfen diğer anonim kullanıcılarla olabilecek olan karmaşayı önlemek için [[Special:UserLogin/signup|bir hesap edinin]] veya [[Special:UserLogin|oturum açın]].''",
        "noarticletext": "Bu sayfa şu anda boştur.\nBu başlığı [[Special:Search/{{PAGENAME}}|diğer sayfalarda arayabilir]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ilgili kayıtları arayabilir],\nya da bu sayfayı [{{fullurl:{{FULLPAGENAME}}|action=edit}} değiştirebilirsiniz]</span>.",
-       "noarticletext-nopermission": "Bu sayfa şu anda boştur. \nBu başlığı [[Special:Search/{{PAGENAME}}|diğer sayfalarda arayabilir]] ya da <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ilgili kayıtları tarayabilirsiniz]</span>, fakat sayfayı yaratma yetkiniz bulunmamaktadır.",
+       "noarticletext-nopermission": "Bu sayfa şu anda boştur. \nBu başlığı [[Special:Search/{{PAGENAME}}|diğer sayfalarda arayabilir]] ya da <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ilgili kayıtları tarayabilirsiniz]</span>, fakat sayfayı oluşturma yetkiniz bulunmamaktadır.",
        "missing-revision": "\"{{FULLPAGENAME}}\" sayfasının #$1 sürümü yok.\n\nBu duruma genellikle silinmiş bir sayfaya eski tarihli bir bağlantının takip edilmesi neden olur.\n\nDaha fazla detaylı bilgi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sayfasında bulunabilir].",
        "userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" kullanıcı hesabı kayıtlı değil. Bu sayfayı oluşturmak/değiştirmek istiyorsanız lütfen kontrol edin.",
        "userpage-userdoesnotexist-view": "\"$1\" kullanıcı hesabı kayıtlı değil.",
        "upload-dialog-button-cancel": "İptal",
        "upload-dialog-button-save": "Kaydet",
        "upload-dialog-button-upload": "Yükle",
-       "upload-dialog-label-select-file": "Dosya seç",
-       "upload-dialog-label-infoform-title": "Ayrıntılar",
-       "upload-dialog-label-infoform-name": "Ad",
-       "upload-dialog-label-infoform-description": "Açıklama",
-       "upload-dialog-label-usage-title": "Kullanımı",
-       "upload-dialog-label-usage-filename": "Dosya adı",
+       "upload-form-label-select-file": "Dosya seç",
+       "upload-form-label-infoform-title": "Ayrıntılar",
+       "upload-form-label-infoform-name": "Ad",
+       "upload-form-label-infoform-description": "Açıklama",
+       "upload-form-label-usage-title": "Kullanımı",
+       "upload-form-label-usage-filename": "Dosya adı",
        "backend-fail-stream": "$1 dosyası okunamadı.",
        "backend-fail-backup": "\"$1\" dosyası yedeklenemedi.",
        "backend-fail-notexists": "$1 dosyası mevcut değil.",
index c2b7e8b..d0985a5 100644 (file)
        "upload-http-error": "Відбулася помилка HTTP: $1",
        "upload-copy-upload-invalid-domain": "З цього домену завантаження неможливе.",
        "upload-dialog-title": "Завантажити файл",
-       "upload-dialog-error": "Сталася помилка",
-       "upload-dialog-warning": "З'явилось попередження",
        "upload-dialog-button-cancel": "Скасувати",
        "upload-dialog-button-done": "Готово",
        "upload-dialog-button-save": "Зберегти",
        "upload-dialog-button-upload": "Завантажити",
-       "upload-dialog-label-select-file": "Обрати файл",
-       "upload-dialog-label-infoform-title": "Деталі",
-       "upload-dialog-label-infoform-name": "Назва",
-       "upload-dialog-label-infoform-description": "Опис",
-       "upload-dialog-label-usage-title": "Використання",
-       "upload-dialog-label-usage-filename": "Назва файлу",
+       "upload-process-error": "Сталася помилка",
+       "upload-process-warning": "З'явилось попередження",
+       "upload-form-label-select-file": "Обрати файл",
+       "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": "Назва файлу",
        "backend-fail-stream": "Не вдалося транслювати файл $1.",
        "backend-fail-backup": "Не вдалося створити резервну копію файлу $1.",
        "backend-fail-notexists": "Файл $1 не існує.",
index 32c714a..07e4bb4 100644 (file)
        "upload-dialog-button-done": "Fato",
        "upload-dialog-button-save": "Salva",
        "upload-dialog-button-upload": "Carga",
-       "upload-dialog-label-select-file": "Siegli el file",
-       "upload-dialog-label-infoform-name": "Nome",
-       "upload-dialog-label-infoform-description": "Descrision",
-       "upload-dialog-label-usage-title": "Uso",
-       "upload-dialog-label-usage-filename": "Nome del file",
+       "upload-form-label-select-file": "Siegli el file",
+       "upload-form-label-infoform-name": "Nome",
+       "upload-form-label-infoform-description": "Descrision",
+       "upload-form-label-usage-title": "Uso",
+       "upload-form-label-usage-filename": "Nome del file",
        "backend-fail-stream": "Inposibiłe traxmetare el file $1.",
        "backend-fail-backup": "Inposibiłe fare el backup del file $1.",
        "backend-fail-notexists": "El file $1 no existe.",
index 6fff828..9dc8fbc 100644 (file)
        "upload-http-error": "Xảy ra lỗi HTTP: $1",
        "upload-copy-upload-invalid-domain": "Không có sẵn các bản sao tải lên tại tên miền này.",
        "upload-dialog-title": "Tải tập tin lên",
-       "upload-dialog-error": "Đã xuất hiện lỗi",
-       "upload-dialog-warning": "Đã xuất hiện cảnh báo",
        "upload-dialog-button-cancel": "Hủy bỏ",
        "upload-dialog-button-done": "Xong",
        "upload-dialog-button-save": "Lưu",
        "upload-dialog-button-upload": "Tải lên",
-       "upload-dialog-label-select-file": "Chọn tập tin",
-       "upload-dialog-label-infoform-title": "Chi tiết",
-       "upload-dialog-label-infoform-name": "Tên",
-       "upload-dialog-label-infoform-description": "Miêu tả",
-       "upload-dialog-label-usage-title": "Sử dụng",
-       "upload-dialog-label-usage-filename": "Tên tập tin",
+       "upload-process-error": "Đã xuất hiện lỗi",
+       "upload-process-warning": "Đã xuất hiện cảnh báo",
+       "upload-form-label-select-file": "Chọn tập tin",
+       "upload-form-label-infoform-title": "Chi tiết",
+       "upload-form-label-infoform-name": "Tên",
+       "upload-form-label-infoform-description": "Miêu tả",
+       "upload-form-label-usage-title": "Sử dụng",
+       "upload-form-label-usage-filename": "Tên tập tin",
        "backend-fail-stream": "Không thể gửi luồng tập tin $1.",
        "backend-fail-backup": "Không thể sao lưu tập tin $1.",
        "backend-fail-notexists": "Tập tin $1 không tồn tại.",
index b200503..8a93629 100644 (file)
        "disclaimers": "Ay aartu",
        "disclaimerpage": "Project:Aartu yu daj",
        "edithelp": "Ndimbal",
-       "mainpage": "Xëtu Njëlbéen",
+       "mainpage": "Xët wu njëkk",
        "mainpage-description": "Xët wu njëkk",
        "policy-url": "Project:àtte",
        "portal": "Buntub askan",
        "nstab-template": "Royuwaay",
        "nstab-help": "Xëtu ndimbal",
        "nstab-category": "Wàll",
+       "mainpage-nstab": "Xët wu njëkk",
        "nosuchaction": "Jëf ji xameesu ko",
        "nosuchactiontext": "Jëf ji nga def ci URL bi xameesu  ko.\nXéj-na dangaa juum ci bind URL bi, walla nga topp lëkkalekaay bu baaxul.\nLii man naa doon it ag njuumte ci tëriin bi ñuy jëfandikoo ci {{SITENAME}}.",
        "nosuchspecialpage": "Xëtu jagleel wu amul",
        "currentrev": "Sumb bi teew",
        "currentrev-asof": "Sumb bi teew bu $1",
        "revisionasof": "Sumb bu $1",
-       "revision-info": "Sumb bu $1, bu: $2",
+       "revision-info": "Sumbu $1, bu: {{GENDER:$6|$2}}$7",
        "previousrevision": "← Sumb bi jiitu",
        "nextrevision": "Sumb bi toftal →",
        "currentrevisionlink": "Sumb bi teew",
        "mergelog": "Yéenekaayu boole yi",
        "revertmerge": "Neenal boole yi",
        "mergelogpagetext": "Lii ci suuf ab lim la ci boole yu mujj yu jaar-jaaru aw xët ak weneen .",
-       "history-title": "Jaar-jaaru sumbi « $1 »",
+       "history-title": "Jaar-jaaru sumbi \"$1\"",
        "difference-title": "$1 wuute gi ci sumb yi",
        "lineno": "Rëdd $1 :",
        "compareselectedversions": "Méngale sumb yi nga fal",
        "rcnotefrom": "Yii ñooy coppite yi dalee '''$2''' (ba '''$1''').",
        "rclistfrom": "Wone coppite yi mujj yi dooree $3 $2",
        "rcshowhideminor": "$1 Coppite yu néewal",
+       "rcshowhideminor-show": "Wone",
        "rcshowhideminor-hide": "Nëbb",
        "rcshowhidebots": "$1 bot yi",
        "rcshowhidebots-show": "Wone",
+       "rcshowhidebots-hide": "Nëbb",
        "rcshowhideliu": "$1 jëfandikukat yi bindu",
        "rcshowhideliu-hide": "Nëbb",
        "rcshowhideanons": "$1 jëfandikukat yu binduwul",
        "rcshowhideanons-hide": "Nëbb",
        "rcshowhidepatr": "$1 coppite bees fuglu",
        "rcshowhidemine": "$1 samay cëru",
+       "rcshowhidemine-show": "Wone",
        "rcshowhidemine-hide": "Nëbb",
        "rclinks": "Wone $1 coppite yi mujj ci $2  fan yi mujj <br />$3.",
        "diff": "wuute",
        "delete-warning-toobig": "Xët wii dafa am jaar-jaar bu bari, bu weesu $1 {{PLURAL:$1|sumb|sumb}}. Seenug farte man naa jur ag jaxasoo ci dáttub njoxeeb {{SITENAME}} ; def ko ak teey.",
        "rollback": "Loppanti coppite yi",
        "rollbacklink": "delloowaat",
+       "rollbacklinkcount": "Delloo $1 {{PLURAL:$1|coppite}}",
        "rollbackfailed": "Loppanti gi antuwul",
        "cantrollback": "Neenal coppite gi manula nekk;\nKi def coppite gi mooy Kenn ki masa cëru ci xët wii.",
        "alreadyrolled": "Loppantig coppite gu mujj gu xët wii di « [[:$1]] » manula nekk, ki ko def di [[User:$2|$2]] ([[User talk:$2|Waxtaan]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nam na keneen ku jota soppi walla loppanti xët wi.\n\nKi mujje soppi xët wi mooy [[User:$3|$3]] ([[User talk:$3|Waxtaan]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "svg-long-desc": "Dencukaay SVG, kem bu jaadu  $1 × $2 pixel, dayoo dencukaay bi: $3",
        "show-big-image": "Dencukaay bi mu bàyyikoo",
        "show-big-image-preview": "Dayoob bii wonendi: $1.",
+       "show-big-image-other": "Yeneen {{PLURAL:$2|ñawaay}}: $1.",
        "show-big-image-size": "$1 × $2 pixel",
        "ilsubmit": "Seet",
        "bydate": "ci diir",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|waxtaan]])",
        "specialpages": "Xëti jagleel",
        "tag-filter": "Seggee ak [[Special:Tags|Tafaan]]:",
-       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tag}}]]: $2)",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tafaan}}]]: $2)",
        "logentry-delete-delete": "$1 {{GENDER:$2|moo far}} xët wi $3",
        "revdelete-restricted": "doxalub digal ngir yorkat yi",
        "revdelete-unrestricted": "digal ngir yorkat yi deñ na",
        "logentry-move-move": "$1 {{GENDER:$2|moo toppale}} xët wii di $3 jëmale ko ci $4",
        "logentry-newusers-create": "Sàqum jëfandikukat $1 sos nañu ko",
+       "logentry-upload-upload": "$1 {{GENDER:$2|moo yeb}} $3",
        "rightsnone": "(menn)",
        "revdelete-summary": "soppi tënk gi",
        "searchsuggest-search": "Seet"
index f23dfee..a845b6d 100644 (file)
        "tog-hideminor": "Баһ ясвр отхн ясвр седкүләс нуух",
        "tog-hidepatrolled": "Шүүсн ясвр отхн ясвр седкүләс нуух",
        "tog-newpageshidepatrolled": "Шүүсн халхс отхн ясвр седкүләс нуух",
-       "tog-extendwatchlist": "Һанц отхн биш хамг ясврта өргн оврхин седкүл",
+       "tog-extendwatchlist": "Һанц отхн биш хамг ясврта өргн оврлң",
        "tog-usenewrc": "Ясрулсн шидрә сольлһна сеткүл олзлх (JavaScript кергтә)",
        "tog-numberheadings": "Эврәр һарцг тойглх",
        "tog-showtoolbar": "Ясврин зевсг үзүлх",
        "tog-editondblclick": "Давхр шавдлһар халх ясх",
        "tog-editsectiononrightclick": "Һарцг барун шавдсар салвр чиклх",
-       "tog-watchcreations": "Мини бүтәсн халхс болн орулсн боомгуд оврхин седкүлд немх",
-       "tog-watchdefault": "Мини яссн халхс болн боомгуд оврхин седкүлд немх",
-       "tog-watchmoves": "Мини зөөсн халхс болн боомгуд оврхин седкүлд немх",
-       "tog-watchdeletion": "Мини әрлһсн халхс болн боомгуд оврхин седкүлд немх",
+       "tog-watchcreations": "Мини бүтәсн халхс болн орулсн боомгуд оврлңд немх",
+       "tog-watchdefault": "Мини яссн халхс болн боомгуд оврлңд немх",
+       "tog-watchmoves": "Мини зөөсн халхс болн боомгуд оврлңд немх",
+       "tog-watchdeletion": "Мини әрлһсн халхс болн боомгуд оврлңд немх",
        "tog-minordefault": "Хамг ясвр баһ шиг таарсар темдглх",
        "tog-previewontop": "Ясврин хәәрцг өмн хәләвр үзүлх",
        "tog-previewonfirst": "Ясврт одхла, хәләвр үзүлх",
        "tog-fancysig": "Онц тәвсн һарин вики эрә (эврән заалһго)",
        "tog-uselivepreview": "Орчн хәләвр керглх",
        "tog-forceeditsummary": "Ясврин үндсн хоосна туск медүлх",
-       "tog-watchlisthideown": "Мини ясвр оврхин седкүләс нуух",
-       "tog-watchlisthidebots": "Көдлгчин ясвр оврхин седкүләс нуух",
-       "tog-watchlisthideminor": "Баһ ясвр оврхин седкүләс нуух",
-       "tog-watchlisthideliu": "Бүрткгдсн демнәчнрин ясвр оврхин седкүләс нуух",
-       "tog-watchlisthideanons": "Нерго демнәчнрин ясвр оврхин седкүләс нуух",
-       "tog-watchlisthidepatrolled": "Шүүгдсн ясвр оврхин седкүләс нуух",
+       "tog-watchlisthideown": "Мини ясвр оврлңгас нуух",
+       "tog-watchlisthidebots": "Көдлгчин ясвр оврлңгас нуух",
+       "tog-watchlisthideminor": "Баһ ясвр оврлңгас нуух",
+       "tog-watchlisthideliu": "Бүрткгдсн демнәчнрин ясвр оврлңгас нуух",
+       "tog-watchlisthideanons": "Нерго демнәчнрин ясвр оврлңгас нуух",
+       "tog-watchlisthidepatrolled": "Шүүгдсн ясвр оврлңгас нуух",
        "tog-ccmeonemails": "Мини бус демнәчт йовулсн бичгин дүрлвр нанд йовулх",
        "tog-diffonly": "Йилһәнә дор халхин дотр эс үзүлх",
        "tog-showhiddencats": "Нуусн әәшлүд үзүлх",
        "mainpage": "Нүр халх",
        "mainpage-description": "Нүр халх",
        "policy-url": "Project:Бодлһн",
-       "portal": "Ниицәнә хург",
-       "portal-url": "Project:Ниицәнә хург",
+       "portal": "Ниицәнә күрә",
+       "portal-url": "Project:Ниицәнә күрә",
        "privacy": "Нуултын бодлһн",
        "privacypage": "Project:Нуултын бодлһн",
        "badaccess": "Зөвшәлин эндү",
        "searchprofile-articles": "Зүүлс",
        "searchprofile-images": "Үзгдл-соңсвр",
        "searchprofile-everything": "Хамг",
+       "searchprofile-advanced": "Нәрн",
        "searchprofile-articles-tooltip": "$1 дотр хәәх",
        "searchprofile-images-tooltip": "Боомг хәәх",
        "search-result-size": "$1 ({{PLURAL:$2|$2 үг|$2 үг|$2 үг}})",
        "datedefault": "Көг уга",
        "prefs-personal": "Демнәчна то-диг",
        "prefs-rc": "Отхн ясвр",
-       "prefs-watchlist": "Оврхин седкүл",
+       "prefs-watchlist": "Оврлң",
        "prefs-watchlist-days": "Шинҗллһнә седкүлд үзүлсн ик гисн өдрин то:",
        "prefs-watchlist-days-max": "$1 {{PLURAL:$1|өдрәс|өдрәс}} удан биш",
        "prefs-misc": "Бус",
        "prefixindex": "Цуг халхс эн эклцтә",
        "newpages": "Шин халхс",
        "move": "Көндәх",
-       "movethispage": "Эн халхд шин нер аль шин орм өгх",
+       "movethispage": "Эн халх дәкн нерәдх",
        "pager-newer-n": "$1 нань шин",
        "pager-older-n": "$1 нань хуучн",
        "booksources": "Дегтрин делгүрс",
        "linksearch": "Һазад заалһ хәәвр",
        "listgrouprights-members": "(мөчүдин сеткүл)",
        "emailuser": "Энд E-mail йовулх",
-       "watchlist": "Оврхин седкүл",
-       "mywatchlist": "Оврхин седкүл",
-       "addedwatchtext": "«[[:$1]]» халх тана [[Special:Watchlist|оврхин седкүлд]] немв.\nЭн халхин болн үүнә меткән халхин ирх сольлһн энд бүрктх.",
+       "watchlist": "Оврлң",
+       "mywatchlist": "Оврлң",
+       "addedwatchtext": "«[[:$1]]» халх тана [[Special:Watchlist|оврлңд]] немв.\nЭн халхин болн меткәнь халхин ирх сольлһн энд бүрктх.",
        "removedwatchtext": "«[[:$1]]» халх тана [[Special:Watchlist|шинҗллһнә сеткүләс]] һарһв.",
        "watch": "Шинҗлх",
        "watchthispage": "Эн халхиг шинҗлх",
        "unwatch": "Шинҗлх биш",
-       "watchlist-details": "Тана оврхин седкүлд меткәнә халхас бус $1 халх.",
+       "watchlist-details": "Тана оврлңд меткәнә халхас бус $1 халх.",
        "wlshowlast": "Сүл $1 цагин $2 өдрин туршк үзүлх",
        "watchlist-options": "Шинҗллһнә сеткүлин көгүд",
        "watching": "Шинҗллһнә бүтлклд немлһн...",
        "tooltip-watch": "Эн халхиг тана шинҗллһнә сеткүлд немх",
        "tooltip-rollback": "Шидрә демнчна сольлһн нег дарцар уга кех",
        "tooltip-undo": "Эн хүврлһиг уга келһн, хәләвртә болн  учрта.",
+       "pageinfo-toolboxlink": "Халхин медәл",
        "previousdiff": "← Урдк сольлһн",
        "nextdiff": "Дарук сольлһн →",
        "file-info": "боомгин кемҗә: $1, MIME төрл: $2",
index 0a79897..af06d31 100644 (file)
        "upload-http-error": "მოხდა HTTP შეცდომა: $1",
        "upload-copy-upload-invalid-domain": "ამ დომენში ატვირთვების კოპირება არ არის ხელმისაწვდომი.",
        "upload-dialog-title": "გეხარგე ფაილეფი",
-       "upload-dialog-error": "ჩილათაქ მოხვადჷ",
        "upload-dialog-button-cancel": "გოუქვაფა",
        "upload-dialog-button-done": "ღოლამირჷ რე",
        "upload-dialog-button-save": "ჩუალა",
        "upload-dialog-button-upload": "ეხარგუა",
-       "upload-dialog-label-select-file": "გეგშაგორით ფაილი",
-       "upload-dialog-label-infoform-title": "დეტალეფი",
-       "upload-dialog-label-infoform-name": "ჯოხო",
-       "upload-dialog-label-infoform-description": "ეჭარუა",
-       "upload-dialog-label-usage-title": "გიმორინაფა",
-       "upload-dialog-label-usage-filename": "ფაილიშ ჯოხო",
+       "upload-process-error": "ჩილათაქ მოხვადჷ",
+       "upload-form-label-select-file": "გეგშაგორით ფაილი",
+       "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": "ფაილიშ ჯოხო",
        "backend-fail-stream": "ფაილი $1 ტრანსლირება ვერ მოხერხდა.",
        "backend-fail-backup": "ფაილი $1 სარეზერვო ასლის გაკეთება ვერ მოხერხდა.",
        "backend-fail-notexists": "ფაილი $1 არ არსებობს.",
index 064e619..dafae55 100644 (file)
        "upload-http-error": "א HTTP גרײַז האט פאַסירט: $1",
        "upload-copy-upload-invalid-domain": "ארויפלאדן טעקעס פון דעם דאמיין נישט מעגלעך.",
        "upload-dialog-title": "אַרױפֿלאָדן טעקע",
-       "upload-dialog-error": "א גרײַז האט פאסירט",
-       "upload-dialog-warning": "א ווארענונג האט פאסירט",
        "upload-dialog-button-cancel": "אַנולירן",
        "upload-dialog-button-done": "ערליידיקט",
        "upload-dialog-button-save": "אויפֿהיטן",
        "upload-dialog-button-upload": "אַרויפֿלאָדן",
-       "upload-dialog-label-select-file": "קלויבן טעקע",
-       "upload-dialog-label-infoform-title": "פרטים",
-       "upload-dialog-label-infoform-name": "נאָמען",
-       "upload-dialog-label-infoform-description": "באַשרײבונג",
-       "upload-dialog-label-usage-title": "באניץ",
-       "upload-dialog-label-usage-filename": "טעקע נאמען",
+       "upload-process-error": "א גרײַז האט פאסירט",
+       "upload-process-warning": "א ווארענונג האט פאסירט",
+       "upload-form-label-select-file": "קלויבן טעקע",
+       "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": "טעקע נאמען",
        "backend-fail-stream": "קען נישט מאכן שטראמען טעקע $1.",
        "backend-fail-notexists": "נישט פֿאראן די טעקע $1.",
        "backend-fail-notsame": "א נישט־אידענטישע טעקע עקזיסטירט שוין ביי \"$1\".",
index d5dc7ad..33dc71d 100644 (file)
        "nstab-template": "模",
        "nstab-help": "幫助頁",
        "nstab-category": "分類",
+       "mainpage-nstab": "頭版",
        "nosuchaction": "冇呢個動作",
        "nosuchactiontext": "呢個 URL 嘅指定動作 係無效嘅。\n你可能打錯咗個 URL ,或者撳錯咗唔啱嘅連結。\n呢個可能係{{SITENAME}}所用嘅軟件入面嘅臭蟲所引致嘅。",
        "nosuchspecialpage": "冇呢頁特別頁",
        "createacct-captcha": "安全檢查",
        "createacct-imgcaptcha-ph": "入你下面見到嘅字",
        "createacct-submit": "開戶口",
-       "createacct-another-submit": "開過個戶口",
+       "createacct-another-submit": "開戶口",
        "createacct-benefit-heading": "{{SITENAME}}係由你同其他人貢獻。",
        "createacct-benefit-body1": "{{PLURAL:$1|次編輯|次編輯}}",
        "createacct-benefit-body2": "{{PLURAL:$1|版|版}}",
        "createacct-benefit-body3": "最近{{PLURAL:$1|貢獻者|貢獻者}}",
        "badretype": "你入嘅密碼唔一致。",
+       "usernameinprogress": "呢個名嘅戶口已經開緊。\n請等等。",
        "userexists": "你入嘅用戶名已經有人用咗。\n唔該揀過個名啦。",
        "loginerror": "登入錯誤",
        "createacct-error": "開戶口出錯",
        "changeemail-password": "你{{SITENAME}}個密碼:",
        "changeemail-submit": "轉電郵",
        "changeemail-throttled": "你試咗登入太多次,請喺$1後再試過。",
+       "changeemail-nochange": "請輸入個唔同嘅新電郵地址。",
        "resettokens": "重設密匙",
        "resettokens-text": "您可以重設有關你戶口私隱資料嘅密匙。\n\n如果你唔小心洩漏密匙,或者戶口畀人入侵,就要重設密匙。",
        "resettokens-no-tokens": "呢度無密匙可以重設。",
        "permissionserrorstext-withaction": "根據下面嘅{{PLURAL:$1|原因|原因}},你並無權限去做$2:",
        "recreate-moveddeleted-warn": "'''警告: 你而家重開一版係先前曾經刪除過嘅。'''\n\n你應該要考慮吓繼續編輯呢一版係唔係適合嘅。\n為咗方便起見,呢一版嘅刪除同搬版記錄已經響下面提供:",
        "moveddeleted-notice": "呢一版已經刪咗。\n呢版嘅刪除同搬版日誌響下面提供咗以便參考。",
+       "moveddeleted-notice-recent": "唔好意思,呢版啱啱刪走咗(最近24個鐘內)。\n呢版刪版同搬版紀錄喺下低做參考。",
        "log-fulllog": "睇成個日誌",
        "edit-hook-aborted": "編輯由鈎取消咗。\n佢無畀到解釋。",
        "edit-gone-missing": "唔能夠更新頁。\n佢可能啱啱刪除咗。",
        "node-count-exceeded-category": "有頁面超出咗指定數",
        "node-count-exceeded-category-desc": "頁數超過最大限制,快啲返去改過。",
        "node-count-exceeded-warning": "頁面超出指定數",
+       "expansion-depth-exceeded-category": "展開深度超出咗限制嘅版面",
+       "expansion-depth-exceeded-category-desc": "版面超出咗量大展開深度。",
+       "expansion-depth-exceeded-warning": "版面超出咗展開深度",
+       "parser-unstrip-loop-warning": "偵測到 Unstrip 迴圈",
+       "parser-unstrip-recursion-limit": "Unstrip 迴圈超出咗限制 ($1)",
+       "converter-manual-rule-error": "手動語言轉換規則入面偵測到出錯",
        "undo-success": "呢個編輯可以取消。請檢查一下個差異去確認呢個係你要去做嘅,跟住儲存下面嘅更改去完成編輯。",
        "undo-failure": "呢個編輯唔能夠取消,由於同途中嘅編輯有衝突。",
        "undo-norev": "呢個編輯唔能夠取消,由於佢唔存在或者刪除咗。",
        "search-category": "(類 $1)",
        "search-file-match": "(夾啱樓案内容)",
        "search-suggest": "你係唔係搵: $1",
+       "search-rewritten": "顯示緊 $1 嘅搵嘢結果,而唔係 $2 嘅。",
        "search-interwiki-caption": "姊妹計劃",
        "search-interwiki-default": "嚟自$1嘅結果:",
        "search-interwiki-more": "(更多)",
        "rows": "行數:",
        "columns": "列數:",
        "searchresultshead": "搵嘢",
-       "stub-threshold": "<a href=\"#\" class=\"stub\">楔位連結</a>格式門檻 (bytes):",
+       "stub-threshold": "楔位連結格式門檻 ($1):",
+       "stub-threshold-sample-link": "樣辦",
        "stub-threshold-disabled": "閂咗",
        "recentchangesdays": "最近更改中嘅顯示日數:",
        "recentchangesdays-max": "最多 $1 日",
        "userrights-notallowed": "你無權限去加減用戶權限。",
        "userrights-changeable-col": "你可以改嘅組",
        "userrights-unchangeable-col": "你唔可以改嘅組",
+       "userrights-conflict": "用戶權限更改有衝突!請再睇過同確認你嘅改動。",
        "userrights-removed-self": "移走自身權限成功,但你冇乜可能入到呢頁。",
        "group": "組:",
        "group-user": "用戶",
        "right-writeapi": "使用編寫嘅API",
        "right-delete": "刪版",
        "right-bigdelete": "刪大量歷史嘅版",
+       "right-deletelogentry": "刪走同取消刪走指定紀錄項目",
        "right-deleterevision": "刪同反刪版嘅指定修訂",
        "right-deletedhistory": "睇刪咗嘅項目,唔包同埋嘅字",
        "right-deletedtext": "睇刪咗嘅修訂度嘅已刪嘅字同更改",
        "right-browsearchive": "搵刪咗嘅版",
        "right-undelete": "反刪版",
        "right-suppressrevision": "睇下、收埋同恢復任何用戶指定頁面版本",
+       "right-viewsuppressed": "睇所有用戶嘅隱藏修訂",
        "right-suppressionlog": "去睇私人嘅日誌",
        "right-block": "封鎖其他用戶唔畀編輯",
        "right-blockemail": "封鎖用戶唔畀寄電郵",
        "right-unblockself": "解封自己",
        "right-protect": "改保護等級同埋編輯流水保護版",
        "right-editprotected": "用「{{int:protect-level-sysop}}」權限去編輯保護版",
+       "right-editsemiprotected": "改保護等級係「{{int:protect-level-autoconfirmed}}」嘅版面",
+       "right-editcontentmodel": "改版面嘅內容模型",
        "right-editinterface": "編輯用戶界面",
        "right-editusercssjs": "編輯其他用戶嘅CSS同埋JavaScript檔",
        "right-editusercss": "編輯其他用戶嘅CSS檔",
        "upload-http-error": "一個HTTP錯誤發生咗: $1",
        "upload-copy-upload-invalid-domain": "從嗰個域名度冇複製上傳功能",
        "upload-dialog-title": "上載檔案",
-       "upload-dialog-error": "出錯",
-       "upload-dialog-warning": "警告",
        "upload-dialog-button-cancel": "取消",
        "upload-dialog-button-done": "搞掂",
        "upload-dialog-button-save": "儲存",
        "upload-dialog-button-upload": "上載",
-       "upload-dialog-label-select-file": "揀檔案",
-       "upload-dialog-label-infoform-title": "細節",
-       "upload-dialog-label-infoform-name": "名",
-       "upload-dialog-label-infoform-description": "描述",
-       "upload-dialog-label-usage-title": "用法",
-       "upload-dialog-label-usage-filename": "文件名",
+       "upload-process-error": "出錯",
+       "upload-process-warning": "警告",
+       "upload-form-label-select-file": "揀檔案",
+       "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": "文件名",
        "backend-fail-stream": "傳送唔到檔案「$1」。",
        "backend-fail-backup": "檔案 \"$1\" 唔備份得。",
        "backend-fail-notexists": "檔案$1唔存在。",
        "filerevert-legend": "回復檔案",
        "filerevert-intro": "你而家回復緊個檔案'''[[Media:$1|$1]]'''到[$4 響$2 $3嘅版本]。",
        "filerevert-comment": "原因:",
-       "filerevert-defaultcomment": "已經回復到響$1 $2嘅版本",
+       "filerevert-defaultcomment": "已經回復到響$1 $2嘅版本 ($3)",
        "filerevert-submit": "回復",
        "filerevert-success": "'''[[Media:$1|$1]]'''已經回復到[$4 響$2 $3嘅版本]。",
        "filerevert-badversion": "呢個檔案所提供嘅時間截記並無之前嘅本地版本。",
        "booksources-text": "以下嘅連結清單列出其它一啲賣新書同二手書嘅網站,可能可以提供到有關你想搵嘅書嘅更多資料:",
        "booksources-invalid-isbn": "個ISBN無效;請檢查原來源複製落來嘅錯。",
        "specialloguserlabel": "執行人:",
-       "speciallogtitlelabel": "目標(題目或者用戶):",
+       "speciallogtitlelabel": "目標(題目或者用戶 {{ns:user}}:用戶名 ):",
        "log": "日誌",
        "all-logs-page": "全部嘅公共日誌",
        "alllogstext": "響{{SITENAME}}度全部日誌嘅綜合顯示。你可以選擇一個日誌類型、用戶名、或者受影響嘅頁面,嚟縮窄顯示嘅範圍。",
        "emailccsubject": "你畀$1: $2封信嘅副本",
        "emailsent": "電郵已傳送",
        "emailsenttext": "你嘅電郵信息已傳送。",
-       "emailuserfooter": "呢封電郵係由$1寄畀$2經{{SITENAME}}嘅「{{int:emailuser}}」功能發出嘅。",
+       "emailuserfooter": "呢封電郵係由$1{{GENDER:$1|寄}}畀{{GENDER:$2|$2}}經{{SITENAME}}嘅「{{int:emailuser}}」功能發出嘅。",
        "usermessage-summary": "留低系統訊息。",
        "usermessage-editor": "系統訊息",
        "watchlist": "監視名單",
        "tooltip-ca-nstab-main": "睇吓內容頁",
        "tooltip-ca-nstab-user": "睇吓用戶頁",
        "tooltip-ca-nstab-media": "睇吓媒體頁",
-       "tooltip-ca-nstab-special": "呢度係特別頁,你修改唔到。",
+       "tooltip-ca-nstab-special": "呢度係特別頁,唔改得。",
        "tooltip-ca-nstab-project": "睇吓專案頁",
        "tooltip-ca-nstab-image": "睇吓檔案頁",
        "tooltip-ca-nstab-mediawiki": "睇吓系統信息",
index 1113d86..4ead3f7 100644 (file)
        "createacct-captcha": "安全检查",
        "createacct-imgcaptcha-ph": "请输入上图中的文字",
        "createacct-submit": "创建您的账户",
-       "createacct-another-submit": "创建另一个账户",
+       "createacct-another-submit": "创建账户",
        "createacct-benefit-heading": "{{SITENAME}}是由同你一样的人们构筑的。",
        "createacct-benefit-body1": "{{PLURAL:$1|编辑}}",
        "createacct-benefit-body2": "{{PLURAL:$1|页面}}",
        "group-bot": "机器人",
        "group-sysop": "管理员",
        "group-bureaucrat": "行政员",
-       "group-suppress": "ç\9b\91ç\9d£å\91\98",
+       "group-suppress": "ç¦\81æ­¢æ\89§è¡\8cè\80\85",
        "group-all": "(所有)",
        "group-user-member": "{{GENDER:$1|用户}}",
        "group-autoconfirmed-member": "自动确认用户",
        "group-bot-member": "机器人",
        "group-sysop-member": "{{GENDER:$1|管理员}}",
        "group-bureaucrat-member": "行政员",
-       "group-suppress-member": "{{GENDER:$1|ç\9b\91ç\9d£å\91\98}}",
+       "group-suppress-member": "{{GENDER:$1|ç¦\81æ­¢æ\89§è¡\8cè\80\85}}",
        "grouppage-user": "{{ns:project}}:用户",
        "grouppage-autoconfirmed": "{{ns:project}}:自动确认用户",
        "grouppage-bot": "{{ns:project}}:机器人",
        "grouppage-sysop": "{{ns:project}}:管理员",
        "grouppage-bureaucrat": "{{ns:project}}:行政员",
-       "grouppage-suppress": "{{ns:project}}:ç\9b\91ç\9d£",
+       "grouppage-suppress": "{{ns:project}}:ç¦\81æ­¢",
        "right-read": "阅读页面",
        "right-edit": "编辑页面",
        "right-createpage": "创建非讨论页面",
        "upload-http-error": "发生HTTP错误:$1",
        "upload-copy-upload-invalid-domain": "不能从该域名上载文件副本。",
        "upload-dialog-title": "上传文件",
-       "upload-dialog-error": "发生错误",
-       "upload-dialog-warning": "发生一条警告",
        "upload-dialog-button-cancel": "取消",
        "upload-dialog-button-done": "完成",
        "upload-dialog-button-save": "保存",
        "upload-dialog-button-upload": "上传",
-       "upload-dialog-label-select-file": "选择文件",
-       "upload-dialog-label-infoform-title": "详细信息",
-       "upload-dialog-label-infoform-name": "名称",
-       "upload-dialog-label-infoform-description": "说明",
-       "upload-dialog-label-usage-title": "用法",
-       "upload-dialog-label-usage-filename": "文件名",
+       "upload-process-error": "发生错误",
+       "upload-process-warning": "发生一条警告",
+       "upload-form-label-select-file": "选择文件",
+       "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": "文件名",
        "backend-fail-stream": "无法流传送文件$1。",
        "backend-fail-backup": "无法备份文件$1。",
        "backend-fail-notexists": "条目$1不存在。",
        "filerevert-legend": "恢复文件",
        "filerevert-intro": "你将要恢复文件'''[[Media:$1|$1]]'''至[$4 $2 $3的版本]。",
        "filerevert-comment": "原因:",
-       "filerevert-defaultcomment": "恢复至$1 $2的版本",
+       "filerevert-defaultcomment": "回退至$1 $2($3)的版本",
        "filerevert-submit": "恢复",
        "filerevert-success": "<strong>[[Media:$1|$1]]</strong>已经恢复至[$4 $2 $3的版本]。",
        "filerevert-badversion": "文件并无所请求时间戳下的早期本地版本。",
        "nopagetext": "您所指定的目标页面并不存在。",
        "pager-newer-n": "前$1个",
        "pager-older-n": "后$1个",
-       "suppress": "ç\9b\91ç\9d£",
+       "suppress": "ç¦\81æ­¢",
        "querypage-disabled": "本特殊页面因性能问题而停用。",
        "apihelp": "API 帮助",
        "apihelp-no-such-module": "找不到模块“$1”。",
        "emailccsubject": "您发送给$1的消息的副本:$2",
        "emailsent": "电子邮件已发送",
        "emailsenttext": "您的电子邮件已经发出。",
-       "emailuserfooter": "本电子邮件是通过{{SITENAME}}的“{{int:emailuser}}”功能被$1发送至$2的。",
+       "emailuserfooter": "本电子邮件是通过{{SITENAME}}的“{{int:emailuser}}”功能被$1{{GENDER:$1|发送}}至{{GENDER:$2|$2}}的。",
        "usermessage-summary": "留下系统消息。",
        "usermessage-editor": "系统信息编辑器",
        "watchlist": "监视列表",
        "deletepage": "删除页面",
        "confirm": "确认",
        "excontent": "内容:“$1”",
-       "excontentauthor": "内容:“$1”(唯一贡献者为“[[Special:Contributions/$2|$2]]”)",
+       "excontentauthor": "内容为:“$1”,唯一贡献者是“[[Special:Contributions/$2|$2]]”([[User talk:$2|讨论]])",
        "exbeforeblank": "被清空前的内容为:“$1”",
        "delete-confirm": "删除“$1”",
        "delete-legend": "删除",
        "logentry-newusers-byemail": "$1创建用户$3,并且密码已通过电子邮件发送",
        "logentry-newusers-autocreate": "用户账户$1被自动{{GENDER:$2|创建}}",
        "logentry-protect-move_prot": "$1将保护设置从$4{{GENDER:$2|移动}}到了$3",
+       "logentry-protect-unprotect": "$1{{GENDER:$2|移除了}}来自$3的保护",
+       "logentry-protect-protect": "$1{{GENDER:$2|保护了}}$3 $4",
+       "logentry-protect-protect-cascade": "$1{{GENDER:$2|保护了}}$3 $4[级联]",
+       "logentry-protect-modify": "$1{{GENDER:$2|更改了}}$3的保护等级$4",
+       "logentry-protect-modify-cascade": "$1{{GENDER:$2|更改了}}$3的保护等级$4[级联]",
        "logentry-rights-rights": "$1{{GENDER:$2|更改}}$3的用户组自$4至$5",
        "logentry-rights-rights-legacy": "$1更改$3的用户组",
        "logentry-rights-autopromote": "$1被自动地{{GENDER:$2|提升}}自$4至$5",
index f2ef8fd..c52a6d1 100644 (file)
@@ -62,7 +62,8 @@
                        "Cbliu",
                        "Citizen01",
                        "Zhxy 519",
-                       "Macofe"
+                       "Macofe",
+                       "578985s"
                ]
        },
        "tog-underline": "底線標示連結:",
        "nstab-template": "模板",
        "nstab-help": "說明頁面",
        "nstab-category": "分類",
+       "mainpage-nstab": "首頁",
        "nosuchaction": "無此動作",
        "nosuchactiontext": "URL 所指定的動作無效。\n您的 URL 可能輸入錯誤,或點選了錯誤的連結。\n這也可能是 {{SITENAME}} 使用的系統出現問題。",
        "nosuchspecialpage": "無此特殊頁面",
        "rcshowhideliu": "$1 已註冊的使用者",
        "rcshowhideliu-show": "顯示",
        "rcshowhideliu-hide": "隱藏",
-       "rcshowhideanons": "$1 匿名使用者",
+       "rcshowhideanons": "$1 匿名使用者",
        "rcshowhideanons-show": "顯示",
        "rcshowhideanons-hide": "隱藏",
        "rcshowhidepatr": "$1 巡查過的編輯",
        "upload-http-error": "發生 HTTP 錯誤:$1",
        "upload-copy-upload-invalid-domain": "此網域不允許複製上傳的檔案。",
        "upload-dialog-title": "上傳檔案",
-       "upload-dialog-error": "發生錯誤",
-       "upload-dialog-warning": "發生警告",
        "upload-dialog-button-cancel": "取消",
        "upload-dialog-button-done": "完成",
        "upload-dialog-button-save": "儲存",
        "upload-dialog-button-upload": "上傳",
-       "upload-dialog-label-select-file": "選擇檔案",
-       "upload-dialog-label-infoform-title": "詳細資訊",
-       "upload-dialog-label-infoform-name": "名稱",
-       "upload-dialog-label-infoform-description": "描述",
-       "upload-dialog-label-usage-title": "用法",
-       "upload-dialog-label-usage-filename": "檔案名稱",
+       "upload-process-error": "發生錯誤",
+       "upload-process-warning": "發生警告",
+       "upload-form-label-select-file": "選擇檔案",
+       "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": "檔案名稱",
        "backend-fail-stream": "無法傳輸檔案 \"$1\"。",
        "backend-fail-backup": "無法備份檔案 \"$1\"。",
        "backend-fail-notexists": "檔案 $1 不存在。",
index 4f84bfb..ccf040a 100644 (file)
@@ -33,8 +33,11 @@ $namespaceAliases = array(
        'Espezial' => NS_SPECIAL,
 );
 
-// Remove Spanish gender aliases (bug 37090)
-$namespaceGenderAliases = array();
+// T113890: Setting $namespaceGenderAliases for Aragonese (an)
+$namespaceGenderAliases = array(
+       NS_USER => array( 'male' => 'Usuario', 'female' => 'Usuaria' ),
+       NS_USER_TALK => array( 'male' => 'Descusión_usuario', 'female' => 'Descusión_usuaria' ),
+);
 
 $magicWords = array(
        'redirect'                  => array( '0', '#ENDRECERA', '#REENDRECERA', '#REDIRECCIÓN', '#REDIRECCION', '#REDIRECT' ),
index 9169f97..acd6ce0 100644 (file)
@@ -32,6 +32,11 @@ $namespaceAliases = array(
        'Imatge_Discussió' => NS_FILE_TALK,
 );
 
+$namespaceGenderAliases = array(
+       NS_USER => array( 'male' => 'Usuari', 'female' => 'Usuària' ),
+       NS_USER_TALK => array( 'male' => 'Usuari_Discussió', 'female' => 'Usuària_Discussió' ),
+); // T113616
+
 $specialPageAliases = array(
        'Activeusers'               => array( 'Usuaris_actius' ),
        'Allmessages'               => array( 'Missatges', 'MediaWiki' ),
index f90746c..4dedc47 100644 (file)
@@ -8,4 +8,4 @@
  *
  */
 
-$fallback = 'ne';
\ No newline at end of file
+$fallback = 'ne';
index dfd97f5..4e6c067 100644 (file)
@@ -29,13 +29,13 @@ $namespaceNames = array(
 
 $namespaceAliases = array(
        'Imagen' => NS_FILE,
-       'Imagen_Discusión' => NS_FILE_TALK,
+       'Imagen_discusión' => NS_FILE_TALK,
 );
 
 $namespaceGenderAliases = array(
        NS_USER => array( 'male' => 'Usuario', 'female' => 'Usuaria' ),
-       NS_USER_TALK => array( 'male' => 'Usuario_Discusión', 'female' => 'Usuaria_Discusión' ),
-);
+       NS_USER_TALK => array( 'male' => 'Usuario_discusión', 'female' => 'Usuaria_discusión' ),
+); // T113499
 
 $specialPageAliases = array(
        'Activeusers'               => array( 'UsuariosActivos' ),
index 1af959b..bc66a64 100644 (file)
@@ -8,7 +8,11 @@
  *
  */
 
+
+$fallback = 'es';
+
 $namespaceNames = array(
        NS_TEMPLATE         => 'Prantilla',
 );
 
+$namespaceGenderAliases = array();
diff --git a/languages/utils/CLDRPluralRuleConverter.php b/languages/utils/CLDRPluralRuleConverter.php
deleted file mode 100644 (file)
index 2eabcab..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * Helper class for converting rules to reverse polish notation (RPN).
- */
-class CLDRPluralRuleConverter {
-       /**
-        * The input string
-        *
-        * @var string
-        */
-       public $rule;
-
-       /**
-        * The current position
-        *
-        * @var int
-        */
-       public $pos;
-
-       /**
-        * The past-the-end position
-        *
-        * @var int
-        */
-       public $end;
-
-       /**
-        * The operator stack
-        *
-        * @var array
-        */
-       public $operators = array();
-
-       /**
-        * The operand stack
-        *
-        * @var array
-        */
-       public $operands = array();
-
-       /**
-        * Precedence levels. Note that there's no need to worry about associativity
-        * for the level 4 operators, since they return boolean and don't accept
-        * boolean inputs.
-        */
-       private static $precedence = array(
-               'or' => 2,
-               'and' => 3,
-               'is' => 4,
-               'is-not' => 4,
-               'in' => 4,
-               'not-in' => 4,
-               'within' => 4,
-               'not-within' => 4,
-               'mod' => 5,
-               ',' => 6,
-               '..' => 7,
-       );
-
-       /**
-        * A character list defining whitespace, for use in strspn() etc.
-        */
-       const WHITESPACE_CLASS = " \t\r\n";
-
-       /**
-        * Same for digits. Note that the grammar given in UTS #35 doesn't allow
-        * negative numbers or decimal separators.
-        */
-       const NUMBER_CLASS = '0123456789';
-
-       /**
-        * A character list of symbolic operands.
-        */
-       const OPERAND_SYMBOLS = 'nivwft';
-
-       /**
-        * An anchored regular expression which matches a word at the current offset.
-        */
-       const WORD_REGEX = '/[a-zA-Z@]+/A';
-
-       /**
-        * Convert a rule to RPN. This is the only public entry point.
-        *
-        * @param string $rule The rule to convert
-        * @return string The RPN representation of the rule
-        */
-       public static function convert( $rule ) {
-               $parser = new self( $rule );
-
-               return $parser->doConvert();
-       }
-
-       /**
-        * Private constructor.
-        * @param string $rule
-        */
-       protected function __construct( $rule ) {
-               $this->rule = $rule;
-               $this->pos = 0;
-               $this->end = strlen( $rule );
-       }
-
-       /**
-        * Do the operation.
-        *
-        * @return string The RPN representation of the rule (e.g. "5 3 mod n is")
-        */
-       protected function doConvert() {
-               $expectOperator = true;
-
-               // Iterate through all tokens, saving the operators and operands to a
-               // stack per Dijkstra's shunting yard algorithm.
-               /** @var CLDRPluralRuleConverterOperator $token */
-               while ( false !== ( $token = $this->nextToken() ) ) {
-                       // In this grammar, there are only binary operators, so every valid
-                       // rule string will alternate between operator and operand tokens.
-                       $expectOperator = !$expectOperator;
-
-                       if ( $token instanceof CLDRPluralRuleConverterExpression ) {
-                               // Operand
-                               if ( $expectOperator ) {
-                                       $token->error( 'unexpected operand' );
-                               }
-                               $this->operands[] = $token;
-                               continue;
-                       } else {
-                               // Operator
-                               if ( !$expectOperator ) {
-                                       $token->error( 'unexpected operator' );
-                               }
-                               // Resolve higher precedence levels
-                               $lastOp = end( $this->operators );
-                               while ( $lastOp && self::$precedence[$token->name] <= self::$precedence[$lastOp->name] ) {
-                                       $this->doOperation( $lastOp, $this->operands );
-                                       array_pop( $this->operators );
-                                       $lastOp = end( $this->operators );
-                               }
-                               $this->operators[] = $token;
-                       }
-               }
-
-               // Finish off the stack
-               while ( $op = array_pop( $this->operators ) ) {
-                       $this->doOperation( $op, $this->operands );
-               }
-
-               // Make sure the result is sane. The first case is possible for an empty
-               // string input, the second should be unreachable.
-               if ( !count( $this->operands ) ) {
-                       $this->error( 'condition expected' );
-               } elseif ( count( $this->operands ) > 1 ) {
-                       $this->error( 'missing operator or too many operands' );
-               }
-
-               $value = $this->operands[0];
-               if ( $value->type !== 'boolean' ) {
-                       $this->error( 'the result must have a boolean type' );
-               }
-
-               return $this->operands[0]->rpn;
-       }
-
-       /**
-        * Fetch the next token from the input string.
-        *
-        * @return CLDRPluralRuleConverterFragment The next token
-        */
-       protected function nextToken() {
-               if ( $this->pos >= $this->end ) {
-                       return false;
-               }
-
-               // Whitespace
-               $length = strspn( $this->rule, self::WHITESPACE_CLASS, $this->pos );
-               $this->pos += $length;
-
-               if ( $this->pos >= $this->end ) {
-                       return false;
-               }
-
-               // Number
-               $length = strspn( $this->rule, self::NUMBER_CLASS, $this->pos );
-               if ( $length !== 0 ) {
-                       $token = $this->newNumber( substr( $this->rule, $this->pos, $length ), $this->pos );
-                       $this->pos += $length;
-
-                       return $token;
-               }
-
-               // Two-character operators
-               $op2 = substr( $this->rule, $this->pos, 2 );
-               if ( $op2 === '..' || $op2 === '!=' ) {
-                       $token = $this->newOperator( $op2, $this->pos, 2 );
-                       $this->pos += 2;
-
-                       return $token;
-               }
-
-               // Single-character operators
-               $op1 = $this->rule[$this->pos];
-               if ( $op1 === ',' || $op1 === '=' || $op1 === '%' ) {
-                       $token = $this->newOperator( $op1, $this->pos, 1 );
-                       $this->pos++;
-
-                       return $token;
-               }
-
-               // Word
-               if ( !preg_match( self::WORD_REGEX, $this->rule, $m, 0, $this->pos ) ) {
-                       $this->error( 'unexpected character "' . $this->rule[$this->pos] . '"' );
-               }
-               $word1 = strtolower( $m[0] );
-               $word2 = '';
-               $nextTokenPos = $this->pos + strlen( $word1 );
-               if ( $word1 === 'not' || $word1 === 'is' ) {
-                       // Look ahead one word
-                       $nextTokenPos += strspn( $this->rule, self::WHITESPACE_CLASS, $nextTokenPos );
-                       if ( $nextTokenPos < $this->end
-                               && preg_match( self::WORD_REGEX, $this->rule, $m, 0, $nextTokenPos )
-                       ) {
-                               $word2 = strtolower( $m[0] );
-                               $nextTokenPos += strlen( $word2 );
-                       }
-               }
-
-               // Two-word operators like "is not" take precedence over single-word operators like "is"
-               if ( $word2 !== '' ) {
-                       $bothWords = "{$word1}-{$word2}";
-                       if ( isset( self::$precedence[$bothWords] ) ) {
-                               $token = $this->newOperator( $bothWords, $this->pos, $nextTokenPos - $this->pos );
-                               $this->pos = $nextTokenPos;
-
-                               return $token;
-                       }
-               }
-
-               // Single-word operators
-               if ( isset( self::$precedence[$word1] ) ) {
-                       $token = $this->newOperator( $word1, $this->pos, strlen( $word1 ) );
-                       $this->pos += strlen( $word1 );
-
-                       return $token;
-               }
-
-               // The single-character operand symbols
-               if ( strpos( self::OPERAND_SYMBOLS, $word1 ) !== false ) {
-                       $token = $this->newNumber( $word1, $this->pos );
-                       $this->pos++;
-
-                       return $token;
-               }
-
-               // Samples
-               if ( $word1 === '@integer' || $word1 === '@decimal' ) {
-                       // Samples are like comments, they have no effect on rule evaluation.
-                       // They run from the first sample indicator to the end of the string.
-                       $this->pos = $this->end;
-
-                       return false;
-               }
-
-               $this->error( 'unrecognised word' );
-       }
-
-       /**
-        * For the binary operator $op, pop its operands off the stack and push
-        * a fragment with rpn and type members describing the result of that
-        * operation.
-        *
-        * @param CLDRPluralRuleConverterOperator $op
-        */
-       protected function doOperation( $op ) {
-               if ( count( $this->operands ) < 2 ) {
-                       $op->error( 'missing operand' );
-               }
-               $right = array_pop( $this->operands );
-               $left = array_pop( $this->operands );
-               $result = $op->operate( $left, $right );
-               $this->operands[] = $result;
-       }
-
-       /**
-        * Create a numerical expression object
-        *
-        * @param string $text
-        * @param int $pos
-        * @return CLDRPluralRuleConverterExpression The numerical expression
-        */
-       protected function newNumber( $text, $pos ) {
-               return new CLDRPluralRuleConverterExpression( $this, 'number', $text, $pos, strlen( $text ) );
-       }
-
-       /**
-        * Create a binary operator
-        *
-        * @param string $type
-        * @param int $pos
-        * @param int $length
-        * @return CLDRPluralRuleConverterOperator The operator
-        */
-       protected function newOperator( $type, $pos, $length ) {
-               return new CLDRPluralRuleConverterOperator( $this, $type, $pos, $length );
-       }
-
-       /**
-        * Throw an error
-        * @param string $message
-        */
-       protected function error( $message ) {
-               throw new CLDRPluralRuleError( $message );
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleConverterExpression.php b/languages/utils/CLDRPluralRuleConverterExpression.php
deleted file mode 100644 (file)
index 1ee6b4c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * Helper for CLDRPluralRuleConverter.
- * An expression object, representing a region of the input string (for error
- * messages), the RPN notation used to evaluate it, and the result type for
- * validation.
- */
-class CLDRPluralRuleConverterExpression extends CLDRPluralRuleConverterFragment {
-       /** @var string */
-       public $type;
-
-       /** @var string */
-       public $rpn;
-
-       function __construct( $parser, $type, $rpn, $pos, $length ) {
-               parent::__construct( $parser, $pos, $length );
-               $this->type = $type;
-               $this->rpn = $rpn;
-       }
-
-       public function isType( $type ) {
-               if ( $type === 'range' && ( $this->type === 'range' || $this->type === 'number' ) ) {
-                       return true;
-               }
-               if ( $type === $this->type ) {
-                       return true;
-               }
-
-               return false;
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleConverterFragment.php b/languages/utils/CLDRPluralRuleConverterFragment.php
deleted file mode 100644 (file)
index df299cb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * Helper for CLDRPluralRuleConverter.
- * The base class for operators and expressions, describing a region of the input string.
- */
-class CLDRPluralRuleConverterFragment {
-       public $parser, $pos, $length, $end;
-
-       function __construct( $parser, $pos, $length ) {
-               $this->parser = $parser;
-               $this->pos = $pos;
-               $this->length = $length;
-               $this->end = $pos + $length;
-       }
-
-       public function error( $message ) {
-               $text = $this->getText();
-               throw new CLDRPluralRuleError( "$message at position " . ( $this->pos + 1 ) . ": \"$text\"" );
-       }
-
-       public function getText() {
-               return substr( $this->parser->rule, $this->pos, $this->length );
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleConverterOperator.php b/languages/utils/CLDRPluralRuleConverterOperator.php
deleted file mode 100644 (file)
index de17f29..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * Helper for CLDRPluralRuleConverter.
- * An operator object, representing a region of the input string (for error
- * messages), and the binary operator at that location.
- */
-class CLDRPluralRuleConverterOperator extends CLDRPluralRuleConverterFragment {
-       /** @var string The name */
-       public $name;
-
-       /**
-        * Each op type has three characters: left operand type, right operand type and result type
-        *
-        *   b = boolean
-        *   n = number
-        *   r = range
-        *
-        * A number is a kind of range.
-        *
-        * @var array
-        */
-       private static $opTypes = array(
-               'or' => 'bbb',
-               'and' => 'bbb',
-               'is' => 'nnb',
-               'is-not' => 'nnb',
-               'in' => 'nrb',
-               'not-in' => 'nrb',
-               'within' => 'nrb',
-               'not-within' => 'nrb',
-               'mod' => 'nnn',
-               ',' => 'rrr',
-               '..' => 'nnr',
-       );
-
-       /**
-        * Map converting from the abbrevation to the full form.
-        *
-        * @var array
-        */
-       private static $typeSpecMap = array(
-               'b' => 'boolean',
-               'n' => 'number',
-               'r' => 'range',
-       );
-
-       /**
-        * Map for converting the new operators introduced in Rev 33 to the old forms
-        */
-       private static $aliasMap = array(
-               '%' => 'mod',
-               '!=' => 'not-in',
-               '=' => 'in'
-       );
-
-       /**
-        * Initialize a new instance of a CLDRPluralRuleConverterOperator object
-        *
-        * @param CLDRPluralRuleConverter $parser The parser
-        * @param string $name The operator name
-        * @param int $pos The length
-        * @param int $length
-        */
-       function __construct( $parser, $name, $pos, $length ) {
-               parent::__construct( $parser, $pos, $length );
-               if ( isset( self::$aliasMap[$name] ) ) {
-                       $name = self::$aliasMap[$name];
-               }
-               $this->name = $name;
-       }
-
-       /**
-        * Compute the operation
-        *
-        * @param CLDRPluralRuleConverterExpression $left The left part of the expression
-        * @param CLDRPluralRuleConverterExpression $right The right part of the expression
-        * @return CLDRPluralRuleConverterExpression The result of the operation
-        */
-       public function operate( $left, $right ) {
-               $typeSpec = self::$opTypes[$this->name];
-
-               $leftType = self::$typeSpecMap[$typeSpec[0]];
-               $rightType = self::$typeSpecMap[$typeSpec[1]];
-               $resultType = self::$typeSpecMap[$typeSpec[2]];
-
-               $start = min( $this->pos, $left->pos, $right->pos );
-               $end = max( $this->end, $left->end, $right->end );
-               $length = $end - $start;
-
-               $newExpr = new CLDRPluralRuleConverterExpression( $this->parser, $resultType,
-                       "{$left->rpn} {$right->rpn} {$this->name}",
-                       $start, $length );
-
-               if ( !$left->isType( $leftType ) ) {
-                       $newExpr->error( "invalid type for left operand: expected $leftType, got {$left->type}" );
-               }
-
-               if ( !$right->isType( $rightType ) ) {
-                       $newExpr->error( "invalid type for right operand: expected $rightType, got {$right->type}" );
-               }
-
-               return $newExpr;
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleError.php b/languages/utils/CLDRPluralRuleError.php
deleted file mode 100644 (file)
index cc0b5d2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * The exception class for all the classes in this file. This will be thrown
- * back to the caller if there is any validation error.
- */
-class CLDRPluralRuleError extends MWException {
-       function __construct( $message ) {
-               parent::__construct( 'CLDR plural rule error: ' . $message );
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleEvaluator.php b/languages/utils/CLDRPluralRuleEvaluator.php
deleted file mode 100644 (file)
index 7e7208a..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-
-/**
- * Parse and evaluate a plural rule.
- *
- * UTS #35 Revision 33
- * http://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Language_Plural_Rules
- *
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0
- * or later
- *
- * 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
- * @since 1.20
- */
-class CLDRPluralRuleEvaluator {
-       /**
-        * Evaluate a number against a set of plural rules. If a rule passes,
-        * return the index of plural rule.
-        *
-        * @param int $number The number to be evaluated against the rules
-        * @param array $rules The associative array of plural rules in pluralform => rule format.
-        * @return int The index of the plural form which passed the evaluation
-        */
-       public static function evaluate( $number, array $rules ) {
-               $rules = self::compile( $rules );
-
-               return self::evaluateCompiled( $number, $rules );
-       }
-
-       /**
-        * Convert a set of rules to a compiled form which is optimised for
-        * fast evaluation. The result will be an array of strings, and may be cached.
-        *
-        * @param array $rules The rules to compile
-        * @return array An array of compile rules.
-        */
-       public static function compile( array $rules ) {
-               // We can't use array_map() for this because it generates a warning if
-               // there is an exception.
-               foreach ( $rules as &$rule ) {
-                       $rule = CLDRPluralRuleConverter::convert( $rule );
-               }
-
-               return $rules;
-       }
-
-       /**
-        * Evaluate a compiled set of rules returned by compile(). Do not allow
-        * the user to edit the compiled form, or else PHP errors may result.
-        *
-        * @param string $number The number to be evaluated against the rules, in English, or it
-        *   may be a type convertible to string.
-        * @param array $rules The associative array of plural rules in pluralform => rule format.
-        * @return int The index of the plural form which passed the evaluation
-        */
-       public static function evaluateCompiled( $number, array $rules ) {
-               // Calculate the values of the operand symbols
-               $number = strval( $number );
-               if ( !preg_match( '/^ -? ( ([0-9]+) (?: \. ([0-9]+) )? )$/x', $number, $m ) ) {
-                       wfDebug( __METHOD__ . ": invalid number input, returning 'other'\n" );
-
-                       return count( $rules );
-               }
-               if ( !isset( $m[3] ) ) {
-                       $operandSymbols = array(
-                               'n' => intval( $m[1] ),
-                               'i' => intval( $m[1] ),
-                               'v' => 0,
-                               'w' => 0,
-                               'f' => 0,
-                               't' => 0
-                       );
-               } else {
-                       $absValStr = $m[1];
-                       $intStr = $m[2];
-                       $fracStr = $m[3];
-                       $operandSymbols = array(
-                               'n' => floatval( $absValStr ),
-                               'i' => intval( $intStr ),
-                               'v' => strlen( $fracStr ),
-                               'w' => strlen( rtrim( $fracStr, '0' ) ),
-                               'f' => intval( $fracStr ),
-                               't' => intval( rtrim( $fracStr, '0' ) ),
-                       );
-               }
-
-               // The compiled form is RPN, with tokens strictly delimited by
-               // spaces, so this is a simple RPN evaluator.
-               foreach ( $rules as $i => $rule ) {
-                       $stack = array();
-                       $zero = ord( '0' );
-                       $nine = ord( '9' );
-                       foreach ( StringUtils::explode( ' ', $rule ) as $token ) {
-                               $ord = ord( $token );
-                               if ( isset( $operandSymbols[$token] ) ) {
-                                       $stack[] = $operandSymbols[$token];
-                               } elseif ( $ord >= $zero && $ord <= $nine ) {
-                                       $stack[] = intval( $token );
-                               } else {
-                                       $right = array_pop( $stack );
-                                       $left = array_pop( $stack );
-                                       $result = self::doOperation( $token, $left, $right );
-                                       $stack[] = $result;
-                               }
-                       }
-                       if ( $stack[0] ) {
-                               return $i;
-                       }
-               }
-               // None of the provided rules match. The number belongs to category
-               // 'other', which comes last.
-               return count( $rules );
-       }
-
-       /**
-        * Do a single operation
-        *
-        * @param string $token The token string
-        * @param mixed $left The left operand. If it is an object, its state may be destroyed.
-        * @param mixed $right The right operand
-        * @throws CLDRPluralRuleError
-        * @return mixed The operation result
-        */
-       private static function doOperation( $token, $left, $right ) {
-               if ( in_array( $token, array( 'in', 'not-in', 'within', 'not-within' ) ) ) {
-                       if ( !( $right instanceof CLDRPluralRuleEvaluatorRange ) ) {
-                               $right = new CLDRPluralRuleEvaluatorRange( $right );
-                       }
-               }
-               switch ( $token ) {
-                       case 'or':
-                               return $left || $right;
-                       case 'and':
-                               return $left && $right;
-                       case 'is':
-                               return $left == $right;
-                       case 'is-not':
-                               return $left != $right;
-                       case 'in':
-                               return $right->isNumberIn( $left );
-                       case 'not-in':
-                               return !$right->isNumberIn( $left );
-                       case 'within':
-                               return $right->isNumberWithin( $left );
-                       case 'not-within':
-                               return !$right->isNumberWithin( $left );
-                       case 'mod':
-                               if ( is_int( $left ) ) {
-                                       return (int)fmod( $left, $right );
-                               }
-
-                               return fmod( $left, $right );
-                       case ',':
-                               if ( $left instanceof CLDRPluralRuleEvaluatorRange ) {
-                                       $range = $left;
-                               } else {
-                                       $range = new CLDRPluralRuleEvaluatorRange( $left );
-                               }
-                               $range->add( $right );
-
-                               return $range;
-                       case '..':
-                               return new CLDRPluralRuleEvaluatorRange( $left, $right );
-                       default:
-                               throw new CLDRPluralRuleError( "Invalid RPN token" );
-               }
-       }
-}
diff --git a/languages/utils/CLDRPluralRuleEvaluatorRange.php b/languages/utils/CLDRPluralRuleEvaluatorRange.php
deleted file mode 100644 (file)
index 996c22e..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström, Tim Starling
- *
- * @copyright Copyright © 2010-2012, Niklas Laxström
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- *
- * @file
- * @since 1.20
- */
-
-/**
- * Evaluator helper class representing a range list.
- */
-class CLDRPluralRuleEvaluatorRange {
-       /**
-        * The parts
-        *
-        * @var array
-        */
-       public $parts = array();
-
-       /**
-        * Initialize a new instance of CLDRPluralRuleEvaluatorRange
-        *
-        * @param int $start The start of the range
-        * @param int|bool $end The end of the range, or false if the range is not bounded.
-        */
-       function __construct( $start, $end = false ) {
-               if ( $end === false ) {
-                       $this->parts[] = $start;
-               } else {
-                       $this->parts[] = array( $start, $end );
-               }
-       }
-
-       /**
-        * Determine if the given number is inside the range.
-        *
-        * @param int $number The number to check
-        * @param bool $integerConstraint If true, also asserts the number is an integer;
-        *   otherwise, number simply has to be inside the range.
-        * @return bool True if the number is inside the range; otherwise, false.
-        */
-       function isNumberIn( $number, $integerConstraint = true ) {
-               foreach ( $this->parts as $part ) {
-                       if ( is_array( $part ) ) {
-                               if ( ( !$integerConstraint || floor( $number ) === (float)$number )
-                                       && $number >= $part[0] && $number <= $part[1]
-                               ) {
-                                       return true;
-                               }
-                       } else {
-                               if ( $number == $part ) {
-                                       return true;
-                               }
-                       }
-               }
-
-               return false;
-       }
-
-       /**
-        * Readable alias for isNumberIn( $number, false ), and the implementation
-        * of the "within" operator.
-        *
-        * @param int $number The number to check
-        * @return bool True if the number is inside the range; otherwise, false.
-        */
-       function isNumberWithin( $number ) {
-               return $this->isNumberIn( $number, false );
-       }
-
-       /**
-        * Add another part to this range.
-        *
-        * @param CLDRPluralRuleEvaluatorRange|int $other The part to add, either
-        *   a range object itself or a single number.
-        */
-       function add( $other ) {
-               if ( $other instanceof self ) {
-                       $this->parts = array_merge( $this->parts, $other->parts );
-               } else {
-                       $this->parts[] = $other;
-               }
-       }
-
-       /**
-        * Returns the string representation of the rule evaluator range.
-        * The purpose of this method is to help debugging.
-        *
-        * @return string The string representation of the rule evaluator range
-        */
-       function __toString() {
-               $s = 'Range(';
-               foreach ( $this->parts as $i => $part ) {
-                       if ( $i ) {
-                               $s .= ', ';
-                       }
-                       if ( is_array( $part ) ) {
-                               $s .= $part[0] . '..' . $part[1];
-                       } else {
-                               $s .= $part;
-                       }
-               }
-               $s .= ')';
-
-               return $s;
-       }
-}
index 04aa3a5..8dad5dc 100644 (file)
@@ -460,7 +460,7 @@ abstract class Maintenance {
                }
 
                # Save additional script dependant options to display
-               # them separately in help
+               #  them separately in help
                $this->mDependantParameters = array_diff_key( $this->mParams, $this->mGenericParameters );
        }
 
@@ -1108,7 +1108,15 @@ abstract class Maintenance {
         */
        private function lockSearchindex( $db ) {
                $write = array( 'searchindex' );
-               $read = array( 'page', 'revision', 'text', 'interwiki', 'l10n_cache', 'user', 'page_restrictions' );
+               $read = array(
+                       'page',
+                       'revision',
+                       'text',
+                       'interwiki',
+                       'l10n_cache',
+                       'user',
+                       'page_restrictions'
+               );
                $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
        }
 
index 3b3fdee..f3b9c3c 100644 (file)
@@ -1,3 +1,3 @@
 -- Hopefully temporary index.
--- For https://bugzilla.wikimedia.org/show_bug.cgi?id=21279
+-- For https://phabricator.wikimedia.org/T23279
 CREATE INDEX /*i*/ar_revid ON /*$wgDBprefix*/archive ( ar_rev_id );
\ No newline at end of file
index 22cc587..9a991b8 100644 (file)
@@ -1,7 +1,7 @@
 --
 -- patch-backlinkindexes.sql
 --
--- Per bug 6440 / http://bugzilla.wikimedia.org/show_bug.cgi?id=6440
+-- Per task T8440 / https://phabricator.wikimedia.org/T8440
 --
 -- Improve performance of the "what links here"-type queries
 --
index 24ad84f..e2b2c3a 100644 (file)
@@ -1,7 +1,7 @@
 --
 -- patch-categorylinksindex.sql
 --
--- Per bug 10280 / http://bugzilla.wikimedia.org/show_bug.cgi?id=10280
+-- Per task T12280 / https://phabricator.wikimedia.org/T12280
 --
 -- Improve enum continuation performance of the what pages belong to a category query
 --
index 7bfb734..265800e 100644 (file)
@@ -193,7 +193,7 @@ class BaseDump {
                while ( $this->reader->read() ) {
                        switch ( $this->reader->nodeType ) {
                                case XMLReader::TEXT:
-                               //case XMLReader::WHITESPACE:
+                               // case XMLReader::WHITESPACE:
                                case XMLReader::SIGNIFICANT_WHITESPACE:
                                        $buffer .= $this->reader->value;
                                        break;
index 27be5fd..11a0590 100644 (file)
@@ -464,8 +464,9 @@ class TextPassDumper extends BackupDumper {
         * is thrown.
         *
         * @param string $id The revision id to get the text for
-        * @param string|bool|null $model The content model used to determine applicable export transformations.
-        *      If $model is null, it will be determined from the database.
+        * @param string|bool|null $model The content model used to determine
+        *  applicable export transformations.
+        *  If $model is null, it will be determined from the database.
         * @param string|null $format The content format used when applying export transformations.
         *
         * @throws MWException
index 4772071..7a85d64 100644 (file)
@@ -12,7 +12,8 @@ require_once __DIR__ . '/Maintenance.php';
 class CheckComposerLockUpToDate extends Maintenance {
        public function __construct() {
                parent::__construct();
-               $this->mDescription = 'Checks whether your composer.lock file is up to date with the current composer.json';
+               $this->mDescription =
+                       'Checks whether your composer.lock file is up to date with the current composer.json';
        }
 
        public function execute() {
@@ -23,7 +24,10 @@ class CheckComposerLockUpToDate extends Maintenance {
                        // Maybe they're using mediawiki/vendor?
                        $lockLocation = "$IP/vendor/composer.lock";
                        if ( !file_exists( $lockLocation ) ) {
-                               $this->error( 'Could not find composer.lock file. Have you run "composer install"?', 1 );
+                               $this->error(
+                                       'Could not find composer.lock file. Have you run "composer install"?',
+                                       1
+                               );
                        }
                }
 
@@ -40,7 +44,9 @@ class CheckComposerLockUpToDate extends Maintenance {
                foreach ( $json->getRequiredDependencies() as $name => $version ) {
                        if ( isset( $installed[$name] ) ) {
                                if ( $installed[$name]['version'] !== $version ) {
-                                       $this->output( "$name: {$installed[$name]['version']} installed, $version required.\n" );
+                                       $this->output(
+                                               "$name: {$installed[$name]['version']} installed, $version required.\n"
+                                       );
                                        $found = true;
                                }
                        } else {
@@ -49,9 +55,14 @@ class CheckComposerLockUpToDate extends Maintenance {
                        }
                }
                if ( $found ) {
-                       $this->error( 'Error: your composer.lock file is not up to date, run "composer update" to install newer dependencies', 1 );
+                       $this->error(
+                               'Error: your composer.lock file is not up to date. ' .
+                                       'Run "composer update" to install newer dependencies',
+                               1
+                       );
                } else {
-                       // The hash is the entire composer.json file, so it can be updated without any of the dependencies changing
+                       // The hash is the entire composer.json file,
+                       // so it can be updated without any of the dependencies changing
                        // We couldn't find any out-of-date dependencies, so assume everything is ok!
                        $this->output( "Your composer.lock file is up to date with current dependencies!\n" );
                }
index 06ae17f..4e19b79 100644 (file)
@@ -19,7 +19,7 @@
  *
  * @file
  * @author TyA <tya.wiki@gmail.com>
- * @see [[bugzilla:30976]]
+ * @see https://phabricator.wikimedia.org/T32976
  * @ingroup Maintenance
  */
 
index 221ebe3..c3ad46a 100644 (file)
@@ -215,7 +215,7 @@ class ConvertLinks extends Maintenance {
                                }
                                $dbw->freeResult( $res );
                                # $this->output( "rowOffset: $rowOffset\ttuplesAdded: "
-                               #       . "$tuplesAdded\tnumBadLinks: $numBadLinks\n" );
+                               #       . "$tuplesAdded\tnumBadLinks: $numBadLinks\n" );
                                if ( $tuplesAdded != 0 ) {
                                        if ( $reportLinksConvProgress ) {
                                                $this->output( "Inserting $tuplesAdded tuples into $links_temp..." );
index dd4f760..983b772 100644 (file)
@@ -32,8 +32,9 @@ require_once __DIR__ . '/Maintenance.php';
 class FetchText extends Maintenance {
        public function __construct() {
                parent::__construct();
-               $this->mDescription = "Fetch the raw revision blob from an old_id.";
-               $this->mDescription .= "\nNOTE: Export transformations are NOT applied. This is left to backupTextPass.php";
+               $this->mDescription = "Fetch the raw revision blob from an old_id.\n" .
+                       "NOTE: Export transformations are NOT applied. " .
+                       "This is left to backupTextPass.php";
        }
 
        /**
index 114366b..0925406 100644 (file)
@@ -190,7 +190,11 @@ class FindHooks extends Maintenance {
 
                $retval = array();
                while ( true ) {
-                       $json = Http::get( wfAppendQuery( 'http://www.mediawiki.org/w/api.php', $params ), array(), __METHOD__ );
+                       $json = Http::get(
+                               wfAppendQuery( 'http://www.mediawiki.org/w/api.php', $params ),
+                               array(),
+                               __METHOD__
+                       );
                        $data = FormatJson::decode( $json, true );
                        foreach ( $data['query']['categorymembers'] as $page ) {
                                if ( preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $m ) ) {
index 3f5d6b6..7bca0ec 100644 (file)
@@ -178,7 +178,7 @@ class PopulateContentModel extends Maintenance {
                                        if ( $dbFormat === $defaultFormat ) {
                                                $toSave[$defaultModel][] = $row->{$key};
                                        } else { // non-default format, just update now
-                                               $this->output( "Updating model to match format for $table $id of $title... ");
+                                               $this->output( "Updating model to match format for $table $id of $title... " );
                                                $dbw->update(
                                                        $table,
                                                        array( $model_column => $defaultModel ),
index e1710c1..4d38710 100644 (file)
@@ -212,7 +212,7 @@ class PPFuzzTest {
 
        function getReport() {
                $s = "Title: " . $this->title->getPrefixedDBkey() . "\n" .
-//                     "Output type: {$this->outputType}\n" .
+//                     "Output type: {$this->outputType}\n" .
                        "Entry point: {$this->entryPoint}\n" .
                        "User: " . ( $this->fancySig ? 'fancy' : 'no-fancy' ) .
                        ' ' . var_export( $this->nickname, true ) . "\n" .
index 8e39978..b1bb353 100644 (file)
@@ -48,7 +48,7 @@ class ImageBuilder extends Maintenance {
                parent::__construct();
 
                global $wgUpdateCompatibleMetadata;
-               //make sure to update old, but compatible img_metadata fields.
+               // make sure to update old, but compatible img_metadata fields.
                $wgUpdateCompatibleMetadata = true;
 
                $this->mDescription = 'Script to update image metadata records';
index 3cb4a2b..16c676d 100644 (file)
@@ -189,7 +189,7 @@ class CompressOld extends Maintenance {
                if ( false !== strpos( $row->old_flags, 'gzip' )
                        || false !== strpos( $row->old_flags, 'object' )
                ) {
-                       #print "Already compressed row {$row->old_id}\n";
+                       # print "Already compressed row {$row->old_id}\n";
                        return false;
                }
                $dbw = wfGetDB( DB_MASTER );
@@ -303,8 +303,8 @@ class CompressOld extends Maintenance {
 
                # Don't work with current revisions
                # Don't lock the page table for update either -- TS 2006-04-04
-               #$tables[] = 'page';
-               #$conds[] = 'page_id=rev_page AND rev_id != page_latest';
+               # $tables[] = 'page';
+               # $conds[] = 'page_id=rev_page AND rev_id != page_latest';
 
                for ( $pageId = $startId; $pageId <= $maxPageId; $pageId++ ) {
                        wfWaitForSlaves();
@@ -384,7 +384,7 @@ class CompressOld extends Maintenance {
 
                                        if ( $text === false ) {
                                                $this->error( "\nError, unable to get text in old_id $oldid" );
-                                               #$dbw->delete( 'old', array( 'old_id' => $oldid ) );
+                                               # $dbw->delete( 'old', array( 'old_id' => $oldid ) );
                                        }
 
                                        if ( $extdb == "" && $j == 0 ) {
index d2dc213..fb637f7 100644 (file)
                }
 
                // Set up the help system
-               $( '.mw-help-field-data' )
+               $( '.config-help-field-data' )
                        .hide()
-                       .closest( '.mw-help-field-container' )
-                               .find( '.mw-help-field-hint' )
+                       .closest( '.config-help-field-container' )
+                               .find( '.config-help-field-hint' )
                                        .show()
                                        .click( function () {
                                                $( this )
-                                                       .closest( '.mw-help-field-container' )
-                                                               .find( '.mw-help-field-data' )
+                                                       .closest( '.config-help-field-container' )
+                                                               .find( '.config-help-field-data' )
                                                                        .slideToggle( 'fast' );
                                        } );
 
index 9b2fd4c..d48a5e0 100644 (file)
@@ -1,6 +1,5 @@
 {
-  "name": "mediawiki",
-  "version": "0.0.0",
+  "private": true,
   "scripts": {
     "test": "grunt test",
     "doc": "jsduck",
index 36ad394..04e8949 100644 (file)
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -1,6 +1,24 @@
 <?xml version="1.0"?>
 <ruleset name="MediaWiki">
-       <rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki"/>
+       <rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
+               <!-- Disable failing rules -->
+               <exclude name="Generic.Files.LineLength"/>
+               <exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
+               <exclude name="MediaWiki.NamingConventions.PrefixedGlobalFunctions.wfPrefix"/>
+               <exclude name="Squiz.Classes.ValidClassName.NotCamelCaps"/>
+               <exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed"/>
+               <exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.EmptyComment"/>
+       </rule>
+       <rule ref="MediaWiki.NamingConventions.PrefixedGlobalFunctions">
+               <properties>
+                       <property name="ignoreList" type="array" value="bfNormalizeTitleStrReplace,bfNormalizeTitleStrTr,cdbShowHelp,codepointToUtf8,compare_point,cssfilter,escapeSingleString,findAuxFile,findFiles,getEscapedProfileUrl,getFileCommentFromSourceWiki,getFileUserFromSourceWiki,hexSequenceToUtf8,mccGetHelp,mccShowUsage,mimeTypeMatch,moveToExternal,NothingFunction,NothingFunctionData,resolveStub,resolveStubs,showUsage,splitFilename,utf8ToCodepoint,utf8ToHexSequence" />
+               </properties>
+       </rule>
+       <rule ref="MediaWiki.NamingConventions.ValidGlobalName">
+               <properties>
+                       <property name="ignoreList" type="array" value="$IP,$messageMemc,$parserMemc" />
+               </properties>
+       </rule>
        <file>.</file>
        <arg name="encoding" value="utf8"/>
        <arg name="extensions" value="php,php5,inc,sample"/>
index f172cfb..f44ee5a 100644 (file)
@@ -320,7 +320,13 @@ if ( isset( $_REQUEST['sort'] ) && in_array( $_REQUEST['sort'], $sorts ) ) {
        $sort = $_REQUEST['sort'];
 }
 
-$res = $dbr->select( 'profiling', '*', array(), 'profileinfo.php', array( 'ORDER BY' => 'pf_name ASC' ) );
+$res = $dbr->select(
+       'profiling',
+       '*',
+       array(),
+       'profileinfo.php',
+       array( 'ORDER BY' => 'pf_name ASC' )
+);
 
 if ( isset( $_REQUEST['filter'] ) ) {
        $filter = $_REQUEST['filter'];
@@ -333,7 +339,9 @@ if ( isset( $_REQUEST['filter'] ) ) {
        <p>
                <input type="text" name="filter" value="<?php echo htmlspecialchars( $filter ); ?>">
                <input type="hidden" name="sort" value="<?php echo htmlspecialchars( $sort ); ?>">
-               <input type="hidden" name="expand" value="<?php echo htmlspecialchars( implode( ",", array_keys( $expand ) ) ); ?>">
+               <input type="hidden" name="expand" value="<?php
+                       echo htmlspecialchars( implode( ",", array_keys( $expand ) ) );
+               ?>">
                <input type="submit" value="Filter">
        </p>
 </form>
@@ -341,15 +349,33 @@ if ( isset( $_REQUEST['filter'] ) ) {
 <table class="mw-profileinfo-table table table-striped table-hover">
        <thead>
        <tr>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'name' ); ?>">Name</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'time' ); ?>">Time (%)</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'memory' ); ?>">Memory (%)</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'count' ); ?>">Count</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'calls_per_req' ); ?>">Calls/req</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_call' ); ?>">ms/call</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_call' ); ?>">kb/call</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_req' ); ?>">ms/req</a></th>
-               <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_req' ); ?>">kb/req</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'name' );
+               ?>">Name</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'time' );
+               ?>">Time (%)</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'memory' );
+               ?>">Memory (%)</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'count' );
+               ?>">Count</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'calls_per_req' );
+               ?>">Calls/req</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'time_per_call' );
+               ?>">ms/call</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'memory_per_call' );
+               ?>">kb/call</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'time_per_req' );
+               ?>">ms/req</a></th>
+               <th><a href="<?php
+                       echo getEscapedProfileUrl( false, 'memory_per_req' );
+               ?>">kb/req</a></th>
        </tr>
        </thead>
        <tbody>
index b35ebad..335775f 100644 (file)
@@ -1381,7 +1381,8 @@ return array(
        ),
        'mediawiki.action.view.filepage' => array(
                'styles' => array(
-                       'resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css' => array( 'media' => 'print' ),
+                       'resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css' =>
+                               array( 'media' => 'print' ),
                        'resources/src/mediawiki.action/mediawiki.action.view.filepage.css',
                ),
                'position' => 'top',
@@ -1774,7 +1775,8 @@ return array(
                        // @todo: Remove mediawiki.page.gallery when cache has cleared
                        'resources/src/mediawiki.page/mediawiki.page.gallery.print.css' => array( 'media' => 'print' ),
                        // @todo: Remove mediawiki.action.view.filepage.print.css when cache has cleared
-                       'resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css' => array( 'media' => 'print' ),
+                       'resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css' =>
+                               array( 'media' => 'print' ),
                        'resources/src/mediawiki.legacy/commonPrint.css' => array( 'media' => 'print' )
                ),
        ),
@@ -1893,7 +1895,9 @@ return array(
                        'resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js',
+                       'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
+                       'resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js',
@@ -1903,7 +1907,7 @@ return array(
                        'default' => array(
                                'resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less',
                                'resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less',
-                               'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
+                               'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less',
                        ),
                ),
                'dependencies' => array(
index eaa138b..f6857e8 100644 (file)
                                new RegExp( /(https?|ftp|file):\/\// )
                        ],
                        isoDate: [
-                               new RegExp( /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/ )
+                               new RegExp( /^([-+]?\d{1,4})-([01]\d)-([0-3]\d)([T\s]((([01]\d|2[0-3])(:?[0-5]\d)?|24:?00)?(:?([0-5]\d))?([.,]\d+)?)([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?/ ),
+                               new RegExp( /^([-+]?\d{1,4})-([01]\d)-([0-3]\d)/ )
                        ],
                        usLongDate: [
                                new RegExp( /^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/ )
                        return ts.rgx.isoDate[ 0 ].test( s );
                },
                format: function ( s ) {
-                       return $.tablesorter.formatFloat( ( s !== '' ) ? new Date( s.replace(
-                       new RegExp( /-/g ), '/' ) ).getTime() : '0' );
+                       var isodate,
+                               matches;
+                       if ( !Date.prototype.toISOString ) {
+                               // Old browsers don't understand iso, Fallback to US date parsing and ignore the time part.
+                               matches = $.trim( s ).match( ts.rgx.isoDate[ 1 ] );
+                               if ( matches ) {
+                                       isodate = new Date( matches[ 2 ]  + '/' + matches[ 3 ] + '/' + matches[ 1 ] );
+                               } else {
+                                       return $.tablesorter.formatFloat( 0 );
+                               }
+                       } else {
+                               isodate = new Date( $.trim( s ) );
+                       }
+                       return $.tablesorter.formatFloat( ( isodate !== undefined ) ? isodate.getTime() : 0 );
                },
                type: 'numeric'
        } );
index ab4535b..dd23e87 100644 (file)
                                if ( response.parse.modules ) {
                                        mw.loader.load( response.parse.modules.concat(
                                                response.parse.modulescripts,
-                                               response.parse.modulestyles,
-                                               response.parse.modulemessages ) );
+                                               response.parse.modulestyles
+                                       ) );
                                }
                                if ( response.parse.displaytitle ) {
                                        $displaytitle = $( $.parseHTML( response.parse.displaytitle ) );
index ee1d6ef..ccc68f1 100644 (file)
@@ -7,6 +7,7 @@
 // cases.
 
 mediaWiki.language.convertGrammar = function ( word, form ) {
+       /*global $ */
        'use strict';
 
        var grammarForms = mediaWiki.language.getData( 'ru', 'grammarForms' );
@@ -52,6 +53,31 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                                word = word.slice( 0, -3 ) + 'нике';
                        }
                        break;
+               case 'languagegen': // язык в родительном падеже ("(с) русского")
+                       if ( word.slice( -3 ) === 'кий' ) {
+                               word = word.slice( 0, -2 ) + 'ого';
+                       } else if ( $.inArray( word, [ 'иврит', 'идиш' ] ) > -1 ) {
+                               word = word + 'а';
+                       }
+                       break;
+               case 'languageprep': // язык в предложном падеже ("(на) русском")
+                       if ( word.slice( -3 ) === 'кий' ) {
+                               word = word.slice( 0, -2 ) + 'ом';
+                       } else if ( $.inArray( word, [ 'иврит', 'идиш' ] ) > -1 ) {
+                               word = word + 'е';
+                       }
+                       break;
+               case 'languageadverb': // наречие с названием языка ("по-русски")
+                       if ( word.slice( -3 ) === 'кий' ) {
+                               word = 'по-' + word.slice( 0, -1 );
+                       } else if ( $.inArray( word, [ 'иврит', 'идиш' ] ) > -1 ) {
+                               word = 'на ' + word + 'е';
+                       } else if ( $.inArray( word, [ 'идо', 'урду', 'хинди', 'эсперанто' ] ) > -1 ) {
+                               word = 'на ' + word;
+                       } else {
+                               word = 'на языке ' + word;
+                       }
+                       break;
        }
        return word;
 };
index a22874b..138045c 100644 (file)
@@ -9,29 +9,24 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
        }
        switch ( form ) {
                case 'genitive': // родовий відмінок
-                       if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) {
-                               if ( word.slice( -1 ) === 'ь' ) {
-                                       word = word.slice( 0, -1 ) + 'я';
-                               } else if ( word.slice( -2 ) === 'ія' ) {
-                                       word = word.slice( 0, -2 ) + 'ії';
-                               } else if ( word.slice( -2 ) === 'ка' ) {
-                                       word = word.slice( 0, -2 ) + 'ки';
-                               } else if ( word.slice( -2 ) === 'ти' ) {
-                                       word = word.slice( 0, -2 ) + 'тей';
-                               } else if ( word.slice( -2 ) === 'ды' ) {
-                                       word = word.slice( 0, -2 ) + 'дов';
-                               } else if ( word.slice( -3 ) === 'ник' ) {
-                                       word = word.slice( 0, -3 ) + 'ника';
-                               }
+                       if ( word.slice( -2 ) === 'ія' ) {
+                               word = word.slice( 0, -2 ) + 'ії';
+                       } else if ( word.slice( -2 ) === 'ти' ) {
+                               word = word.slice( 0, -2 ) + 'т';
+                       } else if ( word.slice( -2 ) === 'ди' ) {
+                               word = word.slice( 0, -2 ) + 'дів';
+                       } else if ( word.slice( -3 ) === 'ник' ) {
+                               word = word.slice( 0, -3 ) + 'ника';
                        }
+
                        break;
                case 'accusative': // знахідний відмінок
-                       if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) {
-                               if ( word.slice( -2 ) === 'ія' ) {
-                                       word = word.slice( 0, -2 ) + 'ію';
-                               }
+                       if ( word.slice( -2 ) === 'ія' ) {
+                               word = word.slice( 0, -2 ) + 'ію';
                        }
+
                        break;
        }
+
        return word;
 };
index e1b3198..77fa753 100644 (file)
@@ -147,24 +147,11 @@ span.texhtml {
 /**
  * Links
  */
-a.stub,
-a.new {
-       color: #ba0000;
-       text-decoration: none;
-}
-
 a {
-       color: black !important;
        background: none !important;
        padding: 0 !important;
 }
 
-a:link, a:visited {
-       color: #520;
-       background: transparent;
-       text-decoration: underline;
-}
-
 /* Expand URLs for printing */
 .mw-body a.external.text:after,
 .mw-body a.external.autonumber:after {
index 961c02b..dd37051 100644 (file)
@@ -116,16 +116,6 @@ abbr[title],
        unicode-bidi: isolate;
 }
 
-/**
- * Links to redirects appear italicized on [[Special:AllPages]], [[Special:PrefixIndex]],
- * [[Special:Watchlist/edit]] and in category listings.
- */
-.allpagesredirect,
-.redirect-in-category,
-.watchlistredir {
-       font-style: italic;
-}
-
 /* Comment portions of RC entries */
 span.comment {
        font-style: italic;
index a13ec3c..60544d3 100644 (file)
@@ -39,6 +39,9 @@ ul.mw-allpages-chunk li {
        vertical-align: top;
        width: 31%;
 }
+.allpagesredirect {
+       font-style: italic;
+}
 
 /* Special:BlockList */
 table.mw-blocklist span.mw-usertoollinks,
@@ -52,6 +55,11 @@ span.mw-blocklist-actions {
        font-weight: bold;
 }
 
+/* Special:EditWatchlist */
+.watchlistredir {
+       font-style: italic;
+}
+
 /* Special:EmailUser */
 td#mw-emailuser-sender,
 td#mw-emailuser-recipient {
index 677d26d..c6ae5ac 100644 (file)
                 *
                 * TODO: Is there a way we can ask the browser what's supported in `<img>`s?
                 *
-                * TODO: Put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
+                * TODO: Put SVG back after working around Firefox 7 bug <https://phabricator.wikimedia.org/T33643>
                 *
                 * @param {File} file
                 * @return {boolean}
index d65b284..f86a41d 100644 (file)
@@ -40,3 +40,8 @@
 #mw-editbutton-hr {
        .background-image("images/@{button-hr}");
 }
+
+// Awful workaround for T113868, while it awaits a better fix.
+#mw-t113868 {
+       background-image: url(images/ar/button_bold.png), url(images/ar/button_headline.png), url(images/ar/button_italic.png), url(images/ar/button_link.png), url(images/ar/button_nowiki.png), url(images/be-tarask/button_bold.png), url(images/be-tarask/button_italic.png), url(images/be-tarask/button_link.png), url(images/de/button_bold.png), url(images/de/button_italic.png), url(images/en/button_bold.png), url(images/en/button_extlink.png), url(images/en/button_headline.png), url(images/en/button_hr.png), url(images/en/button_image.png), url(images/en/button_italic.png), url(images/en/button_link.png), url(images/en/button_media.png), url(images/en/button_nowiki.png), url(images/en/button_sig.png), url(images/fa/button_bold.png), url(images/fa/button_headline.png), url(images/fa/button_italic.png), url(images/fa/button_link.png), url(images/fa/button_nowiki.png), url(images/ksh/button_italic.png), url(images/ru/button_bold.png), url(images/ru/button_italic.png), url(images/ru/button_link.png);
+}
index 21a9019..702eb80 100644 (file)
 /* Theme-specific */
 .mw-widget-calendarWidget-day {
        color: #444;
+       border-radius: 0.1em;
 }
 
 .mw-widget-calendarWidget-day-heading {
 
 .mw-widget-calendarWidget-day-today {
        box-shadow: inset 0 0 0 1px #3787fb;
-       border-radius: ((@calendarHeight / 7) / 2);
 }
 
 .mw-widget-calendarWidget-item-selected {
        background-color: #d8e6fe;
        color: #3787fb;
-
-       &.mw-widget-calendarWidget-day,
-       &.mw-widget-calendarWidget-day-heading {
-               border-radius: ((@calendarHeight / 7) / 2);
-       }
-
-       &.mw-widget-calendarWidget-month {
-               border-radius: ((@calendarHeight / 6) / 2);
-       }
-
-       &.mw-widget-calendarWidget-year {
-               border-radius: ((@calendarHeight / 4) / 2);
-       }
 }
 
 .mw-widget-calendarWidget-item:hover {
        background-color: #eee;
-
-       &.mw-widget-calendarWidget-day,
-       &.mw-widget-calendarWidget-day-heading {
-               border-radius: ((@calendarHeight / 7) / 4);
-               // Hide the border from .mw-widget-calendarWidget-day-today
-               box-shadow: none;
-       }
-
-       &.mw-widget-calendarWidget-month {
-               border-radius: ((@calendarHeight / 6) / 4);
-       }
-
-       &.mw-widget-calendarWidget-year {
-               border-radius: ((@calendarHeight / 4) / 4);
-       }
 }
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css
deleted file mode 100644 (file)
index 2c24b2b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*!
- * MediaWiki Widgets - TitleInputWidget styles.
- *
- * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-
-.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget {
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       min-height: 3.75em;
-       margin-left: 3.75em;
-}
-
-.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget:not(:last-child) {
-       margin-bottom: 1px;
-}
-
-.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .oo-ui-iconElement-icon {
-       display: block;
-       width: 3.75em;
-       height: 3.75em;
-       left: -3.75em;
-       background-color: #ccc;
-       opacity: 0.4;
-}
-
-.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .mw-widget-titleOptionWidget-hasImage {
-       border: 0;
-       background-size: cover;
-       opacity: 1;
-}
-
-.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
-       line-height: 2.8em;
-}
-
-.mw-widget-titleOptionWidget-description {
-       display: none;
-}
-
-.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
-       line-height: 1.5em;
-}
-
-.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget-description {
-       display: block;
-       white-space: nowrap;
-       text-overflow: ellipsis;
-       overflow: hidden;
-}
-
-.oo-ui-menuOptionWidget:not(.oo-ui-optionWidget-selected) .mw-widget-titleOptionWidget-description,
-.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted .mw-widget-titleOptionWidget-description {
-       color: #888;
-}
index d5a7abc..fc1007e 100644 (file)
         *
         * @class
         * @extends OO.ui.TextInputWidget
+        * @mixins mw.widgets.TitleWidget
         * @mixins OO.ui.mixin.LookupElement
         *
         * @constructor
-        * @param {Object} [config] Configuration options
-        * @cfg {number} [limit=10] Number of results to show
-        * @cfg {number} [namespace] Namespace to prepend to queries
-        * @cfg {boolean} [relative=true] If a namespace is set, return a title relative to it
         * @cfg {boolean} [suggestions=true] Display search suggestions
-        * @cfg {boolean} [showRedirectTargets=true] Show the targets of redirects
-        * @cfg {boolean} [showRedlink] Show red link to exact match if it doesn't exist
-        * @cfg {boolean} [showImages] Show page images
-        * @cfg {boolean} [showDescriptions] Show page descriptions
-        * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
         */
        mw.widgets.TitleInputWidget = function MwWidgetsTitleInputWidget( config ) {
-               var widget = this;
-
-               // Config initialization
-               config = $.extend( {
-                       maxLength: 255,
-                       limit: 10
-               }, config );
+               config = config || {};
 
                // Parent constructor
-               mw.widgets.TitleInputWidget.parent.call( this, $.extend( {}, config, { autocomplete: false } ) );
+               mw.widgets.TitleInputWidget.parent.call( this, $.extend( {}, config, {
+                       validate: this.isQueryValid.bind( this ),
+                       autocomplete: false
+               } ) );
 
                // Mixin constructors
+               mw.widgets.TitleWidget.call( this, config );
                OO.ui.mixin.LookupElement.call( this, config );
 
                // Properties
-               this.limit = config.limit;
-               this.maxLength = config.maxLength;
-               this.namespace = config.namespace !== undefined ? config.namespace : null;
-               this.relative = config.relative !== undefined ? config.relative : true;
                this.suggestions = config.suggestions !== undefined ? config.suggestions : true;
-               this.showRedirectTargets = config.showRedirectTargets !== false;
-               this.showRedlink = !!config.showRedlink;
-               this.showImages = !!config.showImages;
-               this.showDescriptions = !!config.showDescriptions;
-               this.cache = config.cache;
 
                // Initialization
                this.$element.addClass( 'mw-widget-titleInputWidget' );
-               this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu' );
+               this.lookupMenu.$element.addClass( 'mw-widget-titleWidget-menu' );
                if ( this.showImages ) {
-                       this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withImages' );
+                       this.lookupMenu.$element.addClass( 'mw-widget-titleWidget-menu-withImages' );
                }
                if ( this.showDescriptions ) {
-                       this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withDescriptions' );
+                       this.lookupMenu.$element.addClass( 'mw-widget-titleWidget-menu-withDescriptions' );
                }
                this.setLookupsDisabled( !this.suggestions );
-
-               this.interwikiPrefixes = [];
-               this.interwikiPrefixesPromise = new mw.Api().get( {
-                       action: 'query',
-                       meta: 'siteinfo',
-                       siprop: 'interwikimap'
-               } ).done( function ( data ) {
-                       $.each( data.query.interwikimap, function ( index, interwiki ) {
-                               widget.interwikiPrefixes.push( interwiki.prefix );
-                       } );
-               } );
        };
 
        /* Setup */
 
        OO.inheritClass( mw.widgets.TitleInputWidget, OO.ui.TextInputWidget );
+       OO.mixinClass( mw.widgets.TitleInputWidget, mw.widgets.TitleWidget );
        OO.mixinClass( mw.widgets.TitleInputWidget, OO.ui.mixin.LookupElement );
 
        /* Methods */
 
        /**
-        * Get the namespace to prepend to titles in suggestions, if any.
-        *
-        * @return {number|null} Namespace number
+        * @inheritdoc mw.widgets.TitleWidget
         */
-       mw.widgets.TitleInputWidget.prototype.getNamespace = function () {
-               return this.namespace;
+       mw.widgets.TitleInputWidget.prototype.getQueryValue = function () {
+               return this.getValue();
        };
 
        /**
-        * Set the namespace to prepend to titles in suggestions, if any.
-        *
-        * @param {number|null} namespace Namespace number
+        * @inheritdoc mw.widgets.TitleWidget
         */
        mw.widgets.TitleInputWidget.prototype.setNamespace = function ( namespace ) {
-               this.namespace = namespace;
+               // Mixin method
+               mw.widgets.TitleWidget.prototype.setNamespace.call( this, namespace );
+
                this.lookupCache = {};
                this.closeLookupMenu();
        };
 
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
+               return this.getSuggestionsPromise();
+       };
+
+       /**
+        * @inheritdoc OO.ui.mixin.LookupElement
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
+               return response.query || {};
+       };
+
+       /**
+        * @inheritdoc OO.ui.mixin.LookupElement
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupMenuOptionsFromData = function ( response ) {
+               return this.getOptionsFromData( response );
+       };
+
        /**
         * @inheritdoc
         */
                return retval;
        };
 
-       /**
-        * @inheritdoc
-        */
-       mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
-               var req,
-                       widget = this,
-                       promiseAbortObject = { abort: function () {
-                               // Do nothing. This is just so OOUI doesn't break due to abort being undefined.
-                       } };
-
-               if ( mw.Title.newFromText( this.value ) ) {
-                       return this.interwikiPrefixesPromise.then( function () {
-                               var params, props,
-                                       interwiki = widget.value.substring( 0, widget.value.indexOf( ':' ) );
-                               if (
-                                       interwiki && interwiki !== '' &&
-                                       widget.interwikiPrefixes.indexOf( interwiki ) !== -1
-                               ) {
-                                       return $.Deferred().resolve( { query: {
-                                               pages: [ {
-                                                       title: widget.value
-                                               } ]
-                                       } } ).promise( promiseAbortObject );
-                               } else {
-                                       params = {
-                                               action: 'query',
-                                               generator: 'prefixsearch',
-                                               gpssearch: widget.value,
-                                               gpsnamespace: widget.namespace !== null ? widget.namespace : undefined,
-                                               gpslimit: widget.limit,
-                                               ppprop: 'disambiguation'
-                                       };
-                                       props = [ 'info', 'pageprops' ];
-                                       if ( widget.showRedirectTargets ) {
-                                               params.redirects = '1';
-                                       }
-                                       if ( widget.showImages ) {
-                                               props.push( 'pageimages' );
-                                               params.pithumbsize = 80;
-                                               params.pilimit = widget.limit;
-                                       }
-                                       if ( widget.showDescriptions ) {
-                                               props.push( 'pageterms' );
-                                               params.wbptterms = 'description';
-                                       }
-                                       params.prop = props.join( '|' );
-                                       req = new mw.Api().get( params );
-                                       promiseAbortObject.abort = req.abort.bind( req ); // todo: ew
-                                       return req;
-                               }
-                       } ).promise( promiseAbortObject );
-               } else {
-                       // Don't send invalid titles to the API.
-                       // Just pretend it returned nothing so we can show the 'invalid title' section
-                       return $.Deferred().resolve( {} ).promise( promiseAbortObject );
-               }
-       };
-
-       /**
-        * Get lookup cache item from server response data.
-        *
-        * @method
-        * @param {Mixed} response Response from server
-        */
-       mw.widgets.TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
-               return response.query || {};
-       };
-
-       /**
-        * Get list of menu items from a server response.
-        *
-        * @param {Object} data Query result
-        * @returns {OO.ui.MenuOptionWidget[]} Menu items
-        */
-       mw.widgets.TitleInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
-               var i, len, index, pageExists, pageExistsExact, suggestionPage, page, redirect, redirects,
-                       items = [],
-                       titles = [],
-                       titleObj = mw.Title.newFromText( this.value ),
-                       redirectsTo = {},
-                       pageData = {};
-
-               if ( data.redirects ) {
-                       for ( i = 0, len = data.redirects.length; i < len; i++ ) {
-                               redirect = data.redirects[ i ];
-                               redirectsTo[ redirect.to ] = redirectsTo[ redirect.to ] || [];
-                               redirectsTo[ redirect.to ].push( redirect.from );
-                       }
-               }
-
-               for ( index in data.pages ) {
-                       suggestionPage = data.pages[ index ];
-                       pageData[ suggestionPage.title ] = {
-                               missing: suggestionPage.missing !== undefined,
-                               redirect: suggestionPage.redirect !== undefined,
-                               disambiguation: OO.getProp( suggestionPage, 'pageprops', 'disambiguation' ) !== undefined,
-                               imageUrl: OO.getProp( suggestionPage, 'thumbnail', 'source' ),
-                               description: OO.getProp( suggestionPage, 'terms', 'description' )
-                       };
-
-                       // Throw away pages from wrong namespaces. This can happen when 'showRedirectTargets' is true
-                       // and we encounter a cross-namespace redirect.
-                       if ( this.namespace === null || this.namespace === suggestionPage.ns ) {
-                               titles.push( suggestionPage.title );
-                       }
-
-                       redirects = redirectsTo[ suggestionPage.title ] || [];
-                       for ( i = 0, len = redirects.length; i < len; i++ ) {
-                               pageData[ redirects[ i ] ] = {
-                                       missing: false,
-                                       redirect: true,
-                                       disambiguation: false,
-                                       description: mw.msg( 'mw-widgets-titleinput-description-redirect', suggestionPage.title )
-                               };
-                               titles.push( redirects[ i ] );
-                       }
-               }
-
-               // If not found, run value through mw.Title to avoid treating a match as a
-               // mismatch where normalisation would make them matching (bug 48476)
-
-               pageExistsExact = titles.indexOf( this.value ) !== -1;
-               pageExists = pageExistsExact || (
-                       titleObj && titles.indexOf( titleObj.getPrefixedText() ) !== -1
-               );
-
-               if ( !pageExists ) {
-                       pageData[ this.value ] = {
-                               missing: true, redirect: false, disambiguation: false,
-                               description: mw.msg( 'mw-widgets-titleinput-description-new-page' )
-                       };
-               }
-
-               if ( this.cache ) {
-                       this.cache.set( pageData );
-               }
-
-               // Offer the exact text as a suggestion if the page exists
-               if ( pageExists && !pageExistsExact ) {
-                       titles.unshift( this.value );
-               }
-               // Offer the exact text as a new page if the title is valid
-               if ( this.showRedlink && !pageExists && titleObj ) {
-                       titles.push( this.value );
-               }
-               for ( i = 0, len = titles.length; i < len; i++ ) {
-                       page = pageData[ titles[ i ] ] || {};
-                       items.push( new mw.widgets.TitleOptionWidget( this.getOptionWidgetData( titles[ i ], page ) ) );
-               }
-
-               return items;
-       };
-
-       /**
-        * Get menu option widget data from the title and page data
-        *
-        * @param {mw.Title} title Title object
-        * @param {Object} data Page data
-        * @return {Object} Data for option widget
-        */
-       mw.widgets.TitleInputWidget.prototype.getOptionWidgetData = function ( title, data ) {
-               var mwTitle = new mw.Title( title );
-               return {
-                       data: this.namespace !== null && this.relative
-                               ? mwTitle.getRelativeText( this.namespace )
-                               : title,
-                       title: mwTitle,
-                       imageUrl: this.showImages ? data.imageUrl : null,
-                       description: this.showDescriptions ? data.description : null,
-                       missing: data.missing,
-                       redirect: data.redirect,
-                       disambiguation: data.disambiguation,
-                       query: this.value
-               };
-       };
-
-       /**
-        * Get title object corresponding to given value, or #getValue if not given.
-        *
-        * @param {string} [value] Value to get a title for
-        * @returns {mw.Title|null} Title object, or null if value is invalid
-        */
-       mw.widgets.TitleInputWidget.prototype.getTitle = function ( value ) {
-               var title = value !== undefined ? value : this.getValue(),
-                       // mw.Title doesn't handle null well
-                       titleObj = mw.Title.newFromText( title, this.namespace !== null ? this.namespace : undefined );
-
-               return titleObj;
-       };
-
        /**
         * @inheritdoc
         */
        mw.widgets.TitleInputWidget.prototype.cleanUpValue = function ( value ) {
                var widget = this;
+
+               // Parent method
                value = mw.widgets.TitleInputWidget.parent.prototype.cleanUpValue.call( this, value );
+
                return $.trimByteLength( this.value, value, this.maxLength, function ( value ) {
                        var title = widget.getTitle( value );
                        return title ? title.getMain() : value;
                } ).newVal;
        };
 
-       /**
-        * @inheritdoc
-        */
-       mw.widgets.TitleInputWidget.prototype.isValid = function () {
-               return $.Deferred().resolve( !!this.getTitle() ).promise();
-       };
-
 }( jQuery, mediaWiki ) );
index ec0c935..1154c9f 100644 (file)
                                        .text( config.description )
                        );
                }
+
+               // Events
+               this.$link.on( 'click', function () {
+                       return false;
+               } );
        };
 
        /* Setup */
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js b/resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js
new file mode 100644 (file)
index 0000000..c37c723
--- /dev/null
@@ -0,0 +1,87 @@
+/*!
+ * MediaWiki Widgets - TitleSearchWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+       /**
+        * Creates an mw.widgets.TitleSearchWidget object.
+        *
+        * @class
+        * @extends OO.ui.SearchWidget
+        * @mixins mw.widgets.TitleWidget
+        *
+        * @constructor
+        */
+       mw.widgets.TitleSearchWidget = function MwWidgetsTitleSearchWidget( config ) {
+               config = config || {};
+
+               // Parent constructor
+               mw.widgets.TitleSearchWidget.parent.call( this, config );
+
+               // Mixin constructors
+               mw.widgets.TitleWidget.call( this, config );
+
+               this.query.setValidation( this.isQueryValid.bind( this ) );
+
+               // Events
+               this.results.connect( this, { choose: 'onTitleSearchResultsChoose' } );
+
+               // Initialization
+               this.$element.addClass( 'mw-widget-titleSearchWidget' );
+               this.results.$element.addClass( 'mw-widget-titleWidget-menu' );
+               if ( this.showImages ) {
+                       this.results.$element.addClass( 'mw-widget-titleWidget-menu-withImages' );
+               }
+               if ( this.showDescriptions ) {
+                       this.results.$element.addClass( 'mw-widget-titleWidget-menu-withDescriptions' );
+               }
+               if ( this.maxLength !== undefined ) {
+                       this.getQuery().$input.attr( 'maxlength', this.maxLength );
+               }
+       };
+
+       /* Setup */
+
+       OO.inheritClass( mw.widgets.TitleSearchWidget, OO.ui.SearchWidget );
+       OO.mixinClass( mw.widgets.TitleSearchWidget, mw.widgets.TitleWidget );
+
+       /* Methods */
+
+       /**
+        * @inheritdoc mw.widgets.TitleWidget
+        */
+       mw.widgets.TitleSearchWidget.prototype.getQueryValue = function () {
+               return this.getQuery().getValue();
+       };
+
+       /**
+        * Handle choose events from the result widget
+        *
+        * @param {OO.ui.OptionWidget} item Chosen item
+        */
+       mw.widgets.TitleSearchWidget.prototype.onTitleSearchResultsChoose = function ( item ) {
+               // TOOD: Pressing enter can incorrectly trigger 'choose' with null.
+               // Remove this check when oojs-ui 0.12.10 lands.
+               if ( item ) {
+                       this.getQuery().setValue( item.getData() );
+               }
+       };
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleSearchWidget.prototype.onQueryChange = function () {
+               var widget = this;
+
+               this.getSuggestionsPromise().done( function ( response ) {
+                       // Parent method
+                       mw.widgets.TitleSearchWidget.parent.prototype.onQueryChange.call( widget );
+
+                       widget.results.addItems( widget.getOptionsFromData( response.query || {} ) );
+               } );
+       };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js b/resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js
new file mode 100644 (file)
index 0000000..f51c559
--- /dev/null
@@ -0,0 +1,285 @@
+/*!
+ * MediaWiki Widgets - TitleWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+       /**
+        * Mixin for title widgets
+        *
+        * @class
+        * @abstract
+        *
+        * @constructor
+        * @param {Object} [config] Configuration options
+        * @cfg {number} [limit=10] Number of results to show
+        * @cfg {number} [namespace] Namespace to prepend to queries
+        * @cfg {number} [maxLength=255] Maximum query length
+        * @cfg {boolean} [relative=true] If a namespace is set, return a title relative to it
+        * @cfg {boolean} [suggestions=true] Display search suggestions
+        * @cfg {boolean} [showRedirectTargets=true] Show the targets of redirects
+        * @cfg {boolean} [showRedlink] Show red link to exact match if it doesn't exist
+        * @cfg {boolean} [showImages] Show page images
+        * @cfg {boolean} [showDescriptions] Show page descriptions
+        * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
+        */
+       mw.widgets.TitleWidget = function MwWidgetsTitleWidget( config ) {
+               var widget = this;
+
+               // Config initialization
+               config = $.extend( {
+                       maxLength: 255,
+                       limit: 10
+               }, config );
+
+               // Properties
+               this.limit = config.limit;
+               this.maxLength = config.maxLength;
+               this.namespace = config.namespace !== undefined ? config.namespace : null;
+               this.relative = config.relative !== undefined ? config.relative : true;
+               this.suggestions = config.suggestions !== undefined ? config.suggestions : true;
+               this.showRedirectTargets = config.showRedirectTargets !== false;
+               this.showRedlink = !!config.showRedlink;
+               this.showImages = !!config.showImages;
+               this.showDescriptions = !!config.showDescriptions;
+               this.cache = config.cache;
+
+               // Initialization
+               this.interwikiPrefixes = [];
+               this.interwikiPrefixesPromise = new mw.Api().get( {
+                       action: 'query',
+                       meta: 'siteinfo',
+                       siprop: 'interwikimap'
+               } ).done( function ( data ) {
+                       $.each( data.query.interwikimap, function ( index, interwiki ) {
+                               widget.interwikiPrefixes.push( interwiki.prefix );
+                       } );
+               } );
+       };
+
+       /* Setup */
+
+       OO.initClass( mw.widgets.TitleWidget );
+
+       /* Methods */
+
+       /**
+        * Get the current value of the search query
+        *
+        * @abstract
+        * @return {string} Search query
+        */
+       mw.widgets.TitleWidget.prototype.getQueryValue = null;
+
+       /**
+        * Get the namespace to prepend to titles in suggestions, if any.
+        *
+        * @return {number|null} Namespace number
+        */
+       mw.widgets.TitleWidget.prototype.getNamespace = function () {
+               return this.namespace;
+       };
+
+       /**
+        * Set the namespace to prepend to titles in suggestions, if any.
+        *
+        * @param {number|null} namespace Namespace number
+        */
+       mw.widgets.TitleWidget.prototype.setNamespace = function ( namespace ) {
+               this.namespace = namespace;
+       };
+
+       /**
+        * Get a promise which resolves with an API repsonse for suggested
+        * links for the current query.
+        */
+       mw.widgets.TitleWidget.prototype.getSuggestionsPromise = function () {
+               var req,
+                       query = this.getQueryValue(),
+                       widget = this,
+                       promiseAbortObject = { abort: function () {
+                               // Do nothing. This is just so OOUI doesn't break due to abort being undefined.
+                       } };
+
+               if ( mw.Title.newFromText( query ) ) {
+                       return this.interwikiPrefixesPromise.then( function () {
+                               var params, props,
+                                       interwiki = query.substring( 0, query.indexOf( ':' ) );
+                               if (
+                                       interwiki && interwiki !== '' &&
+                                       widget.interwikiPrefixes.indexOf( interwiki ) !== -1
+                               ) {
+                                       return $.Deferred().resolve( { query: {
+                                               pages: [ {
+                                                       title: query
+                                               } ]
+                                       } } ).promise( promiseAbortObject );
+                               } else {
+                                       params = {
+                                               action: 'query',
+                                               generator: 'prefixsearch',
+                                               gpssearch: query,
+                                               gpsnamespace: widget.namespace !== null ? widget.namespace : undefined,
+                                               gpslimit: widget.limit,
+                                               ppprop: 'disambiguation'
+                                       };
+                                       props = [ 'info', 'pageprops' ];
+                                       if ( widget.showRedirectTargets ) {
+                                               params.redirects = '1';
+                                       }
+                                       if ( widget.showImages ) {
+                                               props.push( 'pageimages' );
+                                               params.pithumbsize = 80;
+                                               params.pilimit = widget.limit;
+                                       }
+                                       if ( widget.showDescriptions ) {
+                                               props.push( 'pageterms' );
+                                               params.wbptterms = 'description';
+                                       }
+                                       params.prop = props.join( '|' );
+                                       req = new mw.Api().get( params );
+                                       promiseAbortObject.abort = req.abort.bind( req ); // todo: ew
+                                       return req;
+                               }
+                       } ).promise( promiseAbortObject );
+               } else {
+                       // Don't send invalid titles to the API.
+                       // Just pretend it returned nothing so we can show the 'invalid title' section
+                       return $.Deferred().resolve( {} ).promise( promiseAbortObject );
+               }
+       };
+
+       /**
+        * Get option widgets from the server response
+        *
+        * @param {Object} data Query result
+        * @returns {OO.ui.OptionWidget[]} Menu items
+        */
+       mw.widgets.TitleWidget.prototype.getOptionsFromData = function ( data ) {
+               var i, len, index, pageExists, pageExistsExact, suggestionPage, page, redirect, redirects,
+                       items = [],
+                       titles = [],
+                       titleObj = mw.Title.newFromText( this.getQueryValue() ),
+                       redirectsTo = {},
+                       pageData = {};
+
+               if ( data.redirects ) {
+                       for ( i = 0, len = data.redirects.length; i < len; i++ ) {
+                               redirect = data.redirects[ i ];
+                               redirectsTo[ redirect.to ] = redirectsTo[ redirect.to ] || [];
+                               redirectsTo[ redirect.to ].push( redirect.from );
+                       }
+               }
+
+               for ( index in data.pages ) {
+                       suggestionPage = data.pages[ index ];
+                       pageData[ suggestionPage.title ] = {
+                               missing: suggestionPage.missing !== undefined,
+                               redirect: suggestionPage.redirect !== undefined,
+                               disambiguation: OO.getProp( suggestionPage, 'pageprops', 'disambiguation' ) !== undefined,
+                               imageUrl: OO.getProp( suggestionPage, 'thumbnail', 'source' ),
+                               description: OO.getProp( suggestionPage, 'terms', 'description' )
+                       };
+
+                       // Throw away pages from wrong namespaces. This can happen when 'showRedirectTargets' is true
+                       // and we encounter a cross-namespace redirect.
+                       if ( this.namespace === null || this.namespace === suggestionPage.ns ) {
+                               titles.push( suggestionPage.title );
+                       }
+
+                       redirects = redirectsTo[ suggestionPage.title ] || [];
+                       for ( i = 0, len = redirects.length; i < len; i++ ) {
+                               pageData[ redirects[ i ] ] = {
+                                       missing: false,
+                                       redirect: true,
+                                       disambiguation: false,
+                                       description: mw.msg( 'mw-widgets-titleinput-description-redirect', suggestionPage.title )
+                               };
+                               titles.push( redirects[ i ] );
+                       }
+               }
+
+               // If not found, run value through mw.Title to avoid treating a match as a
+               // mismatch where normalisation would make them matching (bug 48476)
+
+               pageExistsExact = titles.indexOf( this.getQueryValue() ) !== -1;
+               pageExists = pageExistsExact || (
+                       titleObj && titles.indexOf( titleObj.getPrefixedText() ) !== -1
+               );
+
+               if ( !pageExists ) {
+                       pageData[ this.getQueryValue() ] = {
+                               missing: true, redirect: false, disambiguation: false,
+                               description: mw.msg( 'mw-widgets-titleinput-description-new-page' )
+                       };
+               }
+
+               if ( this.cache ) {
+                       this.cache.set( pageData );
+               }
+
+               // Offer the exact text as a suggestion if the page exists
+               if ( pageExists && !pageExistsExact ) {
+                       titles.unshift( this.getQueryValue() );
+               }
+               // Offer the exact text as a new page if the title is valid
+               if ( this.showRedlink && !pageExists && titleObj ) {
+                       titles.push( this.getQueryValue() );
+               }
+               for ( i = 0, len = titles.length; i < len; i++ ) {
+                       page = pageData[ titles[ i ] ] || {};
+                       items.push( new mw.widgets.TitleOptionWidget( this.getOptionWidgetData( titles[ i ], page ) ) );
+               }
+
+               return items;
+       };
+
+       /**
+        * Get menu option widget data from the title and page data
+        *
+        * @param {mw.Title} title Title object
+        * @param {Object} data Page data
+        * @return {Object} Data for option widget
+        */
+       mw.widgets.TitleWidget.prototype.getOptionWidgetData = function ( title, data ) {
+               var mwTitle = new mw.Title( title );
+               return {
+                       data: this.namespace !== null && this.relative
+                               ? mwTitle.getRelativeText( this.namespace )
+                               : title,
+                       title: mwTitle,
+                       imageUrl: this.showImages ? data.imageUrl : null,
+                       description: this.showDescriptions ? data.description : null,
+                       missing: data.missing,
+                       redirect: data.redirect,
+                       disambiguation: data.disambiguation,
+                       query: this.getQueryValue()
+               };
+       };
+
+       /**
+        * Get title object corresponding to given value, or #getQueryValue if not given.
+        *
+        * @param {string} [value] Value to get a title for
+        * @returns {mw.Title|null} Title object, or null if value is invalid
+        */
+       mw.widgets.TitleWidget.prototype.getTitle = function ( value ) {
+               var title = value !== undefined ? value : this.getQueryValue(),
+                       // mw.Title doesn't handle null well
+                       titleObj = mw.Title.newFromText( title, this.namespace !== null ? this.namespace : undefined );
+
+               return titleObj;
+       };
+
+       /**
+        * Check if the query is valid
+        *
+        * @return {boolean} The query is valid
+        */
+       mw.widgets.TitleWidget.prototype.isQueryValid = function () {
+               return !!this.getTitle();
+       };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less b/resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less
new file mode 100644 (file)
index 0000000..93c4b20
--- /dev/null
@@ -0,0 +1,63 @@
+/*!
+ * MediaWiki Widgets - TitleWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-titleOptionWidget-description {
+       display: none;
+}
+
+.mw-widget-titleWidget {
+       &-menu-withImages {
+               .mw-widget-titleOptionWidget {
+                       -webkit-box-sizing: border-box;
+                       -moz-box-sizing: border-box;
+                       box-sizing: border-box;
+                       min-height: 3.75em;
+                       margin-left: 3.75em;
+               }
+
+               .mw-widget-titleOptionWidget:not(:last-child) {
+                       margin-bottom: 1px;
+               }
+
+               .oo-ui-iconElement .oo-ui-iconElement-icon {
+                       display: block;
+                       width: 3.75em;
+                       height: 3.75em;
+                       left: -3.75em;
+                       background-color: #ccc;
+                       opacity: 0.4;
+               }
+
+               .oo-ui-iconElement .mw-widget-titleOptionWidget-hasImage {
+                       border: 0;
+                       background-size: cover;
+                       opacity: 1;
+               }
+
+               .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+                       line-height: 2.8em;
+               }
+       }
+
+       &-menu-withDescriptions {
+               .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+                       line-height: 1.5em;
+               }
+
+               .mw-widget-titleOptionWidget-description {
+                       display: block;
+                       white-space: nowrap;
+                       text-overflow: ellipsis;
+                       overflow: hidden;
+               }
+       }
+}
+
+.oo-ui-menuOptionWidget:not(.oo-ui-optionWidget-selected) .mw-widget-titleOptionWidget-description,
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted .mw-widget-titleOptionWidget-description {
+       color: #888;
+}
index 8a81a64..093748d 100644 (file)
@@ -66,7 +66,8 @@ $wgAutoloadClasses += array(
        'TestRecentChangesHelper' => "$testDir/phpunit/includes/changes/TestRecentChangesHelper.php",
 
        # tests/phpunit/includes/content
-       'DummyContentHandlerForTesting' => "$testDir/phpunit/mocks/content/DummyContentHandlerForTesting.php",
+       'DummyContentHandlerForTesting' =>
+               "$testDir/phpunit/mocks/content/DummyContentHandlerForTesting.php",
        'DummyContentForTesting' => "$testDir/phpunit/mocks/content/DummyContentForTesting.php",
        'DummyNonTextContentHandler' => "$testDir/phpunit/mocks/content/DummyNonTextContentHandler.php",
        'DummyNonTextContent' => "$testDir/phpunit/mocks/content/DummyNonTextContent.php",
@@ -91,8 +92,10 @@ $wgAutoloadClasses += array(
        'PasswordTestCase' => "$testDir/phpunit/includes/password/PasswordTestCase.php",
 
        # tests/phpunit/includes/resourceloader
-       'ResourceLoaderImageModuleTest' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php",
-       'ResourceLoaderImageModuleTestable' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php",
+       'ResourceLoaderImageModuleTest' =>
+               "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php",
+       'ResourceLoaderImageModuleTestable' =>
+               "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php",
 
        # tests/phpunit/includes/specials
        'SpecialPageTestBase' => "$testDir/phpunit/includes/specials/SpecialPageTestBase.php",
index f429c30..005ade5 100644 (file)
@@ -134,6 +134,12 @@ class ParserTest {
                $this->setupRecorder( $options );
                $this->keepUploads = isset( $options['keep-uploads'] );
 
+               if ( $this->keepUploads ) {
+                       $this->uploadDir = wfTempDir() . '/mwParser-images';
+               } else {
+                       $this->uploadDir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
+               }
+
                if ( isset( $options['seed'] ) ) {
                        $this->fuzzSeed = intval( $options['seed'] ) - 1;
                }
@@ -147,13 +153,17 @@ class ParserTest {
                        echo "Warning: tidy is not installed, skipping some tests\n";
                }
 
+               if ( !extension_loaded( 'gd' ) ) {
+                       echo "Warning: GD extension is not present, thumbnailing tests will probably fail\n";
+               }
+
                $this->hooks = array();
                $this->functionHooks = array();
                $this->transparentHooks = array();
-               self::setUp();
+               $this->setUp();
        }
 
-       static function setUp() {
+       function setUp() {
                global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
                        $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
                        $wgExtraNamespaces, $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
@@ -171,7 +181,7 @@ class ParserTest {
                $wgLockManagers = array( array(
                        'name' => 'fsLockManager',
                        'class' => 'FSLockManager',
-                       'lockDirectory' => wfTempDir() . '/test-repo/lockdir',
+                       'lockDirectory' => $this->uploadDir . '/lockdir',
                ), array(
                        'name' => 'nullLockManager',
                        'class' => 'NullLockManager',
@@ -186,10 +196,10 @@ class ParserTest {
                                'name' => 'local-backend',
                                'wikiId' => wfWikiId(),
                                'containerPaths' => array(
-                                       'local-public' => wfTempDir() . '/test-repo/public',
-                                       'local-thumb' => wfTempDir() . '/test-repo/thumb',
-                                       'local-temp' => wfTempDir() . '/test-repo/temp',
-                                       'local-deleted' => wfTempDir() . '/test-repo/deleted',
+                                       'local-public' => $this->uploadDir . '/public',
+                                       'local-thumb' => $this->uploadDir . '/thumb',
+                                       'local-temp' => $this->uploadDir . '/temp',
+                                       'local-deleted' => $this->uploadDir . '/deleted',
                                )
                        ) )
                );
@@ -729,7 +739,7 @@ class ParserTest {
                                )*
                                \}              # Close bracket
                        )
-            (?<value>
+                       (?<value>
                                (?:
                                        (?&qstr)                        # Quoted val
                                |
@@ -937,6 +947,7 @@ class ParserTest {
 
                MagicWord::clearCache();
                MWTidy::destroySingleton();
+               RepoGroup::destroySingleton();
 
                return $context;
        }
@@ -1028,7 +1039,7 @@ class ParserTest {
 
                // Remember to update newParserTests.php after changing the below
                // (and it uses a slightly different syntax just for teh lulz)
-               $this->uploadDir = $this->setupUploadDir();
+               $this->setupUploadDir();
                $user = User::createNew( 'WikiSysop' );
                $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) );
                # note that the size/width/height/bits/etc of the file
@@ -1177,20 +1188,15 @@ class ParserTest {
        private function setupUploadDir() {
                global $IP;
 
-               if ( $this->keepUploads ) {
-                       $dir = wfTempDir() . '/mwParser-images';
-
-                       if ( is_dir( $dir ) ) {
-                               return $dir;
-                       }
-               } else {
-                       $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
+               $dir = $this->uploadDir;
+               if ( $this->keepUploads && is_dir( $dir ) ) {
+                       return;
                }
 
                // wfDebug( "Creating upload directory $dir\n" );
                if ( file_exists( $dir ) ) {
                        wfDebug( "Already exists!\n" );
-                       return $dir;
+                       return;
                }
 
                wfMkdirParents( $dir . '/3/3a', null, __METHOD__ );
@@ -1207,7 +1213,7 @@ class ParserTest {
                wfMkdirParents( $dir . '/5/5f', null, __METHOD__ );
                copy( "$IP/tests/phpunit/data/parser/LoremIpsum.djvu", "$dir/5/5f/LoremIpsum.djvu" );
 
-               return $dir;
+               return;
        }
 
        /**
@@ -1239,58 +1245,13 @@ class ParserTest {
                self::deleteFiles(
                        array(
                                "$dir/3/3a/Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/1000px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/100px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/1500px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/177px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/206px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/20px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/265px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/274px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/30px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/353px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/40px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/450px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/600px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/75px-Foobar.jpg",
-                               "$dir/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg",
-
+                               "$dir/thumb/3/3a/Foobar.jpg/*.jpg",
                                "$dir/e/ea/Thumb.png",
-
                                "$dir/0/09/Bad.jpg",
-
                                "$dir/5/5f/LoremIpsum.djvu",
-                               "$dir/thumb/5/5f/LoremIpsum.djvu/page2-2480px-LoremIpsum.djvu.jpg",
-                               "$dir/thumb/5/5f/LoremIpsum.djvu/page2-3720px-LoremIpsum.djvu.jpg",
-                               "$dir/thumb/5/5f/LoremIpsum.djvu/page2-4960px-LoremIpsum.djvu.jpg",
-
+                               "$dir/thumb/5/5f/LoremIpsum.djvu/*-LoremIpsum.djvu.jpg",
                                "$dir/f/ff/Foobar.svg",
-                               "$dir/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/2000px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/3000px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/4000px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/langde-180px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/langde-270px-Foobar.svg.png",
-                               "$dir/thumb/f/ff/Foobar.svg/langde-360px-Foobar.svg.png",
-
+                               "$dir/thumb/f/ff/Foobar.svg/*-Foobar.svg.png",
                                "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
                        )
                );
@@ -1321,6 +1282,7 @@ class ParserTest {
                                "$dir/math/f/a",
                                "$dir/math/f",
                                "$dir/math",
+                               "$dir/lockdir",
                                "$dir",
                        )
                );
@@ -1331,9 +1293,11 @@ class ParserTest {
         * @param array $files Full paths to files to delete.
         */
        private static function deleteFiles( $files ) {
-               foreach ( $files as $file ) {
-                       if ( file_exists( $file ) ) {
-                               unlink( $file );
+               foreach ( $files as $pattern ) {
+                       foreach ( glob( $pattern ) as $file ) {
+                               if ( file_exists( $file ) ) {
+                                       unlink( $file );
+                               }
                        }
                }
        }
@@ -1661,7 +1625,7 @@ class ParserTest {
        }
 
        static function getFakeTimestamp( &$parser, &$ts ) {
-               $ts = 123; //parsed as '1970-01-01T00:02:03Z'
+               $ts = 123; // parsed as '1970-01-01T00:02:03Z'
                return true;
        }
 }
index eec02ed..5e1f1a9 100644 (file)
@@ -41,11 +41,9 @@ class LessFileCompilationTest extends ResourceLoaderTestCase {
                $rlContext = $this->getResourceLoaderContext();
 
                // Bleh
-               $method = new ReflectionMethod( $this->module, 'getLessCompiler' );
+               $method = new ReflectionMethod( $this->module, 'compileLessFile' );
                $method->setAccessible( true );
-               $compiler = $method->invoke( $this->module, $rlContext );
-
-               $this->assertNotNull( $compiler->parseFile( $this->file )->getCss() );
+               $this->assertNotNull( $method->invoke( $this->module, $this->file, $rlContext ) );
        }
 
        public function toString() {
index 08463f1..dd606d8 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
-class MediaWikiPHPUnitTestListener extends PHPUnit_TextUI_ResultPrinter implements PHPUnit_Framework_TestListener {
+class MediaWikiPHPUnitTestListener
+       extends PHPUnit_TextUI_ResultPrinter implements PHPUnit_Framework_TestListener {
 
        /**
         * @var string
index 7dc7027..9bbbf9f 100644 (file)
@@ -103,6 +103,12 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                 */
                ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
 
+               // Sandbox APC by replacing with in-process hash instead.
+               // Ensures values are removed between tests.
+               ObjectCache::$instances['apc'] =
+               ObjectCache::$instances['xcache'] =
+               ObjectCache::$instances['wincache'] = new HashBagOStuff;
+
                $needsResetDB = false;
 
                if ( $this->needsDB() ) {
@@ -217,7 +223,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
        protected function tearDown() {
                $status = ob_get_status();
-               if ( isset( $status['name'] ) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
+               if ( isset( $status['name'] ) &&
+                       $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier'
+               ) {
                        ob_end_flush();
                }
 
@@ -1151,7 +1159,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
        /**
         * Note: we are overriding this method to remove the deprecated error
-        * @see https://bugzilla.wikimedia.org/show_bug.cgi?id=69505
+        * @see https://phabricator.wikimedia.org/T71505
         * @see https://github.com/sebastianbergmann/phpunit/issues/1292
         * @deprecated
         *
@@ -1161,7 +1169,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param bool $isHtml
         */
        public static function assertTag( $matcher, $actual, $message = '', $isHtml = true ) {
-               //trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
+               // trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
 
                self::assertTrue( self::tagMatch( $matcher, $actual, $isHtml ), $message );
        }
@@ -1176,7 +1184,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param bool $isHtml
         */
        public static function assertNotTag( $matcher, $actual, $message = '', $isHtml = true ) {
-               //trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
+               // trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
 
                self::assertFalse( self::tagMatch( $matcher, $actual, $isHtml ), $message );
        }
diff --git a/tests/phpunit/data/filecontentshasher/hash.svg b/tests/phpunit/data/filecontentshasher/hash.svg
new file mode 100644 (file)
index 0000000..44068ba
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="200"
+   height="200"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.765"
+     inkscape:cx="101.66909"
+     inkscape:cy="64.929256"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     showborder="false"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="1132"
+     inkscape:window-height="961"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-193.20113,-609.30267)">
+    <g
+       id="g3829">
+      <g
+         transform="translate(-61.473095,237.81998)"
+         id="g3821">
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:none"
+           id="rect2998"
+           width="120.67989"
+           height="19.546741"
+           x="298.017"
+           y="434.23184"
+           ry="0" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:none"
+           id="rect2998-1"
+           width="120.67989"
+           height="19.546741"
+           x="290.65155"
+           y="488.76447"
+           ry="0" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:none"
+           id="rect2998-7"
+           width="183.60896"
+           height="19.546741"
+           x="384.33142"
+           y="-455.46609"
+           ry="0"
+           transform="matrix(-0.13731609,0.99052728,-1,0,0,0)" />
+        <rect
+           style="fill:#000000;fill-opacity:1;stroke:none"
+           id="rect2998-7-4"
+           width="183.60896"
+           height="19.546741"
+           x="384.04288"
+           y="-406.21848"
+           ry="0"
+           transform="matrix(-0.13731609,0.99052728,-1,0,0,0)" />
+      </g>
+      <rect
+         y="609.30267"
+         x="193.20113"
+         height="200"
+         width="200"
+         id="rect3827"
+         style="fill:none;stroke:none" />
+    </g>
+  </g>
+</svg>
diff --git a/tests/phpunit/data/filecontentshasher/primes.txt b/tests/phpunit/data/filecontentshasher/primes.txt
new file mode 100644 (file)
index 0000000..a2fe1fb
--- /dev/null
@@ -0,0 +1,105 @@
+                         The First 1,000 Primes
+                          (the 1,000th is 7919)
+         For more information on primes see http://primes.utm.edu/
+
+      2      3      5      7     11     13     17     19     23     29
+     31     37     41     43     47     53     59     61     67     71
+     73     79     83     89     97    101    103    107    109    113
+    127    131    137    139    149    151    157    163    167    173
+    179    181    191    193    197    199    211    223    227    229
+    233    239    241    251    257    263    269    271    277    281
+    283    293    307    311    313    317    331    337    347    349
+    353    359    367    373    379    383    389    397    401    409
+    419    421    431    433    439    443    449    457    461    463
+    467    479    487    491    499    503    509    521    523    541
+    547    557    563    569    571    577    587    593    599    601
+    607    613    617    619    631    641    643    647    653    659
+    661    673    677    683    691    701    709    719    727    733
+    739    743    751    757    761    769    773    787    797    809
+    811    821    823    827    829    839    853    857    859    863
+    877    881    883    887    907    911    919    929    937    941
+    947    953    967    971    977    983    991    997   1009   1013
+   1019   1021   1031   1033   1039   1049   1051   1061   1063   1069
+   1087   1091   1093   1097   1103   1109   1117   1123   1129   1151
+   1153   1163   1171   1181   1187   1193   1201   1213   1217   1223
+   1229   1231   1237   1249   1259   1277   1279   1283   1289   1291
+   1297   1301   1303   1307   1319   1321   1327   1361   1367   1373
+   1381   1399   1409   1423   1427   1429   1433   1439   1447   1451
+   1453   1459   1471   1481   1483   1487   1489   1493   1499   1511
+   1523   1531   1543   1549   1553   1559   1567   1571   1579   1583
+   1597   1601   1607   1609   1613   1619   1621   1627   1637   1657
+   1663   1667   1669   1693   1697   1699   1709   1721   1723   1733
+   1741   1747   1753   1759   1777   1783   1787   1789   1801   1811
+   1823   1831   1847   1861   1867   1871   1873   1877   1879   1889
+   1901   1907   1913   1931   1933   1949   1951   1973   1979   1987
+   1993   1997   1999   2003   2011   2017   2027   2029   2039   2053
+   2063   2069   2081   2083   2087   2089   2099   2111   2113   2129
+   2131   2137   2141   2143   2153   2161   2179   2203   2207   2213
+   2221   2237   2239   2243   2251   2267   2269   2273   2281   2287
+   2293   2297   2309   2311   2333   2339   2341   2347   2351   2357
+   2371   2377   2381   2383   2389   2393   2399   2411   2417   2423
+   2437   2441   2447   2459   2467   2473   2477   2503   2521   2531
+   2539   2543   2549   2551   2557   2579   2591   2593   2609   2617
+   2621   2633   2647   2657   2659   2663   2671   2677   2683   2687
+   2689   2693   2699   2707   2711   2713   2719   2729   2731   2741
+   2749   2753   2767   2777   2789   2791   2797   2801   2803   2819
+   2833   2837   2843   2851   2857   2861   2879   2887   2897   2903
+   2909   2917   2927   2939   2953   2957   2963   2969   2971   2999
+   3001   3011   3019   3023   3037   3041   3049   3061   3067   3079
+   3083   3089   3109   3119   3121   3137   3163   3167   3169   3181
+   3187   3191   3203   3209   3217   3221   3229   3251   3253   3257
+   3259   3271   3299   3301   3307   3313   3319   3323   3329   3331
+   3343   3347   3359   3361   3371   3373   3389   3391   3407   3413
+   3433   3449   3457   3461   3463   3467   3469   3491   3499   3511
+   3517   3527   3529   3533   3539   3541   3547   3557   3559   3571
+   3581   3583   3593   3607   3613   3617   3623   3631   3637   3643
+   3659   3671   3673   3677   3691   3697   3701   3709   3719   3727
+   3733   3739   3761   3767   3769   3779   3793   3797   3803   3821
+   3823   3833   3847   3851   3853   3863   3877   3881   3889   3907
+   3911   3917   3919   3923   3929   3931   3943   3947   3967   3989
+   4001   4003   4007   4013   4019   4021   4027   4049   4051   4057
+   4073   4079   4091   4093   4099   4111   4127   4129   4133   4139
+   4153   4157   4159   4177   4201   4211   4217   4219   4229   4231
+   4241   4243   4253   4259   4261   4271   4273   4283   4289   4297
+   4327   4337   4339   4349   4357   4363   4373   4391   4397   4409
+   4421   4423   4441   4447   4451   4457   4463   4481   4483   4493
+   4507   4513   4517   4519   4523   4547   4549   4561   4567   4583
+   4591   4597   4603   4621   4637   4639   4643   4649   4651   4657
+   4663   4673   4679   4691   4703   4721   4723   4729   4733   4751
+   4759   4783   4787   4789   4793   4799   4801   4813   4817   4831
+   4861   4871   4877   4889   4903   4909   4919   4931   4933   4937
+   4943   4951   4957   4967   4969   4973   4987   4993   4999   5003
+   5009   5011   5021   5023   5039   5051   5059   5077   5081   5087
+   5099   5101   5107   5113   5119   5147   5153   5167   5171   5179
+   5189   5197   5209   5227   5231   5233   5237   5261   5273   5279
+   5281   5297   5303   5309   5323   5333   5347   5351   5381   5387
+   5393   5399   5407   5413   5417   5419   5431   5437   5441   5443
+   5449   5471   5477   5479   5483   5501   5503   5507   5519   5521
+   5527   5531   5557   5563   5569   5573   5581   5591   5623   5639
+   5641   5647   5651   5653   5657   5659   5669   5683   5689   5693
+   5701   5711   5717   5737   5741   5743   5749   5779   5783   5791
+   5801   5807   5813   5821   5827   5839   5843   5849   5851   5857
+   5861   5867   5869   5879   5881   5897   5903   5923   5927   5939
+   5953   5981   5987   6007   6011   6029   6037   6043   6047   6053
+   6067   6073   6079   6089   6091   6101   6113   6121   6131   6133
+   6143   6151   6163   6173   6197   6199   6203   6211   6217   6221
+   6229   6247   6257   6263   6269   6271   6277   6287   6299   6301
+   6311   6317   6323   6329   6337   6343   6353   6359   6361   6367
+   6373   6379   6389   6397   6421   6427   6449   6451   6469   6473
+   6481   6491   6521   6529   6547   6551   6553   6563   6569   6571
+   6577   6581   6599   6607   6619   6637   6653   6659   6661   6673
+   6679   6689   6691   6701   6703   6709   6719   6733   6737   6761
+   6763   6779   6781   6791   6793   6803   6823   6827   6829   6833
+   6841   6857   6863   6869   6871   6883   6899   6907   6911   6917
+   6947   6949   6959   6961   6967   6971   6977   6983   6991   6997
+   7001   7013   7019   7027   7039   7043   7057   7069   7079   7103
+   7109   7121   7127   7129   7151   7159   7177   7187   7193   7207
+   7211   7213   7219   7229   7237   7243   7247   7253   7283   7297
+   7307   7309   7321   7331   7333   7349   7351   7369   7393   7411
+   7417   7433   7451   7457   7459   7477   7481   7487   7489   7499
+   7507   7517   7523   7529   7537   7541   7547   7549   7559   7561
+   7573   7577   7583   7589   7591   7603   7607   7621   7639   7643
+   7649   7669   7673   7681   7687   7691   7699   7703   7717   7723
+   7727   7741   7753   7757   7759   7789   7793   7817   7823   7829
+   7841   7853   7867   7873   7877   7879   7883   7901   7907   7919
+end.
diff --git a/tests/phpunit/includes/ConsecutiveParametersMatcher.php b/tests/phpunit/includes/ConsecutiveParametersMatcher.php
deleted file mode 100644 (file)
index adf74bb..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/*
- * This file is part of the PHPUnit_MockObject package.
- *
- * (c) Sebastian Bergmann <sebastian@phpunit.de>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Invocation matcher which looks for sets of specific parameters in the invocations.
- *
- * Checks the parameters of the incoming invocations, the parameter list is
- * checked against the defined constraints in $parameters. If the constraint
- * is met it will return true in matches().
- *
- * It takes a list of match groups and and increases a call index after each invocation.
- * So the first invocation uses the first group of constraints, the second the next and so on.
- */
-class PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
-{
-    /**
-     * @var array
-     */
-    private $_parameterGroups = array();
-
-    /**
-     * @var array
-     */
-    private $_invocations = array();
-
-    /**
-     * @param array $parameterGroups
-     */
-    public function __construct(array $parameterGroups)
-    {
-        foreach ($parameterGroups as $index => $parameters) {
-            foreach ($parameters as $parameter) {
-                if (!($parameter instanceof \PHPUnit_Framework_Constraint)) {
-                    $parameter = new \PHPUnit_Framework_Constraint_IsEqual($parameter);
-                }
-                $this->_parameterGroups[$index][] = $parameter;
-            }
-        }
-    }
-
-    /**
-     * @return string
-     */
-    public function toString()
-    {
-        $text = 'with consecutive parameters';
-
-        return $text;
-    }
-
-    /**
-     * @param  PHPUnit_Framework_MockObject_Invocation $invocation
-     * @return bool
-     */
-    public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
-    {
-        $this->_invocations[] = $invocation;
-        $callIndex            = count($this->_invocations) - 1;
-        $this->verifyInvocation($invocation, $callIndex);
-
-        return false;
-    }
-
-    public function verify()
-    {
-        foreach ($this->_invocations as $callIndex => $invocation) {
-            $this->verifyInvocation($invocation, $callIndex);
-        }
-    }
-
-    /**
-     * Verify a single invocation
-     *
-     * @param  PHPUnit_Framework_MockObject_Invocation      $invocation
-     * @param  int                                          $callIndex
-     * @throws PHPUnit_Framework_ExpectationFailedException
-     */
-    private function verifyInvocation(PHPUnit_Framework_MockObject_Invocation $invocation, $callIndex)
-    {
-
-        if (isset($this->_parameterGroups[$callIndex])) {
-            $parameters = $this->_parameterGroups[$callIndex];
-        } else {
-          // no parameter assertion for this call index
-            return;
-        }
-
-        if ($invocation === null) {
-            throw new PHPUnit_Framework_ExpectationFailedException(
-                'Mocked method does not exist.'
-            );
-        }
-
-        if (count($invocation->parameters) < count($parameters)) {
-            throw new PHPUnit_Framework_ExpectationFailedException(
-                sprintf(
-                    'Parameter count for invocation %s is too low.',
-                    $invocation->toString()
-                )
-            );
-        }
-
-        foreach ($parameters as $i => $parameter) {
-            $parameter->evaluate(
-                $invocation->parameters[$i],
-                sprintf(
-                    'Parameter %s for invocation #%d %s does not match expected ' .
-                    'value.',
-                    $i,
-                    $callIndex,
-                    $invocation->toString()
-                )
-            );
-        }
-    }
-}
index 27959b1..51f0083 100644 (file)
@@ -138,7 +138,7 @@ class EditPageTest extends MediaWikiLangTestCase {
                        $page->doEditContent( $content, "base text for test" );
                        $this->forceRevisionDate( $page, '20120101000000' );
 
-                       //sanity check
+                       // sanity check
                        $page->clear();
                        $currentText = ContentHandler::getContentText( $page->getContent() );
 
@@ -335,7 +335,7 @@ hello
                $textWithNewSectionAdded = "$text\n$newSection";
 
                return array(
-                       array( #0
+                       array( # 0
                                $text,
                                '',
                                'hello',
@@ -343,7 +343,7 @@ hello
                                'hello'
                        ),
 
-                       array( #1
+                       array( # 1
                                $text,
                                '1',
                                $sectionOne,
@@ -351,7 +351,7 @@ hello
                                $textWithNewSectionOne,
                        ),
 
-                       array( #2
+                       array( # 2
                                $text,
                                'new',
                                'hello',
@@ -380,14 +380,14 @@ hello
        public static function provideAutoMerge() {
                $tests = array();
 
-               $tests[] = array( #0: plain conflict
+               $tests[] = array( # 0: plain conflict
                        "Elmo", # base edit user
                        "one\n\ntwo\n\nthree\n",
-                       array( #adam's edit
+                       array( # adam's edit
                                'wpStarttime' => 1,
                                'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
                        ),
-                       array( #berta's edit
+                       array( # berta's edit
                                'wpStarttime' => 2,
                                'wpTextbox1' => "(one)\n\ntwo\n\nthree\n",
                        ),
@@ -396,14 +396,14 @@ hello
                        'expected edit conflict', # message
                );
 
-               $tests[] = array( #1: successful merge
+               $tests[] = array( # 1: successful merge
                        "Elmo", # base edit user
                        "one\n\ntwo\n\nthree\n",
-                       array( #adam's edit
+                       array( # adam's edit
                                'wpStarttime' => 1,
                                'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
                        ),
-                       array( #berta's edit
+                       array( # berta's edit
                                'wpStarttime' => 2,
                                'wpTextbox1' => "one\n\ntwo\n\nTHREE\n",
                        ),
@@ -424,15 +424,15 @@ hello
                // generate expected text after merge
                $expected = str_replace( 'one', 'ONE', str_replace( 'three', 'THREE', $text ) );
 
-               $tests[] = array( #2: merge in section
+               $tests[] = array( # 2: merge in section
                        "Elmo", # base edit user
                        $text,
-                       array( #adam's edit
+                       array( # adam's edit
                                'wpStarttime' => 1,
                                'wpTextbox1' => str_replace( 'one', 'ONE', $section ),
                                'wpSection' => '1'
                        ),
-                       array( #berta's edit
+                       array( # berta's edit
                                'wpStarttime' => 2,
                                'wpTextbox1' => str_replace( 'three', 'THREE', $section ),
                                'wpSection' => '1'
@@ -465,7 +465,7 @@ hello
        ) {
                $this->checkHasDiff3();
 
-               //create page
+               // create page
                $ns = $this->getDefaultWikitextNS();
                $title = Title::newFromText( 'EditPageTest_testAutoMerge', $ns );
                $page = WikiPage::factory( $title );
index c60170f..0a1b7d0 100644 (file)
@@ -13,7 +13,7 @@ class FallbackTest extends MediaWikiTestCase {
 
                $sampleUTF = "Östergötland_coat_of_arms.png";
 
-               //mb_substr
+               // mb_substr
                $substr_params = array(
                        array( 0, 0 ),
                        array( 5, -4 ),
@@ -35,21 +35,21 @@ class FallbackTest extends MediaWikiTestCase {
                        );
                }
 
-               //mb_strlen
+               // mb_strlen
                $this->assertEquals(
                        mb_strlen( $sampleUTF ),
                        Fallback::mb_strlen( $sampleUTF ),
                        'Fallback mb_strlen'
                );
 
-               //mb_str(r?)pos
+               // mb_str(r?)pos
                $strpos_params = array(
-                       //array( 'ter' ),
-                       //array( 'Ö' ),
-                       //array( 'Ö', 3 ),
-                       //array( 'oat_', 100 ),
-                       //array( 'c', -10 ),
-                       //Broken for now
+                       // array( 'ter' ),
+                       // array( 'Ö' ),
+                       // array( 'Ö', 3 ),
+                       // array( 'oat_', 100 ),
+                       // array( 'c', -10 ),
+                       // Broken for now
                );
 
                foreach ( $strpos_params as $param_set ) {
index e89e36f..e39e02f 100644 (file)
@@ -306,7 +306,7 @@ class GlobalTest extends MediaWikiTestCase {
 
                $this->setMwGlobals( array(
                        'wgDebugLogFile' => $debugLogFile,
-                       # @todo FIXME: $wgDebugTimestamps should be tested
+                       #  @todo FIXME: $wgDebugTimestamps should be tested
                        'wgDebugTimestamps' => false
                ) );
 
@@ -353,7 +353,7 @@ class GlobalTest extends MediaWikiTestCase {
                        'gzip;q=1.0' => true,
                        'foozip' => false,
                        'foo*zip' => false,
-                       'gzip;q=abcde' => true, //is this REALLY valid?
+                       'gzip;q=abcde' => true, // is this REALLY valid?
                        'gzip;q=12345678.9' => true,
                        ' gzip' => true,
                );
@@ -551,10 +551,10 @@ class GlobalTest extends MediaWikiTestCase {
 
        public static function provideMakeUrlIndexes() {
                return array(
+                       // Testcase for T30627
                        array(
-                               // just a regular :)
-                               'https://bugzilla.wikimedia.org/show_bug.cgi?id=28627',
-                               array( 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627' )
+                               'https://example.org/test.cgi?id=12345',
+                               array( 'https://org.example./test.cgi?id=12345' )
                        ),
                        array(
                                // mailtos are handled special
@@ -563,7 +563,7 @@ class GlobalTest extends MediaWikiTestCase {
                                array( 'mailto:org.wikimedia@wiki.' )
                        ),
 
-                       // file URL cases per bug 28627...
+                       // file URL cases per T30627...
                        array(
                                // three slashes: local filesystem path Unix-style
                                'file:///whatever/you/like.txt',
@@ -587,12 +587,12 @@ class GlobalTest extends MediaWikiTestCase {
                        // Those will survive the algorithm but with results that
                        // are less consistent.
 
-                       // protocol-relative URL cases per bug 29854...
+                       // protocol-relative URL cases per T31854...
                        array(
-                               '//bugzilla.wikimedia.org/show_bug.cgi?id=28627',
+                               '//example.org/test.cgi?id=12345',
                                array(
-                                       'http://org.wikimedia.bugzilla./show_bug.cgi?id=28627',
-                                       'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627'
+                                       'http://org.example./test.cgi?id=12345',
+                                       'https://org.example./test.cgi?id=12345'
                                )
                        ),
                );
index d4df7b0..92115b0 100644 (file)
@@ -7,7 +7,7 @@
  * @covers ::wfUrlencode
  */
 class WfUrlencodeTest extends MediaWikiTestCase {
-       #### TESTS ##############################################################
+       # ### TESTS ##############################################################
 
        /**
         * @dataProvider provideURLS
@@ -23,7 +23,7 @@ class WfUrlencodeTest extends MediaWikiTestCase {
                $this->verifyEncodingFor( 'Microsoft-IIS/7', $input, $expected );
        }
 
-       #### HELPERS #############################################################
+       # ### HELPERS #############################################################
 
        /**
         * Internal helper that actually run the test.
@@ -76,7 +76,7 @@ class WfUrlencodeTest extends MediaWikiTestCase {
                }
        }
 
-       #### PROVIDERS ###########################################################
+       # ### PROVIDERS ###########################################################
 
        /**
         * Format is either:
@@ -91,7 +91,7 @@ class WfUrlencodeTest extends MediaWikiTestCase {
         */
        public static function provideURLS() {
                return array(
-                       ### RFC 1738 chars
+                       # ## RFC 1738 chars
                        // + is not safe
                        array( '+', '%2B' ),
                        // & and = not safe in queries
@@ -109,7 +109,7 @@ class WfUrlencodeTest extends MediaWikiTestCase {
                                ';@$-_.!*',
                        ),
 
-                       ### Other tests
+                       # ## Other tests
                        // slash remain unchanged. %2F seems to break things
                        array( '/', '/' ),
                        // T105265
index 1c3e853..df54914 100644 (file)
@@ -114,7 +114,7 @@ class HtmlFormatterTest extends MediaWikiTestCase {
                                array(),
                                $removeTags, // Have some rules to trigger a DOM parse
                        ),
-                       // https://bugzilla.wikimedia.org/show_bug.cgi?id=53086
+                       // https://phabricator.wikimedia.org/T55086
                        array(
                                'Foo<sup id="cite_ref-1" class="reference"><a href="#cite_note-1">[1]</a></sup>'
                                        . ' <a href="/wiki/Bar" title="Bar" class="mw-redirect">Bar</a>',
index c5797c4..830a7be 100644 (file)
@@ -103,7 +103,7 @@ class HtmlTest extends MediaWikiTestCase {
         */
        public function testExpandAttributesSkipsNullAndFalse() {
 
-               ### EMPTY ########
+               # ## EMPTY ########
                $this->assertEmpty(
                        Html::expandAttributes( array( 'foo' => null ) ),
                        'skip keys with null value'
@@ -187,7 +187,7 @@ class HtmlTest extends MediaWikiTestCase {
         * @covers Html::expandAttributes
         */
        public function testExpandAttributesVariousExpansions() {
-               ### NOT EMPTY ####
+               # ## NOT EMPTY ####
                $this->assertEquals(
                        ' empty_string=""',
                        Html::expandAttributes( array( 'empty_string' => '' ) ),
@@ -240,7 +240,7 @@ class HtmlTest extends MediaWikiTestCase {
         * @covers Html::expandAttributes
         */
        public function testExpandAttributesListValueAttributes() {
-               ### STRING VALUES
+               # ## STRING VALUES
                $this->assertEquals(
                        ' class="redundant spaces here"',
                        Html::expandAttributes( array( 'class' => ' redundant  spaces  here  ' ) ),
@@ -251,7 +251,7 @@ class HtmlTest extends MediaWikiTestCase {
                        Html::expandAttributes( array( 'class' => 'foo bar foo bar bar' ) ),
                        'Normalization should remove duplicates in string-lists'
                );
-               ### "EMPTY" ARRAY VALUES
+               # ## "EMPTY" ARRAY VALUES
                $this->assertEquals(
                        ' class=""',
                        Html::expandAttributes( array( 'class' => array() ) ),
@@ -262,7 +262,7 @@ class HtmlTest extends MediaWikiTestCase {
                        Html::expandAttributes( array( 'class' => array( null, '', ' ', '  ' ) ) ),
                        'Array with null, empty string and spaces'
                );
-               ### NON-EMPTY ARRAY VALUES
+               # ## NON-EMPTY ARRAY VALUES
                $this->assertEquals(
                        ' class="foo bar"',
                        Html::expandAttributes( array( 'class' => array(
@@ -528,7 +528,7 @@ class HtmlTest extends MediaWikiTestCase {
                # Will be mapped to Html::element()
                $cases = array();
 
-               ### Generic cases, match $attribDefault static array
+               # ## Generic cases, match $attribDefault static array
                $cases[] = array( '<area>',
                        'area', array( 'shape' => 'rect' )
                );
@@ -602,7 +602,7 @@ class HtmlTest extends MediaWikiTestCase {
                        'textarea', array( 'wrap' => 'soft' )
                );
 
-               ### SPECIFIC CASES
+               # ## SPECIFIC CASES
 
                # <link type="text/css">
                $cases[] = array( '<link>',
index 8a0dff7..ea4b646 100644 (file)
@@ -95,8 +95,8 @@ class HttpTest extends MediaWikiTestCase {
                        # (\S+) - host part is made of anything not whitespaces
                        // commented these out in order to remove @group Broken
                        // @todo are these valid tests? if so, fix Http::isValidURI so it can handle them
-                       //array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ),
-                       //array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ),
+                       // array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ),
+                       // array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ),
 
                        # (:[0-9]+)? - port number
                        array( true, 'http://example.org:80/' ),
index 6808105..f011f47 100644 (file)
@@ -172,7 +172,7 @@ class LinkFilterTest extends MediaWikiLangTestCase {
                        //
                        // array( null, 'http://*.test.com', 'http://www.test.com:80', false ),
                        // array( '', 'https://*.wikimedia.org/r/#/q/status:open,n,z',
-                       //      'https://gerrit.wikimedia.org/XXX/r/#/q/status:open,n,z', false ),
+                       //      'https://gerrit.wikimedia.org/XXX/r/#/q/status:open,n,z', false ),
                );
 
        }
index a3efbb8..19ab56f 100644 (file)
@@ -30,7 +30,7 @@ class LinkerTest extends MediaWikiLangTestCase {
                # - optional message
                return array(
 
-                       ### ANONYMOUS USER ########################################
+                       # ## ANONYMOUS USER ########################################
                        array(
                                '<a href="/wiki/Special:Contributions/JohnDoe" '
                                        . 'title="Special:Contributions/JohnDoe" '
@@ -82,7 +82,7 @@ class LinkerTest extends MediaWikiLangTestCase {
                                'Anonymous with IPv4 and an alternative username'
                        ),
 
-                       ### Regular user ##########################################
+                       # ## Regular user ##########################################
                        # TODO!
                );
        }
@@ -93,7 +93,9 @@ class LinkerTest extends MediaWikiLangTestCase {
         * @covers Linker::formatAutocomments
         * @covers Linker::formatLinksInComment
         */
-       public function testFormatComment( $expected, $comment, $title = false, $local = false, $wikiId = null ) {
+       public function testFormatComment(
+               $expected, $comment, $title = false, $local = false, $wikiId = null
+       ) {
                $conf = new SiteConfiguration();
                $conf->settings = array(
                        'wgServer' => array(
index 311350b..4fc54e8 100644 (file)
@@ -29,7 +29,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
                ) );
        }
 
-#### START OF TESTS #########################################################
+# ### START OF TESTS #########################################################
 
        /**
         * @todo Write more texts, handle $wgAllowImageMoving setting
@@ -137,9 +137,9 @@ class MWNamespaceTest extends MediaWikiTestCase {
                $this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) );
        }
 
-       ### Exceptions with getAssociated()
-       ### NS_MEDIA and NS_SPECIAL do not have talk pages. MediaWiki raises
-       ### an exception for them.
+       # ## Exceptions with getAssociated()
+       # ## NS_MEDIA and NS_SPECIAL do not have talk pages. MediaWiki raises
+       # ## an exception for them.
        /**
         * @expectedException MWException
         * @covers MWNamespace::getAssociated
@@ -565,7 +565,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
                $this->assertFalse( MWNamespace::isNonincludable( NS_TEMPLATE ) );
        }
 
-       ####### HELPERS ###########################################################
+       # ###### HELPERS ###########################################################
        function __call( $method, $args ) {
                // Call the real method if it exists
                if ( method_exists( $this, $method ) ) {
index f0d905e..fbb3982 100644 (file)
@@ -323,8 +323,6 @@ class OutputPageTest extends MediaWikiTestCase {
                                        array( 'Cookie', array( 'string-contains=phpsessid' ) ),
                                        array( 'Cookie', array( 'string-contains=phpsessid' ) ),
                                        array( 'Accept-Language', array( 'string-contains=en', 'string-contains=en' ) ),
-
-
                                ),
                                'Vary: Cookie, Accept-Language',
                                'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
@@ -359,6 +357,7 @@ class NullMessageBlobStore extends MessageBlobStore {
 
        public function updateMessage( $key ) {
        }
+
        public function clear() {
        }
 }
index 9a429bc..301ec5c 100644 (file)
@@ -226,7 +226,7 @@ class RevisionStorageTest extends MediaWikiTestCase {
 
                $res = Revision::fetchRevision( $page->getTitle() );
 
-               #note: order is unspecified
+               # note: order is unspecified
                $rows = array();
                while ( ( $row = $res->fetchObject() ) ) {
                        $rows[$row->rev_id] = $row;
@@ -297,7 +297,7 @@ class RevisionStorageTest extends MediaWikiTestCase {
                $this->assertNull( $rev->getContent(),
                        "getContent() should return null if the revision's text blob could not be loaded." );
 
-               //NOTE: check this twice, once for lazy initialization, and once with the cached value.
+               // NOTE: check this twice, once for lazy initialization, and once with the cached value.
                $this->assertNull( $rev->getContent(),
                        "getContent() should return null if the revision's text blob could not be loaded." );
        }
@@ -462,16 +462,16 @@ class RevisionStorageTest extends MediaWikiTestCase {
 
        public static function provideUserWasLastToEdit() {
                return array(
-                       array( #0
+                       array( # 0
                                3, true, # actually the last edit
                        ),
-                       array( #1
+                       array( # 1
                                2, true, # not the current edit, but still by this user
                        ),
-                       array( #2
+                       array( # 2
                                1, false, # edit by another user
                        ),
-                       array( #3
+                       array( # 3
                                0, false, # first edit, by this user, but another user edited in the mean time
                        ),
                );
index 4623b38..eb17588 100644 (file)
@@ -211,7 +211,7 @@ class RevisionTest extends MediaWikiTestCase {
        }
 
        function dataGetContentModel() {
-               //NOTE: we expect the help namespace to always contain wikitext
+               // NOTE: we expect the help namespace to always contain wikitext
                return array(
                        array( 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ),
                        array( 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ),
@@ -231,7 +231,7 @@ class RevisionTest extends MediaWikiTestCase {
        }
 
        function dataGetContentFormat() {
-               //NOTE: we expect the help namespace to always contain wikitext
+               // NOTE: we expect the help namespace to always contain wikitext
                return array(
                        array( 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ),
                        array( 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ),
@@ -252,7 +252,7 @@ class RevisionTest extends MediaWikiTestCase {
        }
 
        function dataGetContentHandler() {
-               //NOTE: we expect the help namespace to always contain wikitext
+               // NOTE: we expect the help namespace to always contain wikitext
                return array(
                        array( 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ),
                        array( 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ),
@@ -272,7 +272,7 @@ class RevisionTest extends MediaWikiTestCase {
        }
 
        function dataGetContent() {
-               //NOTE: we expect the help namespace to always contain wikitext
+               // NOTE: we expect the help namespace to always contain wikitext
                return array(
                        array( 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ),
                        array(
@@ -312,7 +312,7 @@ class RevisionTest extends MediaWikiTestCase {
        }
 
        function dataGetText() {
-               //NOTE: we expect the help namespace to always contain wikitext
+               // NOTE: we expect the help namespace to always contain wikitext
                return array(
                        array( 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ),
                        array( serialize( 'hello world' ), 'Hello', "testing", null, Revision::FOR_PUBLIC, null ),
index 291ed31..c95e69b 100644 (file)
@@ -64,7 +64,16 @@ class StatusTest extends MediaWikiLangTestCase {
                $this->assertTrue( $status->ok );
                $status = Status::newFatal( 'foo', 1, 2 );
                $this->assertFalse( $status->ok );
-               $this->assertArrayEquals( array( array( 'type' => 'error', 'message' => 'foo', 'params' => array( 1, 2 ) ) ), $status->errors );
+               $this->assertArrayEquals(
+                       array(
+                               array(
+                                       'type' => 'error',
+                                       'message' => 'foo',
+                                       'params' => array( 1, 2 )
+                               )
+                       ),
+                       $status->errors
+               );
        }
 
        /**
@@ -439,14 +448,14 @@ class StatusTest extends MediaWikiLangTestCase {
                // and the first call to the setUp method. Because of that you can't access any variables
                // you create there from within a data provider."
                // http://phpunit.de/manual/3.7/en/writing-tests-for-phpunit.html
-//             $status = new Status();
-//             $status->warning( 'fooBar!' );
-//             $status->warning( 'fooBar2!' );
-//             $testCases[ '2StringWarnings' ] = array(
-//                     $status,
-//                     array( new Message( 'fooBar!' ), new Message( 'fooBar2!' ) ),
-//                     "* \$1\n* \$2"
-//             );
+//             $status = new Status();
+//             $status->warning( 'fooBar!' );
+//             $status->warning( 'fooBar2!' );
+//             $testCases[ '2StringWarnings' ] = array(
+//                     $status,
+//                     array( new Message( 'fooBar!' ), new Message( 'fooBar2!' ) ),
+//                     "* \$1\n* \$2"
+//             );
 
                $status = new Status();
                $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
index 6654a5b..aad435e 100644 (file)
@@ -113,7 +113,7 @@ class TitleArrayFromResultTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( $expected, $object->valid() );
        }
 
-       //@todo unit test for key()
-       //@todo unit test for next()
-       //@todo unit test for rewind()
+       // @todo unit test for key()
+       // @todo unit test for next()
+       // @todo unit test for rewind()
 }
index f588ed6..1318d10 100644 (file)
@@ -248,7 +248,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                );
 
                if ( $this->isWikitextNS( NS_MAIN ) ) {
-                       //NOTE: some content models don't allow moving
+                       // NOTE: some content models don't allow moving
                        // @todo find a Wikitext namespace for testing
 
                        $this->setTitle( NS_MAIN );
index a2c6f23..5ede0ab 100644 (file)
@@ -99,9 +99,9 @@ class TitleTest extends MediaWikiTestCase {
                        // XML/HTML character entity references
                        // Note: Commented out because they are not marked invalid by the PHP test as
                        // Title::newFromText runs Sanitizer::decodeCharReferencesAndNormalize first.
-                       //'A &eacute; B',
-                       //'A &#233; B',
-                       //'A &#x00E9; B',
+                       // 'A &eacute; B',
+                       // 'A &#233; B',
+                       // 'A &#x00E9; B',
                        // Subject of NS_TALK does not roundtrip to NS_MAIN
                        array( 'Talk:File:Example.svg', 'title-invalid-talk-namespace' ),
                        // Directory navigation
index 62989fa..469ad29 100644 (file)
@@ -108,7 +108,7 @@ class UserArrayFromResultTest extends MediaWikiTestCase {
                $this->assertEquals( $expected, $object->valid() );
        }
 
-       //@todo unit test for key()
-       //@todo unit test for next()
-       //@todo unit test for rewind()
+       // @todo unit test for key()
+       // @todo unit test for next()
+       // @todo unit test for rewind()
 }
index 77132bb..17c1b8e 100644 (file)
@@ -527,7 +527,7 @@ class UserTest extends MediaWikiTestCase {
 
                $setcookieInvocations = $setcookieSpy->getInvocations();
                $setcookieInvocation = end( $setcookieInvocations );
-               $actualExpiry = $setcookieInvocation->parameters[ 2 ];
+               $actualExpiry = $setcookieInvocation->parameters[2];
 
                // TODO: ± 300 seconds compensates for
                // slow-running tests. However, the dependency on the time
index 9233416..bfb99f2 100644 (file)
@@ -62,7 +62,7 @@ class WikiMapTest extends MediaWikiLangTestCase {
        public function provideMakeForeignLink() {
                return array(
                        'unknown' => array( false, 'xyzzy', 'Foo' ),
-                       'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/Foo">Foo</a>', 'enwiki', 'Foo' ),
+                       'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/Foo">Foo</a>', 'enwiki', 'Foo' ),
                        'ruwiki' => array( '<a class="external" rel="nofollow" href="//ru.example.org/wiki/%D0%A4%D1%83">вар</a>', 'ruwiki', 'Фу', 'вар' ),
                );
        }
@@ -77,7 +77,7 @@ class WikiMapTest extends MediaWikiLangTestCase {
        public function provideForeignUserLink() {
                return array(
                        'unknown' => array( false, 'xyzzy', 'Foo' ),
-                       'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/User:Foo">User:Foo</a>', 'enwiki', 'Foo' ),
+                       'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/User:Foo">User:Foo</a>', 'enwiki', 'Foo' ),
                        'ruwiki' => array( '<a class="external" rel="nofollow" href="//ru.example.org/wiki/User:%D0%A4%D1%83">вар</a>', 'ruwiki', 'Фу', 'вар' ),
                );
        }
@@ -92,7 +92,7 @@ class WikiMapTest extends MediaWikiLangTestCase {
        public function provideGetForeignURL() {
                return array(
                        'unknown' => array( false, 'xyzzy', 'Foo' ),
-                       'enwiki' => array( 'http://en.example.org/w/Foo', 'enwiki', 'Foo' ),
+                       'enwiki' => array( 'http://en.example.org/w/Foo', 'enwiki', 'Foo' ),
                        'ruwiki with fragement' => array( '//ru.example.org/wiki/%D0%A4%D1%83#%D0%B2%D0%B0%D1%80', 'ruwiki', 'Фу', 'вар' ),
                );
        }
@@ -105,4 +105,3 @@ class WikiMapTest extends MediaWikiLangTestCase {
        }
 
 }
-
index 4fe2e85..b72bae7 100644 (file)
@@ -77,4 +77,3 @@ class WikiReferenceTest extends PHPUnit_Framework_TestCase {
        }
 
 }
-
index 3babb97..63e0c8e 100644 (file)
@@ -92,7 +92,7 @@ class ActionTest extends MediaWikiTestCase {
        }
 
        public function testGetActionName_editredlinkWorkaround() {
-               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               // See https://phabricator.wikimedia.org/T22966
                $context = $this->getContext( 'editredlink' );
                $actionName = Action::getActionName( $context );
 
@@ -100,7 +100,7 @@ class ActionTest extends MediaWikiTestCase {
        }
 
        public function testGetActionName_historysubmitWorkaround() {
-               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               // See https://phabricator.wikimedia.org/T22966
                $context = $this->getContext( 'historysubmit' );
                $actionName = Action::getActionName( $context );
 
@@ -108,7 +108,7 @@ class ActionTest extends MediaWikiTestCase {
        }
 
        public function testGetActionName_revisiondeleteWorkaround() {
-               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               // See https://phabricator.wikimedia.org/T22966
                $context = $this->getContext( 'historysubmit' );
                $context->getRequest()->setVal( 'revisiondelete', true );
                $actionName = Action::getActionName( $context );
index 575efd6..e0488b7 100644 (file)
@@ -30,11 +30,11 @@ class ApiBlockTest extends ApiTestCase {
 
        /**
         * This test has probably always been broken and use an invalid token
-        * Bug tracking brokenness is https://bugzilla.wikimedia.org/35646
+        * Bug tracking brokenness is https://phabricator.wikimedia.org/T37646
         *
         * Root cause is https://gerrit.wikimedia.org/r/3434
         * Which made the Block/Unblock API to actually verify the token
-        * previously always considered valid (bug 34212).
+        * previously always considered valid (T36212).
         */
        public function testMakeNormalBlock() {
                $tokens = $this->getTokens();
index 61a8ad1..6a24281 100644 (file)
@@ -106,22 +106,22 @@ class ApiEditPageTest extends ApiTestCase {
         */
        public static function provideEditAppend() {
                return array(
-                       array( #0: append
+                       array( # 0: append
                                'foo', 'append', 'bar', "foobar"
                        ),
-                       array( #1: prepend
+                       array( # 1: prepend
                                'foo', 'prepend', 'bar', "barfoo"
                        ),
-                       array( #2: append to empty page
+                       array( # 2: append to empty page
                                '', 'append', 'foo', "foo"
                        ),
-                       array( #3: prepend to empty page
+                       array( # 3: prepend to empty page
                                '', 'prepend', 'foo', "foo"
                        ),
-                       array( #4: append to non-existing page
+                       array( # 4: append to non-existing page
                                null, 'append', 'foo', "foo"
                        ),
-                       array( #5: prepend to non-existing page
+                       array( # 5: prepend to non-existing page
                                null, 'prepend', 'foo', "foo"
                        ),
                );
index c852d72..40de254 100644 (file)
@@ -11,7 +11,7 @@
  * @todo Port the other Upload tests, and other API tests to this framework
  *
  * @todo Broken test, reports false errors from time to time.
- * See https://bugzilla.wikimedia.org/26169
+ * See https://phabricator.wikimedia.org/T28169
  *
  * @todo This is pretty sucky... needs to be prettified.
  *
index e49c6c0..dc86b22 100644 (file)
@@ -98,7 +98,7 @@ class ApiWatchTest extends ApiTestCase {
                $this->getTokens();
 
                if ( !Title::newFromText( 'Help:UTPage' )->exists() ) {
-                       $this->markTestSkipped( "The article [[Help:UTPage]] does not exist" ); //TODO: just create it?
+                       $this->markTestSkipped( "The article [[Help:UTPage]] does not exist" ); // TODO: just create it?
                }
 
                $data = $this->doApiRequest( array(
index 0cb44e9..09c7c0c 100644 (file)
@@ -134,7 +134,7 @@ class ApiFormatPhpTest extends ApiFormatTestBase {
                } catch ( UsageException $ex ) {
                        ob_end_clean();
                        $this->assertSame(
-                               'This response cannot be represented using format=php. See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776',
+                               'This response cannot be represented using format=php. See https://phabricator.wikimedia.org/T68776',
                                $ex->getMessage(),
                                'Expected exception'
                        );
index db61bc8..3960e88 100644 (file)
@@ -74,7 +74,7 @@ abstract class ApiQueryContinueTestBase extends ApiQueryTestBase {
                                return strcmp( $a, $b );
                        } );
                        $reqStr = http_build_query( $request );
-                       //$reqStr = str_replace( '&', ' & ', $reqStr );
+                       // $reqStr = str_replace( '&', ' & ', $reqStr );
                        $this->assertLessThan( $expectedCount, $count, "$id more data: $reqStr" );
                        if ( $this->mVerbose ) {
                                print "$id (#$count): $reqStr\n";
index 04fb00d..6b22000 100644 (file)
@@ -7,7 +7,7 @@
 class GenderCacheTest extends MediaWikiLangTestCase {
 
        function addDBData() {
-               //ensure the correct default gender
+               // ensure the correct default gender
                $this->mergeMwGlobalArrayValue( 'wgDefaultUserOptions', array( 'gender' => 'unknown' ) );
 
                $user = User::newFromName( 'UTMale' );
@@ -15,7 +15,7 @@ class GenderCacheTest extends MediaWikiLangTestCase {
                        $user->addToDatabase();
                        $user->setPassword( 'UTMalePassword' );
                }
-               //ensure the right gender
+               // ensure the right gender
                $user->setOption( 'gender', 'male' );
                $user->saveSettings();
 
@@ -24,7 +24,7 @@ class GenderCacheTest extends MediaWikiLangTestCase {
                        $user->addToDatabase();
                        $user->setPassword( 'UTFemalePassword' );
                }
-               //ensure the right gender
+               // ensure the right gender
                $user->setOption( 'gender', 'female' );
                $user->saveSettings();
 
@@ -33,7 +33,7 @@ class GenderCacheTest extends MediaWikiLangTestCase {
                        $user->addToDatabase();
                        $user->setPassword( 'UTDefaultGenderPassword' );
                }
-               //ensure the default gender
+               // ensure the default gender
                $user->setOption( 'gender', null );
                $user->saveSettings();
        }
@@ -69,7 +69,7 @@ class GenderCacheTest extends MediaWikiLangTestCase {
                        array( 'UTFemale', 'female' ),
                        array( 'UTDefaultGender', 'unknown' ),
                        array( 'UTNotExist', 'unknown' ),
-                       //some not valid user
+                       // some not valid user
                        array( '127.0.0.1', 'unknown' ),
                        array( 'user@test', 'unknown' ),
                );
index 4d1a936..fd287b5 100644 (file)
@@ -41,44 +41,6 @@ class RecentChangeTest extends MediaWikiTestCase {
                $this->assertEquals( $expected, $rc->getAttributes() );
        }
 
-       /**
-        * The testIrcMsgForAction* tests are supposed to cover the hacky
-        * LogFormatter::getIRCActionText / bug 34508
-        *
-        * Third parties bots listen to those messages. They are clever enough
-        * to fetch the i18n messages from the wiki and then analyze the IRC feed
-        * to reverse engineer the $1, $2 messages.
-        * One thing bots can not detect is when MediaWiki change the meaning of
-        * a message like what happened when we deployed 1.19. $1 became the user
-        * performing the action which broke basically all bots around.
-        *
-        * Should cover the following log actions (which are most commonly used by bots):
-        * - block/block
-        * - block/unblock
-        * - block/reblock
-        * - delete/delete
-        * - delete/restore
-        * - newusers/create
-        * - newusers/create2
-        * - newusers/autocreate
-        * - move/move
-        * - move/move_redir
-        * - protect/protect
-        * - protect/modifyprotect
-        * - protect/unprotect
-        * - protect/move_prot
-        * - upload/upload
-        * - merge/merge
-        * - import/upload
-        * - import/interwiki
-        *
-        * As well as the following Auto Edit Summaries:
-        * - blank
-        * - replace
-        * - rollback
-        * - undo
-        */
-
        /**
         * @covers RecentChange::parseParams
         */
index c4d87c2..59bfb03 100644 (file)
@@ -111,7 +111,7 @@ class CssContentTest extends JavaScriptContentTest {
                );
        }
 
-               public static function dataEquals() {
+       public static function dataEquals() {
                return array(
                        array( new CssContent( 'hallo' ), null, false ),
                        array( new CssContent( 'hallo' ), new CssContent( 'hallo' ), true ),
index 0ee2712..898fa53 100644 (file)
@@ -253,7 +253,7 @@ class JavaScriptContentTest extends TextContentTest {
         * @covers JavaScriptContent::updateRedirect
         * @dataProvider provideUpdateRedirect
         */
-       public function testUpdateRedirect( $oldText, $expectedText) {
+       public function testUpdateRedirect( $oldText, $expectedText ) {
                $this->setMwGlobals( array(
                        'wgServer' => '//example.org',
                        'wgScriptPath' => '/w/index.php',
index fe26375..06609d8 100644 (file)
@@ -93,12 +93,12 @@ class TextContentTest extends MediaWikiLangTestCase {
        public static function dataPreSaveTransform() {
                return array(
                        array(
-                               #0: no signature resolution
+                               # 0: no signature resolution
                                'hello this is ~~~',
                                'hello this is ~~~',
                        ),
                        array(
-                               #1: rtrim
+                               # 1: rtrim
                                " Foo \n ",
                                ' Foo',
                        ),
@@ -421,7 +421,7 @@ class TextContentTest extends MediaWikiLangTestCase {
                        $update = $updates[$class];
 
                        foreach ( $fieldValues as $field => $value ) {
-                               $v = $update->$field; #if the field doesn't exist, just crash and burn
+                               $v = $update->$field; # if the field doesn't exist, just crash and burn
                                $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
                        }
                }
index 7becd6f..b436ebf 100644 (file)
@@ -89,7 +89,7 @@ more stuff
                        $update = $updates[$class];
 
                        foreach ( $fieldValues as $field => $value ) {
-                               $v = $update->$field; #if the field doesn't exist, just crash and burn
+                               $v = $update->$field; # if the field doesn't exist, just crash and burn
                                $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
                        }
                }
index 3db9172..9307b0c 100644 (file)
@@ -295,7 +295,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
 
                // Versions tested
                $versions = array(
-                       //'1.13', disabled for now, was totally screwed up
+                       // '1.13', disabled for now, was totally screwed up
                        // SQLite wasn't included in 1.14
                        '1.15',
                        '1.16',
index 090f439..9866ce1 100644 (file)
@@ -24,7 +24,7 @@ use MediaWikiTestCase;
 use Monolog\Logger;
 
 // not available in the version of phpunit mw uses, so copied into repo
-require_once __DIR__ . '/../../../ConsecutiveParametersMatcher.php';
+require_once __DIR__ . '/../../../phpunit/ConsecutiveParametersMatcher.php';
 
 class KafkaHandlerTest extends MediaWikiTestCase {
 
@@ -52,10 +52,10 @@ class KafkaHandlerTest extends MediaWikiTestCase {
                $produce = $this->getMockBuilder( 'Kafka\Produce' )
                        ->disableOriginalConstructor()
                        ->getMock();
-               $produce->expects($this->any())
-                       ->method('getAvailablePartitions')
-                       ->will($this->returnValue( array( 'A' ) ) );
-               $produce->expects($this->once())
+               $produce->expects( $this->any() )
+                       ->method( 'getAvailablePartitions' )
+                       ->will( $this->returnValue( array( 'A' ) ) );
+               $produce->expects( $this->once() )
                        ->method( 'setMessages' )
                        ->with( $expect, $this->anything(), $this->anything() );
 
index 02f6b2a..bbd196d 100644 (file)
@@ -255,7 +255,7 @@ class LinksUpdateTest extends MediaWikiTestCase {
        ) {
                $update = new LinksUpdate( $title, $parserOutput );
 
-               //NOTE: make sure LinksUpdate does not generate warnings when called inside a transaction.
+               // NOTE: make sure LinksUpdate does not generate warnings when called inside a transaction.
                $update->beginTransaction();
                $update->doUpdate();
                $update->commitTransaction();
index 2e4942f..d40e527 100644 (file)
@@ -1517,7 +1517,7 @@ class FileBackendTest extends MediaWikiTestCase {
                        array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
                        array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
                        # Specific to FS backend with no basePath field set
-                       #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
+                       # array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
                );
        }
 
@@ -2347,7 +2347,7 @@ class FileBackendTest extends MediaWikiTestCase {
                        $this->assertEquals( true, $status->isOK(),
                                "Locking of files succeeded with OK status ($backendName) ($i)." );
 
-                       ## Flip the acquire/release ordering around ##
+                       # # Flip the acquire/release ordering around ##
 
                        $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
                        $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
index a618889..877cb60 100644 (file)
@@ -75,7 +75,7 @@ class SwiftFileBackendTest extends MediaWikiTestCase {
                                array(
                                        'content-length' => 345,
                                        'content-type'   => 'image+bitmap/jpeg',
-                                       'content-disposition' => 'filename='. str_repeat( 'o', 1024 ) . ';inline',
+                                       'content-disposition' => 'filename=' . str_repeat( 'o', 1024 ) . ';inline',
                                        'content-duration' => 35.6363,
                                        'content-custom' => 'hello',
                                        'x-content-custom' => 'hello'
@@ -145,4 +145,4 @@ class SwiftFileBackendTest extends MediaWikiTestCase {
                        )
                );
        }
-}
\ No newline at end of file
+}
index 681e368..ea3f862 100644 (file)
@@ -99,7 +99,7 @@ class FileBackendDBRepoWrapperTest extends MediaWikiTestCase {
                        ->will( $this->returnValue( '96246614d75ba1703bdfd5d7660bb57407aaf5d9' ) );
 
                $backendMock->expects( $this->once() )
-                       ->method( 'getFileContentsMulti')
+                       ->method( 'getFileContentsMulti' )
                        ->will( $this->returnValue( array( $sha1Path => 'foo' ) ) );
 
                $result = $wrapperMock->getFileContentsMulti( array( 'srcs' => array( $filenamePath ) ) );
index 551d3a7..3f08fd2 100644 (file)
@@ -64,14 +64,14 @@ class MigrateFileRepoLayoutTest extends MediaWikiTestCase {
 
        protected function deleteFilesRecursively( $directory ) {
                foreach ( glob( $directory . '/*' ) as $file ) {
-               if ( is_dir( $file ) ) {
-                       $this->deleteFilesRecursively( $file );
-               } else {
-                       unlink( $file );
-               }
-               }
-
-               rmdir( $directory );
+                       if ( is_dir( $file ) ) {
+                               $this->deleteFilesRecursively( $file );
+                       } else {
+                               unlink( $file );
+                       }
+               }
+
+               rmdir( $directory );
        }
 
        protected function tearDown() {
@@ -103,7 +103,7 @@ class MigrateFileRepoLayoutTest extends MediaWikiTestCase {
                        . '/'
                        . substr( $sha1, 2, 1 )
                        . '/'
-                       . $sha1 ;
+                       . $sha1;
 
                $this->assertEquals( file_get_contents( $expectedOriginalFilepath ), $this->text, 'New sha1 file should be exist and have the right contents' );
 
index edfaf16..35a8e4f 100644 (file)
@@ -23,7 +23,7 @@ class RunningStatTest extends PHPUnit_Framework_TestCase {
         */
        public function testRunningStatAccuracy() {
                $rstat = new RunningStat();
-               foreach( $this->points as $point ) {
+               foreach ( $this->points as $point ) {
                        $rstat->push( $point );
                }
 
@@ -51,7 +51,7 @@ class RunningStatTest extends PHPUnit_Framework_TestCase {
        public function testRunningStatMerge() {
                $expected = new RunningStat();
 
-               foreach( $this->points as $point ) {
+               foreach ( $this->points as $point ) {
                        $expected->push( $point );
                }
 
@@ -60,13 +60,13 @@ class RunningStatTest extends PHPUnit_Framework_TestCase {
 
                // Accumulate the first half into one RunningStat object
                $first = new RunningStat();
-               foreach( $sets[0] as $point ) {
+               foreach ( $sets[0] as $point ) {
                        $first->push( $point );
                }
 
                // Accumulate the second half into another RunningStat object
                $second = new RunningStat();
-               foreach( $sets[1] as $point ) {
+               foreach ( $sets[1] as $point ) {
                        $second->push( $point );
                }
 
index 844c9af..1816708 100644 (file)
@@ -307,6 +307,44 @@ class LogFormatterTest extends MediaWikiLangTestCase {
                );
        }
 
+       /**
+        * The testIrcMsgForAction* tests are supposed to cover the hacky
+        * LogFormatter::getIRCActionText / bug 34508
+        *
+        * Third parties bots listen to those messages. They are clever enough
+        * to fetch the i18n messages from the wiki and then analyze the IRC feed
+        * to reverse engineer the $1, $2 messages.
+        * One thing bots can not detect is when MediaWiki change the meaning of
+        * a message like what happened when we deployed 1.19. $1 became the user
+        * performing the action which broke basically all bots around.
+        *
+        * Should cover the following log actions (which are most commonly used by bots):
+        * - block/block
+        * - block/unblock
+        * - block/reblock
+        * - delete/delete
+        * - delete/restore
+        * - newusers/create
+        * - newusers/create2
+        * - newusers/autocreate
+        * - move/move
+        * - move/move_redir
+        * - protect/protect
+        * - protect/modifyprotect
+        * - protect/unprotect
+        * - protect/move_prot
+        * - upload/upload
+        * - merge/merge
+        * - import/upload
+        * - import/interwiki
+        *
+        * As well as the following Auto Edit Summaries:
+        * - blank
+        * - replace
+        * - rollback
+        * - undo
+        */
+
        /**
         * @covers LogFormatter::getIRCActionComment
         * @covers LogFormatter::getIRCActionText
@@ -462,13 +500,13 @@ class LogFormatterTest extends MediaWikiLangTestCase {
         */
        public function testIrcMsgForLogTypeProtect() {
                $protectParams = array(
-                       '[edit=sysop] (indefinite) ‎[move=sysop] (indefinite)'
+                       '4::description' => '[edit=sysop] (indefinite) ‎[move=sysop] (indefinite)'
                );
                $sep = $this->context->msg( 'colon-separator' )->text();
 
                # protect/protect
                $this->assertIRCComment(
-                       $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams[0] )
+                       $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams['4::description'] )
                                ->plain() . $sep . $this->user_comment,
                        'protect', 'protect',
                        $protectParams,
@@ -485,7 +523,7 @@ class LogFormatterTest extends MediaWikiLangTestCase {
 
                # protect/modify
                $this->assertIRCComment(
-                       $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams[0] )
+                       $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams['4::description'] )
                                ->plain() . $sep . $this->user_comment,
                        'protect', 'modify',
                        $protectParams,
index e88452b..f175482 100644 (file)
@@ -49,6 +49,7 @@ abstract class LogFormatterTestCase extends MediaWikiLangTestCase {
 
        private static function removeSomeHtml( $html ) {
                $html = str_replace( '&quot;', '"', $html );
+               $html = preg_replace( '/\xE2\x80[\x8E\x8F]/', '', $html ); // Strip lrm/rlm
                return trim( preg_replace( '/<(a|span)[^>]*>([^<]*)<\/\1>/', '$2', $html ) );
        }
 
index 611b2df..718c08c 100644 (file)
@@ -2,6 +2,365 @@
 
 class ProtectLogFormatterTest extends LogFormatterTestCase {
 
+       /**
+        * Provide different rows from the logging table to test
+        * for backward compatibility.
+        * Do not change the existing data, just add a new database row
+        */
+       public static function provideProtectLogDatabaseRows() {
+               return array(
+                       // Current format
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'protect',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '4::description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '5:bool:cascade' => false,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                               array(
+                                       'text' => 'User protected ProtectPage [Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => false,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+
+                       // Current format with cascade
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'protect',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '4::description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '5:bool:cascade' => true,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => true,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                               array(
+                                       'text' => 'User protected ProtectPage [Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite) [cascading]',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => true,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => true,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+
+                       // Legacy format
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'protect',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '',
+                                       ),
+                               ),
+                               array(
+                                       'legacy' => true,
+                                       'text' => 'User protected ProtectPage [edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => false,
+                                       ),
+                               ),
+                       ),
+
+                       // Legacy format with cascade
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'protect',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade',
+                                       ),
+                               ),
+                               array(
+                                       'legacy' => true,
+                                       'text' => 'User protected ProtectPage [edit=sysop] (indefinite)[move=sysop] (indefinite) [cascading]',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => true,
+                                       ),
+                               ),
+                       ),
+               );
+       }
+
+
+       /**
+        * @dataProvider provideProtectLogDatabaseRows
+        */
+       public function testProtectLogDatabaseRows( $row, $extra ) {
+               $this->doTestLogFormatter( $row, $extra );
+       }
+
+       /**
+        * Provide different rows from the logging table to test
+        * for backward compatibility.
+        * Do not change the existing data, just add a new database row
+        */
+       public static function provideModifyLogDatabaseRows() {
+               return array(
+                       // Current format
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'modify',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '4::description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '5:bool:cascade' => false,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                               array(
+                                       'text' => 'User changed protection level for ProtectPage [Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => false,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+
+                       // Current format with cascade
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'modify',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '4::description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '5:bool:cascade' => true,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => true,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinity',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                               array(
+                                       'text' => 'User changed protection level for ProtectPage [Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite) [cascading]',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => true,
+                                               'details' => array(
+                                                       array(
+                                                               'type' => 'edit',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => true,
+                                                       ),
+                                                       array(
+                                                               'type' => 'move',
+                                                               'level' => 'sysop',
+                                                               'expiry' => 'infinite',
+                                                               'cascade' => false,
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+
+                       // Legacy format
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'modify',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               '',
+                                       ),
+                               ),
+                               array(
+                                       'legacy' => true,
+                                       'text' => 'User changed protection level for ProtectPage [edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => false,
+                                       ),
+                               ),
+                       ),
+
+                       // Legacy format with cascade
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'modify',
+                                       'comment' => 'protect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(
+                                               '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade',
+                                       ),
+                               ),
+                               array(
+                                       'legacy' => true,
+                                       'text' => 'User changed protection level for ProtectPage [edit=sysop] (indefinite)[move=sysop] (indefinite) [cascading]',
+                                       'api' => array(
+                                               'description' => '[edit=sysop] (indefinite)[move=sysop] (indefinite)',
+                                               'cascade' => true,
+                                       ),
+                               ),
+                       ),
+               );
+       }
+
+
+       /**
+        * @dataProvider provideModifyLogDatabaseRows
+        */
+       public function testModifyLogDatabaseRows( $row, $extra ) {
+               $this->doTestLogFormatter( $row, $extra );
+       }
+
+       /**
+        * Provide different rows from the logging table to test
+        * for backward compatibility.
+        * Do not change the existing data, just add a new database row
+        */
+       public static function provideUnprotectLogDatabaseRows() {
+               return array(
+                       // Current format
+                       array(
+                               array(
+                                       'type' => 'protect',
+                                       'action' => 'unprotect',
+                                       'comment' => 'unprotect comment',
+                                       'namespace' => NS_MAIN,
+                                       'title' => 'ProtectPage',
+                                       'params' => array(),
+                               ),
+                               array(
+                                       'text' => 'User removed protection from ProtectPage',
+                                       'api' => array(),
+                               ),
+                       ),
+               );
+       }
+
+
+       /**
+        * @dataProvider provideUnprotectLogDatabaseRows
+        */
+       public function testUnprotectLogDatabaseRows( $row, $extra ) {
+               $this->doTestLogFormatter( $row, $extra );
+       }
+
        /**
         * Provide different rows from the logging table to test
         * for backward compatibility.
index c0871f1..31cda64 100644 (file)
@@ -13,7 +13,7 @@ class DjVuTest extends MediaWikiMediaTestCase {
        protected function setUp() {
                parent::setUp();
 
-               //cli tool setup
+               // cli tool setup
                $djvuSupport = new DjVuSupport();
 
                if ( !$djvuSupport->isEnabled() ) {
index 96ede90..5f1f6ca 100644 (file)
@@ -93,7 +93,7 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
        public function testGetMetadata( $filename, $expected ) {
                $file = $this->dataFile( $filename, 'image/png' );
                $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
-//             $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
+//             $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
                $this->assertEquals( ( $expected ), ( $actual ) );
        }
 
index d36710a..285f280 100644 (file)
@@ -24,7 +24,7 @@ class WebPHandlerTest extends MediaWikiTestCase {
                        array( "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
                                array( 'compression' => 'lossless', 'width' => 400, 'height' => 301 ) ),
                        array( "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301) ),
+                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301 ) ),
                        array( "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
                                array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
                        array( "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
@@ -50,9 +50,9 @@ class WebPHandlerTest extends MediaWikiTestCase {
                        array( "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
                                array( 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ) ),
                        array( "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
-                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 772) ),
+                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 772 ) ),
                        array( "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
-                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 752) ),
+                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 752 ) ),
 
                        // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
                        array( "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
index c011e9a..ec08ef4 100644 (file)
@@ -160,7 +160,7 @@ class WikiPageTest extends MediaWikiLangTestCase {
                $this->hideDeprecated( "WikiPage::getText" );
                $this->hideDeprecated( "Revision::getText" );
 
-               //NOTE: assume help namespace will default to wikitext
+               // NOTE: assume help namespace will default to wikitext
                $title = Title::newFromText( "Help:WikiPageTest_testDoEdit" );
 
                $page = $this->newPage( $title );
@@ -220,7 +220,7 @@ class WikiPageTest extends MediaWikiLangTestCase {
 
                $this->hideDeprecated( "WikiPage::doQuickEdit" );
 
-               //NOTE: assume help namespace will default to wikitext
+               // NOTE: assume help namespace will default to wikitext
                $page = $this->createPage( "Help:WikiPageTest_testDoQuickEdit", "original text" );
 
                $text = "quick text";
@@ -743,7 +743,7 @@ more stuff
 ";
 
        public function dataReplaceSection() {
-               //NOTE: assume the Help namespace to contain wikitext
+               // NOTE: assume the Help namespace to contain wikitext
                return array(
                        array( 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
@@ -938,7 +938,7 @@ more stuff
                $this->assertEquals( 'Admin', $rev1->getUserText() );
 
                # now, try the actual rollback
-               $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
+               $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
                $token = $admin->getEditToken(
                        array( $page->getTitle()->getPrefixedText(), $user2->getName() ),
                        null
@@ -995,7 +995,7 @@ more stuff
                );
 
                # now, try the rollback
-               $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
+               $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
                $token = $admin->getEditToken(
                        array( $page->getTitle()->getPrefixedText(), $user1->getName() ),
                        null
@@ -1026,7 +1026,7 @@ more stuff
        public function testDoRollbackFailureSameContent() {
                $admin = new User();
                $admin->setName( "Admin" );
-               $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
+               $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
 
                $text = "one";
                $page = $this->newPage( "WikiPageTest_testDoRollback" );
@@ -1041,7 +1041,7 @@ more stuff
 
                $user1 = new User();
                $user1->setName( "127.0.1.11" );
-               $user1->addGroup( "sysop" ); #XXX: make the test user a sysop...
+               $user1->addGroup( "sysop" ); # XXX: make the test user a sysop...
                $text .= "\n\ntwo";
                $page = new WikiPage( $page->getTitle() );
                $page->doEditContent(
@@ -1219,7 +1219,7 @@ more stuff
        public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
                global $wgUser;
 
-               //NOTE: assume Help namespace to contain wikitext
+               // NOTE: assume Help namespace to contain wikitext
                $page = $this->newPage( "Help:WikiPageTest_testGetAutoDeleteReason" );
 
                $c = 1;
@@ -1275,7 +1275,7 @@ more stuff
                $user = new User();
                $user->setName( "127.0.0.1" );
 
-               //NOTE: assume Help namespace to contain wikitext
+               // NOTE: assume Help namespace to contain wikitext
                $page = $this->newPage( "Help:WikiPageTest_testPreloadTransform" );
                $text = $page->preSaveTransform( $text, $user );
 
index cd54a9e..8997846 100644 (file)
@@ -84,7 +84,7 @@ class MagicVariableTest extends MediaWikiTestCase {
                return self::createProviderUpTo( 31 );
        }
 
-       ############### TESTS #############################################
+       # ############## TESTS #############################################
        # @todo FIXME:
        #  - those got copy pasted, we can probably make them cleaner
        #  - tests are lacking useful messages
@@ -157,7 +157,7 @@ class MagicVariableTest extends MediaWikiTestCase {
                $this->assertUnPadded( 'revisionmonth1', $month );
        }
 
-       ############### HELPERS ############################################
+       # ############## HELPERS ############################################
 
        /** assertion helper expecting a magic output which is zero padded */
        public function assertZeroPadded( $magic, $value ) {
@@ -189,7 +189,7 @@ class MagicVariableTest extends MediaWikiTestCase {
                );
 
                # please keep the following commented line of code. It helps debugging.
-               //print "\nDEBUG (value $value):" . sprintf( '2010%02d%02d123456', $value, $value ) . "\n";
+               // print "\nDEBUG (value $value):" . sprintf( '2010%02d%02d123456', $value, $value ) . "\n";
 
                # format expectation and test it
                $expected = sprintf( $format, $value );
index df7da98..ff4a527 100644 (file)
@@ -27,7 +27,7 @@ class NewParserTest extends MediaWikiTestCase {
        public $functionHooks = array();
        public $transparentHooks = array();
 
-       //Fuzz test
+       // Fuzz test
        public $maxFuzzTestLength = 300;
        public $fuzzSeed = 0;
        public $memoryLimit = 50;
@@ -54,7 +54,7 @@ class NewParserTest extends MediaWikiTestCase {
 
                parent::setUp();
 
-               //Setup CLI arguments
+               // Setup CLI arguments
                if ( $this->getCliArg( 'regex' ) ) {
                        $this->regex = $this->getCliArg( 'regex' );
                } else {
@@ -210,7 +210,7 @@ class NewParserTest extends MediaWikiTestCase {
        function addDBData() {
                $this->tablesUsed[] = 'site_stats';
                # disabled for performance
-               #$this->tablesUsed[] = 'image';
+               # $this->tablesUsed[] = 'image';
 
                # Update certain things in site_stats
                $this->db->insert( 'site_stats',
@@ -346,7 +346,7 @@ class NewParserTest extends MediaWikiTestCase {
                }
        }
 
-       //ParserTest setup/teardown functions
+       // ParserTest setup/teardown functions
 
        /**
         * Set up the global variables for a consistent environment for each test.
@@ -426,7 +426,7 @@ class NewParserTest extends MediaWikiTestCase {
                        foreach ( $configLines as $line ) {
                                list( $var, $value ) = explode( '=', $line, 2 );
 
-                               $settings[$var] = eval( "return $value;" ); //???
+                               $settings[$var] = eval( "return $value;" ); // ???
                        }
                }
 
@@ -682,7 +682,7 @@ class NewParserTest extends MediaWikiTestCase {
        public function testParserTest( $desc, $input, $result, $opts, $config ) {
                if ( $this->regex != '' && !preg_match( '/' . $this->regex . '/', $desc ) ) {
                        $this->assertTrue( true ); // XXX: don't flood output with "test made no assertions"
-                       //$this->markTestSkipped( 'Filtered out by the user' );
+                       // $this->markTestSkipped( 'Filtered out by the user' );
                        return;
                }
 
@@ -865,7 +865,7 @@ class NewParserTest extends MediaWikiTestCase {
 
                        if ( $id % 100 == 0 ) {
                                $usage = intval( memory_get_usage( true ) / $this->memoryLimit / 1048576 * 100 );
-                               //echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n";
+                               // echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n";
                                if ( $usage > 90 ) {
                                        $ret = "Out of memory:\n";
                                        $memStats = $this->getMemoryBreakdown();
@@ -882,7 +882,7 @@ class NewParserTest extends MediaWikiTestCase {
                }
        }
 
-       //Various getter functions
+       // Various getter functions
 
        /**
         * Get an input dictionary from a set of parser test files
@@ -956,7 +956,7 @@ class NewParserTest extends MediaWikiTestCase {
                return $parser;
        }
 
-       //Various action functions
+       // Various action functions
 
        public function addArticle( $name, $text, $line ) {
                self::$articles[$name] = array( $text, $line );
@@ -999,7 +999,7 @@ class NewParserTest extends MediaWikiTestCase {
                return isset( $wgParser->mTransparentTagHooks[$name] );
        }
 
-       //Various "cleanup" functions
+       // Various "cleanup" functions
 
        /**
         * Remove last character if it is a newline
@@ -1014,7 +1014,7 @@ class NewParserTest extends MediaWikiTestCase {
                }
        }
 
-       //Test options parser functions
+       // Test options parser functions
 
        protected function parseOptions( $instring ) {
                $opts = array();
index 345fd0a..1ebba1a 100644 (file)
@@ -193,7 +193,7 @@ class PreprocessorTest extends MediaWikiTestCase {
        }
 
        /**
-        * Tests from Bug 28642 · https://bugzilla.wikimedia.org/28642
+        * Tests from T30642 · https://phabricator.wikimedia.org/T30642
         */
        public static function provideHeadings() {
                // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
index ce4e30a..b419203 100644 (file)
@@ -191,41 +191,41 @@ class UserPasswordPolicyTest extends MediaWikiTestCase {
        public function provideMaxOfPolicies() {
                return array(
                        array(
-                               array( 'MinimalPasswordLength' => 8 ), //p1
-                               array( 'MinimalPasswordLength' => 2 ), //p2
-                               array( 'MinimalPasswordLength' => 8 ), //max
+                               array( 'MinimalPasswordLength' => 8 ), // p1
+                               array( 'MinimalPasswordLength' => 2 ), // p2
+                               array( 'MinimalPasswordLength' => 8 ), // max
                                'Basic max in p1'
                        ),
                        array(
-                               array( 'MinimalPasswordLength' => 2 ), //p1
-                               array( 'MinimalPasswordLength' => 8 ), //p2
-                               array( 'MinimalPasswordLength' => 8 ), //max
+                               array( 'MinimalPasswordLength' => 2 ), // p1
+                               array( 'MinimalPasswordLength' => 8 ), // p2
+                               array( 'MinimalPasswordLength' => 8 ), // max
                                'Basic max in p2'
                        ),
                        array(
-                               array( 'MinimalPasswordLength' => 8 ), //p1
+                               array( 'MinimalPasswordLength' => 8 ), // p1
                                array(
                                        'MinimalPasswordLength' => 2,
                                        'PasswordCannotMatchUsername' => 1,
-                               ), //p2
+                               ), // p2
                                array(
                                        'MinimalPasswordLength' => 8,
                                        'PasswordCannotMatchUsername' => 1,
-                               ), //max
+                               ), // max
                                'Missing items in p1'
                        ),
                        array(
                                array(
                                        'MinimalPasswordLength' => 8,
                                        'PasswordCannotMatchUsername' => 1,
-                               ), //p1
+                               ), // p1
                                array(
                                        'MinimalPasswordLength' => 2,
-                               ), //p2
+                               ), // p2
                                array(
                                        'MinimalPasswordLength' => 8,
                                        'PasswordCannotMatchUsername' => 1,
-                               ), //max
+                               ), // max
                                'Missing items in p2'
                        ),
                );
diff --git a/tests/phpunit/includes/phpunit/ConsecutiveParametersMatcher.php b/tests/phpunit/includes/phpunit/ConsecutiveParametersMatcher.php
new file mode 100644 (file)
index 0000000..8de467f
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+// @codingStandardsIgnoreFile
+/*
+ * This file is part of the PHPUnit_MockObject package.
+ *
+ * (c) Sebastian Bergmann <sebastian@phpunit.de>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Invocation matcher which looks for sets of specific parameters in the invocations.
+ *
+ * Checks the parameters of the incoming invocations, the parameter list is
+ * checked against the defined constraints in $parameters. If the constraint
+ * is met it will return true in matches().
+ *
+ * It takes a list of match groups and and increases a call index after each invocation.
+ * So the first invocation uses the first group of constraints, the second the next and so on.
+ */
+class PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
+{
+    /**
+     * @var array
+     */
+    private $_parameterGroups = array();
+
+    /**
+     * @var array
+     */
+    private $_invocations = array();
+
+    /**
+     * @param array $parameterGroups
+     */
+    public function __construct(array $parameterGroups)
+    {
+        foreach ($parameterGroups as $index => $parameters) {
+            foreach ($parameters as $parameter) {
+                if (!($parameter instanceof \PHPUnit_Framework_Constraint)) {
+                    $parameter = new \PHPUnit_Framework_Constraint_IsEqual($parameter);
+                }
+                $this->_parameterGroups[$index][] = $parameter;
+            }
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function toString()
+    {
+        $text = 'with consecutive parameters';
+
+        return $text;
+    }
+
+    /**
+     * @param  PHPUnit_Framework_MockObject_Invocation $invocation
+     * @return bool
+     */
+    public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
+    {
+        $this->_invocations[] = $invocation;
+        $callIndex            = count($this->_invocations) - 1;
+        $this->verifyInvocation($invocation, $callIndex);
+
+        return false;
+    }
+
+    public function verify()
+    {
+        foreach ($this->_invocations as $callIndex => $invocation) {
+            $this->verifyInvocation($invocation, $callIndex);
+        }
+    }
+
+    /**
+     * Verify a single invocation
+     *
+     * @param  PHPUnit_Framework_MockObject_Invocation      $invocation
+     * @param  int                                          $callIndex
+     * @throws PHPUnit_Framework_ExpectationFailedException
+     */
+    private function verifyInvocation(PHPUnit_Framework_MockObject_Invocation $invocation, $callIndex)
+    {
+
+        if (isset($this->_parameterGroups[$callIndex])) {
+            $parameters = $this->_parameterGroups[$callIndex];
+        } else {
+          // no parameter assertion for this call index
+            return;
+        }
+
+        if ($invocation === null) {
+            throw new PHPUnit_Framework_ExpectationFailedException(
+                'Mocked method does not exist.'
+            );
+        }
+
+        if (count($invocation->parameters) < count($parameters)) {
+            throw new PHPUnit_Framework_ExpectationFailedException(
+                sprintf(
+                    'Parameter count for invocation %s is too low.',
+                    $invocation->toString()
+                )
+            );
+        }
+
+        foreach ($parameters as $i => $parameter) {
+            $parameter->evaluate(
+                $invocation->parameters[$i],
+                sprintf(
+                    'Parameter %s for invocation #%d %s does not match expected ' .
+                    'value.',
+                    $i,
+                    $callIndex,
+                    $invocation->toString()
+                )
+            );
+        }
+    }
+}
diff --git a/tests/phpunit/includes/phpunit/LICENSE b/tests/phpunit/includes/phpunit/LICENSE
new file mode 100644 (file)
index 0000000..fe178b0
--- /dev/null
@@ -0,0 +1,33 @@
+PHPUnit
+
+Copyright (c) 2001-2014, Sebastian Bergmann <sebastian@phpunit.de>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+ * Neither the name of Sebastian Bergmann nor the names of his
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/phpunit/includes/phpunit/README b/tests/phpunit/includes/phpunit/README
new file mode 100644 (file)
index 0000000..3ec3fd9
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains classes duplicated from new versions of phpunit
+that also work in the older php 3.7.37 used by wmf CI servers.
index d0bc210..fc1887d 100644 (file)
@@ -100,7 +100,8 @@ class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase {
                                array(
                                        'class' => 'ResourceLoaderImageModule',
                                        'selectorWithoutVariant' => '.mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-                                       'selectorWithVariant' => '.mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before',
+                                       'selectorWithVariant' =>
+                                               '.mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before',
                                        'variants' => self::$commonImageVariants,
                                        'images' => self::$commonImageData,
                                ),
@@ -146,7 +147,10 @@ class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase {
         * @covers ResourceLoaderImageModule::getStyles
         */
        public function testGetStyles( $module, $expected ) {
-               $module = new ResourceLoaderImageModuleTestable( $module, __DIR__ . '/../../data/resourceloader' );
+               $module = new ResourceLoaderImageModuleTestable(
+                       $module,
+                       __DIR__ . '/../../data/resourceloader'
+               );
                $styles = $module->getStyles( $this->getResourceLoaderContext() );
                $this->assertEquals( $expected, $styles['all'] );
        }
index cc121ba..b4f1000 100644 (file)
@@ -15,9 +15,16 @@ class ResourceLoaderImageTest extends ResourceLoaderTestCase {
        protected function getTestImage( $name ) {
                $options = ResourceLoaderImageModuleTest::$commonImageData[$name];
                $fileDescriptor = is_string( $options ) ? $options : $options['file'];
-               $allowedVariants = is_array( $options ) && isset( $options['variants'] ) ? $options['variants'] : array();
+               $allowedVariants = is_array( $options ) &&
+                       isset( $options['variants'] ) ? $options['variants'] : array();
                $variants = array_fill_keys( $allowedVariants, array( 'color' => 'red' ) );
-               return new ResourceLoaderImageTestable( $name, 'test', $fileDescriptor, $this->imagesPath, $variants );
+               return new ResourceLoaderImageTestable(
+                       $name,
+                       'test',
+                       $fileDescriptor,
+                       $this->imagesPath,
+                       $variants
+               );
        }
 
        public static function provideGetPath() {
@@ -86,7 +93,10 @@ class ResourceLoaderImageTest extends ResourceLoaderTestCase {
                $data = file_get_contents( $this->imagesPath . '/remove.svg' );
                $dataConstructive = file_get_contents( $this->imagesPath . '/remove_variantize.svg' );
                $this->assertEquals( $image->getImageData( $context, null, 'original' ), $data );
-               $this->assertEquals( $image->getImageData( $context, 'destructive', 'original' ), $dataConstructive );
+               $this->assertEquals(
+                       $image->getImageData( $context, 'destructive', 'original' ),
+                       $dataConstructive
+               );
                // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output
                $this->assertEquals( $image->getImageData( $context, null, 'rasterized' ), 'RASTERIZESTUB' );
 
index 41653fb..e8ca2a3 100644 (file)
@@ -75,7 +75,10 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
                ) );
                $this->assertEquals(
                        $module->getScript( $context ),
-                       'mw.log.error("JavaScript parse error: Parse error: Unexpected token; token } expected in file \'input\' on line 3");',
+                       'mw.log.error(' .
+                               '"JavaScript parse error: Parse error: Unexpected token; ' .
+                               'token } expected in file \'input\' on line 3"' .
+                       ');',
                        'Replace invalid syntax with error logging'
                );
 
index 8cefec7..49e42b4 100644 (file)
@@ -61,7 +61,12 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
                        array( $params, new HashConfig( array( 'UseSiteJs' => false ) + $settings ), array(
                                'MediaWiki:Common.css' => array( 'type' => 'style' ),
                        ) ),
-                       array( $params, new HashConfig( array( 'UseSiteJs' => false, 'UseSiteCss' => false ) ), array() ),
+                       array( $params,
+                               new HashConfig(
+                                       array( 'UseSiteJs' => false, 'UseSiteCss' => false )
+                               ),
+                               array()
+                       ),
                );
        }
 
index ef2ccca..3b95c46 100644 (file)
@@ -38,7 +38,7 @@ class MediaWikiSiteTest extends SiteTest {
                $site = new MediaWikiSite();
                $site->setGlobalId( 'enwiki' );
 
-               //NOTE: this does not actually call out to the enwiki site to perform the normalization,
+               // NOTE: this does not actually call out to the enwiki site to perform the normalization,
                //      but uses a local Title object to do so. This is hardcoded on SiteLink::normalizePageTitle
                //      for the case that MW_PHPUNIT_TEST is set.
                $this->assertEquals( 'Foo', $site->normalizePageName( ' foo ' ) );
index 63d90d2..2f785b5 100644 (file)
@@ -228,23 +228,23 @@ class SiteTest extends MediaWikiTestCase {
        }
 
        public static function provideGetPageUrl() {
-               //NOTE: the assumption that the URL is built by replacing $1
+               // NOTE: the assumption that the URL is built by replacing $1
                //      with the urlencoded version of $page
                //      is true for Site but not guaranteed for subclasses.
                //      Subclasses need to override this provider appropriately.
 
                return array(
-                       array( #0
+                       array( # 0
                                'http://acme.test/TestPath/$1',
                                'Foo',
                                '/TestPath/Foo',
                        ),
-                       array( #1
+                       array( # 1
                                'http://acme.test/TestScript?x=$1&y=bla',
                                'Foo',
                                'TestScript?x=Foo&y=bla',
                        ),
-                       array( #2
+                       array( # 2
                                'http://acme.test/TestPath/$1',
                                'foo & bar/xyzzy (quux-shmoox?)',
                                '/TestPath/foo%20%26%20bar%2Fxyzzy%20%28quux-shmoox%3F%29',
@@ -259,7 +259,7 @@ class SiteTest extends MediaWikiTestCase {
        public function testGetPageUrl( $path, $page, $expected ) {
                $site = new Site();
 
-               //NOTE: the assumption that getPageUrl is based on getLinkPath
+               // NOTE: the assumption that getPageUrl is based on getLinkPath
                //      is true for Site but not guaranteed for subclasses.
                //      Subclasses need to override this test case appropriately.
                $site->setLinkPath( $path );
index 4c40248..ac51183 100644 (file)
@@ -79,7 +79,7 @@ class TestSites {
                $languageCodes = array(
                        'de',
                        'en',
-                       'fa', //right-to-left
+                       'fa', // right-to-left
                        'nl',
                        'nn',
                        'no',
index c3d75aa..0a6336f 100644 (file)
@@ -26,7 +26,7 @@ class SpecialRecentchangesTest extends MediaWikiTestCase {
                $this->rc->setContext( $context );
                $formOptions = $this->rc->setup( null );
 
-               # Filter out rc_timestamp conditions which depends on the test runtime
+               #  Filter out rc_timestamp conditions which depends on the test runtime
                # This condition is not needed as of march 2, 2011 -- hashar
                # @todo FIXME: Find a way to generate the correct rc_timestamp
                $queryConditions = array_filter(
index 13c2838..df9b552 100644 (file)
@@ -207,7 +207,12 @@ class SpecialSearchTestMockResultSet extends SearchResultSet {
        protected $results;
        protected $suggestion;
 
-       public function __construct( $suggestion = null, $rewrittenQuery = null, array $results = array(), $containedSyntax = false) {
+       public function __construct(
+               $suggestion = null,
+               $rewrittenQuery = null,
+               array $results = array(),
+               $containedSyntax = false
+       ) {
                $this->suggestion = $suggestion;
                $this->rewrittenQuery = $rewrittenQuery;
                $this->results = $results;
index 1e5f9d0..6cfddf0 100644 (file)
@@ -93,15 +93,15 @@ class MediaWikiPageLinkRendererTest extends MediaWikiTestCase {
                                '!<a .*href=".*?Foo_Bar.*?".*?>Foo Bar</a>!'
                        ),
                        array(
-                               //NOTE: Linker doesn't include fragments in "broken" links
-                               //NOTE: once this no longer uses Linker, we will get "2" instead of "User" for the namespace.
+                               // NOTE: Linker doesn't include fragments in "broken" links
+                               // NOTE: once this no longer uses Linker, we will get "2" instead of "User" for the namespace.
                                new TitleValue( NS_USER, 'Hansi_Maier', 'stuff' ),
                                'Hansi Maier\'s Stuff',
                                '!<a .*href=".*?User:Hansi_Maier.*?>Hansi Maier\'s Stuff</a>!'
                        ),
                        array(
-                               //NOTE: Linker doesn't include fragments in "broken" links
-                               //NOTE: once this no longer uses Linker, we will get "2" instead of "User" for the namespace.
+                               // NOTE: Linker doesn't include fragments in "broken" links
+                               // NOTE: once this no longer uses Linker, we will get "2" instead of "User" for the namespace.
                                new TitleValue( NS_USER, 'Hansi_Maier', 'stuff' ),
                                null,
                                '!<a .*href=".*?User:Hansi_Maier.*?>User:Hansi Maier#stuff</a>!'
index 78d304c..d0a9831 100644 (file)
@@ -199,8 +199,8 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
        }
 
        public static function provideParseTitle() {
-               //TODO: test capitalization and trimming
-               //TODO: test unicode normalization
+               // TODO: test capitalization and trimming
+               // TODO: test unicode normalization
 
                return array(
                        array( '  : Hansi_Maier _ ', NS_MAIN, 'en',
@@ -233,7 +233,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                        array( ' _ Foo __ Bar_ _', NS_MAIN, 'en',
                                new TitleValue( NS_MAIN, 'Foo_Bar' ) ),
 
-                       //NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync.
+                       // NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync.
                        array( 'Sandbox', NS_MAIN, 'en', ),
                        array( 'A "B"', NS_MAIN, 'en', ),
                        array( 'A \'B\'', NS_MAIN, 'en', ),
@@ -284,7 +284,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
        }
 
        public static function provideParseTitle_invalid() {
-               //TODO: test unicode errors
+               // TODO: test unicode errors
 
                return array(
                        array( '#' ),
@@ -299,7 +299,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                        array( '::1' ), // only valid in user namespace
                        array( 'User::x' ), // leading ":" in a user name is only valid of IPv6 addresses
 
-                       //NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync.
+                       // NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync.
                        array( '' ),
                        array( ':' ),
                        array( '__  __' ),
@@ -319,9 +319,9 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                        // XML/HTML character entity references
                        // Note: Commented out because they are not marked invalid by the PHP test as
                        // Title::newFromText runs Sanitizer::decodeCharReferencesAndNormalize first.
-                       //array( 'A &eacute; B' ),
-                       //array( 'A &#233; B' ),
-                       //array( 'A &#x00E9; B' ),
+                       // array( 'A &eacute; B' ),
+                       // array( 'A &#233; B' ),
+                       // array( 'A &#x00E9; B' ),
                        // Subject of NS_TALK does not roundtrip to NS_MAIN
                        array( 'Talk:File:Example.svg' ),
                        // Directory navigation
index 52c242c..d63af9a 100644 (file)
@@ -19,6 +19,10 @@ class AvroValidatorTest extends PHPUnit_Framework_TestCase {
 
        public function getErrorsProvider() {
                $stringSchema = AvroSchema::parse( json_encode( array( 'type' => 'string' ) ) );
+               $stringArraySchema = AvroSchema::parse( json_encode( array(
+                       'type' => 'array',
+                       'items' => 'string',
+               ) ) );
                $recordSchema = AvroSchema::parse( json_encode( array(
                        'type' => 'record',
                        'name' => 'ut',
@@ -80,6 +84,18 @@ class AvroValidatorTest extends PHPUnit_Framework_TestCase {
                                        )
                                ) )
                        ),
+                       array(
+                               'Empty array is accepted',
+                               $stringArraySchema, array(), array()
+                       ),
+                       array(
+                               'correct array element accepted',
+                               $stringArraySchema, array( 'fizzbuzz' ), array()
+                       ),
+                       array(
+                               'incorrect array element rejected',
+                               $stringArraySchema, array( '12', 34 ), array( 'Expected string, but recieved integer' )
+                       ),
                );
        }
 
index a2b35f3..4684658 100644 (file)
@@ -23,7 +23,7 @@ class BatchRowUpdateTest extends MediaWikiTestCase {
                $writer->write( $updates );
        }
 
-       static protected function mockUpdate( array $changes ) {
+       protected static function mockUpdate( array $changes ) {
                static $i = 0;
                return array(
                        'primaryKey' => array( 'event_id' => $i++ ),
@@ -53,7 +53,7 @@ class BatchRowUpdateTest extends MediaWikiTestCase {
                $this->assertEquals( count( $response ) - 1, $pos );
        }
 
-       static public function provider_readerGetPrimaryKey() {
+       public static function provider_readerGetPrimaryKey() {
                $row = array(
                        'id_field' => 42,
                        'some_col' => 'dvorak',
@@ -84,7 +84,7 @@ class BatchRowUpdateTest extends MediaWikiTestCase {
                $this->assertEquals( $expected, $reader->extractPrimaryKeys( (object) $row ), $message );
        }
 
-       static public function provider_readerSetFetchColumns() {
+       public static function provider_readerSetFetchColumns() {
                return array(
 
                        array(
@@ -136,7 +136,7 @@ class BatchRowUpdateTest extends MediaWikiTestCase {
                $reader->rewind();
        }
 
-       static public function provider_readerSelectConditions() {
+       public static function provider_readerSelectConditions() {
                return array(
 
                        array(
diff --git a/tests/phpunit/includes/utils/FileContentsHasherTest.php b/tests/phpunit/includes/utils/FileContentsHasherTest.php
new file mode 100644 (file)
index 0000000..a03e1fc
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @covers FileContentsHasherTest
+ */
+class FileContentsHasherTest extends MediaWikiTestCase {
+
+       public function provideSingleFile() {
+               return array_map( function ( $file ) {
+                       return array( $file, file_get_contents( $file ) );
+               }, glob( __DIR__ . '/../../data/filecontentshasher/*.*' ) );
+       }
+
+       public function provideMultipleFiles() {
+               return array(
+                       array( $this->provideSingleFile() )
+               );
+       }
+
+       /**
+        * @covers FileContentsHasher::getFileContentHash
+        * @covers FileContentsHasher::getFileContentsHashInternal
+        * @dataProvider provideSingleFile
+        */
+       public function testSingleFileHash( $fileName, $contents ) {
+               foreach ( array( 'md4', 'md5' ) as $algo ) {
+                       $expectedHash = hash( $algo, $contents );
+                       $actualHash = FileContentsHasher::getFileContentsHash( $fileName, $algo );
+                       $this->assertEquals( $expectedHash, $actualHash );
+                       $actualHashRepeat = FileContentsHasher::getFileContentsHash( $fileName, $algo );
+                       $this->assertEquals( $expectedHash, $actualHashRepeat );
+               }
+       }
+
+       /**
+        * @covers FileContentsHasher::getFileContentHash
+        * @covers FileContentsHasher::getFileContentsHashInternal
+        * @dataProvider provideMultipleFiles
+        */
+       public function testMultipleFileHash( $files ) {
+               $fileNames = array();
+               $hashes = array();
+               foreach ( $files as $fileInfo ) {
+                       list( $fileName, $contents ) = $fileInfo;
+                       $fileNames[] = $fileName;
+                       $hashes[] = md5( $contents );
+               }
+
+               $expectedHash = md5( implode( '', $hashes ) );
+               $actualHash = FileContentsHasher::getFileContentsHash( $fileNames, 'md5' );
+               $this->assertEquals( $expectedHash, $actualHash );
+               $actualHashRepeat = FileContentsHasher::getFileContentsHash( $fileNames, 'md5' );
+               $this->assertEquals( $expectedHash, $actualHashRepeat );
+       }
+}
index 1381afb..a301479 100644 (file)
@@ -110,6 +110,71 @@ class LanguageRuTest extends LanguageClassesTestCase {
                                'Викиданные',
                                'prepositional',
                        ),
+                       array(
+                               'русского',
+                               'русский',
+                               'languagegen',
+                       ),
+                       array(
+                               'немецкого',
+                               'немецкий',
+                               'languagegen',
+                       ),
+                       array(
+                               'иврита',
+                               'иврит',
+                               'languagegen',
+                       ),
+                       array(
+                               'эсперанто',
+                               'эсперанто',
+                               'languagegen',
+                       ),
+                       array(
+                               'русском',
+                               'русский',
+                               'languageprep',
+                       ),
+                       array(
+                               'немецком',
+                               'немецкий',
+                               'languageprep',
+                       ),
+                       array(
+                               'идише',
+                               'идиш',
+                               'languageprep',
+                       ),
+                       array(
+                               'эсперанто',
+                               'эсперанто',
+                               'languageprep',
+                       ),
+                       array(
+                               'по-русски',
+                               'русский',
+                               'languageadverb',
+                       ),
+                       array(
+                               'по-немецки',
+                               'немецкий',
+                               'languageadverb',
+                       ),
+                       array(
+                               'на иврите',
+                               'иврит',
+                               'languageadverb',
+                       ),
+                       array(
+                               'на эсперанто',
+                               'эсперанто',
+                               'languageadverb',
+                       ),
+                       array(
+                               'на языке гуарани',
+                               'гуарани',
+                               'languageadverb',
+                       ),
                );
        }
 }
index bfb199f..7643f84 100644 (file)
@@ -65,35 +65,35 @@ class LanguageSrTest extends LanguageClassesTestCase {
         * @covers LanguageConverter::convertTo
         */
        public function testConversionToCyrillic() {
-               //A simple convertion of Latin to Cyrillic
+               // A simple convertion of Latin to Cyrillic
                $this->assertEquals( 'абвг',
                        $this->convertToCyrillic( 'abvg' )
                );
-               //Same as above, but assert that -{}-s must be removed and not converted
+               // Same as above, but assert that -{}-s must be removed and not converted
                $this->assertEquals( 'ljабnjвгdž',
                        $this->convertToCyrillic( '-{lj}-ab-{nj}-vg-{dž}-' )
                );
-               //A simple convertion of Cyrillic to Cyrillic
+               // A simple convertion of Cyrillic to Cyrillic
                $this->assertEquals( 'абвг',
                        $this->convertToCyrillic( 'абвг' )
                );
-               //Same as above, but assert that -{}-s must be removed and not converted
+               // Same as above, but assert that -{}-s must be removed and not converted
                $this->assertEquals( 'ljабnjвгdž',
                        $this->convertToCyrillic( '-{lj}-аб-{nj}-вг-{dž}-' )
                );
-               //This text has some Latin, but is recognized as Cyrillic, so it should not be converted
+               // This text has some Latin, but is recognized as Cyrillic, so it should not be converted
                $this->assertEquals( 'abvgшђжчћ',
                        $this->convertToCyrillic( 'abvgшђжчћ' )
                );
-               //Same as above, but assert that -{}-s must be removed
+               // Same as above, but assert that -{}-s must be removed
                $this->assertEquals( 'љabvgњшђжчћџ',
                        $this->convertToCyrillic( '-{љ}-abvg-{њ}-шђжчћ-{џ}-' )
                );
-               //This text has some Cyrillic, but is recognized as Latin, so it should be converted
+               // This text has some Cyrillic, but is recognized as Latin, so it should be converted
                $this->assertEquals( 'абвгшђжчћ',
                        $this->convertToCyrillic( 'абвгšđžčć' )
                );
-               //Same as above, but assert that -{}-s must be removed and not converted
+               // Same as above, but assert that -{}-s must be removed and not converted
                $this->assertEquals( 'ljабвгnjшђжчћdž',
                        $this->convertToCyrillic( '-{lj}-абвг-{nj}-šđžčć-{dž}-' )
                );
@@ -107,19 +107,19 @@ class LanguageSrTest extends LanguageClassesTestCase {
         * @covers LanguageConverter::convertTo
         */
        public function testConversionToLatin() {
-               //A simple convertion of Latin to Latin
+               // A simple convertion of Latin to Latin
                $this->assertEquals( 'abcd',
                        $this->convertToLatin( 'abcd' )
                );
-               //A simple convertion of Cyrillic to Latin
+               // A simple convertion of Cyrillic to Latin
                $this->assertEquals( 'abcd',
                        $this->convertToLatin( 'абцд' )
                );
-               //This text has some Latin, but is recognized as Cyrillic, so it should be converted
+               // This text has some Latin, but is recognized as Cyrillic, so it should be converted
                $this->assertEquals( 'abcdšđžčć',
                        $this->convertToLatin( 'abcdшђжчћ' )
                );
-               //This text has some Cyrillic, but is recognized as Latin, so it should not be converted
+               // This text has some Cyrillic, but is recognized as Latin, so it should not be converted
                $this->assertEquals( 'абцдšđžčć',
                        $this->convertToLatin( 'абцдšđžčć' )
                );
@@ -177,7 +177,7 @@ class LanguageSrTest extends LanguageClassesTestCase {
                );
        }
 
-       ##### HELPERS #####################################################
+       # #### HELPERS #####################################################
        /**
         *Wrapper to verify text stay the same after applying conversion
         * @param string $text Text to convert
index 9051bcf..5912df6 100644 (file)
@@ -69,4 +69,42 @@ class LanguageUkTest extends LanguageClassesTestCase {
                        array( 'other', 121 ),
                );
        }
+
+       /**
+        * @dataProvider providerGrammar
+        * @covers Language::convertGrammar
+        */
+       public function testGrammar( $result, $word, $case ) {
+               $this->assertEquals( $result, $this->getLang()->convertGrammar( $word, $case ) );
+       }
+
+       public static function providerGrammar() {
+               return array(
+                       array(
+                               'Вікіпедії',
+                               'Вікіпедія',
+                               'genitive',
+                       ),
+                       array(
+                               'Віківидів',
+                               'Віківиди',
+                               'genitive',
+                       ),
+                       array(
+                               'Вікіцитат',
+                               'Вікіцитати',
+                               'genitive',
+                       ),
+                       array(
+                               'Вікіпідручника',
+                               'Вікіпідручник',
+                               'genitive',
+                       ),
+                       array(
+                               'Вікіпедію',
+                               'Вікіпедія',
+                               'accusative',
+                       ),
+               );
+       }
 }
index 4881103..7ef87bf 100644 (file)
@@ -56,7 +56,7 @@ class LanguageUzTest extends LanguageClassesTestCase {
                );
        }
 
-       ##### HELPERS #####################################################
+       # #### HELPERS #####################################################
        /**
         * Wrapper to verify text stay the same after applying conversion
         * @param string $text Text to convert
diff --git a/tests/phpunit/languages/utils/CLDRPluralRuleEvaluatorTest.php b/tests/phpunit/languages/utils/CLDRPluralRuleEvaluatorTest.php
deleted file mode 100644 (file)
index 8e3b114..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-/**
- * @author Niklas Laxström
- * @file
- */
-
-/**
- * @covers CLDRPluralRuleEvaluator
- */
-class CLDRPluralRuleEvaluatorTest extends MediaWikiTestCase {
-       /**
-        * @dataProvider validTestCases
-        */
-       function testValidRules( $expected, $rules, $number, $comment ) {
-               $result = CLDRPluralRuleEvaluator::evaluate( $number, (array)$rules );
-               $this->assertEquals( $expected, $result, $comment );
-       }
-
-       /**
-        * @dataProvider invalidTestCases
-        * @expectedException CLDRPluralRuleError
-        */
-       function testInvalidRules( $rules, $comment ) {
-               CLDRPluralRuleEvaluator::evaluate( 1, (array)$rules );
-       }
-
-       function validTestCases() {
-               $tests = array(
-                       # expected, rule, number, comment
-                       array( 0, 'n is 1', 1, 'integer number and is' ),
-                       array( 0, 'n is 1', "1", 'string integer number and is' ),
-                       array( 0, 'n is 1', 1.0, 'float number and is' ),
-                       array( 0, 'n is 1', "1.0", 'string float number and is' ),
-                       array( 1, 'n is 1', 1.1, 'float number and is' ),
-                       array( 1, 'n is 1', 2, 'float number and is' ),
-
-                       array( 0, 'n in 1,3,5', 3, '' ),
-                       array( 1, 'n not in 1,3,5', 5, '' ),
-
-                       array( 1, 'n in 1,3,5', 2, '' ),
-                       array( 0, 'n not in 1,3,5', 4, '' ),
-
-                       array( 0, 'n in 1..3', 2, '' ),
-                       array( 0, 'n in 1..3', 3, 'in is inclusive' ),
-                       array( 1, 'n in 1..3', 0, '' ),
-
-                       array( 1, 'n not in 1..3', 2, '' ),
-                       array( 1, 'n not in 1..3', 3, 'in is inclusive' ),
-                       array( 0, 'n not in 1..3', 0, '' ),
-
-                       array( 1, 'n is not 1 and n is not 2 and n is not 3', 1, 'and relation' ),
-                       array( 0, 'n is not 1 and n is not 2 and n is not 4', 3, 'and relation' ),
-
-                       array( 0, 'n is not 1 or n is 1', 1, 'or relation' ),
-                       array( 1, 'n is 1 or n is 2', 3, 'or relation' ),
-
-                       array( 0, 'n              is      1', 1, 'extra whitespace' ),
-
-                       array( 0, 'n mod 3 is 1', 7, 'mod' ),
-                       array( 0, 'n mod 3 is not 1', 4.3, 'mod with floats' ),
-
-                       array( 0, 'n within 1..3', 2, 'within with integer' ),
-                       array( 0, 'n within 1..3', 2.5, 'within with float' ),
-                       array( 0, 'n in 1..3', 2, 'in with integer' ),
-                       array( 1, 'n in 1..3', 2.5, 'in with float' ),
-
-                       array( 0, 'n in 3 or n is 4 and n is 5', 3, 'and binds more tightly than or' ),
-                       array( 1, 'n is 3 or n is 4 and n is 5', 4, 'and binds more tightly than or' ),
-
-                       array( 0, 'n mod 10 in 3..4,9 and n mod 100 not in 10..19,70..79,90..99', 24, 'breton rule' ),
-                       array( 1, 'n mod 10 in 3..4,9 and n mod 100 not in 10..19,70..79,90..99', 25, 'breton rule' ),
-
-                       array( 0, 'n within 0..2 and n is not 2', 0, 'french rule' ),
-                       array( 0, 'n within 0..2 and n is not 2', 1, 'french rule' ),
-                       array( 0, 'n within 0..2 and n is not 2', 1.2, 'french rule' ),
-                       array( 1, 'n within 0..2 and n is not 2', 2, 'french rule' ),
-
-                       array( 1, 'n in 3..10,13..19', 2, 'scottish rule - ranges with comma' ),
-                       array( 0, 'n in 3..10,13..19', 4, 'scottish rule - ranges with comma' ),
-                       array( 1, 'n in 3..10,13..19', 12.999, 'scottish rule - ranges with comma' ),
-                       array( 0, 'n in 3..10,13..19', 13, 'scottish rule - ranges with comma' ),
-
-                       array( 0, '5 mod 3 is n', 2, 'n as result of mod - no need to pass' ),
-
-                       # Revision 33 new operand examples
-                       # expected, rule, number, comment
-                       array( 0, 'i is 1', '1.00', 'new operand i' ),
-                       array( 0, 'v is 2', '1.00', 'new operand v' ),
-                       array( 0, 'w is 0', '1.00', 'new operand w' ),
-                       array( 0, 'f is 0', '1.00', 'new operand f' ),
-                       array( 0, 't is 0', '1.00', 'new operand t' ),
-
-                       array( 0, 'i is 1', '1.30', 'new operand i' ),
-                       array( 0, 'v is 2', '1.30', 'new operand v' ),
-                       array( 0, 'w is 1', '1.30', 'new operand w' ),
-                       array( 0, 'f is 30', '1.30', 'new operand f' ),
-                       array( 0, 't is 3', '1.30', 'new operand t' ),
-
-                       array( 0, 'i is 1', '1.03', 'new operand i' ),
-                       array( 0, 'v is 2', '1.03', 'new operand v' ),
-                       array( 0, 'w is 2', '1.03', 'new operand w' ),
-                       array( 0, 'f is 3', '1.03', 'new operand f' ),
-                       array( 0, 't is 3', '1.03', 'new operand t' ),
-
-                       # Revision 33 new operator aliases
-                       # expected, rule, number, comment
-                       array( 0, 'n % 3 is 1', 7, 'new % operator' ),
-                       array( 0, 'n = 1,3,5', 3, 'new = operator' ),
-                       array( 1, 'n != 1,3,5', 5, 'new != operator' ),
-
-                       # Revision 33 samples
-                       # expected, rule, number, comment
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 0, 'n in 1,3,5@integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, …', 3, 'samples' ),
-                       // @codingStandardsIgnoreEnd
-
-                       # Revision 33 some test cases from CLDR
-                       array( 0, 'i = 1 and v = 0 or i = 0 and t = 1', '0.1', 'pt one' ),
-                       array( 0, 'i = 1 and v = 0 or i = 0 and t = 1', '0.01', 'pt one' ),
-                       array( 0, 'i = 1 and v = 0 or i = 0 and t = 1', '0.10', 'pt one' ),
-                       array( 0, 'i = 1 and v = 0 or i = 0 and t = 1', '0.010', 'pt one' ),
-                       array( 0, 'i = 1 and v = 0 or i = 0 and t = 1', '0.100', 'pt one' ),
-                       array( 1, 'i = 1 and v = 0 or i = 0 and t = 1', '0.0', 'pt other' ),
-                       array( 1, 'i = 1 and v = 0 or i = 0 and t = 1', '0.2', 'pt other' ),
-                       array( 1, 'i = 1 and v = 0 or i = 0 and t = 1', '10.0', 'pt other' ),
-                       array( 1, 'i = 1 and v = 0 or i = 0 and t = 1', '100.0', 'pt other' ),
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '2', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '4', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '22', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '102', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '0.2', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '0.4', 'bs few' ),
-                       array( 0, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '10.2', 'bs few' ),
-                       array( 1, 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14', '10.0', 'bs other' ),
-                       // @codingStandardsIgnoreEnd
-               );
-
-               return $tests;
-       }
-
-       function invalidTestCases() {
-               $tests = array(
-                       array( 'n mod mod 5 is 1', 'mod mod' ),
-                       array( 'n', 'just n' ),
-                       array( 'n is in 5', 'is in' ),
-               );
-
-               return $tests;
-       }
-}
index e2fc824..454e9c1 100644 (file)
@@ -816,7 +816,10 @@ class MaintenanceTest extends MediaWikiTestCase {
         */
        public function testGetConfig() {
                $this->assertInstanceOf( 'Config', $this->m->getConfig() );
-               $this->assertSame( ConfigFactory::getDefaultInstance()->makeConfig( 'main' ), $this->m->getConfig() );
+               $this->assertSame(
+                       ConfigFactory::getDefaultInstance()->makeConfig( 'main' ),
+                       $this->m->getConfig()
+               );
        }
 
        /**
index 587d6d0..49b91c3 100755 (executable)
@@ -42,14 +42,28 @@ class PHPUnitMaintClass extends Maintenance {
                        false, # not required
                        false # no arg needed
                );
-               $this->addOption( 'regex', 'Only run parser tests that match the given regex.', false, true );
+               $this->addOption(
+                       'regex',
+                       'Only run parser tests that match the given regex.',
+                       false,
+                       true
+               );
                $this->addOption( 'file', 'File describing parser tests.', false, true );
                $this->addOption( 'use-filebackend', 'Use filebackend', false, true );
                $this->addOption( 'use-bagostuff', 'Use bagostuff', false, true );
                $this->addOption( 'use-jobqueue', 'Use jobqueue', false, true );
-               $this->addOption( 'keep-uploads', 'Re-use the same upload directory for each test, don\'t delete it.', false, false );
+               $this->addOption(
+                       'keep-uploads',
+                       'Re-use the same upload directory for each test, don\'t delete it.',
+                       false,
+                       false
+               );
                $this->addOption( 'use-normal-tables', 'Use normal DB tables.', false, false );
-               $this->addOption( 'reuse-db', 'Init DB only if tables are missing and keep after finish.', false, false );
+               $this->addOption(
+                       'reuse-db', 'Init DB only if tables are missing and keep after finish.',
+                       false,
+                       false
+               );
        }
 
        public function finalSetup() {
@@ -66,11 +80,21 @@ class PHPUnitMaintClass extends Maintenance {
                // wfWarn should cause tests to fail
                $wgDevelopmentWarnings = true;
 
+               // Make sure all caches and stashes are either disabled or use
+               // in-process cache only to prevent tests from using any preconfigured
+               // cache meant for the local wiki from outside the test run.
+               // See also MediaWikiTestCase::run() which mocks CACHE_DB and APC.
+
+               // Disabled in DefaultSettings, override local settings
+               $wgMainWANCache =
                $wgMainCacheType = CACHE_NONE;
-               $wgMainWANCache = CACHE_NONE;
-               $wgMessageCacheType = CACHE_NONE;
-               $wgParserCacheType = CACHE_NONE;
-               $wgLanguageConverterCacheType = CACHE_NONE;
+               // Uses CACHE_ANYTHING in DefaultSettings, use hash instead of db
+               $wgMessageCacheType =
+               $wgParserCacheType =
+               $wgSessionCacheType =
+               $wgLanguageConverterCacheType = 'hash';
+               // Uses db-replicated in DefaultSettings
+               $wgMainStash = 'hash';
 
                $wgUseDatabaseMessages = false; # Set for future resets
 
@@ -104,7 +128,7 @@ class PHPUnitMaintClass extends Maintenance {
 
                # Make sure we have --configuration or PHPUnit might complain
                if ( !in_array( '--configuration', $_SERVER['argv'] ) ) {
-                       //Hack to eliminate the need to use the Makefile (which sucks ATM)
+                       // Hack to eliminate the need to use the Makefile (which sucks ATM)
                        array_splice( $_SERVER['argv'], 1, 0,
                                array( '--configuration', $IP . '/tests/phpunit/suite.xml' ) );
                }
index eefc926..23afabd 100644 (file)
@@ -198,7 +198,7 @@ class ResourcesTest extends MediaWikiTestCase {
                                                        $media,
                                                        $file,
                                                        // XXX: Wrapped in an object to keep it out of PHPUnit output
-                                                       (object)array( 'cssText' => $readStyleFile->invoke( $module, $file, $flip ) ),
+                                                       (object)array( 'cssText' => $readStyleFile->invoke( $module, $file, $flip, $data['context'] ) ),
                                                );
                                        }
                                }
index 032551d..1726a48 100644 (file)
@@ -5,7 +5,7 @@
         */
 
        var text, ipv4,
-               simpleMDYDatesInMDY, simpleMDYDatesInDMY, oldMDYDates, complexMDYDates, clobberedDates, MYDates, YDates,
+               simpleMDYDatesInMDY, simpleMDYDatesInDMY, oldMDYDates, complexMDYDates, clobberedDates, MYDates, YDates, ISODates,
                currencyData, transformedCurrencyData;
 
        QUnit.module( 'jquery.tablesorter.parsers', QUnit.newMwEnvironment( {
        ];
        parserTest( 'Y Dates', 'date', YDates );
 
+       ISODates = [
+               [ '2000',               false, 946684800000, 'Plain 4-digit year' ],
+               [ '2000-01',            false, 946684800000, 'Year with month' ],
+               [ '2000-01-01', true, 946684800000, 'Year with month and day' ],
+               [ '2000-13-01', true, 0, 'Non existant month' ],
+               [ '2000-01-32', true, 0, 'Non existant day' ],
+               [ '2000-01-01T12:30:30',                true, 946729830000, 'Date with a time' ],
+               [ '2000-01-01T12:30:30Z',       true, 946729830000, 'Date with a UTC+0 time' ],
+               [ '2000-01-01T24:30:30Z',       true, 0, 'Date with invalid hours' ],
+               [ '2000-01-01T12:60:30Z',       true, 0, 'Date with invalid minutes' ],
+               [ '2000-01-01T12:30:61Z',       true, 0, 'Date with invalid amount of seconds' ],
+               [ '2000-01-01T23:59:59Z',       true, 946771199000, 'Edges of time' ],
+               [ '2000-01-01T12:30:30.111Z',   true, 946729830111, 'Date with milliseconds' ],
+               [ '2000-01-01T12:30:30.11111Z', true, 946729830111, 'Date with too high precision' ],
+               [ '2000-01-01T12:30:30,111Z',   true, 0, 'Date with milliseconds and , separator' ],
+               [ '2000-01-01T12:30:30+01:00',  true, 946726230000, 'Date time in UTC+1' ],
+               [ '2000-01-01T12:30:30+01:30',  true, 946724430000, 'Date time in UTC+1:30' ],
+               [ '2000-01-01T12:30:30-01:00',  true, 946733430000, 'Date time in UTC-1' ],
+               [ '2000-01-01T12:30:30-01:30',  true, 946735230000, 'Date time in UTC-1:30' ],
+               [ '2000-01-01T12:30:30.111+01:00', true, 946726230111, 'Date time and milliseconds in UTC+1 ' ]
+               /* Disable testcases, because behavior is browser dependant */
+               /*
+               [ '2000-11-31', true, 0, '31 days in 30 day month' ],
+               [ '50-01-01',   false, -60589296000000, 'Year with just two digits' ],
+               [ '-1000-01-01',        true, -93724128000000, 'Year BC' ],
+               [ '+1000-01-01',        true, -30610224000000, 'Date with +sign' ],
+               [ '2000-01-01 12:30:30Z',       true, 0, 'Date and time with no T marker' ],
+               [ '2000-01-01T12:30:60Z',       true, 946729860000, 'Date with leap second' ],
+               [ '2000-01-01T12:30:30-24:00',  true, 946816230000, 'Date time in UTC-24' ],
+               [ '2000-01-01T12:30:30+24:00',  true, 946643430000, 'Date time in UTC+24' ],
+               [ '2000-01-01T12:30:30+0100',   true, 946726230000, 'Time without separator in timezone offset' ]
+               */
+       ];
+       parserTest( 'ISO Dates', 'isoDate', ISODates );
+
        currencyData = [
                [ '1.02 $',     true, 1.02, '' ],
                [ '$ 3.00',     true, 3, '' ],
index d4d0ce1..8026cc3 100644 (file)
                        [ 'January 01 2010' ],
                        [ 'January 16 2010' ],
                        [ 'February 05 2010' ]
+               ],
+               isoDateSorting = [
+                       [ '2010-02-01' ],
+                       [ '2009-12-25T12:30:45.001Z' ],
+                       [ '2010-01-31' ],
+                       [ '2009' ],
+                       [ '2009-12-25T12:30:45' ],
+                       [ '2009-12-25T12:30:45.111' ],
+                       [ '2009-12-25T12:30:45+01:00' ]
+               ],
+               isoDateSortingSorted = [
+                       [ '2009' ],
+                       [ '2009-12-25T12:30:45' ],
+                       [ '2009-12-25T12:30:45+01:00' ],
+                       [ '2009-12-25T12:30:45.001Z' ],
+                       [ '2009-12-25T12:30:45.111' ],
+                       [ '2010-01-31' ],
+                       [ '2010-02-01' ]
                ];
 
        QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment( {
                }
        );
 
+       tableTest(
+               'ISO date sorting',
+               [ 'isoDate' ],
+               isoDateSorting,
+               isoDateSortingSorted,
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+
        QUnit.test( 'Sorting images using alt text', 1, function ( assert ) {
                var $table = $(
                        '<table class="sortable">' +
index e7f4517..161b8e1 100644 (file)
@@ -41,7 +41,7 @@
                        'gender-msg-currentuser': '{{GENDER:|blue|pink|green}}',
 
                        'plural-msg': 'Found $1 {{PLURAL:$1|item|items}}',
-                       // See https://bugzilla.wikimedia.org/69993
+                       // See https://phabricator.wikimedia.org/T71993
                        'plural-msg-explicit-forms-nested': 'Found {{PLURAL:$1|$1 results|0=no results in {{SITENAME}}|1=$1 result}}',
                        // Assume the grammar form grammar_case_foo is not valid in any language
                        'grammar-msg': 'Przeszukaj {{GRAMMAR:grammar_case_foo|{{SITENAME}}}}',
index 399290c..e4c3851 100644 (file)
@@ -99,7 +99,7 @@
                                word: 'Wikipedia',
                                grammarForm: 'תחילית',
                                expected: '־Wikipedia',
-                               description: 'GAdd a hyphen (maqaf) before non-Hebrew letters'
+                               description: 'Add a hyphen (maqaf) before non-Hebrew letters'
                        },
                        {
                                word: '1995',
                                grammarForm: 'prepositional',
                                expected: 'данных',
                                description: 'Grammar test for prepositional case, данные -> данных'
+                       },
+                       {
+                               word: 'русский',
+                               grammarForm: 'languagegen',
+                               expected: 'русского',
+                               description: 'Grammar test for languagegen case, русский -> русского'
+                       },
+                       {
+                               word: 'немецкий',
+                               grammarForm: 'languagegen',
+                               expected: 'немецкого',
+                               description: 'Grammar test for languagegen case, немецкий -> немецкого'
+                       },
+                       {
+                               word: 'иврит',
+                               grammarForm: 'languagegen',
+                               expected: 'иврита',
+                               description: 'Grammar test for languagegen case, иврит -> иврита'
+                       },
+                       {
+                               word: 'эсперанто',
+                               grammarForm: 'languagegen',
+                               expected: 'эсперанто',
+                               description: 'Grammar test for languagegen case, эсперанто -> эсперанто'
+                       },
+                       {
+                               word: 'русский',
+                               grammarForm: 'languageprep',
+                               expected: 'русском',
+                               description: 'Grammar test for languageprep case, русский -> русском'
+                       },
+                       {
+                               word: 'немецкий',
+                               grammarForm: 'languageprep',
+                               expected: 'немецком',
+                               description: 'Grammar test for languageprep case, немецкий -> немецком'
+                       },
+                       {
+                               word: 'идиш',
+                               grammarForm: 'languageprep',
+                               expected: 'идише',
+                               description: 'Grammar test for languageprep case, идиш -> идише'
+                       },
+                       {
+                               word: 'эсперанто',
+                               grammarForm: 'languageprep',
+                               expected: 'эсперанто',
+                               description: 'Grammar test for languageprep case, эсперанто -> эсперанто'
+                       },
+                       {
+                               word: 'русский',
+                               grammarForm: 'languageadverb',
+                               expected: 'по-русски',
+                               description: 'Grammar test for languageadverb case, русский -> по-русски'
+                       },
+                       {
+                               word: 'немецкий',
+                               grammarForm: 'languageadverb',
+                               expected: 'по-немецки',
+                               description: 'Grammar test for languageadverb case, немецкий -> по-немецки'
+                       },
+                       {
+                               word: 'иврит',
+                               grammarForm: 'languageadverb',
+                               expected: 'на иврите',
+                               description: 'Grammar test for languageadverb case, иврит -> на иврите'
+                       },
+                       {
+                               word: 'эсперанто',
+                               grammarForm: 'languageadverb',
+                               expected: 'на эсперанто',
+                               description: 'Grammar test for languageadverb case, эсперанто -> на эсперанто'
+                       },
+                       {
+                               word: 'гуарани',
+                               grammarForm: 'languageadverb',
+                               expected: 'на языке гуарани',
+                               description: 'Grammar test for languageadverb case, гуарани -> на языке гуарани'
                        }
                ],
 
                ],
 
                uk: [
-                       {
-                               word: 'тесть',
-                               grammarForm: 'genitive',
-                               expected: 'тестя',
-                               description: 'Grammar test for genitive case'
-                       },
                        {
                                word: 'Вікіпедія',
                                grammarForm: 'genitive',
                                description: 'Grammar test for genitive case'
                        },
                        {
-                               word: 'установка',
-                               grammarForm: 'genitive',
-                               expected: 'установки',
-                               description: 'Grammar test for genitive case'
-                       },
-                       {
-                               word: 'похоти',
+                               word: 'Віківиди',
                                grammarForm: 'genitive',
-                               expected: 'поÑ\85оÑ\82ей',
+                               expected: 'Ð\92Ñ\96кÑ\96видÑ\96в',
                                description: 'Grammar test for genitive case'
                        },
                        {
-                               word: 'доводÑ\8b',
+                               word: 'Ð\92Ñ\96кÑ\96Ñ\86иÑ\82аÑ\82и',
                                grammarForm: 'genitive',
-                               expected: 'доводов',
+                               expected: 'Ð\92Ñ\96кÑ\96Ñ\86иÑ\82аÑ\82',
                                description: 'Grammar test for genitive case'
                        },
                        {
-                               word: 'пеÑ\81Ñ\87аник',
+                               word: 'Ð\92Ñ\96кÑ\96пÑ\96дÑ\80Ñ\83Ñ\87ник',
                                grammarForm: 'genitive',
-                               expected: 'пеÑ\81Ñ\87аника',
+                               expected: 'Ð\92Ñ\96кÑ\96пÑ\96дÑ\80Ñ\83Ñ\87ника',
                                description: 'Grammar test for genitive case'
                        },
                        {
index 111d85b..cec0552 100644 (file)
 
                hello = mw.message( 'hello' );
 
-               // https://bugzilla.wikimedia.org/show_bug.cgi?id=44459
+               // https://phabricator.wikimedia.org/T46459
                assert.equal( hello.format, 'text', 'Message property "format" defaults to "text"' );
 
                assert.strictEqual( hello.map, mw.messages, 'Message property "map" defaults to the global instance in mw.messages' );
index 16f458b..d73496f 100644 (file)
@@ -458,8 +458,11 @@ class TestFileIterator implements Iterator {
                        $this->sectionData['config'] = '';
                }
 
-               $isDisabled = preg_match( '/\\bdisabled\\b/i', $this->sectionData['options'] ) && !$this->parserTest->runDisabled;
-               $isParsoidOnly = preg_match( '/\\bparsoid\\b/i', $this->sectionData['options'] ) && $result == 'html' && !$this->parserTest->runParsoid;
+               $isDisabled = preg_match( '/\\bdisabled\\b/i', $this->sectionData['options'] ) &&
+                       !$this->parserTest->runDisabled;
+               $isParsoidOnly = preg_match( '/\\bparsoid\\b/i', $this->sectionData['options'] ) &&
+                       $result == 'html' &&
+                       !$this->parserTest->runParsoid;
                $isFiltered = !preg_match( "/" . $this->parserTest->regex . "/i", $this->sectionData['test'] );
                if ( $input == false || $result == false || $isDisabled || $isParsoidOnly || $isFiltered ) {
                        # disabled test
index d39d43b..bd14e41 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -38,7 +38,7 @@ if ( defined( 'THUMB_HANDLER' ) ) {
 $mediawiki = new MediaWiki();
 $mediawiki->doPostOutputShutdown( 'fast' );
 
-//--------------------------------------------------------------------------
+// --------------------------------------------------------------------------
 
 /**
  * Handle a thumbnail request via thumbnail file URL
@@ -250,11 +250,16 @@ function wfStreamThumb( array $params ) {
        try {
                $thumbName = $img->thumbName( $params );
                if ( !strlen( $thumbName ) ) { // invalid params?
-                       throw new MediaTransformInvalidParametersException( 'Empty return from File::thumbName' );
+                       throw new MediaTransformInvalidParametersException(
+                               'Empty return from File::thumbName'
+                       );
                }
                $thumbName2 = $img->thumbName( $params, File::THUMB_FULL_NAME ); // b/c; "long" style
        } catch ( MediaTransformInvalidParametersException $e ) {
-               wfThumbError( 400, 'The specified thumbnail parameters are not valid: ' . $e->getMessage() );
+               wfThumbError(
+                       400,
+                       'The specified thumbnail parameters are not valid: ' . $e->getMessage()
+               );
                return;
        } catch ( MWException $e ) {
                wfThumbError( 500, $e->getHTML() );
@@ -294,7 +299,8 @@ function wfStreamThumb( array $params ) {
        $dispositionType = isset( $params['download'] ) ? 'attachment' : 'inline';
 
        // Suggest a good name for users downloading this thumbnail
-       $headers[] = "Content-Disposition: {$img->getThumbDisposition( $thumbName, $dispositionType )}";
+       $headers[] =
+               "Content-Disposition: {$img->getThumbDisposition( $thumbName, $dispositionType )}";
 
        if ( count( $varyHeader ) ) {
                $headers[] = 'Vary: ' . implode( ', ', $varyHeader );
@@ -333,7 +339,9 @@ function wfStreamThumb( array $params ) {
        $errorCode = 500;
        if ( !$thumb ) {
                $errorMsg = $errorMsg ?: $msg->rawParams( 'File::transform() returned false' )->escaped();
-               if ( $errorMsg instanceof MessageSpecifier && $errorMsg->getKey() === 'thumbnail_image-failure-limit' ) {
+               if ( $errorMsg instanceof MessageSpecifier &&
+                       $errorMsg->getKey() === 'thumbnail_image-failure-limit'
+               ) {
                        $errorCode = 429;
                }
        } elseif ( $thumb->isError() ) {
@@ -341,8 +349,9 @@ function wfStreamThumb( array $params ) {
        } elseif ( !$thumb->hasFile() ) {
                $errorMsg = $msg->rawParams( 'No path supplied in thumbnail object' )->escaped();
        } elseif ( $thumb->fileIsSource() ) {
-               $errorMsg = $msg->
-                       rawParams( 'Image was not scaled, is the requested width bigger than the source?' )->escaped();
+               $errorMsg = $msg
+                       ->rawParams( 'Image was not scaled, is the requested width bigger than the source?' )
+                       ->escaped();
                $errorCode = 400;
        }
 
@@ -585,7 +594,9 @@ function wfThumbError( $status, $msgHtml ) {
        }
        if ( $wgShowHostnames ) {
                header( 'X-MW-Thumbnail-Renderer: ' . wfHostname() );
-               $url = htmlspecialchars( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '' );
+               $url = htmlspecialchars(
+                       isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : ''
+               );
                $hostname = htmlspecialchars( wfHostname() );
                $debug = "<!-- $url -->\n<!-- $hostname -->\n";
        } else {