From: jenkins-bot Date: Fri, 2 Feb 2018 02:45:27 +0000 (+0000) Subject: Merge "Warn if stateful ParserOutput transforms are used" X-Git-Tag: 1.31.0-rc.0~734 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=74426f3cf796b149f1ae445e41815bbe148640b2;hp=c8e482371407477ecd4f0a1b5778e565d3963a93 Merge "Warn if stateful ParserOutput transforms are used" --- diff --git a/.gitattributes b/.gitattributes index f230c60f7e..786c09f0e5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,12 @@ *.sh eol=lf *.icc binary *.webp binary -*.mp3 binary \ No newline at end of file +*.mp3 binary +*~ export-ignore +#*# export-ignore +.* export-ignore +package.json export-ignore +README.mediawiki export-ignore +Gemfile* export-ignore +vendor/pear/net_smtp/README.rst export-ignore + diff --git a/.gitignore b/.gitignore index b991e115a3..bb3a946593 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ sftp-config.json /images/thumb ## Extension:EasyTimeline /images/timeline +## Extension:Score +/images/lilypond /images/tmp /maintenance/.mweval_history /maintenance/.mwsql_history diff --git a/.mailmap b/.mailmap index c4f86040f3..08e1aaa15f 100644 --- a/.mailmap +++ b/.mailmap @@ -167,6 +167,7 @@ Gabriel Wicke Gabriel Wicke Gabriel Wicke Geoffrey Mon +Geoffrey Trang Gergő Tisza Gergő Tisza Giftpflanze @@ -196,7 +197,7 @@ Jack Phoenix Jackmcbarn Jackmcbarn jagori -James Forrester +James D. Forrester Jaime Crespo Jan Gerber Jan Luca Naumann @@ -278,9 +279,11 @@ Matt Johnston Matthew Britton Matthew Flaschen Matthew Walker +MatthiasDD Matthias Mullie Matthias Mullie Matěj Grabovský +Matěj Suchánek Max Semenik Max Semenik Max Semenik @@ -329,6 +332,7 @@ Philip Tzou physikerwelt (Moritz Schubotz) PiRSquared17 Platonides +pppery PranavK Prateek Saxena Prateek Saxena @@ -383,7 +387,7 @@ Sam Reed Sam Smith Santhosh Thottingal Santhosh Thottingal -Schnark +Schnark (Michael M.) Scimonster Sean Colombo Sean Pringle @@ -450,6 +454,7 @@ Victor Vasiliev Victor Vasiliev Vikas S Yaligar Vivek Ghaisas +Volker E wctaiwan withoutaname X! diff --git a/.phpcs.xml b/.phpcs.xml index 3170381fda..7f90f2788b 100644 --- a/.phpcs.xml +++ b/.phpcs.xml @@ -21,12 +21,14 @@ - + + + diff --git a/.travis.yml b/.travis.yml index cde7193424..b06d9f431b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,12 +27,18 @@ matrix: - env: dbtype=postgres dbuser=travis php: 5.5 # https://docs.travis-ci.com/user/languages/php#HHVM-versions - - env: dbtype=mysql dbuser=root - php: hhvm-3.12 - env: dbtype=mysql dbuser=root php: hhvm-3.18 + - env: dbtype=mysql dbuser=root + php: hhvm-3.21 + - env: dbtype=mysql dbuser=root + php: hhvm-3.24 - env: dbtype=mysql dbuser=root php: 7 + - env: dbtype=mysql dbuser=root + php: 7.1 + - env: dbtype=mysql dbuser=root + php: 7.2 services: - mysql diff --git a/CREDITS b/CREDITS index 6ab4ad3e14..95d6a6cfa6 100644 --- a/CREDITS +++ b/CREDITS @@ -1,5 +1,5 @@ {{int:version-credits-summary}} * Alex Z. * Alexander I. Mashin * Alexander Lehmann +* Alexander Mashin * Alexander Monk * Alexander Sigachov * Alexandre Emsenhuber @@ -62,6 +63,7 @@ The following list can be found parsed under Special:Version/Credits --> * Angela Beesley Starling * ankur * Antoine Musso +* Antoni Siek * Antonio Ospite * apexkid * April King @@ -134,6 +136,7 @@ The following list can be found parsed under Special:Version/Credits --> * Cindy Cicalese * ckoerner * Conrad Irwin +* Cormac Parle * cryptocoryne * Dan Barrett * Dan Collins @@ -156,6 +159,7 @@ The following list can be found parsed under Special:Version/Credits --> * Darkdragon09 * DaSch * datguy +* David Barratt * David Baumgarten * David Causse * David Chan @@ -163,6 +167,8 @@ The following list can be found parsed under Special:Version/Credits --> * David Lynch * David McCabe * David Mudrák +* David Sn +* Dayllan Maza * dcausse * dennisroczek * Denny Vrandecic @@ -170,10 +176,12 @@ The following list can be found parsed under Special:Version/Credits --> * Derk-Jan Hartman * Derric Atzrott * Derrick Coetzee +* Deskana * Dévai Tamás * Devi Krishnan * Diederik van Liere * divadsn +* Dmaza * Domas Mituzas * Douglas Gardner * DPStokesNZ @@ -183,6 +191,7 @@ The following list can be found parsed under Special:Version/Credits --> * Eddie Greiner-Petter * Edward Chernenko * Edward Z. Yang +* Egbe Eugene * Elisabeth Bauer * Elliott Eggleston * Elvis Stansvik @@ -194,6 +203,7 @@ The following list can be found parsed under Special:Version/Credits --> * Emufarmers * enigmaeth * Entlinkt +* Envel Le Hir * Eranroz * Eric Evans * Eric Schneider @@ -209,10 +219,13 @@ The following list can be found parsed under Special:Version/Credits --> * ExplosiveHippo * Faidon Liambotis * Federico Leva +* Felipe L. Ewald * Fenzik Joseph +* Filippo Giunchedi * firebus * Florian Schmidt * fomafix +* Framawiki * Fran Rogers * Fred Emmott * FunPika @@ -220,6 +233,7 @@ The following list can be found parsed under Special:Version/Credits --> * Gary Guo * gbt248 * Geoffrey Mon +* GeoffreyT2000 * georggi * Gergő Tisza * Gero Scholz @@ -231,6 +245,7 @@ The following list can be found parsed under Special:Version/Credits --> * Giuseppe Lavagetto * gladoscc * glaisher +* golopot * Greg Maxwell * Greg Sabino Mullane * Gregory Szorc @@ -246,9 +261,11 @@ The following list can be found parsed under Special:Version/Credits --> * Helder * Henning Snater * Hojjat +* Hoto Cocoa * Huji * Hydriz * Ian Baker +* Ian Marlier * Ilmari Karonen * Inez Korczyński * IoannisKydonis @@ -264,7 +281,7 @@ The following list can be found parsed under Special:Version/Credits --> * Jaime Crespo * Jakub Vrana * James Earl Douglas -* James Forrester +* James D. Forrester * Jan Berkel * Jan Drewniak * Jan Gerber @@ -277,6 +294,7 @@ The following list can be found parsed under Special:Version/Credits --> * jarry1250 * Jaska Zedlik * Jason Richey +* Jayprakash12345 * jeblad * Jeff Hobson * Jeff Janes @@ -291,6 +309,7 @@ The following list can be found parsed under Special:Version/Credits --> * Jerome Jamnicky * Jesús Martínez Novo * jhobs +* jhsoby * Jiabao * Jidanni * Jimmy Collins @@ -307,11 +326,13 @@ The following list can be found parsed under Special:Version/Credits --> * John N * Jon Harald Søby * Jon Robson +* Jonathan * Jonathan Wiltshire * Jools Wills * jsahleen * Julian Ostrow * Juliano F. Ravasi +* Julien Girault * Juliusz Gonera * Jure Kajzer * Justin Du @@ -321,6 +342,7 @@ The following list can be found parsed under Special:Version/Credits --> * Kartik Mistry * Karun Dambiec * Katie Filbert +* KeerthanaS * Kevin Israel * Kghbln * Kim Eik @@ -372,6 +394,7 @@ The following list can be found parsed under Special:Version/Credits --> * madurangasiriwardena * Magnus Manske * mainframe98 +* Mako Bates * Manuel Menal * Manuel Schneider * Marc Ordinas i Llopis @@ -381,6 +404,7 @@ The following list can be found parsed under Special:Version/Credits --> * Marco Schuster * MarcoAurelio * Marcus Buck +* Margaret Epps * Marius Hoch * Mark Bergsma * Mark Clements @@ -394,7 +418,6 @@ The following list can be found parsed under Special:Version/Credits --> * Massaf * Matěj Grabovský * Matěj Suchánek -* matejsuchanek * Mathias Ertl * mati * Matt Fitzpatrick @@ -411,6 +434,7 @@ The following list can be found parsed under Special:Version/Credits --> * Max Semenik * Max Sikström * mayankmadan +* Mehmet Mert Yıldıran * Meno25 * merl * Merlijn S. van Deen @@ -420,7 +444,6 @@ The following list can be found parsed under Special:Version/Credits --> * Michael Dale * Michael De La Rue * Michael Holloway -* Michael M. * Michael Newton * Michael Walsh * Michał Łazowik @@ -475,6 +498,7 @@ The following list can be found parsed under Special:Version/Credits --> * nullspoon * Nuria Ruiz * Nx.devnull +* Obaid Raza * Ocean behind ears * Od1n * Olaf Lenz @@ -498,6 +522,7 @@ The following list can be found parsed under Special:Version/Credits --> * Pavel Selitskas * Pcoombe * Perside Rosalie +* petarpetkovic * Peter Coombe * Peter Gehres * Peter Hedenskog @@ -511,6 +536,7 @@ The following list can be found parsed under Special:Version/Credits --> * physikerwelt (Moritz Schubotz) * PieRRoMaN * Pikne +* Piotr Miazga * PiRSquared17 * Platonides * Pmlineditor @@ -531,6 +557,7 @@ The following list can be found parsed under Special:Version/Credits --> * rahul21 * Raimond Spekking * Ramunas Geciauskas +* RazeSoldier * Remember the dot * René Kijewski * Reza @@ -566,6 +593,7 @@ The following list can be found parsed under Special:Version/Credits --> * Ryan Kaldari * Ryan Lane * Ryan Schmidt +* ryan10145 * S Page * Salvatore Ingala * Sam Reed @@ -573,7 +601,7 @@ The following list can be found parsed under Special:Version/Credits --> * Sam Wilson * Santhosh Thottingal * saptaks -* Schnark +* Schnark (Michael M.) * Scimonster * scnd * Scott Colcord @@ -585,6 +613,7 @@ The following list can be found parsed under Special:Version/Credits --> * Sébastien Santoro * Sergio Santoro * Sethakill +* Sfic * Shahyar * Shane Gibbons * Shane King @@ -593,6 +622,7 @@ The following list can be found parsed under Special:Version/Credits --> * shirayuki * Sidhant Gupta * Siebrand Mazeland +* Simeon Dahl * Simon Walker * Smriti Singh * Solitarius @@ -616,6 +646,7 @@ The following list can be found parsed under Special:Version/Credits --> * Subin Siby * Subramanya Sastry * Sumit Asthana +* Suriyaa Kudo * svip * Szymon Świerkosz * T.D. Corell @@ -665,13 +696,14 @@ The following list can be found parsed under Special:Version/Credits --> * UltrasonicNXT * Umherirrender * utkarsh95 +* Valerio Bozzolan * Van de Bugger * Viačeslav * Victor Barbu * Victor Porton * Victor Vasiliev -* victorbarbu * Ville Stadista +* vinithegit * vishnu * Vitaliy Filippov * Vivek Ghaisas @@ -703,6 +735,7 @@ The following list can be found parsed under Special:Version/Credits --> * Zhaofeng Li * Zhengzhu Feng * Zhuyifei1999 +* zoranzoki21 * Zppix * محمد شعیب diff --git a/HISTORY b/HISTORY index 1f30b7068e..244d681902 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,267 @@ -Change notes from older releases. For current info see RELEASE-NOTES-1.30. +Change notes from older releases. For current info see RELEASE-NOTES-1.31. + += MediaWiki 1.30 = + +== MediaWiki 1.30.0 == + +=== Changes since MediaWiki 1.30.0-rc.0 === +* Upgraded Moment.js from v2.15.0 to v2.19.3. +* Add ip_changes to postgres/tables.sql. +* Skip null shell parameters. +* Add wfWaitForSlaves() to maintenance/migrateComments.php. +* (T182245) Fix join conditions in ImageListPager. +* (T178626) Revert #contentSub and #jump-to-nav margin changes. + +=== MySQL version requirement in 1.30 === +As of 1.30, MediaWiki now requires MySQL 5.5.8 or higher (see Compatibility +section). + +=== Configuration changes in 1.30 === +* The "C.UTF-8" locale should be used for $wgShellLocale, if available, to avoid + unexpected behavior when code uses locale-sensitive string comparisons. For + example, the Scribunto extension considers "bar" < "Foo" in most locales + since it ignores case. +* $wgShellLocale now affects LC_ALL rather than only LC_CTYPE. See + documentation of $wgShellLocale for details. +* $wgShellLocale is now applied for all requests. wfInitShellLocale() is + deprecated and a no-op, as it is no longer needed. +* $wgJobClasses may now specify callback functions as an alternative to plain + class names. This is intended for extensions that want control over the + instantiation of their jobs, to allow for proper dependency injection. +* $wgResourceModules may now specify callback functions as an alternative + to plain class names, using the 'factory' key in the module description + array. This allows dependency injection to be used for ResourceLoader modules. +* $wgExceptionHooks has been removed. +* (T163562) $wgRangeContributionsCIDRLimit was introduced to control the size + of IP ranges that can be queried at Special:Contributions. +* (T45547) $wgUsePigLatinVariant added (off by default). +* (T152540) MediaWiki now supports a section ID escaping style that allows to display + non-Latin characters verbatim on many modern browsers. This is controlled by the + new configuration setting, $wgFragmentMode. +* $wgExperimentalHtmlIds is now deprecated and will be removed in a future version, + use $wgFragmentMode to migrate off it to a modern alternative. +* $wgExternalInterwikiFragmentMode was introduced to control how fragments in + sinterwikis going outside of current wiki farm are encoded. +* (T120333) Soft-deprecated the use of PHP extension 'mysql' in favor of 'mysqli'. + This PHP extension was deprecated in PHP 5.5 and removed in PHP 7.0. MediaWiki + auto-selects the 'mysqli' driver since MediaWiki 1.22, except if explicitly + requested through the configuration parameter $wgDBservers. +* $wgOOUIEditPage was removed, as it is now the default. This was documented as a + temporary variable during the migration period. + +=== New features in 1.30 === +* (T37247) Output from Parser::parse() will now be wrapped in a div with + class="mw-parser-output" by default. This may be changed or disabled using + ParserOptions::setWrapOutputClass(). +* (T163562) Added ability to search for contributions within an IP ranges + at Special:Contributions. +* Added 'ChangeTagsAllowedAdd' hook, enabling extensions to allow software- + specific tags to be added by users. +* Added a 'ParserOptionsRegister' hook to allow extensions to register + additional parser options. +* (T45547) Included Pig Latin, a language game in English, as a + LanguageConverter variant. This allows English-speaking developers + to develop and test LanguageConverter more easily. Pig Latin can be + enabled by setting $wgUsePigLatinVariant to true. +* Added RecentChangesPurgeRows hook to allow extensions to purge data that + depends on the recentchanges table. +* Added JS config values wgDiffOldId/wgDiffNewId to the output of diff pages. +* (T2424) Added direct unwatch links to entries in Special:Watchlist (if the + 'watchlistunwatchlinks' preference option is enabled). With JavaScript + enabled, these links toggle so the user can also re-watch pages that have + just been unwatched. +* Added $wgParserTestMediaHandlers, where mock media handlers can be passed to + MediaHandlerFactory for parser tests. +* Edit summaries, block reasons, and other "comments" are now stored in a + separate database table. Use the CommentFormatter class to access them. +** This is currently gated by $wgCommentTableSchemaMigrationStage. Most wikis + can set this to MIGRATION_NEW and run maintenance/migrateComments.php as + soon as any necessary extensions are updated. +* (T138166) Added ability for users to prohibit other users from sending them + emails with Special:Emailuser. Can be enabled by setting + $wgEnableUserEmailBlacklist to true. +* (T67297) $wgBrowserBlacklist is deprecated, and changing it will have no effect. + Instead, users using browsers that do not support Unicode will be unable to edit + and should upgrade to a modern browser instead. + +=== External library changes in 1.30 === + +==== Upgraded external libraries ==== +* Updated justinrainbow/json-schema from v3.0 to v5.2. +* Updated mediawiki/mediawiki-codesniffer from v0.7.2 to v0.12.0. +* Updated wikimedia/composer-merge-plugin from v1.4.0 to v1.4.1. +* Updated wikimedia/relpath from v1.0.3 to v2.0.0. +* Updated OOjs from v2.0.0 to v2.1.0. +* Updated OOUI from v0.21.1 to v0.23.0. +* Updated QUnit from v1.23.1 to v2.4.0. +* Updated phpunit/phpunit from v4.8.35 to v4.8.36. +* Upgraded Moment.js from v2.15.0 to v2.19.3. + +==== New external libraries ==== +* The class \TestingAccessWrapper has been moved to the external library + wikimedia/testing-access-wrapper and renamed \Wikimedia\TestingAccessWrapper. +* Purtle, a fast, lightweight RDF generator. + +==== Removed and replaced external libraries ==== +* … + +=== Bug fixes in 1.30 === +* (T151633) Ordered list items use now Devanagari digits in Nepalese + (thanks to Sfic) + +=== Action API changes in 1.30 === +* (T37247) action=parse output will be wrapped in a div with + class="mw-parser-output" by default. This may be changed or disabled using + the new 'wrapoutputclass' parameter. +* When errorformat is not 'bc', abort reasons from action=login will be + formatted as specified by the error formatter parameters. +* action=compare can now handle arbitrary text, deleted revisions, and + returning users and edit comments. +* (T164106) The 'rvdifftotext', 'rvdifftotextpst', 'rvdiffto', + 'rvexpandtemplates', 'rvgeneratexml', 'rvparse', and 'rvprop=parsetree' + parameters to prop=revisions are deprecated, as are the similarly named + parameters to prop=deletedrevisions, list=allrevisions, and + list=alldeletedrevisions. Use action=compare, action=parse, or + action=expandtemplates instead. + +=== Action API internal changes in 1.30 === +* ApiBase::getDescriptionMessage() and the "apihelp-*-description" messages are + deprecated. The existing message should be split between "apihelp-*-summary" + and "apihelp-*-extended-description". +* (T123931) Individual values of multi-valued parameters can now be marked as + deprecated. + +=== Languages updated in 1.30 === +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 Phabricator reports. + +* Added: kbp (Kabɩyɛ / Kabiyè) +* Added: skr (Saraiki, سرائیکی) +* Added: tay (Tayal / Atayal) +* Removed: tokipona (Toki Pona) + +==== Pig Latin added ==== +* (T45547) Added Pig Latin, a made-up English variant (en-x-piglatin), + for easier variant development and testing. Disabled by default. It can be + enabled by setting $wgUsePigLatinVariant to true. + +=== Other changes in 1.30 === +* The use of an associative array for $wgProxyList, where the IP address is in + the key instead of the value, is deprecated (e.g. [ '127.0.0.1' => 'value' ]). + Please convert these arrays to indexed/sequential ones (e.g. [ '127.0.0.1' ]). +* mw.user.bucket (deprecated in 1.23) was removed. +* LoadBalancer::getServerInfo() and LoadBalancer::setServerInfo() are + deprecated. There are no known callers. +* File::getStreamHeaders() was deprecated. +* MediaHandler::getStreamHeaders() was deprecated. +* Title::canTalk() was deprecated. The new Title::canHaveTalkPage() should be + used instead. +* MWNamespace::canTalk() was deprecated. The new MWNamespace::hasTalkNamespace() + should be used instead. +* The ExtractThumbParameters hook (deprecated in 1.21) was removed. +* The OutputPage::addParserOutputNoText and ::getHeadLinks methods (both + deprecated in 1.24) were removed. +* wfMemcKey() and wfGlobalCacheKey() were deprecated. BagOStuff::makeKey() and + BagOStuff::makeGlobalKey() should be used instead. +* (T146304) Preprocessor handling of LanguageConverter markup has been improved. + As a result of the new uniform handling, '-{' may need to be escaped + (for example, as '-{') where it occurs inside template arguments + or wikilinks. +* (T163966) Page moves are now counted as edits for the purposes of + autopromotion, i.e., they increment the user_editcount field in the database. +* Two new hooks, LogEventsListLineEnding and NewPagesLineEnding, were added for + manipulating Special:Log and Special:NewPages lines. +* The OldChangesListRecentChangesLine, EnhancedChangesListModifyLineData, + PageHistoryLineEnding, ContributionsLineEnding and DeletedContributionsLineEnding + hooks have an additional parameter, for manipulating HTML data attributes of + RC/history lines. EnhancedChangesListModifyBlockLineData can do that via the + $data['attribs'] subarray. +* (T130632) The OutputPage::enableTOC() method was removed. +* WikiPage::getParserOutput() will now throw an exception if passed + ParserOptions that would pollute the parser cache. Callers should use + WikiPage::makeParserOptions() to create the ParserOptions object and only + change options that affect the parser cache key. +* Article::viewRedirect() is deprecated. +* IP::isValidBlock() was deprecated. Use the equivalent IP::isValidRange(). +* DeprecatedGlobal no longer supports passing in a direct value, it requires a + callable factory function or a class name. +* The $parserMemc global, wfGetParserCacheStorage(), and ParserCache::singleton() + are all deprecated. The main ParserCache instance should be obtained from + MediaWikiServices instead. Access to the underlying BagOStuff is possible + through the new ParserCache::getCacheStorage() method. +* .mw-ui-constructive CSS class (deprecated in 1.27) was removed. +* Sanitizer::escapeId() was deprecated, use escapeIdForAttribute(), + escapeIdForLink() or escapeIdForExternalInterwiki() instead. +* Title::escapeFragmentForURL() was deprecated, use one of the aforementioned + Sanitizer functions or, if possible, Title::getFragmentForURL(). +* Second parameter to Sanitizer::escapeIdReferenceList() ($options) now does + nothing and is deprecated. +* mw.util.escapeId() was deprecated, use escapeIdForAttribute() or + escapeIdForLink(). +* MagicWord::replaceMultiple() (deprecated in 1.25) was removed. +* WikiImporter now requires the second parameter to be an instance of the Config, + class. Prior to that, the Config parameter was optional (a behavior deprecated in + 1.25). +* Removed 'jquery.mwExtension' module. (deprecated since 1.26) +* mediawiki.ui: Deprecate greys, which are not part of WikimediaUI color palette + any more. +* CdbReader, CdbWriter, CdbException classes (deprecated in 1.25) were removed. + The namespaced classes in the Cdb namespace should be used instead. +* IPSet class (deprecated in 1.26) was removed. The namespaced IPSet\IPSet + should be used instead. +* RunningStat class (deprecated in 1.27) was removed. The namespaced + RunningStat\RunningStat should be used instead. +* MWMemcached and MemCachedClientforWiki classes (deprecated in 1.27) were removed. + The MemcachedClient class should be used instead. +* EditPage underwent some refactoring and deprecations: + * EditPage::isOouiEnabled() is deprecated and will always return true. + * EditPage::getSummaryInput() and ::getSummaryInputOOUI() are deprecated. Please + use ::getSummaryInputWidget() instead. + * EditPage::getCheckboxes() and ::getCheckboxesOOUI() are deprecated. Please + use ::getCheckboxesWidget() instead. + * Creating an EditPage instance without calling EditPage::setContextTitle() should + be avoided and will be deprecated in a future release. + * EditPage::safeUnicodeInput() and ::safeUnicodeOutput() are deprecated and no-ops. + * EditPage::$isCssJsSubpage, ::$isCssSubpage, and ::$isJsSubpage are deprecated. The + corresponding methods from Title should be used instead. + * EditPage::$isWrongCaseCssJsPage is deprecated. There is no replacement. + * EditPage::$mArticle and ::$mTitle are deprecated for public usage. The getters + ::getArticle() and ::getTitle() should be used instead. + * Trying to control or fake EditPage context by overriding $wgUser, $wgRequest, $wgOut, + and $wgLang is no longer supported and won't work. The IContextSource returned from + EditPage::getContext() must be modified instead. +* Parser::getRandomString() (deprecated in 1.26) was removed. +* Parser::uniqPrefix() (deprecated in 1.26) was removed. +* Parser::extractTagsAndParams() now only accepts three arguments. The fourth, + $uniq_prefix was deprecated in 1.26 and has now been removed. +* (T172514) The following tables have had their UNIQUE indexes turned into proper + PRIMARY KEYs for increased maintainability: categorylinks, imagelinks, iwlinks, + langlinks, log_search, module_deps, objectcache, pagelinks, query_cache, site_stats, + templatelinks, text, transcache, user_former_groups, user_properties. +* IDatabase::nextSequenceValue() is no longer needed by any database backends + (formerly it was needed by PostgreSQL and Oracle), and is now deprecated. +* (T146591) The lc_lang_key index on the l10n_cache table has been changed into a + PRIMARY KEY. +* (T157227) bot_password.bp_user, change_tag.ct_log_id, change_tag.ct_rev_id, + page_restrictions.pr_user, tag_summary.ts_log_id, tag_summary.ts_rev_id and + user_properties.up_user have all been made unsigned on MySQL. +* DB_SLAVE is deprecated. DB_REPLICA should be used instead. +* wfUsePHP() is deprecated. +* wfFixSessionID() was removed. +* wfShellExec() and related functions are deprecated, use Shell::command(). This also + slightly changes the behavior of how execution time limits are calculated when only + some of defaults are overridden per-call. When in doubt, always override both wall + clock and CPU time. +* (T138166) SpecialEmailUser::getTarget() now requires a second argument, the sending + user object. Using the method without the second argument is deprecated. +* (T67297) Browsers that don't support Unicode will have their edits rejected. +* (T178450) The module 'jquery.badge' is deprecated and will be removed in a future + release. For notifying the user of an event, the Notifications ("Echo") system + should be used instead. +* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and browser + sends non-standard url escaping. +* (T165846) SECURITY: BotPassword login attempts weren't throttled. = MediaWiki 1.29 = diff --git a/RELEASE-NOTES-1.30 b/RELEASE-NOTES-1.30 deleted file mode 100644 index 1449dab47e..0000000000 --- a/RELEASE-NOTES-1.30 +++ /dev/null @@ -1,304 +0,0 @@ -== MediaWiki 1.30 == - -THIS IS NOT A RELEASE YET - -MediaWiki 1.30 is an alpha-quality branch and is not recommended for use in -production. - -=== MySQL version requirement in 1.30 === -As of 1.30, MediaWiki now requires MySQL 5.5.8 or higher (see Compatibility -section). - -=== Configuration changes in 1.30 === -* The "C.UTF-8" locale should be used for $wgShellLocale, if available, to avoid - unexpected behavior when code uses locale-sensitive string comparisons. For - example, the Scribunto extension considers "bar" < "Foo" in most locales - since it ignores case. -* $wgShellLocale now affects LC_ALL rather than only LC_CTYPE. See - documentation of $wgShellLocale for details. -* $wgShellLocale is now applied for all requests. wfInitShellLocale() is - deprecated and a no-op, as it is no longer needed. -* $wgJobClasses may now specify callback functions as an alternative to plain - class names. This is intended for extensions that want control over the - instantiation of their jobs, to allow for proper dependency injection. -* $wgResourceModules may now specify callback functions as an alternative - to plain class names, using the 'factory' key in the module description - array. This allows dependency injection to be used for ResourceLoader modules. -* $wgExceptionHooks has been removed. -* (T163562) $wgRangeContributionsCIDRLimit was introduced to control the size - of IP ranges that can be queried at Special:Contributions. -* (T45547) $wgUsePigLatinVariant added (off by default). -* (T152540) MediaWiki now supports a section ID escaping style that allows to display - non-Latin characters verbatim on many modern browsers. This is controlled by the - new configuration setting, $wgFragmentMode. -* $wgExperimentalHtmlIds is now deprecated and will be removed in a future version, - use $wgFragmentMode to migrate off it to a modern alternative. -* $wgExternalInterwikiFragmentMode was introduced to control how fragments in - sinterwikis going outside of current wiki farm are encoded. -* (T120333) Soft-deprecated the use of PHP extension 'mysql' in favor of 'mysqli'. - This PHP extension was deprecated in PHP 5.5 and removed in PHP 7.0. MediaWiki - auto-selects the 'mysqli' driver since MediaWiki 1.22, except if explicitly - requested through the configuration parameter $wgDBservers. -* $wgOOUIEditPage was removed, as it is now the default. This was documented as a - temporary variable during the migration period. - -=== New features in 1.30 === -* (T37247) Output from Parser::parse() will now be wrapped in a div with - class="mw-parser-output" by default. This may be changed or disabled using - ParserOptions::setWrapOutputClass(). -* (T163562) Added ability to search for contributions within an IP ranges - at Special:Contributions. -* Added 'ChangeTagsAllowedAdd' hook, enabling extensions to allow software- - specific tags to be added by users. -* Added a 'ParserOptionsRegister' hook to allow extensions to register - additional parser options. -* (T45547) Included Pig Latin, a language game in English, as a - LanguageConverter variant. This allows English-speaking developers - to develop and test LanguageConverter more easily. Pig Latin can be - enabled by setting $wgUsePigLatinVariant to true. -* Added RecentChangesPurgeRows hook to allow extensions to purge data that - depends on the recentchanges table. -* Added JS config values wgDiffOldId/wgDiffNewId to the output of diff pages. -* (T2424) Added direct unwatch links to entries in Special:Watchlist (if the - 'watchlistunwatchlinks' preference option is enabled). With JavaScript - enabled, these links toggle so the user can also re-watch pages that have - just been unwatched. -* Added $wgParserTestMediaHandlers, where mock media handlers can be passed to - MediaHandlerFactory for parser tests. -* Edit summaries, block reasons, and other "comments" are now stored in a - separate database table. Use the CommentFormatter class to access them. -** This is currently gated by $wgCommentTableSchemaMigrationStage. Most wikis - can set this to MIGRATION_NEW and run maintenance/migrateComments.php as - soon as any necessary extensions are updated. -* (T138166) Added ability for users to prohibit other users from sending them - emails with Special:Emailuser. Can be enabled by setting - $wgEnableUserEmailBlacklist to true. -* (T67297) $wgBrowserBlacklist is deprecated, and changing it will have no effect. - Instead, users using browsers that do not support Unicode will be unable to edit - and should upgrade to a modern browser instead. - -=== External library changes in 1.30 === - -==== Upgraded external libraries ==== -* Updated justinrainbow/json-schema from v3.0 to v5.2. -* Updated mediawiki/mediawiki-codesniffer from v0.7.2 to v0.12.0. -* Updated wikimedia/composer-merge-plugin from v1.4.0 to v1.4.1. -* Updated wikimedia/relpath from v1.0.3 to v2.0.0. -* Updated OOjs from v2.0.0 to v2.1.0. -* Updated OOUI from v0.21.1 to v0.23.0. -* Updated QUnit from v1.23.1 to v2.4.0. -* Updated phpunit/phpunit from v4.8.35 to v4.8.36. - -==== New external libraries ==== -* The class \TestingAccessWrapper has been moved to the external library - wikimedia/testing-access-wrapper and renamed \Wikimedia\TestingAccessWrapper. -* Purtle, a fast, lightweight RDF generator. - -==== Removed and replaced external libraries ==== -* … - -=== Bug fixes in 1.30 === -* (T151633) Ordered list items use now Devanagari digits in Nepalese - (thanks to Sfic) - -=== Action API changes in 1.30 === -* (T37247) action=parse output will be wrapped in a div with - class="mw-parser-output" by default. This may be changed or disabled using - the new 'wrapoutputclass' parameter. -* When errorformat is not 'bc', abort reasons from action=login will be - formatted as specified by the error formatter parameters. -* action=compare can now handle arbitrary text, deleted revisions, and - returning users and edit comments. -* (T164106) The 'rvdifftotext', 'rvdifftotextpst', 'rvdiffto', - 'rvexpandtemplates', 'rvgeneratexml', 'rvparse', and 'rvprop=parsetree' - parameters to prop=revisions are deprecated, as are the similarly named - parameters to prop=deletedrevisions, list=allrevisions, and - list=alldeletedrevisions. Use action=compare, action=parse, or - action=expandtemplates instead. - -=== Action API internal changes in 1.30 === -* ApiBase::getDescriptionMessage() and the "apihelp-*-description" messages are - deprecated. The existing message should be split between "apihelp-*-summary" - and "apihelp-*-extended-description". -* (T123931) Individual values of multi-valued parameters can now be marked as - deprecated. - -=== Languages updated in 1.30 === -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 Phabricator reports. - -* Added: kbp (Kabɩyɛ / Kabiyè) -* Added: skr (Saraiki, سرائیکی) -* Added: tay (Tayal / Atayal) -* Removed: tokipona (Toki Pona) - -==== Pig Latin added ==== -* (T45547) Added Pig Latin, a made-up English variant (en-x-piglatin), - for easier variant development and testing. Disabled by default. It can be - enabled by setting $wgUsePigLatinVariant to true. - -=== Other changes in 1.30 === -* The use of an associative array for $wgProxyList, where the IP address is in - the key instead of the value, is deprecated (e.g. [ '127.0.0.1' => 'value' ]). - Please convert these arrays to indexed/sequential ones (e.g. [ '127.0.0.1' ]). -* mw.user.bucket (deprecated in 1.23) was removed. -* LoadBalancer::getServerInfo() and LoadBalancer::setServerInfo() are - deprecated. There are no known callers. -* File::getStreamHeaders() was deprecated. -* MediaHandler::getStreamHeaders() was deprecated. -* Title::canTalk() was deprecated. The new Title::canHaveTalkPage() should be - used instead. -* MWNamespace::canTalk() was deprecated. The new MWNamespace::hasTalkNamespace() - should be used instead. -* The ExtractThumbParameters hook (deprecated in 1.21) was removed. -* The OutputPage::addParserOutputNoText and ::getHeadLinks methods (both - deprecated in 1.24) were removed. -* wfMemcKey() and wfGlobalCacheKey() were deprecated. BagOStuff::makeKey() and - BagOStuff::makeGlobalKey() should be used instead. -* (T146304) Preprocessor handling of LanguageConverter markup has been improved. - As a result of the new uniform handling, '-{' may need to be escaped - (for example, as '-{') where it occurs inside template arguments - or wikilinks. -* (T163966) Page moves are now counted as edits for the purposes of - autopromotion, i.e., they increment the user_editcount field in the database. -* Two new hooks, LogEventsListLineEnding and NewPagesLineEnding, were added for - manipulating Special:Log and Special:NewPages lines. -* The OldChangesListRecentChangesLine, EnhancedChangesListModifyLineData, - PageHistoryLineEnding, ContributionsLineEnding and DeletedContributionsLineEnding - hooks have an additional parameter, for manipulating HTML data attributes of - RC/history lines. EnhancedChangesListModifyBlockLineData can do that via the - $data['attribs'] subarray. -* (T130632) The OutputPage::enableTOC() method was removed. -* WikiPage::getParserOutput() will now throw an exception if passed - ParserOptions that would pollute the parser cache. Callers should use - WikiPage::makeParserOptions() to create the ParserOptions object and only - change options that affect the parser cache key. -* Article::viewRedirect() is deprecated. -* IP::isValidBlock() was deprecated. Use the equivalent IP::isValidRange(). -* DeprecatedGlobal no longer supports passing in a direct value, it requires a - callable factory function or a class name. -* The $parserMemc global, wfGetParserCacheStorage(), and ParserCache::singleton() - are all deprecated. The main ParserCache instance should be obtained from - MediaWikiServices instead. Access to the underlying BagOStuff is possible - through the new ParserCache::getCacheStorage() method. -* .mw-ui-constructive CSS class (deprecated in 1.27) was removed. -* Sanitizer::escapeId() was deprecated, use escapeIdForAttribute(), - escapeIdForLink() or escapeIdForExternalInterwiki() instead. -* Title::escapeFragmentForURL() was deprecated, use one of the aforementioned - Sanitizer functions or, if possible, Title::getFragmentForURL(). -* Second parameter to Sanitizer::escapeIdReferenceList() ($options) now does - nothing and is deprecated. -* mw.util.escapeId() was deprecated, use escapeIdForAttribute() or - escapeIdForLink(). -* MagicWord::replaceMultiple() (deprecated in 1.25) was removed. -* WikiImporter now requires the second parameter to be an instance of the Config, - class. Prior to that, the Config parameter was optional (a behavior deprecated in - 1.25). -* Removed 'jquery.mwExtension' module. (deprecated since 1.26) -* mediawiki.ui: Deprecate greys, which are not part of WikimediaUI color palette - any more. -* CdbReader, CdbWriter, CdbException classes (deprecated in 1.25) were removed. - The namespaced classes in the Cdb namespace should be used instead. -* IPSet class (deprecated in 1.26) was removed. The namespaced IPSet\IPSet - should be used instead. -* RunningStat class (deprecated in 1.27) was removed. The namespaced - RunningStat\RunningStat should be used instead. -* MWMemcached and MemCachedClientforWiki classes (deprecated in 1.27) were removed. - The MemcachedClient class should be used instead. -* EditPage underwent some refactoring and deprecations: - * EditPage::isOouiEnabled() is deprecated and will always return true. - * EditPage::getSummaryInput() and ::getSummaryInputOOUI() are deprecated. Please - use ::getSummaryInputWidget() instead. - * EditPage::getCheckboxes() and ::getCheckboxesOOUI() are deprecated. Please - use ::getCheckboxesWidget() instead. - * Creating an EditPage instance without calling EditPage::setContextTitle() should - be avoided and will be deprecated in a future release. - * EditPage::safeUnicodeInput() and ::safeUnicodeOutput() are deprecated and no-ops. - * EditPage::$isCssJsSubpage, ::$isCssSubpage, and ::$isJsSubpage are deprecated. The - corresponding methods from Title should be used instead. - * EditPage::$isWrongCaseCssJsPage is deprecated. There is no replacement. - * EditPage::$mArticle and ::$mTitle are deprecated for public usage. The getters - ::getArticle() and ::getTitle() should be used instead. - * Trying to control or fake EditPage context by overriding $wgUser, $wgRequest, $wgOut, - and $wgLang is no longer supported and won't work. The IContextSource returned from - EditPage::getContext() must be modified instead. -* Parser::getRandomString() (deprecated in 1.26) was removed. -* Parser::uniqPrefix() (deprecated in 1.26) was removed. -* Parser::extractTagsAndParams() now only accepts three arguments. The fourth, - $uniq_prefix was deprecated in 1.26 and has now been removed. -* (T172514) The following tables have had their UNIQUE indexes turned into proper - PRIMARY KEYs for increased maintainability: categorylinks, imagelinks, iwlinks, - langlinks, log_search, module_deps, objectcache, pagelinks, query_cache, site_stats, - templatelinks, text, transcache, user_former_groups, user_properties. -* IDatabase::nextSequenceValue() is no longer needed by any database backends - (formerly it was needed by PostgreSQL and Oracle), and is now deprecated. -* (T146591) The lc_lang_key index on the l10n_cache table has been changed into a - PRIMARY KEY. -* (T157227) bot_password.bp_user, change_tag.ct_log_id, change_tag.ct_rev_id, - page_restrictions.pr_user, tag_summary.ts_log_id, tag_summary.ts_rev_id and - user_properties.up_user have all been made unsigned on MySQL. -* DB_SLAVE is deprecated. DB_REPLICA should be used instead. -* wfUsePHP() is deprecated. -* wfFixSessionID() was removed. -* wfShellExec() and related functions are deprecated, use Shell::command(). This also - slightly changes the behavior of how execution time limits are calculated when only - some of defaults are overridden per-call. When in doubt, always override both wall - clock and CPU time. -* (T138166) SpecialEmailUser::getTarget() now requires a second argument, the sending - user object. Using the method without the second argument is deprecated. -* (T67297) Browsers that don't support Unicode will have their edits rejected. -* (T178450) The module 'jquery.badge' is deprecated and will be removed in a future - release. For notifying the user of an event, the Notifications ("Echo") system - should be used instead. - -== Compatibility == -MediaWiki 1.30 requires PHP 5.5.9 or later. There is experimental support for -HHVM 3.6.5 or later. - -MySQL/MariaDB 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.5.8 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.30 has several database changes since 1.29, 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 a long time (minutes on a medium sized site, -many hours on a large site). - -Don't forget to always back up your database before upgrading! - -See the file UPGRADE for more detailed upgrade instructions, including -important information when upgrading from versions prior to 1.11. - -For notes on 1.29.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/Special:MyLanguage/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/RELEASE-NOTES-1.31 b/RELEASE-NOTES-1.31 index 139773b573..ad24852e73 100644 --- a/RELEASE-NOTES-1.31 +++ b/RELEASE-NOTES-1.31 @@ -17,6 +17,13 @@ production. not have the right to mark things patrolled. * Wikis that contain imported revisions or CentralAuth global blocks should run maintenance/cleanupUsersWithNoId.php. +* $wgResourceLoaderMinifierStatementsOnOwnLine and $wgResourceLoaderMinifierMaxLineLength + were removed (deprecated since 1.27). +* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that are not + using the latest version of the Referrer Policy specification. +* $wgFragmentMode is now set to [ 'legacy', 'html5' ] by default. This is a first step of + migration to human-readable section IDs that will later result in 'html5' being the + default mode. === New features in 1.31 === * Wikimedia\Rdbms\IDatabase->select() and similar methods now support @@ -33,10 +40,23 @@ production. users during an import. * Added a hook, ParserOutputPostCacheTransform, to allow extensions to affect the ParserOutput::getText() post-cache transformations. +* Added a hook, UploadForm:getInitialPageText, to allow extensions to alter the + initial page text for file uploads. +* (T181651) The info page for File pages now displays the file's base-16 SHA1 + hash value in the table of basic information. === External library changes in 1.31 === ==== Upgraded external libraries ==== +* Updated jquery.chosen from v0.9.14 to v1.8.2. +* Updated composer/spdx-licenses from 1.1.4 to + 1.3.0 (development dependency). +* Updated nikic/php-parser from 2.1.0 to 3.1.3 + (development dependency). +* Updated wikimedia/ip-set from 1.1.0 to 1.2.0. +* Updated wikimedia/relpath from 2.0.0 to 2.1.1. +* Updated wikimedia/running-stat from 1.1.0 to 1.2.0. +* Updated wikimedia/wrappedstring from 2.2.0 to 2.3.0. * … ==== New external libraries ==== @@ -56,7 +76,9 @@ production. * (T90902) Non-breaking space in header ID breaks anchor === Action API changes in 1.31 === -* … +* (T185058) The 'name' value to tgprop for action=query&list=tags has been + removed. It has never made a difference in the output, the name was always + returned regardless. === Action API internal changes in 1.31 === * … @@ -67,8 +89,13 @@ regularly. Below only new and removed languages are listed, as well as changes to languages because of Phabricator reports. * (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK namespaces. +* (T182305) New language support: Nyungar (nys). === Other changes in 1.31 === +* Introducing multi-content-revision capability into the storage layer. For details, + see . +* The Revision class was deprecated in favor of RevisionStore, BlobStore, and + RevisionRecord and its subclasses. * MessageBlobStore::insertMessageBlob() (deprecated in 1.27) was removed. * The global function wfBCP47 was renamed to LanguageCode::bcp47. * The global function wfBCP47 is now deprecated. @@ -121,6 +148,9 @@ changes to languages because of Phabricator reports. * The Block class will no longer accept usable-but-missing usernames for 'byText' or ->setBlocker(). Callers should either ensure the blocker exists locally or use a new interwiki-format username like "iw>Example". +* The RevisionInsertComplete hook is now deprecated, use RevisionRecordInserted instead. + RevisionInsertComplete is still called, but the second and third parameter will always be null. + Hard deprecation is scheduled for 1.32. * The following methods that get and set ParserOutput state are deprecated. Callers should use the new stateless $options parameter to ParserOutput::getText() instead. @@ -133,10 +163,43 @@ changes to languages because of Phabricator reports. * OutputPage::enableSectionEditLinks() * OutputPage::sectionEditLinksEnabled() * The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens are also deprecated. +* The following methods and constants from the WatchedItem class were deprecated in + 1.27 have been removed. + * WatchedItem::getTitle() + * WatchedItem::fromUserTitle() + * WatchedItem::addWatch() + * WatchedItem::removeWatch() + * WatchedItem::isWatched() + * WatchedItem::duplicateEntries() + * WatchedItem::IGNORE_USER_RIGHTS + * WatchedItem::CHECK_USER_RIGHTS + * WatchedItem::DEPRECATED_USAGE_TIMESTAMP +* The $statementsOnOwnLine parameter of JavaScriptMinifier::minify was removed. + The corresponding configuration variable ($wgResourceLoaderMinifierStatementsOnOwnLine) + has been deprecated since 1.27 and was removed as well. +* The $maxLineLength parameter of JavaScriptMinifier::minify was removed. + The corresponding configuration variable ($wgResourceLoaderMinifierMaxLineLength) + has been deprecated since 1.27 and was removed as well. +* The HtmlFormatter class was removed (deprecated in 1.27). The namespaced + HtmlFormatter\HtmlFormatter class should be used instead. +* License::getLicenses has been deprecated; use License::getLines instead. +* The driver 'mysql' for MySQL, deprecated in MediaWiki 1.30, has been removed. + The driver has been deprecated since PHP 5.5 and was removed in PHP 7.0. The + default driver for MySQL has been 'mysqli' since MediaWiki 1.22. +* The following properties of PreparedEdit were deprecated in 1.21 and have been removed: + * PreparedEdit->newText + * PreparedEdit->oldText + * PreparedEdit->pst +* QuickTemplate::setRef() was deprecated in favour of QuickTemplate::set(). + Setting template variables by reference allowed violating the principle of data being + immutable once added to the skin template. In practice, this method was not being + used for that. Rather, setRef() existed as memory optimisation for PHP 4. +* Passing false to ParserOptions::setWrapOutputClass() is deprecated. Use the + 'unwrap' transform to ParserOutput::getText() instead. == Compatibility == -MediaWiki 1.31 requires PHP 5.5.9 or later. There is experimental support for -HHVM 3.6.5 or later. +MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported, +it is generally advised to use PHP 5.5.9 or later for long term support. MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used, but support for them is somewhat less mature. There is experimental support for diff --git a/autoload.php b/autoload.php index 2661fd7ed3..168998e152 100644 --- a/autoload.php +++ b/autoload.php @@ -1,11 +1,12 @@ __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php', 'APCUBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCUBagOStuff.php', + 'AbkhazUppercaseCollation' => __DIR__ . '/includes/collation/AbkhazUppercaseCollation.php', 'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php', 'Action' => __DIR__ . '/includes/actions/Action.php', 'ActiveUsersPager' => __DIR__ . '/includes/specials/pagers/ActiveUsersPager.php', @@ -175,7 +176,7 @@ $wgAutoloadLocalClasses = [ 'BadRequestError' => __DIR__ . '/includes/exception/BadRequestError.php', 'BadTitleError' => __DIR__ . '/includes/exception/BadTitleError.php', 'BagOStuff' => __DIR__ . '/includes/libs/objectcache/BagOStuff.php', - 'BaseDump' => __DIR__ . '/maintenance/backupPrefetch.inc', + 'BaseDump' => __DIR__ . '/includes/export/BaseDump.php', 'BaseTemplate' => __DIR__ . '/includes/skins/BaseTemplate.php', 'BashkirUppercaseCollation' => __DIR__ . '/includes/collation/BashkirUppercaseCollation.php', 'BatchRowIterator' => __DIR__ . '/includes/utils/BatchRowIterator.php', @@ -196,6 +197,7 @@ $wgAutoloadLocalClasses = [ 'BenchmarkLruHash' => __DIR__ . '/maintenance/benchmarks/benchmarkLruHash.php', 'BenchmarkParse' => __DIR__ . '/maintenance/benchmarks/benchmarkParse.php', 'BenchmarkPurge' => __DIR__ . '/maintenance/benchmarks/benchmarkPurge.php', + 'BenchmarkSanitizer' => __DIR__ . '/maintenance/benchmarks/benchmarkSanitizer.php', 'BenchmarkTidy' => __DIR__ . '/maintenance/benchmarks/benchmarkTidy.php', 'Benchmarker' => __DIR__ . '/maintenance/benchmarks/Benchmarker.php', 'BitmapHandler' => __DIR__ . '/includes/media/Bitmap.php', @@ -345,7 +347,6 @@ $wgAutoloadLocalClasses = [ 'DatabaseLag' => __DIR__ . '/maintenance/lag.php', 'DatabaseLogEntry' => __DIR__ . '/includes/logging/LogEntry.php', 'DatabaseMssql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMssql.php', - 'DatabaseMysql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysql.php', 'DatabaseMysqlBase' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqlBase.php', 'DatabaseMysqli' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqli.php', 'DatabaseOracle' => __DIR__ . '/includes/db/DatabaseOracle.php', @@ -449,7 +450,7 @@ $wgAutoloadLocalClasses = [ 'Exif' => __DIR__ . '/includes/media/Exif.php', 'ExifBitmapHandler' => __DIR__ . '/includes/media/ExifBitmap.php', 'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php', - 'ExportProgressFilter' => __DIR__ . '/maintenance/backup.inc', + 'ExportProgressFilter' => __DIR__ . '/includes/export/ExportProgressFilter.php', 'ExportSites' => __DIR__ . '/maintenance/exportSites.php', 'ExtensionJsonValidationError' => __DIR__ . '/includes/registration/ExtensionJsonValidationError.php', 'ExtensionJsonValidator' => __DIR__ . '/includes/registration/ExtensionJsonValidator.php', @@ -462,6 +463,7 @@ $wgAutoloadLocalClasses = [ 'ExternalStoreHttp' => __DIR__ . '/includes/externalstore/ExternalStoreHttp.php', 'ExternalStoreMedium' => __DIR__ . '/includes/externalstore/ExternalStoreMedium.php', 'ExternalStoreMwstore' => __DIR__ . '/includes/externalstore/ExternalStoreMwstore.php', + 'ExternalUserNames' => __DIR__ . '/includes/user/ExternalUserNames.php', 'FSFile' => __DIR__ . '/includes/libs/filebackend/fsfile/FSFile.php', 'FSFileBackend' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php', 'FSFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php', @@ -606,7 +608,6 @@ $wgAutoloadLocalClasses = [ 'Hooks' => __DIR__ . '/includes/Hooks.php', 'Html' => __DIR__ . '/includes/Html.php', 'HtmlArmor' => __DIR__ . '/includes/libs/HtmlArmor.php', - 'HtmlFormatter' => __DIR__ . '/includes/HtmlFormatter.php', 'Http' => __DIR__ . '/includes/http/Http.php', 'HttpError' => __DIR__ . '/includes/exception/HttpError.php', 'HttpStatus' => __DIR__ . '/includes/libs/HttpStatus.php', @@ -705,7 +706,6 @@ $wgAutoloadLocalClasses = [ 'LanguageAr' => __DIR__ . '/languages/classes/LanguageAr.php', 'LanguageAz' => __DIR__ . '/languages/classes/LanguageAz.php', 'LanguageBe_tarask' => __DIR__ . '/languages/classes/LanguageBe_tarask.php', - 'LanguageBg' => __DIR__ . '/languages/classes/LanguageBg.php', 'LanguageBs' => __DIR__ . '/languages/classes/LanguageBs.php', 'LanguageCode' => __DIR__ . '/languages/LanguageCode.php', 'LanguageConverter' => __DIR__ . '/languages/LanguageConverter.php', @@ -713,8 +713,6 @@ $wgAutoloadLocalClasses = [ 'LanguageCu' => __DIR__ . '/languages/classes/LanguageCu.php', 'LanguageDsb' => __DIR__ . '/languages/classes/LanguageDsb.php', 'LanguageEn' => __DIR__ . '/languages/classes/LanguageEn.php', - 'LanguageEs' => __DIR__ . '/languages/classes/LanguageEs.php', - 'LanguageEt' => __DIR__ . '/languages/classes/LanguageEt.php', 'LanguageFi' => __DIR__ . '/languages/classes/LanguageFi.php', 'LanguageGa' => __DIR__ . '/languages/classes/LanguageGa.php', 'LanguageGan' => __DIR__ . '/languages/classes/LanguageGan.php', @@ -729,21 +727,17 @@ $wgAutoloadLocalClasses = [ 'LanguageKm' => __DIR__ . '/languages/classes/LanguageKm.php', 'LanguageKsh' => __DIR__ . '/languages/classes/LanguageKsh.php', 'LanguageKu' => __DIR__ . '/languages/classes/LanguageKu.php', - 'LanguageKu_ku' => __DIR__ . '/languages/classes/LanguageKu_ku.php', 'LanguageLa' => __DIR__ . '/languages/classes/LanguageLa.php', 'LanguageMl' => __DIR__ . '/languages/classes/LanguageMl.php', 'LanguageMy' => __DIR__ . '/languages/classes/LanguageMy.php', 'LanguageOs' => __DIR__ . '/languages/classes/LanguageOs.php', - 'LanguagePl' => __DIR__ . '/languages/classes/LanguagePl.php', 'LanguageQqx' => __DIR__ . '/languages/classes/LanguageQqx.php', - 'LanguageRu' => __DIR__ . '/languages/classes/LanguageRu.php', 'LanguageShi' => __DIR__ . '/languages/classes/LanguageShi.php', 'LanguageSl' => __DIR__ . '/languages/classes/LanguageSl.php', 'LanguageSr' => __DIR__ . '/languages/classes/LanguageSr.php', 'LanguageTg' => __DIR__ . '/languages/classes/LanguageTg.php', 'LanguageTr' => __DIR__ . '/languages/classes/LanguageTr.php', 'LanguageTyv' => __DIR__ . '/languages/classes/LanguageTyv.php', - 'LanguageUk' => __DIR__ . '/languages/classes/LanguageUk.php', 'LanguageUz' => __DIR__ . '/languages/classes/LanguageUz.php', 'LanguageWa' => __DIR__ . '/languages/classes/LanguageWa.php', 'LanguageYue' => __DIR__ . '/languages/classes/LanguageYue.php', @@ -886,15 +880,13 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\EditPage\\TextboxBuilder' => __DIR__ . '/includes/editpage/TextboxBuilder.php', 'MediaWiki\\Edit\\PreparedEdit' => __DIR__ . '/includes/edit/PreparedEdit.php', 'MediaWiki\\HeaderCallback' => __DIR__ . '/includes/HeaderCallback.php', + 'MediaWiki\\Http\\HttpRequestFactory' => __DIR__ . '/includes/http/HttpRequestFactory.php', 'MediaWiki\\Interwiki\\ClassicInterwikiLookup' => __DIR__ . '/includes/interwiki/ClassicInterwikiLookup.php', 'MediaWiki\\Interwiki\\InterwikiLookup' => __DIR__ . '/includes/interwiki/InterwikiLookup.php', 'MediaWiki\\Interwiki\\InterwikiLookupAdapter' => __DIR__ . '/includes/interwiki/InterwikiLookupAdapter.php', 'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/languages/data/CrhExceptions.php', 'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php', 'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php', - 'MediaWiki\\Linker\\LinkRenderer' => __DIR__ . '/includes/linker/LinkRenderer.php', - 'MediaWiki\\Linker\\LinkRendererFactory' => __DIR__ . '/includes/linker/LinkRendererFactory.php', - 'MediaWiki\\Linker\\LinkTarget' => __DIR__ . '/includes/linker/LinkTarget.php', 'MediaWiki\\Logger\\ConsoleLogger' => __DIR__ . '/includes/debug/logger/ConsoleLogger.php', 'MediaWiki\\Logger\\ConsoleSpi' => __DIR__ . '/includes/debug/logger/ConsoleSpi.php', 'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php', @@ -913,6 +905,8 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php', 'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php', 'MediaWiki\\MediaWikiServices' => __DIR__ . '/includes/MediaWikiServices.php', + 'MediaWiki\\Preferences\\DefaultPreferencesFactory' => __DIR__ . '/includes/preferences/DefaultPreferencesFactory.php', + 'MediaWiki\\Preferences\\PreferencesFactory' => __DIR__ . '/includes/preferences/PreferencesFactory.php', 'MediaWiki\\ProcOpenError' => __DIR__ . '/includes/exception/ProcOpenError.php', 'MediaWiki\\Search\\ParserOutputSearchDataExtractor' => __DIR__ . '/includes/search/ParserOutputSearchDataExtractor.php', 'MediaWiki\\Services\\CannotReplaceActiveServiceException' => __DIR__ . '/includes/services/CannotReplaceActiveServiceException.php', @@ -945,6 +939,23 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Shell\\Result' => __DIR__ . '/includes/shell/Result.php', 'MediaWiki\\Shell\\Shell' => __DIR__ . '/includes/shell/Shell.php', 'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php', + 'MediaWiki\\Storage\\BlobAccessException' => __DIR__ . '/includes/Storage/BlobAccessException.php', + 'MediaWiki\\Storage\\BlobStore' => __DIR__ . '/includes/Storage/BlobStore.php', + 'MediaWiki\\Storage\\BlobStoreFactory' => __DIR__ . '/includes/Storage/BlobStoreFactory.php', + 'MediaWiki\\Storage\\IncompleteRevisionException' => __DIR__ . '/includes/Storage/IncompleteRevisionException.php', + 'MediaWiki\\Storage\\MutableRevisionRecord' => __DIR__ . '/includes/Storage/MutableRevisionRecord.php', + 'MediaWiki\\Storage\\MutableRevisionSlots' => __DIR__ . '/includes/Storage/MutableRevisionSlots.php', + 'MediaWiki\\Storage\\RevisionAccessException' => __DIR__ . '/includes/Storage/RevisionAccessException.php', + 'MediaWiki\\Storage\\RevisionArchiveRecord' => __DIR__ . '/includes/Storage/RevisionArchiveRecord.php', + 'MediaWiki\\Storage\\RevisionFactory' => __DIR__ . '/includes/Storage/RevisionFactory.php', + 'MediaWiki\\Storage\\RevisionLookup' => __DIR__ . '/includes/Storage/RevisionLookup.php', + 'MediaWiki\\Storage\\RevisionRecord' => __DIR__ . '/includes/Storage/RevisionRecord.php', + 'MediaWiki\\Storage\\RevisionSlots' => __DIR__ . '/includes/Storage/RevisionSlots.php', + 'MediaWiki\\Storage\\RevisionStore' => __DIR__ . '/includes/Storage/RevisionStore.php', + 'MediaWiki\\Storage\\RevisionStoreRecord' => __DIR__ . '/includes/Storage/RevisionStoreRecord.php', + 'MediaWiki\\Storage\\SlotRecord' => __DIR__ . '/includes/Storage/SlotRecord.php', + 'MediaWiki\\Storage\\SqlBlobStore' => __DIR__ . '/includes/Storage/SqlBlobStore.php', + 'MediaWiki\\Storage\\SuppressedDataException' => __DIR__ . '/includes/Storage/SuppressedDataException.php', 'MediaWiki\\Tidy\\BalanceActiveFormattingElements' => __DIR__ . '/includes/tidy/Balancer.php', 'MediaWiki\\Tidy\\BalanceElement' => __DIR__ . '/includes/tidy/Balancer.php', 'MediaWiki\\Tidy\\BalanceMarker' => __DIR__ . '/includes/tidy/Balancer.php', @@ -964,6 +975,7 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Tidy\\RemexMungerData' => __DIR__ . '/includes/tidy/RemexMungerData.php', 'MediaWiki\\Tidy\\TidyDriverBase' => __DIR__ . '/includes/tidy/TidyDriverBase.php', 'MediaWiki\\User\\UserIdentity' => __DIR__ . '/includes/user/UserIdentity.php', + 'MediaWiki\\User\\UserIdentityValue' => __DIR__ . '/includes/user/UserIdentityValue.php', 'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . '/includes/widget/ComplexNamespaceInputWidget.php', 'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . '/includes/widget/ComplexTitleInputWidget.php', 'MediaWiki\\Widget\\DateInputWidget' => __DIR__ . '/includes/widget/DateInputWidget.php', @@ -1002,6 +1014,7 @@ $wgAutoloadLocalClasses = [ 'MessageContent' => __DIR__ . '/includes/content/MessageContent.php', 'MessageLocalizer' => __DIR__ . '/languages/MessageLocalizer.php', 'MessageSpecifier' => __DIR__ . '/includes/libs/MessageSpecifier.php', + 'MigrateArchiveText' => __DIR__ . '/maintenance/migrateArchiveText.php', 'MigrateComments' => __DIR__ . '/maintenance/migrateComments.php', 'MigrateFileRepoLayout' => __DIR__ . '/maintenance/migrateFileRepoLayout.php', 'MigrateUserGroup' => __DIR__ . '/maintenance/migrateUserGroup.php', @@ -1039,7 +1052,9 @@ $wgAutoloadLocalClasses = [ 'NewFilesPager' => __DIR__ . '/includes/specials/pagers/NewFilesPager.php', 'NewPagesPager' => __DIR__ . '/includes/specials/pagers/NewPagesPager.php', 'NewUsersLogFormatter' => __DIR__ . '/includes/logging/NewUsersLogFormatter.php', + 'NoWriteWatchedItemStore' => __DIR__ . '/includes/watcheditem/NoWriteWatchedItemStore.php', 'NolinesImageGallery' => __DIR__ . '/includes/gallery/NolinesImageGallery.php', + 'NorthernSamiUppercaseCollation' => __DIR__ . '/includes/collation/NorthernSamiUppercaseCollation.php', 'NotRecursiveIterator' => __DIR__ . '/includes/libs/iterators/NotRecursiveIterator.php', 'NukeNS' => __DIR__ . '/maintenance/nukeNS.php', 'NukePage' => __DIR__ . '/maintenance/nukePage.php', @@ -1661,7 +1676,6 @@ $wgAutoloadLocalClasses = [ 'Wikimedia\\Rdbms\\Database' => __DIR__ . '/includes/libs/rdbms/database/Database.php', 'Wikimedia\\Rdbms\\DatabaseDomain' => __DIR__ . '/includes/libs/rdbms/database/DatabaseDomain.php', 'Wikimedia\\Rdbms\\DatabaseMssql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMssql.php', - 'Wikimedia\\Rdbms\\DatabaseMysql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysql.php', 'Wikimedia\\Rdbms\\DatabaseMysqlBase' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqlBase.php', 'Wikimedia\\Rdbms\\DatabaseMysqli' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqli.php', 'Wikimedia\\Rdbms\\DatabasePostgres' => __DIR__ . '/includes/libs/rdbms/database/DatabasePostgres.php', diff --git a/composer.json b/composer.json index 35783f2313..1730942f49 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "ext-xml": "*", "liuggio/statsd-php-client": "1.0.18", "mediawiki/at-ease": "1.1.0", - "oojs/oojs-ui": "0.24.3", + "oojs/oojs-ui": "0.25.1", "oyejorge/less.php": "1.7.0.14", "php": ">=5.5.9", "psr/log": "1.0.2", @@ -35,28 +35,28 @@ "wikimedia/cldr-plural-rule-parser": "1.0.0", "wikimedia/composer-merge-plugin": "1.4.1", "wikimedia/html-formatter": "1.0.1", - "wikimedia/ip-set": "1.1.0", + "wikimedia/ip-set": "1.2.0", "wikimedia/php-session-serializer": "1.0.4", "wikimedia/purtle": "1.0.6", - "wikimedia/relpath": "2.0.0", - "wikimedia/remex-html": "1.0.1", - "wikimedia/running-stat": "1.1.0", + "wikimedia/relpath": "2.1.1", + "wikimedia/remex-html": "1.0.2", + "wikimedia/running-stat": "1.2.1", "wikimedia/scoped-callback": "1.0.0", "wikimedia/utfnormal": "1.1.0", "wikimedia/timestamp": "1.0.0", "wikimedia/wait-condition-loop": "1.0.1", - "wikimedia/wrappedstring": "2.2.0", + "wikimedia/wrappedstring": "2.3.0", "zordius/lightncandy": "0.23" }, "require-dev": { - "composer/spdx-licenses": "1.1.4", + "composer/spdx-licenses": "1.3.0", "hamcrest/hamcrest-php": "^2.0", "jakub-onderka/php-parallel-lint": "0.9.2", "jetbrains/phpstorm-stubs": "dev-master#1b9906084d6635456fcf3f3a01f0d7d5b99a578a", "justinrainbow/json-schema": "~5.2", - "mediawiki/mediawiki-codesniffer": "14.1.0", + "mediawiki/mediawiki-codesniffer": "15.0.0", "monolog/monolog": "~1.22.1", - "nikic/php-parser": "2.1.0", + "nikic/php-parser": "3.1.3", "nmred/kafka-php": "0.1.5", "phpunit/phpunit": "4.8.36", "psy/psysh": "0.8.11", diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index 7cfebcafa4..0763e7de63 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -210,8 +210,8 @@ "description": "Group which this module should be loaded together with" }, "deprecated": { - "type": ["object", "boolean"], - "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message." + "type": ["object", "string", "boolean"], + "description": "Whether the module is deprecated and usage is discouraged. Either a boolean, or a string or an object with key message can be used to customise deprecation message." }, "position": { "type": "string", @@ -567,6 +567,10 @@ "type": "object", "description": "SpecialPages implemented in this extension (mapping of page name to class name)" }, + "AutoloadNamespaces": { + "type": "object", + "description": "Mapping of PSR-4 compliant namespace to directory for autoloading" + }, "AutoloadClasses": { "type": "object" }, diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index 75a4f2c6fc..e13129bb56 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -211,8 +211,8 @@ "description": "Group with which this module should be loaded" }, "deprecated": { - "type": ["object", "boolean"], - "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message." + "type": ["object", "string", "boolean"], + "description": "Whether the module is deprecated and usage is discouraged. Either a boolean, or a string or an object with key message can be used to customise deprecation message." }, "position": { "type": "string", @@ -588,6 +588,10 @@ "type": "object", "description": "SpecialPages implemented in this extension (mapping of page name to class name)" }, + "AutoloadNamespaces": { + "type": "object", + "description": "Mapping of PSR-4 compliant namespace to directory for autoloading" + }, "AutoloadClasses": { "type": "object" }, @@ -665,7 +669,7 @@ }, "SkinOOUIThemes": { "type": "object", - "description": "Map of skin names to OOjs UI themes to use. Same format as ResourceLoaderOOUIModule::$builtinSkinThemeMap." + "description": "Map of skin names to OOUI themes to use. Same format as ResourceLoaderOOUIModule::$builtinSkinThemeMap." }, "PasswordPolicy": { "type": "object", diff --git a/docs/hooks.txt b/docs/hooks.txt index 29883b25a6..7084b51d56 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -951,7 +951,7 @@ $id: the page ID (original ID in case of page deletions) in a Category page. Gives extensions the opportunity to batch load any related data about the pages. $type: The category type. Either 'page', 'file' or 'subcat' -$res: Query result from DatabaseBase::select() +$res: Query result from Wikimedia\Rdbms\IDatabase::select() 'CategoryViewer::generateLink': Before generating an output link allow extensions opportunity to generate a more specific or relevant link. @@ -1666,6 +1666,13 @@ $query: query options passed to Title::getInternalURL() 'GetIP': modify the ip of the current user (called only once). &$ip: string holding the ip as determined so far +'GetLangPreferredVariant': Called in LanguageConverter#getPreferredVariant() to + allow fetching the language variant code from cookies or other such + alternative storage. +&$req: language variant from the URL (string) or boolean false if no variant + was specified in the URL; the value of this variable comes from + LanguageConverter#getURLVariant() + 'GetLinkColours': modify the CSS class of an array of page links. $linkcolour_ids: array of prefixed DB keys of the pages linked to, indexed by page_id. @@ -1840,7 +1847,7 @@ $revisionInfo: Array of revision information Return false to stop further processing of the tag $reader: XMLReader object -'ImportHandleUnknownUser': When a user does exist locally, this hook is called +'ImportHandleUnknownUser': When a user doesn't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name: User name @@ -2810,14 +2817,14 @@ called after the addition of 'qunit' and MediaWiki testing resources. added to any module. &$ResourceLoader: object -'RevisionInsertComplete': Called after a revision is inserted into the database. -&$revision: the Revision -$data: the data stored in old_text. The meaning depends on $flags: if external - is set, it's the URL of the revision text in external storage; otherwise, - it's the revision text itself. In either case, if gzip is set, the revision - text is gzipped. -$flags: a comma-delimited list of strings representing the options used. May - include: utf8 (this will always be set for new revisions); gzip; external. +'RevisionRecordInserted': Called after a revision is inserted into the database. +$revisionRecord: the RevisionRecord that has just been inserted. + +'RevisionInsertComplete': DEPRECATED! Use RevisionRecordInserted hook instead. +Called after a revision is inserted into the database. +$revision: the Revision +$data: DEPRECATED! Always null! +$flags: DEPRECATED! Always null! 'SearchableNamespaces': An option to modify which namespaces are searchable. &$arr: Array of namespaces ($nsId => $name) which will be used. @@ -3521,6 +3528,12 @@ blank form with no error message; use UploadVerification and UploadVerifyFile instead. &$form: UploadForm object +'UploadForm:getInitialPageText': After the initial page text for file uploads +is generated, to allow it to be altered. +&$pageText: the page text +$msg: array of header messages +$config: Config object + 'UploadForm:initial': Before the upload form is generated. You might set the member-variables $uploadFormTextTop and $uploadFormTextAfterSummary to inject text (HTML) either before or after the editform. @@ -3803,12 +3816,16 @@ After a user's group memberships are changed. $add: Array of strings corresponding to groups added $remove: Array of strings corresponding to groups removed -'UserSaveOptions': Called just before saving user preferences/options. -$user: User object -&$options: Options, modifiable +'UserSaveOptions': Called just before saving user preferences. Hook handlers can either add or +manipulate options, or reset one back to it's default to block changing it. Hook handlers are also +allowed to abort the process by returning false, e.g. to save to a global profile instead. Compare +to the UserSaveSettings hook, which is called after the preferences have been saved. +$user: The User for which the options are going to be saved +&$options: The users options as an associative array, modifiable -'UserSaveSettings': Called when saving user settings. -$user: User object +'UserSaveSettings': Called directly after user preferences (user_properties in the database) have +been saved. Compare to the UserSaveOptions hook, which is called before. +$user: The User for which the options have been saved 'UserSetCookies': DEPRECATED! If you're trying to replace core session cookie handling, you want to create a subclass of MediaWiki\Session\CookieSessionProvider @@ -3917,14 +3934,15 @@ dumps. One, and only one hook should set this, and return false. &$opts: Options to use for the query &$join: Join conditions -'WikiPageDeletionUpdates': manipulate the list of DataUpdates to be applied when +'WikiPageDeletionUpdates': manipulate the list of DeferrableUpdates to be applied when a page is deleted. Called in WikiPage::getDeletionUpdates(). Note that updates specific to a content model should be provided by the respective Content's getDeletionUpdates() method. $page: the WikiPage -$content: the Content to generate updates for (or null, if the Content could not be loaded -due to an error) -&$updates: the array of DataUpdate objects. Hook function may want to add to it. +$content: the Content to generate updates for, or null in case the page revision could not be + loaded. The delete will succeed despite this. +&$updates: the array of objects that implement DeferrableUpdate. Hook function may want to add to + it. 'WikiPageFactory': Override WikiPage class used for a title $title: Title of the page diff --git a/docs/ontology.owl b/docs/ontology.owl index 6b2e0b7f44..19476a35f2 100644 --- a/docs/ontology.owl +++ b/docs/ontology.owl @@ -38,6 +38,11 @@ MediaWiki category. + + HiddenCategory + MediaWiki hidden category. + + ' . htmlspecialchars( $text ); - - if ( !empty( $this->debug ) ) { - $html .= ""; - } } return $html; @@ -1682,7 +1677,7 @@ abstract class Installer { // implementation that won't stomp on PHP's cookies. $GLOBALS['wgSessionProviders'] = [ [ - 'class' => 'InstallerSessionProvider', + 'class' => InstallerSessionProvider::class, 'args' => [ [ 'priority' => 1, ] ] diff --git a/includes/installer/InstallerOverrides.php b/includes/installer/InstallerOverrides.php index eba3a20d6c..c9154b9a86 100644 --- a/includes/installer/InstallerOverrides.php +++ b/includes/installer/InstallerOverrides.php @@ -30,9 +30,9 @@ class InstallerOverrides { if ( !$overrides ) { $overrides = [ - 'LocalSettingsGenerator' => 'LocalSettingsGenerator', - 'WebInstaller' => 'WebInstaller', - 'CliInstaller' => 'CliInstaller', + 'LocalSettingsGenerator' => LocalSettingsGenerator::class, + 'WebInstaller' => WebInstaller::class, + 'CliInstaller' => CliInstaller::class, ]; foreach ( glob( "$IP/mw-config/overrides/*.php" ) as $file ) { require $file; diff --git a/includes/installer/LocalSettingsGenerator.php b/includes/installer/LocalSettingsGenerator.php index bdaeaca86c..b4ef49d7c6 100644 --- a/includes/installer/LocalSettingsGenerator.php +++ b/includes/installer/LocalSettingsGenerator.php @@ -185,7 +185,7 @@ class LocalSettingsGenerator { $jsonFile = 'skin.json'; $function = 'wfLoadSkin'; } else { - throw new InvalidArgumentException( '$dir was not "extensions" or "skins' ); + throw new InvalidArgumentException( '$dir was not "extensions" or "skins"' ); } $encName = self::escapePhpString( $name ); diff --git a/includes/installer/MssqlUpdater.php b/includes/installer/MssqlUpdater.php index 411d2c8cb2..1fd1d9b444 100644 --- a/includes/installer/MssqlUpdater.php +++ b/includes/installer/MssqlUpdater.php @@ -105,6 +105,17 @@ class MssqlUpdater extends DatabaseUpdater { // 1.30 [ 'modifyField', 'image', 'img_media_type', 'patch-add-3d.sql' ], [ 'addIndex', 'site_stats', 'PRIMARY', 'patch-site_stats-pk.sql' ], + + // Should have been in 1.30 + [ 'addTable', 'comment', 'patch-comment-table.sql' ], + [ 'migrateComments' ], + + // 1.31 + [ 'addTable', 'slots', 'patch-slots.sql' ], + [ 'addTable', 'content', 'patch-content.sql' ], + [ 'addTable', 'slot_roles', 'patch-slot_roles.sql' ], + [ 'addTable', 'content_models', 'patch-content_models.sql' ], + [ 'migrateArchiveText' ], ]; } diff --git a/includes/installer/MysqlInstaller.php b/includes/installer/MysqlInstaller.php index ab5701a8bf..6256204d97 100644 --- a/includes/installer/MysqlInstaller.php +++ b/includes/installer/MysqlInstaller.php @@ -73,7 +73,7 @@ class MysqlInstaller extends DatabaseInstaller { * @return bool */ public function isCompiled() { - return self::checkExtension( 'mysql' ) || self::checkExtension( 'mysqli' ); + return self::checkExtension( 'mysqli' ); } /** diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php index 466ad0f074..bce540557d 100644 --- a/includes/installer/MysqlUpdater.php +++ b/includes/installer/MysqlUpdater.php @@ -329,6 +329,13 @@ class MysqlUpdater extends DatabaseUpdater { [ 'renameIndex', 'l10n_cache', 'lc_lang_key', 'PRIMARY', false, 'patch-l10n_cache-primary-key.sql' ], [ 'doUnsignedSyncronisation' ], + + // 1.31 + [ 'addTable', 'slots', 'patch-slots.sql' ], + [ 'addTable', 'content', 'patch-content.sql' ], + [ 'addTable', 'slot_roles', 'patch-slot_roles.sql' ], + [ 'addTable', 'content_models', 'patch-content_models.sql' ], + [ 'migrateArchiveText' ], ]; } @@ -425,7 +432,7 @@ class MysqlUpdater extends DatabaseUpdater { } protected function doOldLinksUpdate() { - $cl = $this->maintenance->runChild( 'ConvertLinks' ); + $cl = $this->maintenance->runChild( ConvertLinks::class ); $cl->execute(); } @@ -865,7 +872,8 @@ class MysqlUpdater extends DatabaseUpdater { $this->applyPatch( 'patch-templatelinks.sql', false, "Creating templatelinks table" ); $this->output( "Populating...\n" ); - if ( wfGetLB()->getServerCount() > 1 ) { + $services = MediaWikiServices::getInstance(); + if ( $services->getDBLoadBalancer()->getServerCount() > 1 ) { // Slow, replication-friendly update $res = $this->db->select( 'pagelinks', [ 'pl_from', 'pl_namespace', 'pl_title' ], [ 'pl_namespace' => NS_TEMPLATE ], __METHOD__ ); @@ -873,7 +881,7 @@ class MysqlUpdater extends DatabaseUpdater { foreach ( $res as $row ) { $count = ( $count + 1 ) % 100; if ( $count == 0 ) { - $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); + $lbFactory = $services->getDBLoadBalancerFactory(); $lbFactory->waitForReplication( [ 'wiki' => wfWikiID() ] ); } $this->db->insert( 'templatelinks', @@ -934,7 +942,7 @@ class MysqlUpdater extends DatabaseUpdater { $this->output( "done.\n" ); $this->output( "Migrating old restrictions to new table...\n" ); - $task = $this->maintenance->runChild( 'UpdateRestrictions' ); + $task = $this->maintenance->runChild( UpdateRestrictions::class ); $task->execute(); } @@ -957,7 +965,7 @@ class MysqlUpdater extends DatabaseUpdater { "may want to hit Ctrl-C and do this manually with maintenance/\n" . "populateCategory.php.\n" ); - $task = $this->maintenance->runChild( 'PopulateCategory' ); + $task = $this->maintenance->runChild( PopulateCategory::class ); $task->execute(); $this->output( "Done populating category table.\n" ); } @@ -969,7 +977,7 @@ class MysqlUpdater extends DatabaseUpdater { "databases, you may want to hit Ctrl-C and do this manually with\n" . "maintenance/populateParentId.php.\n" ); - $task = $this->maintenance->runChild( 'PopulateParentId' ); + $task = $this->maintenance->runChild( PopulateParentId::class ); $task->execute(); } } diff --git a/includes/installer/OracleInstaller.php b/includes/installer/OracleInstaller.php index 05f078fab7..e5418e43cc 100644 --- a/includes/installer/OracleInstaller.php +++ b/includes/installer/OracleInstaller.php @@ -335,11 +335,11 @@ class OracleInstaller extends DatabaseInstaller { * @return bool Whether the connection string is valid. */ public static function checkConnectStringFormat( $connect_string ) { - // @@codingStandardsIgnoreStart Long lines with regular expressions. + // phpcs:disable Generic.Files.LineLength // @todo Very long regular expression. Make more readable? $isValid = preg_match( '/^[[:alpha:]][\w\-]*(?:\.[[:alpha:]][\w\-]*){0,2}$/', $connect_string ); // TNS name $isValid |= preg_match( '/^(?:\/\/)?[\w\-\.]+(?::[\d]+)?(?:\/(?:[\w\-\.]+(?::(pooled|dedicated|shared))?)?(?:\/[\w\-\.]+)?)?$/', $connect_string ); // EZConnect - // @@codingStandardsIgnoreEnd + // phpcs:enable return (bool)$isValid; } } diff --git a/includes/installer/OracleUpdater.php b/includes/installer/OracleUpdater.php index 040b54a124..3ee51eab9e 100644 --- a/includes/installer/OracleUpdater.php +++ b/includes/installer/OracleUpdater.php @@ -127,6 +127,17 @@ class OracleUpdater extends DatabaseUpdater { [ 'doAutoIncrementTriggers' ], [ 'addIndex', 'site_stats', 'PRIMARY', 'patch-site_stats-pk.sql' ], + // Should have been in 1.30 + [ 'addTable', 'comment', 'patch-comment-table.sql' ], + [ 'migrateComments' ], + + // 1.31 + [ 'addTable', 'slots', 'patch-slots.sql' ], + [ 'addTable', 'content', 'patch-content.sql' ], + [ 'addTable', 'slot_roles', 'patch-slot_roles.sql' ], + [ 'addTable', 'content_models', 'patch-content_models.sql' ], + [ 'migrateArchiveText' ], + // KEEP THIS AT THE BOTTOM!! [ 'doRebuildDuplicateFunction' ], diff --git a/includes/installer/PhpBugTests.php b/includes/installer/PhpBugTests.php index d412216aaa..4e1e365dbf 100644 --- a/includes/installer/PhpBugTests.php +++ b/includes/installer/PhpBugTests.php @@ -18,9 +18,11 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @defgroup PHPBugTests PHP known bugs tests */ +/** + * @defgroup PHPBugTests PHP known bugs tests + */ /** * Test for PHP+libxml2 bug which breaks XML input subtly with certain versions. * Known fixed with PHP 5.2.9 + libxml2-2.7.3 diff --git a/includes/installer/PostgresInstaller.php b/includes/installer/PostgresInstaller.php index cb1b47e1e3..21d83d2397 100644 --- a/includes/installer/PostgresInstaller.php +++ b/includes/installer/PostgresInstaller.php @@ -152,7 +152,7 @@ class PostgresInstaller extends DatabaseInstaller { /** * Open a PG connection with given parameters * @param string $user User name - * @param string $password Password + * @param string $password * @param string $dbName Database name * @param string $schema Database schema * @return Status diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php index c38eb6aabc..8d1240495f 100644 --- a/includes/installer/PostgresUpdater.php +++ b/includes/installer/PostgresUpdater.php @@ -481,8 +481,16 @@ class PostgresUpdater extends DatabaseUpdater { [ 'changeNullableField', 'protected_titles', 'pt_reason', 'NOT NULL', true ], [ 'addPgField', 'protected_titles', 'pt_reason_id', 'INTEGER NOT NULL DEFAULT 0' ], [ 'addTable', 'comment', 'patch-comment-table.sql' ], + [ 'migrateComments' ], [ 'addIndex', 'site_stats', 'site_stats_pkey', 'patch-site_stats-pk.sql' ], [ 'addTable', 'ip_changes', 'patch-ip_changes.sql' ], + + // 1.31 + [ 'addTable', 'slots', 'patch-slots-table.sql' ], + [ 'addTable', 'content', 'patch-content-table.sql' ], + [ 'addTable', 'content_models', 'patch-content_models-table.sql' ], + [ 'addTable', 'slot_roles', 'patch-slot_roles-table.sql' ], + [ 'migrateArchiveText' ], ]; } @@ -657,6 +665,13 @@ END; } } + protected function dropSequence( $table, $ns ) { + if ( $this->db->sequenceExists( $ns ) ) { + $this->output( "Dropping sequence $ns\n" ); + $this->db->query( "DROP SEQUENCE $ns CASCADE" ); + } + } + protected function renameSequence( $old, $new ) { if ( $this->db->sequenceExists( $new ) ) { $this->output( "...sequence $new already exists.\n" ); diff --git a/includes/installer/SqliteInstaller.php b/includes/installer/SqliteInstaller.php index d5909f4e1f..31718fefa0 100644 --- a/includes/installer/SqliteInstaller.php +++ b/includes/installer/SqliteInstaller.php @@ -321,7 +321,7 @@ EOT; return "# SQLite-specific settings \$wgSQLiteDataDir = \"{$dir}\"; \$wgObjectCaches[CACHE_DB] = [ - 'class' => 'SqlBagOStuff', + 'class' => SqlBagOStuff::class, 'loggroup' => 'SQLBagOStuff', 'server' => [ 'type' => 'sqlite', diff --git a/includes/installer/SqliteUpdater.php b/includes/installer/SqliteUpdater.php index 9f71001441..afb8b224b9 100644 --- a/includes/installer/SqliteUpdater.php +++ b/includes/installer/SqliteUpdater.php @@ -193,6 +193,13 @@ class SqliteUpdater extends DatabaseUpdater { [ 'migrateComments' ], [ 'renameIndex', 'l10n_cache', 'lc_lang_key', 'PRIMARY', false, 'patch-l10n_cache-primary-key.sql' ], + + // 1.31 + [ 'addTable', 'content', 'patch-content.sql' ], + [ 'addTable', 'content_models', 'patch-content_models.sql' ], + [ 'addTable', 'slots', 'patch-slots.sql' ], + [ 'addTable', 'slot_roles', 'patch-slot_roles.sql' ], + [ 'migrateArchiveText' ], ]; } diff --git a/includes/installer/i18n/be-tarask.json b/includes/installer/i18n/be-tarask.json index b427c19566..ffcbe39433 100644 --- a/includes/installer/i18n/be-tarask.json +++ b/includes/installer/i18n/be-tarask.json @@ -312,6 +312,7 @@ "config-install-mainpage-failed": "Немагчыма ўставіць галоўную старонку: $1", "config-install-done": "Віншуем!\nВы ўсталявалі MediaWiki.\n\nПраграма ўсталяваньня стварыла файл LocalSettings.php.\nЁн утрымлівае ўсе Вашыя налады.\n\nВам неабходна загрузіць яго і захаваць у карэнную дырэкторыю Вашай вікі (у тую ж самую дырэкторыю, дзе знаходзіцца index.php). Загрузка павінна пачацца аўтаматычна.\n\nКалі загрузка не пачалася, ці Вы яе адмянілі, Вы можаце перазапусьціць яе націснуўшы на спасылку ніжэй:\n\n$3\n\nЗаўвага: калі Вы гэтага ня зробіце зараз, то створаны файл ня будзе даступны Вам потым, калі Вы выйдзеце з праграмы ўсталяваньня безь яго загрузкі.\n\nКалі Вы гэта зробіце, Вы можаце [$2 ўвайсьці ў Вашую вікі].", "config-install-done-path": "Віншуем!\nВы ўсталявалі MediaWiki.\n\nПраграма ўсталёўкі стварыла файл LocalSettings.php. Ён утрымлівае ўсе вашыя налады.\n\nВам трэба спампаваць яго і пакласьці ў $4. Спампоўка павінна пачацца аўтаматычна.\n\nКалі спампоўка не пачалася або вы адмянілі яе, вы можаце пачаць яе наноў, калі націсьніце на наступную спасылку:\n\n$3\n\nЗаўвага: Калі вы ня зробіце гэта зараз, то створаны файл ня будзе даступны вам па выхадзе з праграмы безь яго спампоўкі.\n\nКалі вы зробіце гэта, вы можаце [$2 ўвайсьці ў вашую вікі].", + "config-install-success": "MediaWiki была пасьпяхова ўсталяваная. Цяпер вы можаце наведаць <$1$2>, каб пабачыць вашую вікі. Калі вы маеце пытаньні, сьпярша паглядзіце сьпіс адказаў на частыя пытаньні: ці скарыстайцеся адным з форумаў падтрымкі, пазначаных на гэтай старонцы.", "config-download-localsettings": "Загрузіць LocalSettings.php", "config-help": "дапамога", "config-help-tooltip": "націсьніце, каб разгарнуць", diff --git a/includes/installer/i18n/bg.json b/includes/installer/i18n/bg.json index 40e143b2f5..8668ed557a 100644 --- a/includes/installer/i18n/bg.json +++ b/includes/installer/i18n/bg.json @@ -5,7 +5,8 @@ "아라", "StanProg", "Vodnokon4e", - "Seb35" + "Seb35", + "ShockD" ] }, "config-desc": "Инсталатор на МедияУики", @@ -81,6 +82,7 @@ "config-no-cli-uploads-check": "Предупреждение: Директорията по подразбиране за качване на файлове ($1) не е проверена за уязвимости при изпълнение на произволен скрипт по време на инсталацията от командния ред.", "config-brokenlibxml": "Вашата система използва комбинация от версии на PHP и libxml2, които са с много грешки и могат да причинят скрити повреди на данните в МедияУики или други уеб приложения.\nНеобходимо е обновяване до libxml2 2.7.3 или по-нова версия ([https://bugs.php.net/bug.php?id=45996 докладвана грешка при PHP]).\nИнсталацията беше прекратена.", "config-suhosin-max-value-length": "Suhosin е инсталиран и ограничава дължината GET параметъра length на $1 байта. Компонентът на МедияУики ResourceLoader ще може да пренебрегне частично това ограничение, но това ще намали производителността. По възможност е препоръчително да се настрои suhosin.get.max_value_length на 1024 или по-голяма стойност в php.ini и в LocalSettings.php да се настрои $wgResourceLoaderMaxQueryLength със същата стойност.", + "config-using-32bit": "Внимание: изглежда, че системата Ви работи с 32-битови числа. Това [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit не се препоръчва].", "config-db-type": "Тип на базата от данни:", "config-db-host": "Хост на базата от данни:", "config-db-host-help": "Ако базата от данни е на друг сървър, в кутията се въвежда името на хоста или IP адреса.\n\nАко се използва споделен уеб хостинг, доставчикът на услугата би трябвало да е предоставил в документацията си коректния хост.\n\nАко инсталацията протича на Windows-сървър и се използва MySQL, използването на \"localhost\" може да е неприемливо. В такива случаи се използва \"127.0.0.1\" за локален IP адрес.\n\nПри използване на PostgreSQL, това поле се оставя празно, за свързване чрез Unix socket.", @@ -306,11 +308,14 @@ "config-install-mainpage-failed": "Вмъкването на Началната страница беше невъзможно: $1", "config-install-done": "Поздравления!\nИнсталирането на МедияУики приключи успешно.\n\nИнсталаторът създаде файл LocalSettings.php.\nТой съдържа всичката необходима основна конфигурация на уикито.\n\nНеобходимо е той да бъде изтеглен и поставен в основната директория на уикито (директорията, в която е и index.php). Изтеглянето би трябвало да започне автоматично.\n\nАко изтеглянето не започне автоматично или е било прекратено, файлът може да бъде изтеглен чрез щракване на препратката по-долу:\n\n$3\n\nЗабележка: Ако това не бъде извършено сега, генерираният конфигурационен файл няма да е достъпен на по-късен етап ако не бъде изтеглен сега или инсталацията приключи без изтеглянето му.\n\nКогато файлът вече е в основната директория, [$2 уикито ще е достъпно на този адрес].", "config-install-done-path": "Поздравления!\nИнсталирането на МедияУики приключи успешно.\n\nИнсталаторът създаде файл LocalSettings.php.\nТой съдържа всички ваши настройки.\n\nНеобходимо е той да бъде изтеглен и поставен в $4. Изтеглянето би трябвало да започне автоматично.\n\nАко изтеглянето не започне автоматично или е било прекратено, файлът може да бъде изтеглен чрез щракване на препратката по-долу:\n\n$3\n\nЗабележка: Ако това не бъде направено сега, генерираният конфигурационен файл няма да е достъпен на по-късен етап ако не бъде изтеглен сега или инсталацията приключи без изтеглянето му.\n\nКогато файлът вече е в основната директория, [$2 уикито ще е достъпно на този адрес].", + "config-install-success": "МедияУики беше успешно инсталиран. Можете да посетите <$1$2> за да видите Вашето уики.\nАко имате въпроси, вижте списъка с често задавани въпроси:\n или използвайте някой от форумите за поддръжка на тази страница.", "config-download-localsettings": "Изтегляне на LocalSettings.php", "config-help": "помощ", "config-help-tooltip": "щракнете за разгръщане", "config-nofile": "Файлът „$1“ не може да бъде открит. Да не е бил изтрит?", "config-extension-link": "Знаете ли, че това уики поддържа [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions разширения]?\n\nМожете да разгледате [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category разширенията по категория] или [https://www.mediawiki.org/wiki/Extension_Matrix Матрицата на разширенията] за пълен списък на разширенията.", + "config-skins-screenshots": "$1 (снимки на екрана: $2)", + "config-screenshot": "снимка на екран", "mainpagetext": "МедияУики беше успешно инсталирано.", "mainpagedocfooter": "Разгледайте [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents ръководството] за подробна информация относно използването на уики софтуера.\n\n== Първи стъпки ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Настройки за конфигуриране]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ ЧЗВ за МедияУики]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Пощенски списък относно нови версии на МедияУики]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Локализиране на МедияУики]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Научете как да се справяте със спама във вашето уики]" } diff --git a/includes/installer/i18n/ca.json b/includes/installer/i18n/ca.json index c86b824447..54a7de8cb3 100644 --- a/includes/installer/i18n/ca.json +++ b/includes/installer/i18n/ca.json @@ -257,6 +257,8 @@ "config-help-tooltip": "feu clic per ampliar", "config-nofile": "No s'ha pogut trobar el fitxer «$1». S'ha suprimit?", "config-extension-link": "Sabíeu que el vostre wiki permet l'ús d'[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions]?\n\nPodeu navegar les [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions per categoria] o la [https://www.mediawiki.org/wiki/Extension_Matrix matriu d'extensions] per a veure'n una llista sencera.", + "config-skins-screenshots": "$1 (captures de pantalla: $2)", + "config-screenshot": "captura de pantalla", "mainpagetext": "MediaWiki s'ha instal·lat.", "mainpagedocfooter": "Consulteu la [https://meta.wikimedia.org/wiki/Help:Contents Guia d'Usuari] per a més informació sobre com utilitzar aquest programari wiki.\n\n== Primers passos ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Llista de paràmetres configurables]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ PMF del MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Llista de correu per a anuncis del MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducció de MediaWiki en la vostra llengua]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Aprengueu com combatre la brossa que pot atacar el vostre wiki]" } diff --git a/includes/installer/i18n/ckb.json b/includes/installer/i18n/ckb.json index 3bfa8a6f54..20f2f24bd2 100644 --- a/includes/installer/i18n/ckb.json +++ b/includes/installer/i18n/ckb.json @@ -4,7 +4,8 @@ "Asoxor", "Calak", "Muhammed taha", - "Lost Whispers" + "Lost Whispers", + "Épine" ] }, "config-desc": "دامەزرێنەرەکە بۆ میدیاویکی", diff --git a/includes/installer/i18n/cs.json b/includes/installer/i18n/cs.json index 2ff49fcbf8..5ac35c89ce 100644 --- a/includes/installer/i18n/cs.json +++ b/includes/installer/i18n/cs.json @@ -314,6 +314,7 @@ "config-install-mainpage-failed": "Nepodařilo se vložit hlavní stranu: $1", "config-install-done": "Gratulujeme!\nNainstalovali jste MediaWiki.\n\nInstalátor vytvořil soubor LocalSettings.php.\nTen obsahuje veškerou vaši konfiguraci.\n\nBudete si ho muset stáhnout a uložit do základního adresáře vaší instalace wiki (do stejného adresáře jako soubor index.php). Stažení souboru se mělo spustit automaticky.\n\nPokud se vám stažení nenabídlo nebo jste ho zrušili, můžete ho spustit znovu kliknutím na následující odkaz:\n\n$3\n\nPoznámka: Pokud to neuděláte hned, tento vygenerovaný konfigurační soubor nebude později dostupný, pokud instalaci opustíte, aniž byste si ho stáhli.\n\nAž to dokončíte, můžete [$2 vstoupit do své wiki].", "config-install-done-path": "Gratulujeme!\nNainstalovali jste MediaWiki.\n\nInstalátor vytvořil soubor LocalSettings.php.\nTen obsahuje veškerou vaši konfiguraci.\n\nBudete si ho muset stáhnout a uložit do $4. Stažení souboru se mělo spustit automaticky.\n\nPokud se vám stažení nenabídlo nebo jste ho zrušili, můžete ho spustit znovu kliknutím na následující odkaz:\n\n$3\n\nPoznámka: Pokud to neuděláte hned, tento vygenerovaný konfigurační soubor nebude později dostupný, pokud instalaci opustíte, aniž byste si ho stáhli.\n\nAž to dokončíte, můžete [$2 vstoupit do své wiki].", + "config-install-success": "MediaWiki byla úspěšně nainstalována. Nyní můžete\nnavštívit <$1$2>, abyste si prohlédli svou novou wiki.\nPokud máte dotazy, podívejte se do našeho seznamu často kladených otázek:\n nebo použijte jedno\nz tam odkazovaných diskusních fór.", "config-download-localsettings": "Stáhnout LocalSettings.php", "config-help": "nápověda", "config-help-tooltip": "rozbalíte kliknutím", diff --git a/includes/installer/i18n/de.json b/includes/installer/i18n/de.json index ca649dcab5..bd944f14e9 100644 --- a/includes/installer/i18n/de.json +++ b/includes/installer/i18n/de.json @@ -234,7 +234,7 @@ "config-license-cc-0": "''Creative Commons'' „Zero“ (Gemeinfreiheit)", "config-license-gfdl": "GNU-Lizenz für freie Dokumentation 1.3 oder höher", "config-license-pd": "Gemeinfreiheit", - "config-license-cc-choose": "Eine benutzerdefinierte Creative-Commons-Lizenz auswählen", + "config-license-cc-choose": "Eine andere Creative-Commons-Lizenz auswählen", "config-license-help": "Viele öffentliche Wikis publizieren alle Beiträge unter einer [http://freedomdefined.org/Definition/De freien Lizenz.]\nDies trägt dazu bei, ein Gefühl von Gemeinschaft zu schaffen, und ermutigt zu längerfristiger Mitarbeit.\nHingegen ist im Allgemeinen eine freie Lizenz auf geschlossenen Wikis nicht notwendig.\n\nSofern man Texte aus der Wikipedia verwenden möchte und umgekehrt, sollte die Lizenz {{int:config-license-cc-by-sa}} gewählt werden.\n\nDie Wikipedia nutzte vormals die GNU-Lizenz für freie Dokumentation (GFDL).\nDie GFDL ist eine gültige Lizenz, die allerdings schwer zu verstehen ist.\nEs ist zudem schwierig, gemäß dieser Lizenz lizenzierte Inhalte wiederzuverwenden.", "config-email-settings": "E-Mail-Einstellungen", "config-enable-email": "Ausgehende E-Mails ermöglichen", @@ -321,6 +321,7 @@ "config-install-mainpage-failed": "Die Hauptseite konnte nicht erstellt werden: $1", "config-install-done": "'''Herzlichen Glückwunsch!'''\nMediaWiki wurde erfolgreich installiert.\n\nDas Installationsprogramm hat die Datei LocalSettings.php erzeugt.\nSie enthält alle vorgenommenen Konfigurationseinstellungen.\n\nDiese Datei muss nun heruntergeladen und anschließend in das Stammverzeichnis der MediaWiki-Installation hochgeladen werden. Dies ist dasselbe Verzeichnis, in dem sich auch die Datei index.php befindet. Das Herunterladen sollte inzwischen automatisch gestartet worden sein.\n\nSofern dies nicht der Fall war, oder das Herunterladen unterbrochen wurde, kann der Vorgang durch einen Klick auf den folgenden Link erneut gestartet werden:\n\n$3\n\n'''Hinweis:''' Die Konfigurationsdatei sollte jetzt unbedingt heruntergeladen werden. Sie wird nach Beenden des Installationsprogramms, nicht mehr zur Verfügung stehen.\n\nSobald alles erledigt wurde, kann auf das '''[$2 Wiki zugegriffen werden]'''. Wir wünschen viel Spaß und Erfolg mit dem Wiki.", "config-install-done-path": "Herzlichen Glückwunsch!\nDu hast MediaWiki installiert.\n\nDas Installationsprogramm hat eine Datei „LocalSettings.php“ erzeugt.\nSie enthält deine gesamte Konfiguration.\n\nDu musst sie herunterladen und unter $4 ablegen. Der Download sollte automatisch gestartet sein.\n\nFalls der Download nicht angeboten wird oder du ihn abgebrochen hast, kannst du ihn durch Anklicken des folgenden Links neu starten:\n\n$3\n\nHinweis: Falls du dies jetzt nicht tust, wird die erzeugte Konfigurationsdatei später nicht verfügbar sein, wenn du die Installation ohne Herunterladen verlässt.\n\nBei Fertigstellung kannst du [$2 dein Wiki aufrufen].", + "config-install-success": "MediaWiki wurde erfolgreich installiert. Du kannst jetzt\n<$1$2> aufrufen, um dein Wiki anzusehen.\nFalls du Fragen hast, lies unsere Liste der häufig gestellten Fragen:\n oder benutze eines der\nSupport-Foren, die auf dieser Seite verlinkt sind.", "config-download-localsettings": "LocalSettings.php herunterladen", "config-help": "Hilfe", "config-help-tooltip": "Zum Expandieren klicken", diff --git a/includes/installer/i18n/el.json b/includes/installer/i18n/el.json index f9bab3edd0..0c057fc9ac 100644 --- a/includes/installer/i18n/el.json +++ b/includes/installer/i18n/el.json @@ -9,7 +9,8 @@ "Stam.nikos", "Giorgos456", "Badseed", - "Macofe" + "Macofe", + "KATRINE1992" ] }, "config-desc": "Το πρόγραμμα εγκατάστασης για το MediaWiki", @@ -227,6 +228,7 @@ "config-install-extension-tables": "Γίνεται δημιουργία πινάκων για τις εγκατεστημένες επεκτάσεις", "config-install-mainpage-failed": "Δεν ήταν δυνατή η εισαγωγή της αρχικής σελίδας: $1", "config-install-done": "Συγχαρητήρια!\nΈχετε εγκαταστήσει με επιτυχία το MediaWiki.\n\nΤο πρόγραμμα εγκατάστασης έχει δημιουργήσει το αρχείο LocalSettings.php.\nΠεριέχει όλες τις ρυθμίσεις παραμέτρων σας.\n\nΘα πρέπει να το κατεβάσετε και να το βάλετε στη βάση της εγκατάστασης του wiki σας (στον ίδιο κατάλογο όπως το index.php). Η λήψη θα αρχίσει αυτόματα.\n\nΑν η λήψη δεν προσφέφθηκε, ή αν την ακυρώσατε, μπορείτε να επανεκκινήσετε τη λήψη κάνοντας κλικ στο παρακάτω link:\n\n$3\n\nΣημείωση: Εάν δεν το κάνετε αυτό τώρα, αυτό το αρχείο ρύθμισης παραμέτρων δεν θα είναι διαθέσιμο για σας αργότερα, αν βγείτε από την εγκατάσταση, χωρίς να το κατεβάσετε!\n\nΌταν γίνει αυτό, μπορείτε να [$2 μπείτε στο wiki σας].", + "config-install-success": " Το σύστημα της MediaWiki έχει εγκατασταθεί με επιτυχία. Μπορείτε τώρα να επισκεφθείτε το \n <$1$2> για να δείτε το wiki σας.\nΑν έχετε ερωτήσεις, ελέγξετε την λίστα με τις πιο συχνές ερωτήσεις:\n ή χρησιμοποιήστε ένα από τα φόρουμ υποστήριξης που είναι συνδεδεμένα σε αυτήν την σελίδα.", "config-download-localsettings": "Λήψη του LocalSettings.php", "config-help": "βοήθεια", "config-help-tooltip": "κλικ για ανάπτυξη", diff --git a/includes/installer/i18n/es.json b/includes/installer/i18n/es.json index 0eecddb904..1df61566ca 100644 --- a/includes/installer/i18n/es.json +++ b/includes/installer/i18n/es.json @@ -33,7 +33,8 @@ "Peter Bowman", "Dgstranz", "Irus", - "Tinss" + "Tinss", + "KATRINE1992" ] }, "config-desc": "El instalador de MediaWiki", @@ -266,7 +267,7 @@ "config-email-auth-help": "Si esta opción está habilitada, los usuarios tienen que confirmar su dirección de correo electrónico mediante un enlace que se les envía a ellos cuando éstos lo establecen o lo cambian.\nSolo las direcciones de correo electrónico autenticadas pueden recibir correos electrónicos de otros usuarios o correos electrónicos de notificación de cambios.\nEsta opción está '''recomendada''' para wikis públicos debido a posibles abusos de las características del correo electrónico.", "config-email-sender": "Dirección de correo electrónico de retorno:", "config-email-sender-help": "Escribe la dirección de correo electrónico que se usará como dirección de retorno en los mensajes electrónicos de salida.\nAquí llegarán los correos electrónicos que no lleguen a su destino.\nMuchos servidores de correo electrónico exigen que por lo menos la parte del nombre del dominio sea válida.", - "config-upload-settings": "Subidas de imágenes y archivos", + "config-upload-settings": "Cargas de imágenes y archivos", "config-upload-enable": "Habilitar la subida de archivos", "config-upload-help": "La subida de archivos potencialmente expone tu servidor a riesgos de seguridad.\nPara obtener más información, consulta la [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security sección de seguridad] en el manual.\n\nPara activar la subida de archivos, cambia el modo en el subdirectorio images bajo el directorio raíz de MediaWiki para que el servidor web pueda escribir en él.\nLuego, activa esta opción.", "config-upload-deleted": "Directorio para los archivos eliminados:", @@ -338,9 +339,10 @@ "config-install-mainpage-failed": "No se pudo insertar la página principal: $1", "config-install-done": "¡Felicidades!\nHas instalado MediaWiki.\n\nEl instalador ha generado un archivo LocalSettings.php.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en la base de la instalación de wiki (el mismo directorio que index.php). La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\nNota: si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás [$2 entrar en tu wiki].", "config-install-done-path": "¡Felicidades!\nHas instalado MediaWiki.\n\nEl instalador ha generado un archivo LocalSettings.php.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en $4. La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\nNota: si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás [$2 entrar en tu wiki].", + "config-install-success": "Se instaló MediaWiki correctamente. Ahora puedes visitar\n<$1$2> para ver el wiki.\nSi tienes dudas, echa un vistazo a la lista de preguntas frecuentes:\n, o bien, utiliza uno de\nlos foros de asistencia que se enumeran en esa página.", "config-download-localsettings": "Descargar LocalSettings.php", "config-help": "ayuda", - "config-help-tooltip": "haz clic para ampliar", + "config-help-tooltip": "pulsa para ampliar", "config-nofile": "No se pudo encontrar el archivo «$1». Quizá se eliminó.", "config-extension-link": "¿Sabías que tu wiki admite [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensiones]?\n\nPuedes navegar por las [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category categorías] o visitar el [https://www.mediawiki.org/wiki/Extension_Matrix centro de extensiones] para ver una lista completa.", "config-skins-screenshots": "$1 (capturas de pantalla: $2)", diff --git a/includes/installer/i18n/eu.json b/includes/installer/i18n/eu.json index ae97154cc0..a9b01f58ff 100644 --- a/includes/installer/i18n/eu.json +++ b/includes/installer/i18n/eu.json @@ -77,11 +77,16 @@ "config-no-cli-uri": "Oharra. Ez da zehaztu --scriptpath, erabiltzen estandar $1 .", "config-using-server": "\"$1\" zerbitzari-izena erabiltzen.", "config-using-uri": "\"$1$2\" zerbitzariaren URLa erabiltzen.", + "config-uploads-not-safe": "Oharra: Zure igoerak egiteko $1 direktorio lehenetsia gidoi arbitrarioen exekuzioek kaltetu dezakete.\nMediaWiki-k segurtasunerako kargatutako fitxategi guztiak egiaztatzen dituen arren, oso gomendagarria da [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security segurtasun-ahultasun hau itxi] erabiltzea gaitu aurretik.", + "config-no-cli-uploads-check": "Oharra: Zure kargatutako direktorio ($1) lehenetsia ez da hauteman ahultasunerako\nscript arbitrarioak exekutatzeko CLI instalazioan zehar.", "config-brokenlibxml": "Zure sistemak dauka PHP-ko eta libxml2-ko konbinazio akastun bat eta eragin ahal du korrupzioa datarekin MediaWikin eta beste web aplikazioetan.\nAktualizatu libxml2 2.7.3-era edo berrietara ([https://bugs.php.net/bug.php?id=45996 bug filed with PHP]).\nInstalazioa geldiarazi egin da.", + "config-suhosin-max-value-length": "Suhosin instalatuta dago eta GET parametroaren luzeera $1 byte-ra mugatzen du.\nMediaWiki-ren ResourceLoader osagaia muga honen inguruan lan egingo du, baina horrek errendimendua kaltetu egingo du.\nAhal izanez gero, suhosin.get.max_value_length 1024 edo handiagoa ezarri beharko zenuke php.ini, eta LocalSettings.php-n $wgResourceLoaderMaxQueryLength balio bera ezarri.", + "config-using-32bit": "Oharra: zure sistemak 32 bit-ekin jarduten duela dirudi. Hau da [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit not advised].", "config-db-type": "Datu-base mota:", "config-db-host": "Datu-basearen zerbitzaria:", "config-db-host-help": "Zure datu-basearen zerbitzaria beste zerbitzari batean badago, sartu ostalariaren izena edo IP helbidea hemen.\n\nPartekatutako web-ostatua erabiltzen ari bazara, zure ostalaritza-hornitzaileak dokumentazio-ostalariaren izen egokia eman beharko lizuke.\n\nWindows zerbitzari batean instalatzen bazara eta MySQL erabiliz, \"localhost\" agian ez du zerbitzariaren izenerako funtzionatuko. Ez badago, saiatu \"127.0.0.1\" tokiko IP helbideetarako.\n\nPostgreSQL erabiltzen ari bazara, utzi eremu hau hutsik Unix socket bidez konektatzeko.", "config-db-host-oracle": "Datu-baseko TNS:", + "config-db-host-oracle-help": "Sartu baliozko [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Konekzio izan lokala]; instalazio honetarako tnsnames.ora fitxategia ikusgai egon behar da.
Bezeroen 10g liburutegiak edo berriagoak erabiltzen ari bazara, [http://download.oracle.com/docs/cd/E11882_01/network.112 ere erabil dezakezu. /e10836/naming.htm Konektatzeko erraza] izendatzeko metodoa.", "config-db-wiki-settings": "Wiki hau identifikatu", "config-db-name": "Datu-base izena:", "config-db-name-help": "Aukeratu zure Wikia identifikatzen duen izena.\nEzin dira espazioak eabili.\n\nErabiltzen ari bazara web hosting partekatua, hostin-eko hornitzaileak emango dizu datu-basearen izen espezifikoa edo kontrol panel baten bitzrtez zure datu-basea sortzea utziko dizu.", @@ -104,6 +109,7 @@ "config-db-schema-help": "Patroi hau normalean egokia da. Bakarrik aldatu beharrezkoa bada.", "config-pg-test-error": "Ezin da datu-basearekin konektatu $1: $2", "config-sqlite-dir": "SQLite -eko informazioaren direktorioa:", + "config-sqlite-dir-help": "SQLite-k datu guztiak fitxategi bakarrean gordetzen ditu.\n\nHornitu duzun direktorioa web zerbitzariaren bidez idatzia izateko aukera eman beharko duu instalazioan zehar.\n\nEz da webgunearen bidez eskuragarri egon behar; horregatik zure PHP fitxategiak non dauden ez dugu erakutsi.\n\nInstalatzaileak .htaccess fitxategi bat idatziko du bertan, baina horrek huts egiten badu zure datu base gordinera norbait sar daiteke.\nErabiltzaileen datu gordinak (helbide elektronikoak, pasahitzak), ezabatutako berrikusketa eta gainontzeko datu mugatuak ere barnean hartuz.\n\nDatu-basea beste nonbait jartzearen inguruan hausnartu, adibidez, /var/lib/mediawiki/yourwiki-n.", "config-oracle-def-ts": "Taula-toki lehenetsia:", "config-oracle-temp-ts": "Aldi baterako taula:", "config-type-mysql": "MySQL (edo bateragarria)", @@ -136,6 +142,8 @@ "config-postgres-old": "PostgreSQL $1 edo berriagoa behar da. Zuk $2 badaukazu.", "config-mssql-old": "Microsoft SQL Server $1 edo berriagoa behar da. Zuk $2 badaukazu.", "config-sqlite-name-help": "Aukeratu zure wikia identifikatzen duen izen bat.\nEz erabili zuriunerik edo gidoirik.\nHau erabiliko da SQLite datuen artxiborako.", + "config-sqlite-parent-unwritable-group": "Ezin da datu-direktorioa sortu $1, web zerbitzariak ezin baitu $2 guraso direktorioan idatzi.\n\nInstalatzaileak webgunea exekutatzen ari den bitartean zure erabiltzailea zehaztu du.\nEgin $3 direktorioan idazteko gai izatea jarraitzeko.\nUnix/Linux sistema batean:\n\n
cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3
", + "config-sqlite-parent-unwritable-nogroup": "Ezin da datu-direktorioa sortu $1, web zerbitzariak ezin baitu $2 guraso direktorioan idatzi.\n\nInstalatzaileak webgunea exekutatzen ari den bitartean zure erabiltzailea zehaztu dezake.\nEgin $3 direktorioa globalean idazteko gai izatea (horretarako eta besteentzako!) jarraitzeko.\nUnix/Linux sistema batean:\n\n
cd $2\nmkdir $3\nchmod a+w $3
", "config-sqlite-mkdir-error": "Arazo bat sortu da datuen direktorioa sortzerakoan \"$1\".\nLokalizazio egiaztatu eta berriro saiatu.", "config-sqlite-dir-unwritable": "Ezin izan da \"$1\" direktoriora idatzi.\nAldatu baimenak web-serbidoreak idatzi ahal izateko, eta berriro saiatu.", "config-sqlite-connection-error": "$1.\n\nDatu direktorioa eta datu-basea egiaztatu eta berriro saiatu.", @@ -143,6 +151,7 @@ "config-sqlite-cant-create-db": "Ezin izan da $1 datu-basearen artxiboa sortu.", "config-sqlite-fts3-downgrade": "PHPn FTS3 laguntza falta da, taulen gradua jeisten.", "config-can-upgrade": "Datu base honetan MediaWiki taulak daude.\nMediaWiki $1ra graduz igotzeko, Jarraitu klikatu.", + "config-upgrade-done": "Berritzea burutu da.\n\nOrain [$1 zure wiki-a erabiltzen hasi] ahal zara.\n\nZure LocalSettings.php fitxategia birsortzea nahi baduzu, egin klik beheko botoian.\nHau ez da gomendagarria zure wikiarekin arazoak izan ezean.", "config-upgrade-done-no-regenerate": "Eguneratze prozesua amaitu egin da.\n\nHasi ahal zara [ $1 wikia arabiltzen]", "config-regenerate": "Birsortu LocalSettings.php →", "config-show-table-status": "SHOW TABLE STATUS kontsulta huts egin du!", @@ -157,10 +166,14 @@ "config-mysql-myisam": "MyISAM", "config-mysql-myisam-dep": "Oharra: MyISAM MySQL biltegiratze-motor gisa aukeratu duzu, MediaWikirekin erabiltzeko gomendagarria ez dena honengatik:\n*taula blokeoak direla-eta gauza gutxi onartu ohi du\n*beste motore batzuek baino ustelkeria gehiago izateko aukerak ditu\n*MediaWiki-ren kode baseak ez du beti kudeatzen MyISAM behar bezala\n\nZure MySQL instalazioa InnoDB onartzen badu, hori aukeratzeko gomendatzen da.\nZure MySQL instalazioa InnoDB ez badu onartzen, baliteke bertsioa berritzeko ordua izatea.", "config-mysql-only-myisam-dep": " Oharra: MyISAM makinaren MySQL biltegiratze motarako bakarra da, eta hau ez da MediaWiki-rekin erabiltzeko gomendatzen, honengatik:\n* maiztasunez taula blokeoek konkurrentzia ez dute onartzen \n* Beste motore batzuek baino ustelkeria gehiago izaten dute\n* MediaWiki-ren kodekak ez du beti kudeatzen MyISAM behar bezala\n\nZure MySQL instalazioak ez du InnoDB onartzen, agian bertsio berritzeko ordua da.", + "config-mysql-engine-help": "InnoDB ia beti aukerarik onena da, konkurrentzia-laguntza ona duelako.\n\nMyISAM erabiltzaile bakarreko edo irakurketa bakarreko instalazioetan azkarragoa izan daiteke.\nMyISAM datu-basea gehiagokotan hondatuta ageri da InnoDB datu-baseareakin baino.", "config-mysql-charset": "Datu-basearen karaktere multzoa:", "config-mysql-binary": "Bitarra", "config-mysql-utf8": "UTF-8", + "config-mysql-charset-help": "Modu bitarrean, MediaWiki-k UTF-8 testua datu-baseko eremu bitarretan gordetzen du.\nHau MySQL-en UTF-8 modua baino eraginkorragoa da eta Unicode karaktereen barruti osoa erabiltzea ahalbidetzen du.\n\nUTF-8 moduan, MySQL-k jakingo du zer karakterean zure datuak konfiguratzen dituen, aurkeztu eta behar bezala bihurtzeko, baina ez dizkizu karaktereak [https://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Oinarrizko Eleaniztasun Plana]-ren gainetik gordetzen utziko.", "config-mssql-auth": "Autentifikazio mota:", + "config-mssql-install-auth": "Aukeratu instalazio prozesuan zehar datu-basera konektatzeko erabiliko den autentifikazio mota.\n\"{{Int: config-mssql-windowsauth}}\" hautatzen baduzu, web zerbitzariak duen edozein erabiltzailek erabiliko duen kredentziala erabiliko da.", + "config-mssql-web-auth": "Aukeratu instalazio prozesuan zehar datu-base zerbitzariari konektatzeko erabiliko den autentifikazio mota.\n\"{{Int: config-mssql-windowsauth}}\" hautatzen baduzu, web zerbitzariak duen edozein erabiltzailek erabiliko duen kredentziala erabiliko da.", "config-mssql-sqlauth": "SQL Serbidorearen Autentifikazioa", "config-mssql-windowsauth": "Windows-eko Autentifikazioa.", "config-site-name": "Wikiaren izena:", @@ -172,6 +185,8 @@ "config-ns-other": "Bestelakoa (zehaztu)", "config-ns-other-default": "MyWiki", "config-project-namespace-help": "Wikipedia-ren adibidea jarraitzen, wiki askok beren orrien politika mantentzen dute beren edukien orrialdeetatik bereizita, '' 'proiektuaren izen-eremuan' ''.\nOrrialde honetako izenburu guztiek aurrizki jakin batekin hasten dira, hemen zehaztu ahal direnak.\nNormalean, aurrizkia wikiaren izenetik dator, baina ezin du \"#\" edo \":\" puntuazio-karaktereak eduki.", + "config-ns-invalid": "Zehaztutako \"$1\" izena baliogabea da.\nZehaztu beste proiektu baten izenaren eremua.", + "config-ns-conflict": "\"$1\" zehaztutako izen-eremuak lehenetsitako MediaWiki izen-eremu batekin gatazkan ari da.\nZehaztu beste proiektu izen-eremu bat.", "config-admin-box": "Administratzaile kontua", "config-admin-name": "Zure erabiltzaile-izena:", "config-admin-password": "Pasahitza:", @@ -183,9 +198,14 @@ "config-admin-password-mismatch": "Sartutako bi pasahitzak ez datoz bat.", "config-admin-email": "E-posta helbidea:", "config-admin-email-help": "Sartu email bat baimena emateko mezuak jasotzeko, pasahitza aldatzeko and orrien aldaketeei buruz berri edukitzeko.\nHutsik utzi ahal duzu.", + "config-admin-error-user": "Barneko errorea \"$1\" izeneko administratzailea sortzerakoan.", "config-admin-error-password": "Barne-arazoa administratzailearen pasahitza sortzerakoan.\"$1\".
$2
", "config-admin-error-bademail": "Helbide elektroniko okerra idatzi duzu.", + "config-subscribe": "Harpidetu [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce posta zerrenda bidez egindako iragarki ohar] zerrendara.", + "config-subscribe-help": "Hau bolumen baxuko oharren iragarkietarako erabiltzen den zerrenda da, segurtasun iragarki garrantzitsuak barne.\nHarpidetu horretara eta zure MediaWiki instalazioa eguneratu bertsio berriak ateratzean.", + "config-subscribe-noemail": "Ohar iragarkien posta elektroniko zerrendara harpidetzen saiatu zara, helbide elektroniko bat eman gabe.\nEman ezazu helbide elektronikoa posta zerrendan harpidetzea nahi baduzu.", "config-pingback": "Elkarbanatu informazioa instalazio prozesuari buruz MediaWiki-ko sustatzaileekin.", + "config-pingback-help": "Aukera hau hautatzen baduzu, MediaWiki-k https://www.mediawiki.org guneari periodikoki ping egingo dio MediaWiki-ren instantzia honi buruzko oinarrizko datuekin. Datu horietan, adibidez, sistema mota, PHP bertsioa eta hautatutako datu-base motorra agertzen dira. Wikimedia Fundazioak datu hauek partekatzen dituu MediaWiki garatzaileekin etorkizuneko garapen-ahaleginak gidatzeko. Ondorengo datuak zure sistemara bidaliko dira:\n
$1
", "config-almost-done": "Ia amaitu duzu!\nFalta den konfigurazioa saltatu ahal duzu eta zuzenean wikia instalatu.", "config-optional-continue": "Galdera gehiago egin.", "config-optional-skip": "Aspertuta nago, wikia instalatu bakarrik.", @@ -194,16 +214,20 @@ "config-profile-no-anon": "Kontua sortzea beharrezkoa da", "config-profile-fishbowl": "Baimendutako editoreak bakarrik", "config-profile-private": "Wiki pribatua", + "config-profile-help": "Wikiak hobeto funtzionatzen dute ahalik eta jende gehiagok editatzeko aukera duenean.\nMediaWikian, erraza da azken aldaketak berrikustea eta erabiltzaile desegokiek egindako kalteak konpontzea.\n\nHala eta guztiz ere, askok MediaWiki rol ezberdinetarako baliagarri ikusi dute, nahiz eta batzuetan erraza ez izan wikiaren onureen inguruan konbentzitzea.\nBeraz, aukera zuk egiten duzu.\n\n{{int:config-profile-wiki}} ereduak edonork edita dezake, nahiz eta saioa hasi.\n{{int:config-profile-no-anon}} -ko wiki batek aparteko erantzukizuna ematen du, baina aldi baterako laguntzaileak alda ditzake.\n\n{{int:config-profile-fishbowl}} planteamenduak aukera ematen du baimendutako erabiltzaileek editatzeko, baina publikoak orrialdeak ikusi ditzake, historiak barne.\n{{int:config-profile-private}} bat soilik onartutako erabiltzaileei orriak ikusteko aukera ematen die, talde berak editatu ahal izateko.\n\nErabiltzaileen eskubideen ezarpen konplexuagoak eskuragarri daude instalazioa egin ondoren, ikus ezazu [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights eskuzko sarrera garrantzitsua].", "config-license": "Copyright eta lizentzia:", "config-license-none": "Ez jarri lizentzia orriaren baimenik", "config-license-cc-by-sa": "Creative Commons-eko esleipen-lizentzia", "config-license-cc-by": "Creative Commons Aitorpena", + "config-license-cc-by-nc-sa": "Creative Commons Attribution-NonCommercial-ShareAlike", "config-license-cc-0": "Creative Commons Zero (Jabari Publikoa)", "config-license-gfdl": "\nGNU Free Documentation License 1.3 edo berriagoa", "config-license-pd": "Domeinu Askea", "config-license-cc-choose": "Aukeratu Creative Commons lizentzia pertsonalizatua", + "config-license-help": "Wikilari publiko askok ekarpen guztiak jartzen dituzte [http://freedomdefined.org/Definition lizentzia aske] azpian.\nHonek komunitatearen jabetza zentzuaren kontzeptua sortzen laguntzen du eta epe luzerako ekarpena bultzatzen du.\nEz da, oro har, wiki pribatu edo korporatiborik behar.\n\nWikipediatik testua erabiltzeko aukera izan nahi baduzu eta Wikipediak zure wikietatik kopiatutako testua onartzeko gai izatea nahi baduzu, {{int:config-license-cc-by-sa}} aukeratu beharko zenuke.\n\nWikipedia lehenago erabili izan du GNU Dokumentazio Librearen Lizentzia.\nGFDL baliozko lizentzia da, baina ulertzeko zaila da.\nGFDLren baimenarekin lotutako edukiak berrerabiltzea ere zaila da.", "config-email-settings": "E-posta hobespenak", "config-enable-email": "Aktibatu irteerako emaila.", + "config-enable-email-help": "Lan egiteko email-a nahi baduzu, [http://www.php.net/manual/en/mail.configuration.php PHP's mail settings] ondo konfiguratu egin behar da. Email ezaugarririk ez baduzu nahi, hemen kendu ditzakezu.", "config-email-user": "Aktibatu erabiltzaileen arteko emaila.", "config-email-user-help": "Baimena eman erabiltzaileei beraien artean emailak bidaltzeko, lehentasunetan aukera aktibatuta badaukate.", "config-email-usertalk": "Aktibatu erabiltzaileen eztabaida orrien jakinarazpena", @@ -213,13 +237,16 @@ "config-email-auth": "Aktibatu emailaren autentifikazioa.", "config-email-auth-help": "Aukera hau aktibatuta badago, erabiltzaileak konfirmatu behar du bere emaila, sortzerakoen edota aldetzerakoan bidali zaion linka erabiltzen.\n\nBakarrik kautotaku emailak gai izango dira beste erabiltzaileen emailak jasotzeko edota jakinarazpen emailak aldatzeko.\n\nAukera hau hautatzea gomendagarria da Wiki publikoentzat, emaileen erramintien abusua dela eta.", "config-email-sender": "Itzuli helbide elektronikoa:", + "config-email-sender-help": "Idatzi helbide elektronikoa bueltan mezuak jasotzeko helbide elektroniko gisa.\nErreboteak bidaliko dira horra.\nPosta-zerbitzari askok gutxienez domeinu izenaren zati bat behar dute baliozkoa izan dadin.", "config-upload-settings": "Irudi eta fitxategi igoerak", "config-upload-enable": "Fitxategi igoera gaitu", "config-upload-help": "Fitxategiak kargatzeak zure zerbitzaria segurtasun arriskuei eragin diezaioke.\nInformazio gehiagorako, irakurri [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security security section] eskuliburuan.\n\nFitxategiak igotzea aktibatzeko, aldatu images subdirektorio modua MediaWiki-ren erroko direktorioaren azpian, web zerbitzariak honela idatz dezake.\nOndoren, gaitu aukera hau.", "config-upload-deleted": "Ezabatutako artxiboentzako direktorioa:", "config-upload-deleted-help": "Aukeratu fitxategi bat ezabatutako artxiboak gordetzeko.\nGomendagarria da hau webgunetik ez egotea eskuragarri.", "config-logo": "Logo URL:", + "config-logo-help": "MediaWiki-ren lehenetsitako azala alboko barrako menuaren gainetik 135x160 pixeleko logotipo batentzako espazioa dauka.\nKargatu tamaina egokia duen irudia, eta sartu URLa hemen.\n\n$wgStylePath edo $wgScriptPath erabil dezakezu zure logotipoa bide horiei egokitzekotan.\n\nLogotipo bat nahi ez baduzu, utzi lauki hau hutsik.", "config-instantcommons": "Instant Commons gaitu", + "config-instantcommons-help": "[https://www.mediawiki.org/wiki/InstantCommons Instant Commons] aukerak [https://commons.wikimedia.org/ Wikimedia Commons] gunean wikietan aurkitutako irudiak, soinuak eta beste multimedia batzuk erabiltzeko aukera ematen du.\nHorretarako, MediaWiki-k Interneteko sarbidea behar du.\n\nEginbide honi buruzko informazio gehiago lortzeko, wikientzako konfiguratzeko argibideak barne eta Wikimedia Commons-tik at, kontsultatu [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos eskuliburua].", "config-cc-error": "Creative Commons lizentziaren aukeratzaileak ez du emaitzarik eman.\nEskuz sartu lizentzia.", "config-cc-again": "Berriz aukeratu...", "config-cc-not-chosen": "Aukeratu ze Creative Common lizentzi nahi duzu eta sakatu \"proceed\"", @@ -244,6 +271,7 @@ "config-skins-must-enable-some": "Gutxienez aukeratu behar duzu ikusizko estilo bat aktibatzeko.", "config-skins-must-enable-default": "Lehenetsia bezala aukeratu duzun ikusizko estilo aktibatuta egon behar da.", "config-install-alreadydone": "Oharra:Badirudi MediaWikia instalatu daukazula eta berriz instalatzen saiatzen ari zarela.\n\nMesedez, hurrengo orrian jarraitu", + "config-install-begin": "\"{{int:config-continue}}\" sakatuz, MediaWiki instalazioa hasiko duzu.\nAldaketak oraindik egin nahi badituzu, sakatu \"{{int:config-back}}\".", "config-install-step-done": "egina", "config-install-step-failed": "Huts egin du", "config-install-extensions": "Luzapenak barne", @@ -270,6 +298,7 @@ "config-install-interwiki-exists": "Oharra: Interwikiko taula badirudi sarrerak dituela. \nTaula estandarra saltatzen.", "config-install-stats": "Estatistikak hasten", "config-install-keys": "Gako sekretuak sortzen", + "config-insecure-keys": "Oharra: ($1) instalazioan zehar sortu {{PLURAL:$2|den|diren}} {{PLURAL:$2|gako segurua|gako seguruak}}ez d(ir)a guztiz segurua(k). Kontuan hartu {{PLURAL:$2|hau|hauek}} eskuz aldatzeko aukera.", "config-install-updates": "Saihestu egikaratzen behar ez diren aktualizazioak", "config-install-updates-failed": "Errore Sartzea eguneratze-gakoak taulen barruan huts egin du hurrengo errorearekin: $1", "config-install-sysop": "Administratzaile kontua sortzen", @@ -281,6 +310,7 @@ "config-install-mainpage-failed": "Orri nagusia ezin izan da txertatu: $1", "config-install-done": "Zorionak!\nMediaWiki instalatu duzu.\n\nInstalatzaileak LocalSettings.php fitxategia sortu egin du. \nZure konfigurazio guztia darama.\n\nDeskargatu egin beharko duzu eta zure wiki instalazio oinarrian jarri (index.php-rako direktorio berean). Deskarga automakikoki hasi behar izan da.\n\nDeskargatzeko aukerarik ez bazaizu eskaini, edo kantzelatu egin baduzu, hurrengo linkean klikatu berrabiarazteko deskarga:\n\n$3\n\nOharra: Orain ez baduzu egiten, sortutako konfigurazio fitxategi hau ez da erabilgarri egongo geroago instalazioa bertan behera uzten baduzu deskargatu gabe.\n\nBehin hori eginda, [$2 zure wikia sartu] ahal duzu.", "config-install-done-path": "Zorionak!\nMediaWiki instalatu duzu.\n\nInstalatzaileak sortu egin du LocalSettings.php\nZure konfigurazio guztia dauka.\n\nDeskargatu egin behar duzu eta jarri $4 -ean . Deskarga automakikoki hasiko da.\n\nEz badizu deskargatzeko aukerarik eman, edo kantzalatu egin baduzu, hurrengo linkean klikatu berrabiatzeko:\n\n$3\n\nOharra: Instalazio prozesuatik ateratzen bazara konfigurazio artxikoa deskargatu barik, gero ez da egongo eskuragarri.\n\nBehin hori eginda, [$2 enter your wiki] ahal duzu.", + "config-install-success": "MediaWiki arrakastaz instalatu da. Orain <$1$2> bisitatu dezakezu zure wikia ikusteko.\nGalderarik izanez gero, begiratu gure maiztasunez egiten diren galderen zerrenda:\n edo erabili orrialde honi lotuta dauden laguntza foroetako bat.", "config-download-localsettings": "Jaitsi LocalSettings.php", "config-help": "Laguntza", "config-help-tooltip": "sakatu zabaltzeko", diff --git a/includes/installer/i18n/fa.json b/includes/installer/i18n/fa.json index 97a09a3e9c..75252b7bb9 100644 --- a/includes/installer/i18n/fa.json +++ b/includes/installer/i18n/fa.json @@ -317,6 +317,7 @@ "config-install-mainpage-failed": "قادر به درج صفحهٔ اصلی نمی‌باشد:$1", "config-install-done": "'''تبریک!'''\nبا موفقیت مدیاویکی را نصب کردید.\nبرنامه نصب‌کننده پرونده LocalSettings.php را درست کرد.\nکه شامل تمام تنظیمات می‌باشد.\n\nشما نیاز به دریافت آن دارید و آن را در پایهٔ نصب ویکی قرار دهید (همان پوشهٔ index.php). دریافت باید به صورت خودکار شروع شده‌باشد.\n\nاگر دریافت شروع نشد یا اگر آن را لغو کردید با کلیک روی پیوند زیر می‌توانید آن را دریافت کنید:\n\n$3\n\n'''توجه داشته باشید:''' اگر این را الآن انجام ندهید، این پرونده تولیدشده در صورتی که نصب را بدون دریافت آن تمام کردید بعداً در اختیار شما قرار نخواهد گرفت.\n\nوقتی انجام شد شما می‌توانید '''[$2 وارد ویکی شوید]'''.", "config-install-done-path": "تبریک!\nمدیاویکی با موفقیت نصب گردید.\nبرنامه نصب‌کننده یک پرونده LocalSettings.php ایجاد کرده است که شامل تمام تنظیمات می‌باشد.\n\nلازم است شما آن را دریافت کرده و در $4 قرار دهید. اِن دریافت می باِست به صورت خودکار شروع شده‌باشد.\n\nاگر دریافت شروع نشده بود و یا آن را لغو کرده اید با کلیک روی پیوند زیر می‌توانید آن را دریافت کنید:\n\n$3\n\nتوجه: اگر این کار را هم اکنون انجام ندهید و بدون دریافت آن از برنامه نصب خارج شويد، این پرونده تنظیمات تولیدشده در آینده در اختیار شما قرار نخواهد داشت.\n\nوقتی که آن کار را انجام داديد، می‌توانید [$2 وارد ويکی خودتان شويد].", + "config-install-success": "مدیاویکی به صورت موفقیت‌آمیز نصب شد. شما می‌توانید\nاز <$1$2> برای دیدن ویکی‌تان بازدید کنید.\nاگر پرسشی داشتید، فهرست سوال‌های متداول ما را مطالعه کنید:\n یا از یکی از انجمن‌های پشیبانی ما که در آن صفحه فهرست شده‌اند استفاده کنید.", "config-download-localsettings": "دریافت LocalSettings.php", "config-help": "راهنما", "config-help-tooltip": "برای گسترش کلیک کنید", diff --git a/includes/installer/i18n/fi.json b/includes/installer/i18n/fi.json index 6c99a4234e..6b204bc862 100644 --- a/includes/installer/i18n/fi.json +++ b/includes/installer/i18n/fi.json @@ -150,6 +150,7 @@ "config-postgres-old": "MediaWiki tarvitsee PostgreSQL:n version $1 tai uudemman. Nykyinen versio on $2.", "config-mssql-old": "Vaaditaan Microsoft SQL Server $1 tai uudempi. Sinulla on käytössä $2.", "config-sqlite-name-help": "Valitse nimi, joka yksilöi tämän wikin.\nÄlä käytä välilyöntejä tai viivoja.\nNimeä käytetään SQLite-tietokannan tiedostonimessä.", + "config-sqlite-mkdir-error": "Virhe luodessa datakansiota \"$1\".\nTarkista sijainti ja yritä uudelleen", "config-sqlite-dir-unwritable": "Hakemistoon ”$1” kirjoittaminen epäonnistui.\nMuuta hakemiston käyttöoikeuksia siten, että palvelinohjelmisto voi kirjoittaa siihen ja yritä uudelleen.", "config-sqlite-connection-error": "$1.\n\nTarkista tietohakemiston ja tietokannan nimi alla ja yritä uudelleen.", "config-sqlite-readonly": "Tiedostoon $1 ei voi kirjoittaa.", @@ -204,6 +205,7 @@ "config-subscribe": "Liity [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce päivityssähköpostilistalle].", "config-subscribe-help": "Tällä harvoin käytettävällä sähköpostilistalla julkaistaan päivitysilmoituksia ja turvallisuuspäivityksiä.\nLiittymistä listalle suositellaan samoin kuin päivittämään MediaWiki kun uusi versio julkaistaan.", "config-subscribe-noemail": "Yritit liittyä päivityssähköpostilistalle antamatta sähköpostiosoitetta.\nSyötä sähköpostiosoite jos haluat liittyä listalle.", + "config-pingback": "Jaa tietoja tästä asennuksesta MediaWiki-kehittäjien kanssa.", "config-almost-done": "Olet jo lähes valmis!\nVoit ohittaa jäljellä olevat määritykset ja asentaa wikin juuri nyt.", "config-optional-continue": "Säädä lisää asetuksia.", "config-optional-skip": "Nyt riittää, asenna wiki näillä tiedoilla.", @@ -213,6 +215,7 @@ "config-profile-fishbowl": "Vain hyväksytyt muokkaajat", "config-profile-private": "Yksityinen wiki", "config-license": "Tekijänoikeus ja lisenssi:", + "config-license-none": "Ei lisenssin alatunnistetta", "config-license-cc-by-sa": "Creative Commons Nimeä-Tarttuva", "config-license-cc-by": "Creative Commons Nimeä", "config-license-cc-by-nc-sa": "Creative Commons Nimeä-Epäkaupallinen-Tarttuva", @@ -296,7 +299,7 @@ "config-install-subscribe-notpossible": "cURL-ohjelmaa ei ole asennettu eikä allow_url_fopen ole saatavilla.", "config-install-mainpage": "Luodaan etusivu oletussisällöllä", "config-install-mainpage-exists": "Etusivu on jo olemassa, ohitetaan", - "config-install-extension-tables": "Luodaan tauluja käyttöönotetuille laajuennuksille", + "config-install-extension-tables": "Luodaan tauluja käyttöönotetuille laajennuksille", "config-install-mainpage-failed": "Etusivun lisääminen ei onnistunut: $1", "config-install-done": "Onnittelut!\nOlet asentanut MediaWikin.\n\nAsennusohjelma on luonut LocalSettings.php -tiedoston.\nSiinä on kaikki MediaWikin asetukset.\n\nLataa tiedosto ja laita se MediaWikin asennushakemistoon (sama kuin missä on index.php). Lataamisen olisi pitänyt alkaa automaattisesti.\n\nMikäli latausta ei tarjottu tai keskeytit latauksen, käynnistä se uudestaan tästä linkistä:\n\n$3\n\nHuom: Mikäli et nyt lataa tiedostoa, luotu tiedosto ei ole saatavissa myöhemmin, jos poistut asennuksesta lataamatta sitä.\n\nKun olet laittanut tiedoston oikeaan paikkaan, voit [$2 mennä wikiisi].", "config-install-done-path": "Onnittelut!\nOlet asentanut MediaWikin.\n\nAsennusohjelma on luonut LocalSettings.php -tiedoston.\nSiinä on kaikki MediaWikin asetukset.\n\nLataa tiedosto ja laita se sijaintiin $4. Lataamisen olisi pitänyt alkaa automaattisesti.\n\nMikäli latausta ei tarjottu tai keskeytit latauksen, käynnistä se uudestaan tästä linkistä:\n\n$3\n\nHuom: Mikäli et nyt lataa tiedostoa, luotu tiedosto ei ole saatavissa myöhemmin, jos poistut asennuksesta lataamatta sitä.\n\nKun olet laittanut tiedoston oikeaan paikkaan, voit [$2 mennä wikiisi].", @@ -305,6 +308,8 @@ "config-help-tooltip": "Klikkaa laajentaaksesi", "config-nofile": "Tiedostoa \"$1\" ei löytynyt. Onko se poistettu?", "config-extension-link": "Tiesitkö että wiki tukee [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions laajennuksia]?\n\nLaajennuksia voi hakea myös [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category luokittain].", + "config-skins-screenshots": "$1 (kuvakaappaukset: $2)", + "config-screenshot": "kuvakaappaus", "mainpagetext": "MediaWiki on onnistuneesti asennettu.", "mainpagedocfooter": "Lisätietoja wiki-ohjelmiston käytöstä on [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents käyttöoppaassa].\n\n=== Aloittaminen ===\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Asetusten teko-ohjeita]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWikin FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Sähköpostilista, jolla tiedotetaan MediaWikin uusista versioista]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Käännä MediaWikiä kielellesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Katso, kuinka torjua spämmiä wikissäsi]\n\n=== Asetukset ===\n\nTarkista, että alla olevat taivutusmuodot ovat oikein. Jos eivät, tee tarvittavat muutokset tiedostoon LocalSettings.php seuraavasti:\n $wgGrammarForms['fi']['genitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['partitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['elative']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['inessive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['illative']['{{SITENAME}}'] = '...';\nTaivutusmuodot: {{GRAMMAR:genitive|{{SITENAME}}}} (yön) – {{GRAMMAR:partitive|{{SITENAME}}}} (yötä) – {{GRAMMAR:elative|{{SITENAME}}}} (yöstä) – {{GRAMMAR:inessive|{{SITENAME}}}} (yössä) – {{GRAMMAR:illative|{{SITENAME}}}} (yöhön)." } diff --git a/includes/installer/i18n/fr.json b/includes/installer/i18n/fr.json index 2bfe36f574..57c6acbc44 100644 --- a/includes/installer/i18n/fr.json +++ b/includes/installer/i18n/fr.json @@ -28,7 +28,8 @@ "C13m3n7", "The RedBurn", "Trial", - "Tinss" + "Tinss", + "Thibaut120094" ] }, "config-desc": "Le programme d’installation de MediaWiki", @@ -68,37 +69,37 @@ "config-help-restart": "Voulez-vous effacer toutes les données enregistrées que vous avez entrées et relancer le processus d'installation ?", "config-restart": "Oui, le relancer", "config-welcome": "=== Vérifications liées à l’environnement ===\nDes vérifications de base vont maintenant être effectuées pour voir si cet environnement est adapté à l’installation de MediaWiki.\nRappelez-vous d’inclure ces informations si vous recherchez de l’aide sur la manière de terminer l’installation.", - "config-copyright": "=== Droit d’auteur et conditions ===\n\n$1\n\nCe programme est un logiciel gratuit : vous pouvez le redistribuer ou le modifier selon les termes de la Licence Publique Générale GNU telle que publiée par la Free Software Foundation (version 2 de la Licence, ou, à votre choix, toute version ultérieure).\n\nCe programme est distribué dans l’espoir qu’il sera utile, mais '''sans aucune garantie''' : sans même les garanties implicites de '''commercialisabilité''' ou d’'''adéquation à un usage particulier'''.\nVoir la Licence Publique Générale GNU pour plus de détails.\n\nVous devriez avoir reçu une copie de la Licence Publique Générale GNU avec ce programme ; dans le cas contraire, écrivez à la Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ou [http://www.gnu.org/copyleft/gpl.html lisez-la en ligne].", + "config-copyright": "=== Droit d’auteur et conditions ===\n\n$1\n\nCe programme est un logiciel libre : vous pouvez le redistribuer ou le modifier selon les termes de la Licence Publique Générale GNU telle que publiée par la Free Software Foundation (version 2 de la Licence, ou, à votre choix, toute version ultérieure).\n\nCe programme est distribué dans l’espoir qu’il sera utile, mais '''sans aucune garantie''' : sans même les garanties implicites de '''commercialisabilité''' ou d’'''adéquation à un usage particulier'''.\nVoir la Licence Publique Générale GNU pour plus de détails.\n\nVous devriez avoir reçu une copie de la Licence Publique Générale GNU avec ce programme ; dans le cas contraire, écrivez à la Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ou [http://www.gnu.org/copyleft/gpl.html lisez-la en ligne].", "config-sidebar": "* [https://www.mediawiki.org Accueil MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guide de l’utilisateur]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guide de l’administrateur]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* Lisez-moi\n* Notes de publication\n* Copie\n* Mise à jour", "config-env-good": "L’environnement a été vérifié.\nVous pouvez installer MediaWiki.", "config-env-bad": "L’environnement a été vérifié.\nVous ne pouvez pas installer MediaWiki.", "config-env-php": "PHP $1 est installé.", "config-env-hhvm": "HHVM $1 est installé.", - "config-unicode-using-intl": "Utilisation de [http://pecl.php.net/intl l'extension PECL intl] pour la normalisation Unicode.", - "config-unicode-pure-php-warning": "Attention : L’[http://pecl.php.net/intl extension PECL intl] n’est pas disponible pour la normalisation d’Unicode, retour à la version lente implémentée en PHP.\nSi votre site web sera très fréquenté, vous devriez lire ceci : [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (en anglais).", - "config-unicode-update-warning": "Attention: La version installée du normalisateur Unicode utilise une ancienne version de la [http://site.icu-project.org/ bibliothèque logicielle ''ICU Project''].\nVous devriez faire une [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations mise à jour] si vous êtes concerné par l'usage d'Unicode.", + "config-unicode-using-intl": "Utilisation de [http://pecl.php.net/intl l’extension PECL intl] pour la normalisation Unicode.", + "config-unicode-pure-php-warning": "Attention : L’[http://pecl.php.net/intl extension PECL intl] n’est pas disponible pour la normalisation d’Unicode, retour à la version lente implémentée en PHP seulement.\nSi votre site web sera très fréquenté, vous devriez lire ceci : [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (en anglais).", + "config-unicode-update-warning": "Attention : la version installée du normalisateur Unicode utilise une ancienne version de la bibliothèque logicielle du [http://site.icu-project.org/ ''Projet ICU''].\nVous devriez faire une [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations mise à jour] si vous êtes concerné par l’usage d’Unicode.", "config-no-db": "Impossible de trouver un pilote de base de données approprié ! Vous devez installer un pilote de base de données pour PHP. {{PLURAL:$2|Le type suivant|Les types suivants}} de bases de données {{PLURAL:$2|est reconnu|sont reconnus}} : $1.\n\nSi vous avez compilé PHP vous-même, reconfigurez-le avec un client de base de données actif, par exemple en utilisant ./configure --with-mysqli. Si vous avez installé PHP depuis un paquet Debian ou Ubuntu, alors vous devrez aussi installer, par exemple, le paquet php5-mysql.", - "config-outdated-sqlite": "'''Attention''': vous avez SQLite $1, qui est inférieur à la version minimale requise $2. SQLite sera indisponible.", - "config-no-fts3": "'''Attention :''' SQLite est compilé sans le module [//sqlite.org/fts3.html FTS3] ; les fonctions de recherche ne seront pas disponibles sur ce moteur.", - "config-pcre-old": "'''Fatal :''' PCRE $1 ou ultérieur est nécessaire.\nVotre binaire PHP est lié avec PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Plus d’information sur PCRE].", - "config-pcre-no-utf8": "Erreur fatale: le module PCRE de PHP semble être compilé sans la prise en charge de PCRE_UTF8.\nMédiaWiki a besoin de la gestion d’UTF-8 pour fonctionner correctement.", + "config-outdated-sqlite": "Attention : vous avez SQLite $1, qui est inférieur à la version minimale requise $2. SQLite sera indisponible.", + "config-no-fts3": "Attention : SQLite est compilé sans le [//sqlite.org/fts3.html module FTS3] ; les fonctions de recherche ne seront pas disponibles sur ce moteur.", + "config-pcre-old": "Erreur fatale : PCRE $1 ou ultérieur est nécessaire.\nVotre binaire PHP est lié avec PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Plus d’information sur PCRE].", + "config-pcre-no-utf8": "Erreur fatale : le module PCRE de PHP semble être compilé sans la prise en charge de PCRE_UTF8.\nMediaWiki a besoin de la gestion d’UTF-8 pour fonctionner correctement.", "config-memory-raised": "Le paramètre memory_limit de PHP était à $1, porté à $2.", - "config-memory-bad": "'''Attention :''' Le paramètre memory_limit de PHP est à $1.\nCette valeur est probablement trop faible.\nIl est possible que l’installation échoue !", + "config-memory-bad": "Attention : Le paramètre memory_limit de PHP est à $1.\nCette valeur est probablement trop faible.\nIl est possible que l’installation échoue !", "config-xcache": "[http://xcache.lighttpd.net/ XCache] est installé", "config-apc": "[http://www.php.net/apc APC] est installé", "config-apcu": "[http://www.php.net/apcu APCu] est installé", "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] est installé", - "config-no-cache-apcu": "Attention : Impossible de trouver [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ou [http://www.iis.net/download/WinCacheForPhp WinCache].\nLa mise en cache d'objets n'est pas activée.", - "config-mod-security": "'''Attention''': Votre serveur web a [http://modsecurity.org/ mod_security] activé. S’il est mal configuré, cela peut poser des problèmes à MediaWiki ou à d’autres applications qui permettent aux utilisateurs de publier un contenu quelconque.\nReportez-vous à [http://modsecurity.org/documentation/ la documentation de mod_security] ou contactez le soutien de votre hébergeur si vous rencontrez des erreurs aléatoires.", + "config-no-cache-apcu": "Attention : impossible de trouver [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ou [http://www.iis.net/download/WinCacheForPhp WinCache].\nLa mise en cache d’objets n’est pas activée.", + "config-mod-security": "Attention : votre serveur web a [http://modsecurity.org/ mod_security] activé. S’il est mal configuré, cela peut poser des problèmes à MediaWiki ou à d’autres applications qui permettent aux utilisateurs de publier un contenu quelconque. Si possible, ceci devrait être désactivé. Sinon, reportez-vous à [http://modsecurity.org/documentation/ la documentation de mod_security] ou contactez l’assistance de votre hébergeur si vous rencontrez des erreurs aléatoires.", "config-diff3-bad": "GNU diff3 introuvable.", "config-git": "Logiciel de contrôle de version Git trouvé : $1.", "config-git-bad": "Logiciel de contrôle de version Git non trouvé.", - "config-imagemagick": "ImageMagick trouvé : $1.\nLa miniaturisation d'images sera activée si vous activez le téléversement de fichiers.", + "config-imagemagick": "ImageMagick trouvé : $1.\nLa génération de vignettes d’images sera activée si vous activez les téléversements.", "config-gd": "La bibliothèque graphique GD intégrée a été trouvée.\nLa miniaturisation d'images sera activée si vous activez le téléversement de fichiers.", - "config-no-scaling": "Impossible de trouver la bibliothèque GD ou ImageMagick.\nLa miniaturisation d'images sera désactivée.", - "config-no-uri": "'''Erreur :''' Impossible de déterminer l'URI du script actuel.\nInstallation interrompue.", - "config-no-cli-uri": "'''Attention''': Aucun --scriptpath n'a été spécifié; $1 sera utilisé par défaut", - "config-using-server": "Utilisation du nom de serveur \"$1\".", + "config-no-scaling": "Impossible de trouver la bibliothèque GD ou ImageMagick.\nLa miniaturisation d’images sera désactivée.", + "config-no-uri": "Erreur : impossible de déterminer l’URI du script actuel.\nInstallation interrompue.", + "config-no-cli-uri": "Attention : Aucun --scriptpath n’a été spécifié ; $1 sera utilisé par défaut.", + "config-using-server": "Utilisation du nom de serveur « $1 ».", "config-using-uri": "Utilisation de l'URL de serveur \"$1$2\".", "config-uploads-not-safe": "Attention : Votre répertoire par défaut pour les téléversements, $1, est vulnérable, car il peut exécuter n’importe quel script.\nBien que MediaWiki vérifie tous les fichiers téléversés, il est fortement recommandé de [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security fermer cette faille de sécurité] (texte en anglais) avant d’activer les téléversements.", "config-no-cli-uploads-check": "'''Attention:''' Votre répertoire par défaut pour les imports($1) n'est pas contrôlé concernant la vulnérabilité d'exécution de scripts arbitraires lors de l'installation CLI.", @@ -143,7 +144,7 @@ "config-support-info": "MediaWiki prend en charge ces systèmes de bases de données :\n\n$1\n\nSi vous ne voyez pas le système de base de données que vous essayez d’utiliser ci-dessous, alors suivez les instructions ci-dessus (voir liens) pour activer la prise en charge.", "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] est le premier choix pour MediaWiki et est le mieux pris en charge. MediaWiki fonctionne aussi avec [{{int:version-db-mariadb-url}} MariaDB] et [{{int:version-db-percona-url}} Percona Server], qui sont compatibles avec MySQL. ([http://www.php.net/manual/en/mysqli.installation.php Comment compiler PHP avec la prise en charge de MySQL])", "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] est un système de base de données populaire en ''source ouverte'' qui peut être une alternative à MySQL ([http://www.php.net/manual/en/pgsql.installation.php Comment compiler PHP avec la prise en charge de PostgreSQL]).", - "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] est un système de base de données léger bien pris en charge. ([http://www.php.net/manual/fr/pdo.installation.php Comment compiler PHP avec la prise en charge de SQLite], en utilisant PDO)", + "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] est un système de base de données léger bien pris en charge ([http://www.php.net/manual/fr/pdo.installation.php Comment compiler PHP avec la prise en charge de SQLite], en utilisant PDO).", "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] est un système commercial de gestion de base de données d’entreprise. ([http://www.php.net/manual/en/oci8.installation.php Comment compiler PHP avec la prise en charge d’OCI8])", "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] est une base de données commerciale d’entreprise pour Windows. ([http://www.php.net/manual/en/sqlsrv.installation.php Comment compiler PHP avec la prise en charge de SQLSRV])", "config-header-mysql": "Paramètres de MySQL", @@ -237,7 +238,7 @@ "config-profile-no-anon": "Création de compte requise", "config-profile-fishbowl": "Éditeurs autorisés seulement", "config-profile-private": "Wiki privé", - "config-profile-help": "Les wikis fonctionnent au mieux lorsque vous laissez un maximum de personnes les modifier.\nAvec MediaWiki, il est facile de vérifier les modifications récentes et de révoquer tout dommage créé par des utilisateurs débutants ou mal intentionnés.\n\nCependant, MediaWiki est utilisé dans bien d’autres cas et il n’est pas toujours facile de convaincre chacun des bénéfices de l’esprit wiki.\nVous avez donc le choix.\n\nLe modèle {{int:config-profile-wiki}} autorise toute personne à modifier, y compris sans s’identifier.\n{{int:config-profile-no-anon}} fournit plus de contrôle, mais peut rebuter les contributeurs occasionnels.\n\n{{int:config-profile-fishbowl}} autorise la modification par les utilisateurs approuvés mais le public peut toujours consulter les pages et leur historique.\n{{int:config-profile-private}} n’autorise que les utilisateurs approuvés à voir et modifier les pages.\n\nDes configurations de droits d’utilisateurs plus complexes sont disponibles après l’installation, voir la [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights page correspondante du manuel].", + "config-profile-help": "Les wikis fonctionnent au mieux lorsque vous laissez un maximum de personnes les modifier.\nAvec MediaWiki, il est facile de vérifier les modifications récentes et de révoquer tout dommage créé par des utilisateurs débutants ou mal intentionnés.\n\nCependant, MediaWiki est utilisé dans bien d’autres cas et il n’est pas toujours facile de convaincre chacun des bénéfices de l’esprit wiki.\nVous avez donc le choix.\n\nLe modèle {{int:config-profile-wiki}} autorise toute personne à modifier, y compris sans s’identifier.\nUn wiki avec {{int:config-profile-no-anon}} fournit plus de contrôle, mais peut rebuter les contributeurs occasionnels.\n\nLe scénario {{int:config-profile-fishbowl}} autorise la modification par les utilisateurs approuvés mais le public peut toujours consulter les pages et leur historique.\n{{int:config-profile-private}} n’autorise que les utilisateurs approuvés à voir et modifier les pages.\n\nDes configurations de droits d’utilisateurs plus complexes sont disponibles après l’installation, voir la [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights page correspondante du manuel].", "config-license": "Droits d'auteur et licence :", "config-license-none": "Aucune licence en bas de page", "config-license-cc-by-sa": "Creative Commons attribution partage à l'identique", @@ -333,6 +334,7 @@ "config-install-mainpage-failed": "Impossible d’insérer la page principale : $1", "config-install-done": "Félicitations!\nVous avez installé MediaWiki.\n\nLe programme d'installation a généré un fichier LocalSettings.php. Il contient tous les paramètres de votre configuration.\n\nVous devrez le télécharger et le mettre à la racine de votre installation wiki (dans le même répertoire que index.php). Le téléchargement devrait démarrer automatiquement.\n\nSi le téléchargement n'a pas été proposé, ou que vous l'avez annulé, vous pouvez redémarrer le téléchargement en cliquant ce lien :\n\n$3\n\nNote : Si vous ne le faites pas maintenant, ce fichier de configuration généré ne sera pas disponible plus tard si vous quittez l'installation sans le télécharger.\n\nLorsque c'est fait, vous pouvez [$2 accéder à votre wiki] .", "config-install-done-path": "Félicitations !\nVous avez installé MédiaWiki.\n\nL’installeur a généré un fichier LocalSettings.php.\nIl contient toute votre configuration.\n\nVous devez le télécharger et le mettre dans $4. Le téléchargement devrait avoir démarré automatiquement.\n\nSi le téléchargement n’a pas été proposé ou si vous l’avez annulé, vous pouvez le redémarrer en cliquant sur le lien ci-dessous :\n\n$3\n\nNote : Si vous ne le faites pas maintenant, ce fichier de configuration généré ne sera plus disponible ultérieurement si vous quittez l’installation sans le télécharger.\n\nUne fois ceci fait, vous pouvez [$2 entrer dans votre wiki].", + "config-install-success": "MédiaWiki a bien été installé. Vous pouvez maintenant\nvisiter <$1$2> pour voir votre wiki.\nSi vous avez des questions, consultez notre liste de questions fréquemment posées :\n ou utilisez un des\nforums de soutien liés sur cette page.", "config-download-localsettings": "Télécharger LocalSettings.php", "config-help": "aide", "config-help-tooltip": "cliquer pour agrandir", @@ -341,5 +343,5 @@ "config-skins-screenshots": "$1 (captures d’écran : $2)", "config-screenshot": "Captures d’écrans", "mainpagetext": "MediaWiki a été installé.", - "mainpagedocfooter": "Consultez le [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guide de l’utilisateur du contenu] pour plus d’informations sur l’utilisation de ce logiciel de wiki.\n\n== Pour démarrer ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Liste des paramètres de configuration]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/fr Questions courantes sur MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Liste de discussion sur les distributions de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Adaptez MediaWiki dans votre langue]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Apprendre comment lutter contre le pourriel dans votre wiki]" + "mainpagedocfooter": "Consultez le [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guide de l’utilisateur] pour plus d’informations sur l’utilisation de ce logiciel de wiki.\n\n== Pour démarrer ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Liste des paramètres de configuration]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/fr Questions courantes sur MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Liste de discussion sur les distributions de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Adaptez MediaWiki dans votre langue]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Apprendre comment lutter contre le pourriel dans votre wiki]" } diff --git a/includes/installer/i18n/gl.json b/includes/installer/i18n/gl.json index e6e4b67455..08434f6af1 100644 --- a/includes/installer/i18n/gl.json +++ b/includes/installer/i18n/gl.json @@ -312,6 +312,7 @@ "config-install-mainpage-failed": "Non se puido inserir a páxina principal: $1", "config-install-done": "Parabéns!\nInstalou MediaWiki.\n\nO programa de instalación xerou un ficheiro LocalSettings.php.\nEste ficheiro contén toda a súa configuración.\n\nTerá que descargalo e poñelo na base da instalación do seu wiki (no mesmo directorio ca index.php). A descarga debería comezar automaticamente.\n\nSe non comezou a descarga ou se a cancelou, pode facer que comece de novo premendo na ligazón que aparece a continuación:\n\n$3\n\nNota: Se non fai iso agora, este ficheiro de configuración xerado non estará dispoñible máis adiante se sae da instalación sen descargalo.\n\nCando faga todo isto, xa poderá [$2 entrar no seu wiki].", "config-install-done-path": "Parabéns!\nInstalou MediaWiki.\n\nO instalador xerou un ficheiro LocalSettings.php.\nEste contén toda a súa configuración.\n\nDeberá descargalo e poñerlo en $4. A descarga debería ter comezado automaticamente.\n\nSe non comenzou a descarga, ou se a cancelou, podes reiniciala descarga premendo na seguinte ligazón:\n\n$3\n\nNota: se non fai isto agora, este ficheiro de configuración xerado non estará dispoñible máis tarde se sae da instalación sen descargarlo.\n\nCando o teña feito, poderá [$2 entrar na súa wiki].", + "config-install-success": "MediaWiki instalouse con éxito. Agora podes \nvisitar <$1$2> para ver a túa wiki.\nSe tes dúbidas, revisa a nosa lista de preguntas frecuentes:\n ou usa un dos\nforos de axuda ligados nesa páxina.", "config-download-localsettings": "Descargar o LocalSettings.php", "config-help": "axuda", "config-help-tooltip": "prema para expandir", diff --git a/includes/installer/i18n/he.json b/includes/installer/i18n/he.json index 7583455207..e2dfea8c53 100644 --- a/includes/installer/i18n/he.json +++ b/includes/installer/i18n/he.json @@ -312,6 +312,7 @@ "config-install-mainpage-failed": "לא הצליחה הכנסת דף ראשי: $1.", "config-install-done": "מזל טוב!\nהתקנת את תוכנת מדיה־ויקי.\n\nתוכנת ההתקנה יצרה את הקובץ LocalSettings.php.\nהוא מכיל את כל ההגדרות שלך.\n\nיש להוריד אותו ולהכניס אותו לתיקיית הבסיס שבה הותקן הוויקי שלך (אותה התיקייה שבה נמצא הקובץ index.php). ההורדה אמורה להתחיל באופן אוטומטי.\n\nאם ההורדה לא התחילה, או אם ביטלת אותה, אפשר להתחיל אותה מחדש באמצעות לחיצה על הקישור הבא:\n\n$3\n\nלתשומת לבך: אם ההורדה לא תבוצע כעת, קובץ ההגדרות לא יהיה זמין מאוחר יותר אם תוכנת ההתקנה תיסגר לפני שהקובץ יורד.\n\nלאחר שביצעת את הפעולות שלהלן, באפשרותך [$2 להיכנס לאתר הוויקי שלך].", "config-install-done-path": "מזל טוב!\nהתקנת את תוכנת מדיה־ויקי.\n\nתוכנת ההתקנה יצרה את הקובץ LocalSettings.php.\nהוא מכיל את כל ההגדרות שלך.\n\nיש להוריד אותו ולהכניס אותו לתיקייה $4. ההורדה אמורה להתחיל באופן אוטומטי.\n\nאם ההורדה לא התחילה, או אם ביטלת אותה, אפשר להתחיל אותה מחדש באמצעות לחיצה על הקישור הבא:\n\n$3\n\nלתשומת לבך: אם ההורדה לא תבוצע כעת, קובץ ההגדרות לא יהיה זמין מאוחר יותר אם תוכנת ההתקנה תיסגר לפני שהקובץ יורד.\n\nלאחר שביצעת את הפעולות שלהלן, באפשרותך [$2 להיכנס לאתר הוויקי שלך].", + "config-install-success": "מדיה־ויקי הותקנה בהצלחה. עכשיו אפשר\nלבקר בכתובת <$1$2> כדי לצפות בוויקי שלך.\nאם יש לך שאלות, ר' את רשימת השאלות הנפוצות שלנו:\n ואפשר גם להשתמש\nבאתרי התמיכה שקישורים אליהם מופיעים באותו הדף.", "config-download-localsettings": "הורדת LocalSettings.php", "config-help": "עזרה", "config-help-tooltip": "להרחיב", diff --git a/includes/installer/i18n/ia.json b/includes/installer/i18n/ia.json index e1625fbd72..76748956de 100644 --- a/includes/installer/i18n/ia.json +++ b/includes/installer/i18n/ia.json @@ -308,6 +308,7 @@ "config-install-mainpage-failed": "Non poteva inserer le pagina principal: $1", "config-install-done": "Felicitationes!\nTu ha installate MediaWiki.\n\nLe installator ha generate un file LocalSettings.php.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in le base del installation wiki (le mesme directorio que index.php).\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, recomencia le discargamento con un clic sur le ligamine sequente:\n\n$3\n\nNota: Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote [$2 entrar in tu wiki].", "config-install-done-path": "Felicitationes!\nTu ha installate MediaWiki.\n\nLe installator ha generate un file LocalSettings.php.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in $4.\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, recomencia le discargamento con un clic sur le ligamine sequente:\n\n$3\n\nNota: Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote [$2 entrar in tu wiki].", + "config-install-success": "MediaWiki ha essite installate con successo. Tu pote ora\nvisitar <$1$2> pro vider tu wiki.\nSi tu ha questiones, consulta nostre lista de questiones frequentemente ponite:\n o usa un del\nforos de supporto indicate sur ille pagina.", "config-download-localsettings": "Discargar LocalSettings.php", "config-help": "adjuta", "config-help-tooltip": "clicca pro displicar", diff --git a/includes/installer/i18n/ko.json b/includes/installer/i18n/ko.json index f268215f1d..fcc54689e8 100644 --- a/includes/installer/i18n/ko.json +++ b/includes/installer/i18n/ko.json @@ -315,6 +315,7 @@ "config-install-mainpage-failed": "대문을 삽입할 수 없습니다: $1", "config-install-done": "축하합니다!\n미디어위키를 설치했습니다.\n\n설치 관리자가 LocalSettings.php 파일을 만들었습니다.\n여기에 모든 설정이 포함되어 있습니다.\n\n파일을 다운로드하여 위키 설치의 거점에 넣어야 합니다. (index.php와 같은 디렉터리) 다운로드가 자동으로 시작됩니다.\n\n다운로드가 제공되지 않을 경우나 그것을 취소한 경우에는 아래의 링크를 클릭하여 다운로드를 다시 시작할 수 있습니다:\n\n$3\n\n참고: 이 생성한 설정 파일을 다운로드하지 않고 설치를 끝내면 이 파일은 나중에 사용할 수 없습니다.\n\n완료되었으면 [$2 위키에 들어갈 수 있습니다].", "config-install-done-path": "축하합니다!\n미디어위키가 설치되었습니다.\n\n설치 관리자가 LocalSettings.php 파일을 생성했습니다.\n이 파일에 모든 설정이 포함되어 있습니다.\n\n이 파일을 다운로드하여 $4 위치에 넣으세요. 다운로드가 자동으로 시작되었을 것입니다.\n\n다운로드가 시작되지 않았거나 취소했다면, 아래 링크를 클릭하여 다운로드를 재시작할 수 있습니다.\n\n$3\n\n알림: 지금 다운로드하지 않는다면, 이후에는 이 설정 파일을 다운로드할 수 없습니다.\n\n모든 작업이 완료되었다면, [$2 위키에 들어갈 수 있습니다].", + "config-install-success": "미디어위키가 성공적으로 설치되었습니다. 이제\n<$1$2>에 방문하여 위키를 볼 수 있습니다.\n질문이 있으시다면 자주 묻는 질문 목록을 살펴보십시오:\n 아니면\n해당 문서에 연결된 지원 포럼 중 한곳을 이용하십시오.", "config-download-localsettings": "LocalSettings.php 다운로드", "config-help": "도움말", "config-help-tooltip": "확장하려면 클릭", diff --git a/includes/installer/i18n/mk.json b/includes/installer/i18n/mk.json index d028a8c4d8..ee5bb8de23 100644 --- a/includes/installer/i18n/mk.json +++ b/includes/installer/i18n/mk.json @@ -230,7 +230,7 @@ "config-email-user": "Овозможи е-пошта од корисник до корисник", "config-email-user-help": "Дозволи сите корисници да можат да си праќаат е-пошта ако ја имаат овозможено во нагодувањата.", "config-email-usertalk": "Овозможи известувања за промени во кориснички страници за разговор", - "config-email-usertalk-help": "Овозможи корисниците да добиваат известувања за промени во нивните кориснички страници за разговор ако ги имаат овозможено во нагодувањата.", + "config-email-usertalk-help": "Овозможи корисниците да добиваат известувања за промени во нивните кориснички разговорни страници ако ги имаат овозможено во нагодувањата.", "config-email-watchlist": "Овозможи известувања за список на набљудувања", "config-email-watchlist-help": "Овозможи корисниците да добиваат известувања за нивните набљудувани страници ако ги имаат овозможено во нагодувањата.", "config-email-auth": "Овозможи потврдување на е-пошта", @@ -309,6 +309,7 @@ "config-install-mainpage-failed": "Не можев да вметнам главна страница: $1", "config-install-done": "Честитаме!\nУспешно го воспоставивте МедијаВики.\n\nВоспоставувачот создаде податотека LocalSettings.php.\nТаму се содржат сите ваши нагодувања.\n\nЌе треба да ја преземете и да ја ставите во основата на воспоставката (истата папка во која се наоѓа index.php). Преземањето треба да е започнато автоматски.\n\nАко не ви е понудено преземање, или пак ако сте го откажале, можете да го почнете одново стискајќи на следнава врска:\n\n$3\n\nНапомена: Ако ова не го направите сега, податотеката со поставки повеќе нема да биде на достапна.\n\nОткога ќе завршите со тоа, можете да [$2 влезете на вашето вики].", "config-install-done-path": "Честитаме!\nГо воспоставивте МедијаВики.\n\nВоспоставувачот создаде податотека LocalSettings.php.\nТаму се содржат сите ваши нагодувања.\n\nЌе треба да ја преземете и да ја ставите во $4. Преземањето треба да е започнато автоматски.\n\nАко не ви е понудено преземање, или пак ако сте го откажале, можете да го почнете одново стискајќи на следнава врска:\n\n$3\n\nНапомена: Ако ова не го направите сега, создадената податотека со поставки повеќе нема да биде на достапна, освен ако не ја преземете пред да излезете.\n\nОткога ќе завршите со тоа, можете да [$2 влезете на вашето вики].", + "config-install-success": "МедијаВики е успешно воспоставен. Сега можете да појдете на <$1$2> за да го погледате вашето вики.\nАко имате било какви прашања, погледајте го списокот на често поставувани прашања:\n или појдете на еден од форумите за поддршка наведени на таа страница.", "config-download-localsettings": "Преземи го LocalSettings.php", "config-help": "помош", "config-help-tooltip": "стиснете да расклопите", diff --git a/includes/installer/i18n/nb.json b/includes/installer/i18n/nb.json index 1eb418ed45..c271a90ad3 100644 --- a/includes/installer/i18n/nb.json +++ b/includes/installer/i18n/nb.json @@ -52,7 +52,7 @@ "config-copyright": "=== Opphavsrett og vilkår ===\n\n$1\n\nMediaWiki er fri programvare; du kan redistribuere det og/eller modifisere det under betingelsene i GNU General Public License som publisert av Free Software Foundation; enten versjon 2 av lisensen, eller (etter eget valg) enhver senere versjon.\n\nDette programmet er distribuert i håp om at det vil være nyttig, men '''uten noen garanti'''; ikke engang implisitt garanti av '''salgbarhet''' eller '''egnethet for et bestemt formål'''.\nSe GNU General Public License for flere detaljer.\n\nDu skal ha mottatt en kopi av GNU General Public License sammen med dette programmet; hvis ikke, skriv til Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA eller [http://www.gnu.org/copyleft/gpl.html les det på nettet].", "config-sidebar": "* [https://www.mediawiki.org MediaWiki hjem]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Brukerguide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Administratorguide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ OSS]\n----\n* Les meg\n* Utgivelsesnotater\n* Kopiering\n* Oppgradering", "config-env-good": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.", - "config-env-bad": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.", + "config-env-bad": "Miljøet har blitt sjekket.\nDu kan ikke installere MediaWiki.", "config-env-php": "PHP $1 er installert.", "config-env-hhvm": "HHVM $1 er installert.", "config-unicode-using-intl": "Bruker [http://pecl.php.net/intl intl PECL-utvidelsen] for Unicode-normalisering.", @@ -314,6 +314,7 @@ "config-install-mainpage-failed": "Kunne ikke sette inn hovedside: $1", "config-install-done": "Gratulrerer!\nDu har lykkes i å installere MediaWiki.\n\nInstallasjonsprogrammet har generert en LocalSettings.php-fil.\nDen inneholder alle dine konfigureringer.\n\nDu må laste den ned og legge den på hovedfolderen for din wiki-installasjon (der index.php ligger). Nedlastingen skulle ha startet automatisk.\n\nHvis ingen nedlasting ble tilbudt, eller du avbrøt den, kan du få den i gang ved å klikke på lenken under:\n\n$3\n\nOBS: Hvis du ikke gjør dette nå, vil den genererte konfigurasjonsfilen ikke være tilgjengelig for deg senere.\n\nNår dette er gjort, kan du [$2 gå inn i wikien].", "config-install-done-path": "Gratulerer!\nDu har installert MediaWiki.\n\nInstallereren har generert en LocalSettings.php-fil.\nDen inneholder all konfigurasjonen for wikien.\n\nDu må laste den ned og legge den i $4. Nedlastingen skal ha startet automatisk.\n\nOm nedlastingen ikke ble startet, eller om du avbrøt den, kan du starte på nytt ved å klikke lenken nedenfor:\n\n$3\n\nMerk: Om du ikke gjør dette nå vil den genererte konfigurasjonen ikke være tilgjengelig senere.\n\nNår dette er gjort kan du [$2 gå til wikien din].", + "config-install-success": "MediaWiki har blitt installert. Du kan nå\nbesøke <$1$2> for å se wikien din.\nOm du har spørsmål, sjekk de ofte stilte spørsmålene:\n eller bruk et av\nsupportforumene som lenkes til fra den siden.", "config-download-localsettings": "Last ned LocalSettings.php", "config-help": "hjelp", "config-help-tooltip": "klikk for å utvide", diff --git a/includes/installer/i18n/nl-informal.json b/includes/installer/i18n/nl-informal.json index 299b3b140b..8b8dbc6776 100644 --- a/includes/installer/i18n/nl-informal.json +++ b/includes/installer/i18n/nl-informal.json @@ -3,7 +3,8 @@ "authors": [ "Siebrand", "Seb35", - "Macofe" + "Macofe", + "Mar(c)" ] }, "config-localsettings-badkey": "De sleutel die je hebt opgegeven is onjuist", @@ -29,7 +30,7 @@ "config-db-host-help": "Als je databaseserver een andere server is, voer dan de hostnaam of het IP-adres hier in.\n\nAls je gebruik maakt van gedeelde webhosting, hoort je provider je de juiste hostnaam te hebben verstrekt.\n\nAls je MediaWiki op een Windowsserver installeert en MySQL gebruikt, dan werkt \"localhost\" mogelijk niet als servernaam.\nAls het inderdaad niet werkt, probeer dan \"127.0.0.1\" te gebruiken als lokaal IP-adres.\n\nAls je PostgreSQL gebruikt, laat dit veld dan leeg om via een Unix-socket te verbinden.", "config-db-host-oracle-help": "Voer een geldige [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name] in; een tnsnames.ora-bestand moet zichtbaar zijn voor deze installatie.
Als je gebruik maakt van clientlibraries 10g of een latere versie, kan je ook gebruik maken van de naamgevingsmethode [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].", "config-db-name-help": "Kies een naam die je wiki identificeert.\nEr mogen geen spaties gebruikt worden.\nAls je gebruik maakt van gedeelde webhosting, dan hoort je provider ofwel jou een te gebruiken databasenaam gegeven te hebben, of je aangegeven te hebben hoe je databases kunt aanmaken.", - "config-db-account-oracle-warn": "Er zijn drie ondersteunde scenario's voor het installeren van Oracle als databasebackend:\n\nAls je een databasegebruiker wilt aanmaken als onderdeel van het installatieproces, geef dan de gegevens op van een databasegebruiker in met de rol SYSDBA voor de installatie en voer de gewenste aanmeldgegevens in voor de gebruiker met webtoegang. Je kunt ook de gebruiker met webtoegang handmatig aanmaken en alleen van die gebruiker de aanmeldgegevens opgeven als deze de vereiste rechten heeft om schemaobjecten aan te maken. Als laatste is het mogelijk om aanmeldgegevens van twee verschillende gebruikers op te geven; een met de rechten om schemaobjecten aan te maken, en een met alleen webtoegang.\n\nEen script voor het aanmaken van een gebruiker met de vereiste rechten is te vinden in de map \"maintenance/oracle/\" van deze installatie. Onthoud dat het gebruiken van een gebruiker met beperkte rechten alle mogelijkheden om beheerscripts uit te voeren met de standaard gebruiker onmogelijk maakt.", + "config-db-account-oracle-warn": "Er zijn drie ondersteunde scenario's voor het installeren van Oracle als databasebackend:\n\nAls je een database-account wilt aanmaken als onderdeel van het installatieproces, geef dan de gegevens op van een database-account in met de rol SYSDBA voor de installatie en voer de gewenste aanmeldgegevens in voor het account met webtoegang. Je kunt ook het account met webtoegang handmatig aanmaken en alleen van dat account de aanmeldgegevens opgeven als deze de vereiste rechten heeft om schemaobjecten aan te maken. Als laatste is het mogelijk om aanmeldgegevens van twee verschillende accounts op te geven; een met de rechten om schemaobjecten aan te maken, en een met alleen webtoegang.\n\nEen script voor het aanmaken van een account met de vereiste rechten is te vinden in de map \"maintenance/oracle/\" van deze installatie. Onthoud dat het gebruiken van een account met beperkte rechten alle mogelijkheden om beheerscripts uit te voeren met het standaardaccount onmogelijk maakt.", "config-db-prefix-help": "Als je een database moet gebruiken voor meerdere wiki's, of voor MediaWiki en een andere toepassing, dan kan je ervoor kiezen om een voorvoegsel toe te voegen aan de tabelnamen om conflicten te voorkomen.\nGebruik geen spaties.\n\nDit veld wordt meestal leeg gelaten.", "config-mysql-old": "Je moet MySQL $1 of later gebruiken.\nJij gebruikt $2.", "config-db-schema-help": "Dit schema klopt meestal.\nWijzig het alleen als je weet dat dit nodig is.", @@ -42,7 +43,7 @@ "config-sqlite-name-help": "Kies een naam die je wiki identificeert.\nGebruik geen spaties of koppeltekens.\nDeze naam wordt gebruikt voor het gegevensbestand van SQLite.", "config-upgrade-done": "Het bijwerken is afgerond.\n\nJe kunt [$1 je wiki nu gebruiken].\n\nAls je je LocalSettings.php opnieuw wilt aanmaken, klik dan op de knop hieronder.\nDit is '''niet aan te raden''' tenzij je problemen hebt met je wiki.", "config-upgrade-done-no-regenerate": "Het bijwerken is afgerond.\n\nJe kunt nu [$1 je wiki gebruiken].", - "config-db-web-no-create-privs": "De gebruiker die je hebt opgegeven voor de installatie heeft niet voldoende rechten om een gebruiker aan te maken.\nDe gebruiker die je hier opgeeft moet al bestaan.", + "config-db-web-no-create-privs": "Het account dat je voor installatie hebt opgegeven, heeft niet voldoende rechten om een account aan te maken.\nHet account dat je hier opgeeft, moet al bestaan.", "config-mysql-myisam-dep": "'''Waarschuwing''': je hebt MyISAM geselecteerd als opslagengine voor MySQL. Dit is niet aan te raden voor MediaWiki omdat:\n* het nauwelijks ondersteuning biedt voor gebruik door meerdere gebruikers tegelijkertijd door het locken van tabellen;\n* het meer vatbaar is voor corruptie dan andere engines;\n* de code van MediaWiki niet alstijd omgaat met MyISAM zoals dat zou moeten.\n\nAls je installatie van MySQL InnoDB ondersteunt, gebruik dat dan vooral.\nAls je installatie van MySQL geen ondersteuning heeft voor InnoDB, denk dan na over upgraden.", "config-mysql-charset-help": "In '''binaire modus''' slaat MediaWiki tekst in UTF-8 op in binaire databasevelden.\nDit is efficiënter dan de UTF-8-modus van MySQL en stelt je in staat de volledige reeks Unicodetekens te gebruiken.\n\nIn '''UTF-8-modus''' kent MySQL de tekenset van je gegevens en kan de databaseserver ze juist weergeven en converteren.\nHet is dat niet mogelijk tekens op te slaan die de \"[https://nl.wikipedia.org/wiki/Lijst_van_Unicode-subbereiken#Basic_Multilingual_Plane Basic Multilingual Plane]\" te boven gaan.", "config-project-namespace-help": "In het kielzog van Wikipedia beheren veel wiki's hun beleidspagina's apart van hun inhoudelijke pagina's in een \"'''projectnaamruimte'''\".\nAlle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat je hier kunt opgeven.\nDit voorvoegsel wordt meestal afgeleid van de naam van de wiki, maar het kan geen bijzondere tekens bevatten als \"#\" of \":\".", @@ -66,9 +67,9 @@ "config-install-alreadydone": "'''Waarschuwing:''' het lijkt alsof je MediaWiki al hebt geïnstalleerd en probeert het programma opnieuw te installeren.\nGa door naar de volgende pagina.", "config-install-begin": "Als je nu op \"{{int:config-continue}}\" klikt, begint de installatie van MediaWiki.\nAls je nog wijzigingen wilt maken, klik dan op \"Terug\".", "config-pg-no-plpgsql": "Je moet de taal PL/pgSQL installeren in de database $1", - "config-pg-no-create-privs": "De gebruiker die je hebt opgegeven door de installatie heeft niet voldoende rechten om een gebruiker aan te maken.", - "config-pg-not-in-role": "De gebruiker die je hebt opgegeven voor de webgebruiker bestaat al.\nDe gebruiker die je hebt opgegeven voor installatie is geen superuser en geen lid van de rol van de webgebruiker, en kan het dus geen objecten aanmaken die van de webgebruiker zijn.\n\nMediaWiki vereist momenteel dat de tabellen van de webgebruiker zijn. Geef een andere webgebruikersnaam op, of klik op \"terug\" en geef een gebruiker op die voldoende installatierechten heeft.", - "config-install-user-missing-create": "De opgegeven gebruiker \"$1\" bestaat niet.\nKlik op \"registreren\" onderaan als je de gebruiker wilt aanmaken.", + "config-pg-no-create-privs": "Het account dat je voor installatie hebt opgegeven, heeft niet voldoende rechten om een account aan te maken.", + "config-pg-not-in-role": "Het account dat je voor de webgebruiker hebt opgegeven, bestaat al.\nHet account dat je voor installatie hebt opgegeven, is geen superuser en geen lid van de rol van de webgebruiker, en kan het dus geen objecten aanmaken die van de webgebruiker zijn.\n\nMediaWiki vereist momenteel dat de tabellen van de webgebruiker zijn. Geef een andere webaccountnaam op, of klik op \"terug\" en geef een gebruiker op die voldoende installatierechten heeft.", + "config-install-user-missing-create": "Het opgegeven account \"$1\" bestaat niet.\nKlik op \"registreren\" onderaan als je het account wilt aanmaken.", "config-install-done": "'''Gefeliciteerd!'''\nJe hebt MediaWiki met geïnstalleerd.\n\nHet installatieprogramma heeft het bestand LocalSettings.php aangemaakt.\nDit bevat al je instellingen.\n\nJe moet het bestand downloaden en in de hoofdmap van uw wikiinstallatie plaatsten; in dezelfde map als index.php.\nDe download moet je automatisch zijn aangeboden.\n\nAls de download niet is aangeboden of als je de download hebt geannuleerd, dan kan je de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\n'''Let op''': als je dit niet nu doet, dan het is bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kan je '''[$2 je wiki betreden]'''.", "mainpagedocfooter": "Raadpleeg de [https://meta.wikimedia.org/wiki/Help:Contents Inhoudsopgave handleiding] voor informatie over het gebruik van de wikisoftware.\n\n== Meer hulp over MediaWiki ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lijst met instellingen]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Veelgestelde vragen (FAQ)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Mailinglijst voor aankondigingen van nieuwe versies]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Maak MediaWiki beschikbaar in jouw taal]" } diff --git a/includes/installer/i18n/nl.json b/includes/installer/i18n/nl.json index 6185ef4c22..dd2cef4317 100644 --- a/includes/installer/i18n/nl.json +++ b/includes/installer/i18n/nl.json @@ -107,7 +107,7 @@ "config-db-name": "Databasenaam:", "config-db-name-help": "Kies een naam die uw wiki identificeert.\nEr mogen geen spaties gebruikt worden.\nAls u gebruik maakt van gedeelde webhosting, dan hoort uw provider ofwel u een te gebruiken databasenaam gegeven te hebben, of u aangegeven te hebben hoe u databases kunt aanmaken.", "config-db-name-oracle": "Databaseschema:", - "config-db-account-oracle-warn": "Er zijn drie ondersteunde scenario's voor het installeren van Oracle als databasebackend:\n\nAls u een databasegebruiker wilt aanmaken als onderdeel van het installatieproces, geef dan de gegevens op van een databasegebruiker in met de rol SYSDBA voor de installatie en voer de gewenste aanmeldgegevens in voor de gebruiker met webtoegang. U kunt ook de gebruiker met webtoegang handmatig aanmaken en alleen van die gebruiker de aanmeldgegevens opgeven als deze de vereiste rechten heeft om schemaobjecten aan te maken. Als laatste is het mogelijk om aanmeldgegevens van twee verschillende gebruikers op te geven; een met de rechten om schemaobjecten aan te maken, en een met alleen webtoegang.\n\nEen script voor het aanmaken van een gebruiker met de vereiste rechten is te vinden in de map \"maintenance/oracle/\" van deze installatie. Onthoud dat het gebruiken van een gebruiker met beperkte rechten alle mogelijkheden om beheerscripts uit te voeren met de standaard gebruiker onmogelijk maakt.", + "config-db-account-oracle-warn": "Er zijn drie ondersteunde scenario's voor het installeren van Oracle als databasebackend:\n\nAls u een database-account wilt aanmaken als onderdeel van het installatieproces, geef dan de gegevens op van een database-account in met de rol SYSDBA voor de installatie en voer de gewenste aanmeldgegevens in voor het account met webtoegang. U kunt ook het account met webtoegang handmatig aanmaken en alleen van dat account de aanmeldgegevens opgeven als deze de vereiste rechten heeft om schemaobjecten aan te maken. Als laatste is het mogelijk om aanmeldgegevens van twee verschillende accounts op te geven; een met de rechten om schemaobjecten aan te maken, en een met alleen webtoegang.\n\nEen script voor het aanmaken van een account met de vereiste rechten is te vinden in de map \"maintenance/oracle/\" van deze installatie. Onthoud dat het gebruiken van een account met beperkte rechten alle mogelijkheden om beheerscripts uit te voeren met het standaardaccount onmogelijk maakt.", "config-db-install-account": "Gebruiker voor installatie", "config-db-username": "Gebruikersnaam voor database:", "config-db-password": "Wachtwoord voor database:", @@ -153,8 +153,8 @@ "config-invalid-db-prefix": "Ongeldig databasevoorvoegsel \"$1\".\nGebruik alleen letters (a-z, A-Z), cijfers (0-9) en liggende streepjes (_) en streepjes (-).", "config-connection-error": "$1.\n\nControleer de host, gebruikersnaam en wachtwoord en probeer het opnieuw.", "config-invalid-schema": "Ongeldig schema voor MediaWiki \"$1\".\nGebruik alleen letters (a-z, A-Z), cijfers (0-9) en liggende streepjes (_).", - "config-db-sys-create-oracle": "Het installatieprogramma biedt alleen de mogelijkheid een nieuwe gebruiker aan te maken met de SYSDBA-gebruiker.", - "config-db-sys-user-exists-oracle": "De gebruiker \"$1\" bestaat al. SYSDBA kan alleen gebruikt worden voor het aanmaken van een nieuwe gebruiker!", + "config-db-sys-create-oracle": "Het installatieprogramma biedt alleen de mogelijkheid een nieuw account aan te maken met een SYSDBA-account.", + "config-db-sys-user-exists-oracle": "Gebruikersaccount \"$1\" bestaat al. SYSDBA kan alleen gebruikt worden voor het aanmaken van een nieuw account!", "config-postgres-old": "PostgreSQL $1 of hoger is vereist.\nU gebruikt $2.", "config-mssql-old": "Microsoft SQL Server $1 of hoger is vereist. U hebt $2.", "config-sqlite-name-help": "Kies een naam die uw wiki identificeert.\nGebruik geen spaties of koppeltekens.\nDeze naam wordt gebruikt voor het gegevensbestand van SQLite.", @@ -176,7 +176,7 @@ "config-db-web-help": "Selecteer de gebruikersnaam en het wachtwoord die de webserver gebruikt om verbinding te maken met de databaseserver na de installatie.", "config-db-web-account-same": "Hetzelfde account gebruiken als voor de installatie", "config-db-web-create": "Maak de gebruiker aan als deze nog niet bestaat", - "config-db-web-no-create-privs": "De gebruiker die u hebt opgegeven voor de installatie heeft niet voldoende rechten om een gebruiker aan te maken.\nDe gebruiker die u hier opgeeft moet al bestaan.", + "config-db-web-no-create-privs": "Het account dat u voor de installatie hebt opgegeven, heeft niet voldoende rechten om een account aan te maken.\nHet account dat u hier opgeeft, moet al bestaan.", "config-mysql-engine": "Opslagmethode:", "config-mysql-innodb": "InnoDB", "config-mysql-myisam": "MyISAM", @@ -298,14 +298,14 @@ "config-install-pg-commit": "Wijzigingen worden doorgevoerd", "config-install-pg-plpgsql": "Controle op de taal PL/pgSQL", "config-pg-no-plpgsql": "U moet de taal PL/pgSQL installeren in de database $1", - "config-pg-no-create-privs": "De gebruiker die u hebt opgegeven door de installatie heeft niet voldoende rechten om een gebruiker aan te maken.", - "config-pg-not-in-role": "De gebruiker die u hebt opgegeven voor de webgebruiker bestaat al.\nDe gebruiker die u hebt opgegeven voor installatie is geen superuser en geen lid van de rol van de webgebruiker, en kan het dus geen objecten aanmaken die van de webgebruiker zijn.\n\nMediaWiki vereist momenteel dat de tabellen van de webgebruiker zijn. Geef een andere webgebruikersnaam op, of klik op \"terug\" en geef een gebruiker op die voldoende installatierechten heeft.", + "config-pg-no-create-privs": "Het account dat u voor installatie hebt opgegeven, heeft niet voldoende rechten om een account aan te maken.", + "config-pg-not-in-role": "Het account dat u voor de webgebruiker hebt opgegeven, bestaat al.\nHet account dat u voor installatie hebt opgegeven, is geen superuser en geen lid van de rol van webgebruiker, en kan dus geen objecten aanmaken die van de webgebruiker zijn.\n\nMediaWiki vereist momenteel dat de tabellen van de webgebruiker zijn. Geef een andere webaccountnaam op, of klik op \"terug\" en geef een gebruiker op die voldoende installatierechten heeft.", "config-install-user": "Databasegebruiker aan het aanmaken", "config-install-user-alreadyexists": "Gebruiker \"$1\" bestaat al", - "config-install-user-create-failed": "Het aanmaken van de gebruiker \"$1\" is mislukt: $2", + "config-install-user-create-failed": "Aanmaken van account \"$1\" is mislukt: $2", "config-install-user-grant-failed": "Het geven van rechten aan gebruiker \"$1\" is mislukt: $2", "config-install-user-missing": "De opgegeven gebruiker \"$1\" bestaat niet.", - "config-install-user-missing-create": "De opgegeven gebruiker \"$1\" bestaat niet.\nKlik op \"registreren\" onderaan als u de gebruiker wilt aanmaken.", + "config-install-user-missing-create": "Het opgegeven account \"$1\" bestaat niet.\nKlik op \"registreren\" onderaan als u het account wilt aanmaken.", "config-install-tables": "Tabellen aanmaken", "config-install-tables-exist": "'''Waarschuwing''': de MediaWikitabellen lijken al te bestaan.\nHet aanmaken wordt overgeslagen.", "config-install-tables-failed": "'''Fout''': het aanmaken van een tabel is mislukt met de volgende foutmelding: $1", @@ -326,6 +326,7 @@ "config-install-mainpage-failed": "Het was niet mogelijk de hoofdpagina in te voegen: $1", "config-install-done": "Gefeliciteerd!\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand LocalSettings.php aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in de hoofdmap van uw wiki-installatie plaatsen, in dezelfde map als index.php.\nDe download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\nLet op: als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u [$2 uw wiki gebruiken].", "config-install-done-path": "Gefeliciteerd!\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand LocalSettings.php aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in $4 plaatsen. De download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\nLet op: Als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u [$2 uw wiki gebruiken].", + "config-install-success": "MediaWiki is geïnstalleerd. U kunt nu\n<$1$2> bezoeken om uw wiki te bekijken.\nAls u vragen hebt, bekijk dan onze lijst met veelgestelde vragen:\n, of gebruik een van de hulpforums vermeld op die pagina.", "config-download-localsettings": "LocalSettings.php downloaden", "config-help": "hulp", "config-help-tooltip": "klik om uit te vouwen", diff --git a/includes/installer/i18n/pl.json b/includes/installer/i18n/pl.json index a19dbc315d..7d2ab8f979 100644 --- a/includes/installer/i18n/pl.json +++ b/includes/installer/i18n/pl.json @@ -323,11 +323,13 @@ "config-install-mainpage-failed": "Nie udało się wstawić strony głównej: $1", "config-install-done": "'''Gratulacje!\nUdało Ci się zainstalować MediaWiki.\n\nInstalator wygenerował plik konfiguracyjny LocalSettings.php.\n\nMusisz go pobrać i umieścić w katalogu głównym Twojej instalacji wiki (tym samym katalogu co index.php). Pobieranie powinno zacząć się automatycznie.\n\nJeżeli pobieranie nie zostało zaproponowane lub jeśli użytkownik je anulował, można ponownie uruchomić pobranie klikając poniższe łącze:\n\n$3\n\nUwaga: Jeśli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie już dostępny po zakończeniu instalacji.\n\nPo załadowaniu pliku konfiguracyjnego możesz [$2 wejść na wiki].", "config-install-done-path": "Gratulacje!\nZainstalowałeś właśnie MediaWiki.\n\nInstalator wygenerował plik LocalSettings.php.\nZawiera całą Twoją konfigurację.\n\nMusisz go pobrać i umieścić w $4. Pobieranie powinno rozpocząć się automatycznie.\n\nJeżeli nie pojawiła się informacja o pobieraniu lub jeżeli ja anulowałeś, kliknij poniższy link:\n\n$3\n\nUwaga: Jeżeli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie potem dostępny, jeżeli wyjdziesz z instalacji bez jego pobrania.\n\nGdy to będzie zrobione, możesz [$2 wejść na swoją wiki].", + "config-install-success": "MediaWiki została pomyślnie zainstalowana. Możesz teraz\nodwiedzić <$1$2>, aby zobaczyć swoją wiki.\nJeśli masz pytania, sprawdź naszą listę najczęściej zadawanych pytań:\n lub użyj jednej z\nform wsparcia odsyłanej z tej strony.", "config-download-localsettings": "Pobierz LocalSettings.php", "config-help": "pomoc", "config-help-tooltip": "kliknij, aby rozwinąć", "config-nofile": "Nie udało się odnaleźć pliku \"$1\". Czy nie został usunięty?", "config-extension-link": "Czy wiesz, że twoja wiki obsługuje [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions rozszerzenia]?\n\nMożesz przejrzeć [https://www.mediawiki.org/wiki/Category:Extensions_by_category rozszerzenia według kategorii] lub [https://www.mediawiki.org/wiki/Extension_Matrix Extension Matrix], aby zobaczyć pełną listę rozszerzeń.", + "config-skins-screenshots": "$1 (zrzut ekranu: $2)", "config-screenshot": "zrzut ekranu", "mainpagetext": "Instalacja MediaWiki powiodła się.", "mainpagedocfooter": "Zapoznaj się z [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Podręcznikiem użytkownika] zawierającym informacje o tym jak korzystać z oprogramowania wiki.\n\n== Na początek ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista ustawień konfiguracyjnych]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Komunikaty o nowych wersjach MediaWiki (lista dyskusyjna)]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Przetłumacz MediaWiki na swój język]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Dowiedz się, jak walczyć ze spamem na swojej wiki]" diff --git a/includes/installer/i18n/pt.json b/includes/installer/i18n/pt.json index adc3e3428c..228064452a 100644 --- a/includes/installer/i18n/pt.json +++ b/includes/installer/i18n/pt.json @@ -18,7 +18,9 @@ "Macofe", "Diniscoelho", "Ruila", - "Seb35" + "Seb35", + "MokaAkashiyaPT", + "Athena in Wonderland" ] }, "config-desc": "O instalador do MediaWiki", @@ -65,12 +67,12 @@ "config-env-php": "O PHP $1 está instalado.", "config-env-hhvm": "HHVM $1 está instalado.", "config-unicode-using-intl": "A usar a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.", - "config-unicode-pure-php-warning": "Aviso: A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode. Irá recorrer-se à implementação em PHP puro, que é mais lenta.\nSe o seu site tem alto volume de tráfego, devia informar-se um pouco sobre a [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/pt normalização Unicode].", + "config-unicode-pure-php-warning": "Aviso: A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode. Irá recorrer-se à implementação em PHP puro, que é mais lenta.\nSe o seu sítio tem alto volume de tráfego, devia informar-se um pouco sobre a [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/pt normalização Unicode].", "config-unicode-update-warning": "Aviso: A versão instalada do wrapper de normalização Unicode usa uma versão mais antiga da biblioteca do [http://site.icu-project.org/ projeto ICU].\nDevia [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations atualizá-la] se tem quaisquer preocupações sobre o uso do Unicode.", "config-no-db": "Não foi possível encontrar um controlador apropriado da base de dados! Precisa de instalar um controlador da base de dados para o PHP. {{PLURAL:$2|É aceite o seguinte tipo|São aceites os seguintes tipos}} de base de dados: $1.\n\nSe fez a compilação do PHP, reconfigure-o com um cliente de base de dados ativado; por exemplo, usando ./configure --with-mysqli.\nSe instalou o PHP a partir de um pacote Debian ou Ubuntu, então precisa de instalar também, por exemplo, o pacote php5-mysql.", "config-outdated-sqlite": "Aviso: Tem a versão $1 do SQLite, que é anterior à versão mínima necessária, a $2. O SQLite não estará disponível.", "config-no-fts3": "Aviso: O SQLite foi compilado sem o módulo [//sqlite.org/fts3.html FTS3]; as funcionalidades de pesquisa não estarão disponíveis nesta instalação.", - "config-pcre-old": "Erro fatal: É necessário o PCRE $1 ou versão posterior.\nO link do seu binário PHP foi feito com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].", + "config-pcre-old": "Erro fatal: É necessário o PCRE $1 ou versão posterior.\nO seu binário PHP foi linkado com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].", "config-pcre-no-utf8": "'''Erro fatal''': O módulo PCRE do PHP parece ter sido compilado sem suporte PCRE_UTF8.\nO MediaWiki necessita do suporte UTF-8 para funcionar corretamente.", "config-memory-raised": "A configuração memory_limit do PHP era $1; foi aumentada para $2.", "config-memory-bad": "Aviso: A configuração memory_limit do PHP é $1.\nIsto é provavelmente demasiado baixo.\nA instalação poderá falhar!", @@ -130,7 +132,7 @@ "config-type-sqlite": "SQLite", "config-type-oracle": "Oracle", "config-type-mssql": "Microsoft SQL Server", - "config-support-info": "O MediaWiki suporta as seguintes plataformas de base de dados:\n\n$1\n\nSe a plataforma que pretende usar não está listada abaixo, siga as instruções nos links acima para ativar o suporte.", + "config-support-info": "O MediaWiki suporta as seguintes plataformas de base de dados:\n\n$1\n\nSe a plataforma que pretende usar não está listada abaixo, siga as instruções nas hiperligações acima para ativar o suporte.", "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] é a plataforma primária do MediaWiki e é a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MySQL. ([http://www.php.net/manual/en/mysql.installation.php Como compilar PHP com suporte a MySQL])", "config-dbsupport-postgres": "* O [{{int:version-db-postgres-url}} PostgreSQL] é uma plataforma popular de base de dados de código aberto, alternativa ao MySQL. ([http://www.php.net/manual/en/pgsql.installation.php Como compilar o PHP com suporte PostgreSQL])", "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([http://www.php.net/manual/en/pdo.installation.php Como compilar o PHP com suporte SQLite], usa PDO)", @@ -191,7 +193,7 @@ "config-mssql-windowsauth": "Autenticação do Windows", "config-site-name": "Nome da wiki:", "config-site-name-help": "Este nome aparecerá no título da janela do seu navegador e em vários outros sítios.", - "config-site-name-blank": "Introduza o nome do site.", + "config-site-name-blank": "Introduza o nome do sítio.", "config-project-namespace": "Espaço nominal do projeto:", "config-ns-generic": "Projeto", "config-ns-site-name": "O mesmo que o nome da wiki: $1", @@ -248,7 +250,7 @@ "config-email-watchlist": "Ativar notificação de alterações às páginas vigiadas", "config-email-watchlist-help": "Permitir que os utilizadores recebam notificações de alterações às suas páginas vigiadas, se tiverem ativado esta funcionalidade nas suas preferências.", "config-email-auth": "Ativar autenticação do correio eletrónico", - "config-email-auth-help": "Se esta opção for ativada, os utilizadores têm de confirmar o seu endereço de correio eletrónico usando um link que lhes é enviado sempre que o definirem ou alterarem.\nSó os endereços de correio eletrónico autenticados podem receber mensagens eletrónicas dos outros utilizadores ou alterar as mensagens de notificação.\nÉ '''recomendado''' que esta opção seja ativada nas wikis de acesso público para impedir o uso abusivo das funcionalidades de correio eletrónico.", + "config-email-auth-help": "Se esta opção for ativada, os utilizadores têm de confirmar o seu endereço de correio eletrónico usando uma hiperligação que lhes é enviada sempre que o definirem ou alterarem.\nSó os endereços de correio eletrónico autenticados podem receber mensagens eletrónicas dos outros utilizadores ou alterar as mensagens de notificação.\nÉ '''recomendado''' que esta opção seja ativada nas wikis de acesso público para impedir o uso abusivo das funcionalidades de correio eletrónico.", "config-email-sender": "Endereço de correio eletrónico de retorno:", "config-email-sender-help": "Introduza o endereço de correio eletrónico que será usado como endereço de retorno nas mensagens eletrónicas de saída.\nÉ para este endereço que serão enviadas as mensagens que não podem ser entregues.\nMuitos servidores de correio eletrónico exigem que pelo menos a parte do nome do domínio seja válida. \\", "config-upload-settings": "Carregamento de imagens e ficheiros", @@ -259,13 +261,13 @@ "config-logo": "URL do logótipo:", "config-logo-help": "O tema padrão do MediaWiki inclui espaço para um logótipo de 135x160 píxeis acima do menu da barra lateral.\nColoque na wiki uma imagem com estas dimensões e introduza aqui o URL dessa imagem.\n\nSe não pretende usar um logótipo, deixe este campo em branco.", "config-instantcommons": "Ativar Instant Commons", - "config-instantcommons-help": "O [https://www.mediawiki.org/wiki/InstantCommons Instant Commons] é uma funcionalidade que permite que as wikis usem imagens, áudio e outros ficheiros multimédia disponíveis no site [https://commons.wikimedia.org/ Wikimedia Commons].\nPara poder usá-los, o MediaWiki necessita de acesso à Internet.\n\nPara mais informações sobre esta funcionalidade, incluindo instruções sobre como configurá-la para usar outras wikis em vez da Wikimedia Commons, consulte o [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos Manual Técnico].", + "config-instantcommons-help": "O [https://www.mediawiki.org/wiki/InstantCommons Instant Commons] é uma funcionalidade que permite que as wikis usem imagens, áudio e outros ficheiros multimédia disponíveis no sítio [https://commons.wikimedia.org/ Wikimedia Commons].\nPara poder usá-los, o MediaWiki necessita de acesso à Internet.\n\nPara mais informações sobre esta funcionalidade, incluindo instruções sobre como configurá-la para usar outras wikis em vez da Wikimedia Commons, consulte o [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos Manual Técnico].", "config-cc-error": "O auxiliar de escolha de licenças da Creative Commons não produziu resultados.\nIntroduza o nome da licença manualmente.", "config-cc-again": "Escolha outra vez...", "config-cc-not-chosen": "Escolha a licença da Creative Commons que pretende e clique \"proceed\".", "config-advanced-settings": "Configuração avançada", "config-cache-options": "Configuração da cache de objetos:", - "config-cache-help": "A cache de objetos é usada para melhorar o desempenho do MediaWiki. Armazena dados usados com frequência.\nSites de tamanho médio ou grande são altamente encorajados a ativar esta funcionalidade e os sites pequenos também terão alguns benefícios em fazê-lo.", + "config-cache-help": "A cache de objetos é usada para melhorar o desempenho do MediaWiki. Armazena dados usados com frequência.\nSítios de tamanho médio ou grande são altamente encorajados a ativar esta funcionalidade e os sítios pequenos também terão alguns benefícios em fazê-lo.", "config-cache-none": "Sem cache (não é removida nenhuma funcionalidade, mas a velocidade de operação pode ser afectada nas wikis grandes)", "config-cache-accel": "Cache de objetos do PHP (APC, APCu, XCache ou WinCache)", "config-cache-memcached": "Usar Memcached (requer instalação e configurações adicionais)", @@ -306,7 +308,7 @@ "config-install-tables": "A criar as tabelas", "config-install-tables-exist": "Aviso: As tabelas do MediaWiki parecem já existir.\nA criação das tabelas será saltada.", "config-install-tables-failed": "Erro: A criação das tabelas falhou com o seguinte erro: $1", - "config-install-interwiki": "A preencher a tabela padrão de links interwikis", + "config-install-interwiki": "A preencher a tabela padrão de hiperligações interwikis", "config-install-interwiki-list": "Não foi possível ler o ficheiro interwiki.list.", "config-install-interwiki-exists": "Aviso: A tabela de interwikis parece já conter entradas.\nO preenchimento padrão desta tabela será saltado.", "config-install-stats": "A inicializar as estatísticas", @@ -321,8 +323,9 @@ "config-install-mainpage-exists": "A página principal já existe; a saltar este passo", "config-install-extension-tables": "A criar as tabelas das extensões ativadas", "config-install-mainpage-failed": "Não foi possível inserir a página principal: $1", - "config-install-done": "Parabéns!\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro LocalSettings.php.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório de raiz da sua instalação (o mesmo diretório onde está o ficheiro index.php). Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na ligação abaixo:\n\n$3\n\nNota: Se não o descarregar agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode [$2 entrar na wiki].", + "config-install-done": "Parabéns!\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro LocalSettings.php.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório de raiz da sua instalação (o mesmo diretório onde está o ficheiro index.php). Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na hiperligação abaixo:\n\n$3\n\nNota: Se não o descarregar agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode [$2 entrar na wiki].", "config-install-done-path": "Parabéns!\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro LocalSettings.php.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório $4. Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na ligação abaixo:\n\n$3\n\nNota: Se não fizer o descarregamento agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode [$2 entrar na wiki].", + "config-install-success": "O MediaWiki foi instalado. Já pode visitar <$1$2> para ver a sua wiki.\nSe tiver dúvidas, veja a nossa lista de perguntas frequentes,\n, ou utilize um dos fóruns de suporte indicados nessa página.", "config-download-localsettings": "Descarregar LocalSettings.php", "config-help": "ajuda", "config-help-tooltip": "clique para expandir", diff --git a/includes/installer/i18n/ru.json b/includes/installer/i18n/ru.json index 904560556f..3142e71d12 100644 --- a/includes/installer/i18n/ru.json +++ b/includes/installer/i18n/ru.json @@ -329,6 +329,7 @@ "config-install-mainpage-failed": "Не удаётся вставить главную страницу: $1", "config-install-done": "Поздравляем!\nВы установили MediaWiki.\n\nВо время установки был создан файл LocalSettings.php.\nОн содержит все ваши настройки.\n\nВам необходимо скачать его и положить в корневую директорию вашей вики (ту же директорию, где находится файл index.php). Его загрузка должна начаться автоматически.\n\nЕсли автоматическая загрузка не началась или вы её отменили, вы можете скачать по ссылке ниже:\n\n$3\n\nПримечание: Если вы не сделаете этого сейчас, то сгенерированный файл конфигурации не будет доступен вам в дальнейшем, если вы выйдете из установки, не скачивая его.\n\nПо окончании действий, описанных выше, вы сможете [$2 войти в вашу вики].", "config-install-done-path": "Поздравляем!\nВы установили MediaWiki.\n\nВо время установки был создан файл LocalSettings.php.\nОн содержит все ваши настройки.\n\nВам необходимо скачать его и положить в $4. Его загрузка должна начаться автоматически.\n\nЕсли автоматическая загрузка не началась или вы её отменили, вы можете скачать по ссылке ниже:\n\n$3\n\nПримечание: Если вы не сделаете этого сейчас, то сгенерированный файл конфигурации не будет доступен вам в дальнейшем, если вы выйдете из установки, не скачивая его.\n\nПо окончании действий, описанных выше, вы сможете [$2 войти в вашу вики].", + "config-install-success": "MediaWiki успешно установлена. Сейчас вы можете перейти на <$1 $2>, чтобы просмотреть свою вики\nЕсли у вас есть вопросы, ознакомьтесь с нашим часто задаваемыми вопросами:\n или используйте один из форумов поддержки, указанный на этой странице.", "config-download-localsettings": "Загрузить LocalSettings.php", "config-help": "справка", "config-help-tooltip": "нажмите, чтобы развернуть", diff --git a/includes/installer/i18n/sr-ec.json b/includes/installer/i18n/sr-ec.json index 02f633593e..2e65c8764f 100644 --- a/includes/installer/i18n/sr-ec.json +++ b/includes/installer/i18n/sr-ec.json @@ -6,12 +6,14 @@ "Milicevic01", "Aktron", "Сербијана", - "Zoranzoki21" + "Zoranzoki21", + "Acamicamacaraca" ] }, "config-desc": "Инсталација за Медијавики", "config-title": "Инсталација Медијавикија $1", - "config-information": "Информације", + "config-information": "Информација", + "config-localsettings-key": "Кључ за уградњу:", "config-session-error": "Грешка при започињању сесије: $1", "config-session-expired": "Ваши подаци о сесији су истекли.\nСесије су подешене да трају $1.\nЊихов рок можете повећати постављањем session.gc_maxlifetime у php.ini.\nПоново покрените инсталацију.", "config-no-session": "Ваши подаци о сесији су изгубљени!\nПроверите Ваш php.ini и обезбедите да је session.save_path постављен на одговарајући директоријум.", @@ -22,12 +24,12 @@ "config-back": "← Назад", "config-continue": "Настави →", "config-page-language": "Језик", - "config-page-welcome": "Добро дошли на МедијаВики!", + "config-page-welcome": "Добро дошли на Медијавики!", "config-page-dbconnect": "Повезивање са базом података", "config-page-upgrade": "Надоградња постојеће инсталације", "config-page-dbsettings": "Подешавања базе података", "config-page-name": "Назив", - "config-page-options": "Поставке", + "config-page-options": "Подешавања", "config-page-install": "Инсталирај", "config-page-complete": "Завршено!", "config-page-restart": "Поновно покретање инсталације", @@ -45,8 +47,13 @@ "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] је инсталиран", "config-db-type": "Тип базе података:", "config-db-host": "Хост базе података", + "config-db-wiki-settings": "Идентификуј овај вики", "config-db-name": "Назив базе података:", - "config-db-password": "Лозинка за базу података:", + "config-db-name-oracle": "Шема базе података:", + "config-db-username": "Корисничко име базе података:", + "config-db-password": "Лозинка базе података:", + "config-db-port": "Порт базе података:", + "config-db-schema": "Шема за Медијавики:", "config-type-mysql": "MySQL (или компактибилан)", "config-type-postgres": "PostgreSQL", "config-type-sqlite": "SQLite", @@ -60,13 +67,13 @@ "config-mysql-myisam": "MyISAM", "config-mysql-utf8": "UTF-8", "config-mssql-auth": "Тип провере идентитета:", - "config-mssql-sqlauth": "Провера идентитета за SQL Server", - "config-mssql-windowsauth": "Провера идентитета Windows-а", + "config-mssql-sqlauth": "Провера идентитета SQL Server-а", + "config-mssql-windowsauth": "Провера идентитета Виндоуса", "config-site-name": "Име викија:", - "config-admin-name": "Корисничко име:", + "config-admin-name": "Ваше корисничко име:", "config-admin-password": "Лозинка:", "config-admin-email": "Имејл адреса:", - "config-optional-skip": "Досадно ми је, хајде да инсталирамо вики.", + "config-optional-skip": "Досадно ми је, само инсталирај вики.", "config-profile-no-anon": "Неопходно је отворити налог", "config-profile-fishbowl": "Само овлашћени корисници", "config-profile-private": "Приватна вики", @@ -76,16 +83,25 @@ "config-license-cc-by": "Creative Commons Ауторство (CC BY)", "config-license-cc-by-nc-sa": "Creative Commons Ауторство-Некомерцијално-Делити под истим условима (CC BY-NC-SA)", "config-license-cc-0": "Creative Commons Zero (јавно власништво)", - "config-license-gfdl": "ГНУ-ова лиценца за слободну документацију верзија 1.3 или новија верзија", + "config-license-gfdl": "ГНУ-ова лиценца за слободну документацију издање 1.3 или новије", "config-license-pd": "Јавно власништво", "config-email-settings": "Подешавања имејла", "config-cc-not-chosen": "Одаберите која Кријејтив комонс лиценца вам одговара и потврдите.", "config-skins": "Теме", "config-install-step-done": "готово", "config-install-step-failed": "није успело", + "config-install-extensions": "Обухвата екстензије", + "config-install-schema": "Прављење шеме", + "config-install-tables": "Прављење табела", + "config-install-keys": "Генеришем тајне кључеве", "config-install-mainpage-exists": "Главна страна већ постоји, прескакање", + "config-install-mainpage-failed": "Не могу да убацим главну страну: „$1”", + "config-download-localsettings": "Преузми LocalSettings.php", "config-help": "помоћ", "config-help-tooltip": "кликните да проширите", + "config-nofile": "Не могу да пронађем датотеку „$1”. Није ли она била избрисана?", + "config-skins-screenshots": "„$1” (снимци екрана: $2)", + "config-screenshot": "снимак екрана", "mainpagetext": "Медијавики је успешно инсталиран.", - "mainpagedocfooter": "Погледајте [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents кориснички водич] за коришћење програма.\n\n== Увод ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Помоћ у вези са подешавањима]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Често постављена питања]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Дописна листа о издањима Медијавикија]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Научите како да се борете против спама на Вашој вики]" + "mainpagedocfooter": "Погледајте [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents кориснички водич] за коришћење програма.\n\n== Увод ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Помоћ у вези са подешавањима]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Често постављена питања]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Дописни списак о издањима Медијавикија]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Научите како да се борите против спама на Вашој вики]" } diff --git a/includes/installer/i18n/sv.json b/includes/installer/i18n/sv.json index a338387a64..861e3e62e4 100644 --- a/includes/installer/i18n/sv.json +++ b/includes/installer/i18n/sv.json @@ -311,6 +311,7 @@ "config-install-mainpage-failed": "Kunde inte infoga huvudsidan: $1", "config-install-done": "Grattis!\nDu har installerat MediaWiki.\n\nInstallationsprogrammet har genererat filen LocalSettings.php.\nDet innehåller alla dina konfigurationer.\n\nDu kommer att behöva ladda ner den och placera den i roten för din wiki-installation (samma katalog som index.php). Nedladdningen borde ha startats automatiskt.\n\nOm ingen nedladdning erbjöds, eller om du har avbrutit det kan du starta om nedladdningen genom att klicka på länken nedan:\n\n$3\n\nOBS: Om du inte gör detta nu, kommer denna genererade konfigurationsfil inte vara tillgänglig för dig senare om du avslutar installationen utan att ladda ned den.\n\nNär det är klart, kan du [$2 gå in på din wiki]", "config-install-done-path": "Grattis!\nDu har installerat MediaWiki.\n\nInstallationsprogrammet har genererat filen LocalSettings.php.\nDet innehåller alla dina konfigurationer.\n\nDu kommer att behöva ladda ner den och placera den i $4. Nedladdningen borde ha startats automatiskt.\n\nOm ingen nedladdning erbjöds, eller om du har avbrutit det kan du starta om nedladdningen genom att klicka på länken nedan:\n\n$3\n\nOBS: Om du inte gör detta nu, kommer denna genererade konfigurationsfil inte vara tillgänglig för dig senare om du avslutar installationen utan att ladda ned den.\n\nNär det är klart, kan du [$2 gå in på din wiki]", + "config-install-success": "MediaWiki har installerats. Du kan nu besöka <$1$2> för att se din wiki.\nOm du undrar någonting, kolla in vår lista över vanliga ställda frågor:\n eller använda något supportforum som länkas på sidan.", "config-download-localsettings": "Ladda ner LocalSettings.php", "config-help": "hjälp", "config-help-tooltip": "klicka för att expandera", diff --git a/includes/installer/i18n/tr.json b/includes/installer/i18n/tr.json index bc5be92a77..3365ad8df3 100644 --- a/includes/installer/i18n/tr.json +++ b/includes/installer/i18n/tr.json @@ -18,7 +18,8 @@ "McAang", "Elftrkn", "Vito Genovese", - "Incelemeelemani" + "Incelemeelemani", + "Hedda" ] }, "config-desc": "MediaWiki yükleyicisi", @@ -65,16 +66,21 @@ "config-env-php": "PHP $1 kurulu.", "config-env-hhvm": "HHVM $1 kuruldu", "config-unicode-using-intl": "Unikod normalleştirmesi için [http://pecl.php.net/intl intl PECL uzantısı] kullanılıyor.", - "config-unicode-pure-php-warning": "Uyarı: [http://pecl.php.net/intl intl PECL uzantısı] Unicode normalizasyonunu kaldırabilecek şekilde müsait değil; bu yüzden sayfa saf PHP uygulamasına dönüyor. Yüksek trafik alan bir sayfa çalıştırıyorsanız, [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalizasyonu] ile ilgili biraz bilgi almalısınız.", + "config-unicode-pure-php-warning": "Uyarı: [http://pecl.php.net/intl intl PECL uzantısı] Unicode normalizasyonunu kaldırabilecek şekilde müsait değil; bu yüzden sayfa saf PHP uygulamasına dönüyor. Yüksek trafik alan bir sayfa çalıştırıyorsanız, [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalizasyonu] ile ilgili biraz bilgi almalısınız.", + "config-unicode-update-warning": "Uyarı: Yüklü durumdaki Unicode normalleştirme sarıcı [http://site.icu-project.org/ ICU proje] kütüphanesinin eski bir sürümünü kullanır.\nUnicode kullanımı konusunda endişeleriniz varsa [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations yükseltme] yapmanız gerekmektedir.", + "config-no-db": "Uygun bir veri tabanı sürücüsü bulunamadı! PHP için bir veri tabanı sürücüsü kurmanız gerekir. Şu veri tabanı {{PLURAL:$2|türleri|türleri}} desteklenmektedir: $1\n\nEğer PHP'yi kendiniz derlediyseniz, bu durumda ./configure --with-mysqli kullanarak etkinleştirilmiş veri tabanı istemcisi ile yeniden yapılandırmalısınız.\nPHP'yi bir Debian veya Ubuntu paketinden yüklediyseniz, bu durumda php5-mysql paketini de kurmanız gerekir.", "config-outdated-sqlite": "Uyarı: Elinizde SQLite $1 var. Gerekli minimum sürüm: $2. SQLite kullanılamayacaktır.", "config-no-fts3": "Uyarı: SQLite [//sqlite.org/fts3.html FTS3 modülü] olmadan derlendi, bu arkayüzde arama özellikleri kullanılamayacaktır.", "config-pcre-old": "Ağır hata: PCRE $1 veya daha üst versiyon gerekli.\nSizin PHP kurulumunuz PCRE $2 ile bağlı.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Daha fazla bilgi].", + "config-pcre-no-utf8": "Önemli hata: PHP'nin PCRE modülü PCRE_UTF8 desteği olmadan derlenmiş gözüküyor.\nMediaWiki'nin doğru çalışabilmesi için UTF-8 desteği gereklidir.", "config-memory-raised": "PHP'nin memory_limit (hafıza sınırı) değeri $1, $2'ye yükseltildi.", "config-memory-bad": "Uyarı: PHP'nin memory_limit (hafıza sınırı) değeri $1.\nBu büyük ihtimalle çok düşük.\nKurulum başarısız olabilir!", "config-xcache": "[http://xcache.lighttpd.net/ XCache] kurulu", "config-apc": "[http://www.php.net/apc APC] kurulu", + "config-apcu": "[http://www.php.net/apcu APCu] yüklendi", "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] kurulu", - "config-mod-security": "'''Uyarı:''' Web sunucunuz [http://modsecurity.org/ mod_security] etkin. Eğer yanlış yapılandırılmış ise, bu MediaWiki ve kullanıcılara isteğe bağlı içerik göndermesine izin veren diğer yazılımlar için sorun oluşturabilir.\nRastgele hatalar alırsanız [http://modsecurity.org/documentation/ mod_security belgelemesine] bakın ya da sunucunuzun desteğine başvurun.", + "config-no-cache-apcu": "Uyarı: [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ya da [http://www.iis.net/download/WinCacheForPhp WinCache] kurulumu bulunamadı.\nNesne önbellekleme etkin değil.", + "config-mod-security": "'''Uyarı:''' Web sunucunuz [http://modsecurity.org/mod_security2 mod_security] etkin. Bunun birçok yaygın yapılandırması bulunur ve eğer yanlış yapılandırılmış ise, bu MediaWiki ve kullanıcılara isteğe bağlı içerik göndermesine izin veren diğer yazılımlar için sorun oluşturabilir.\nMümkünse bu devre dışı bırakılmalıdır. Aksi takdirde rastgele hatalar alırsanız [http://modsecurity.org/documentation/ mod_security belgelemesine] bakın ya da sunucunuzun desteğine başvurun.", "config-diff3-bad": "GNU diff3 bulunamadı.", "config-git": "Sürüm kontrol yazılımı Git bulundu: $1.", "config-git-bad": "Sürüm kontrol yazılımı Git bulunamadı.", @@ -189,6 +195,11 @@ "config-profile-private": "Özel wiki", "config-profile-help": "Vikiler, mümkün olan en fazla kişiye değişiklik imkânı verdiğinizde, en iyi şekilde çalışır.\nMediaWiki'de son değişiklikleri incelemek ve tecrübesiz veya kötü niyetli kullanıcıların verdiği zararları geri almak kolaydır.\n\nAncak birçok kişi MediaWiki'yi farklı şekillerde kullanışlı bulmaktadır ve bazen herkesi viki yolunun faydalarına ikna etmek zordur.\nYani seçim sizin.\n\n{{int:config-profile-wiki}} modeli, giriş yapmamış olsa bile herkese değişiklik izni verir.\n\n{{int:config-profile-no-anon}} kullanan bir viki ise daha izlenebilirdir ancak sıradan, basit, gündelik katkı yapan kullanıcıları caydırabilir.\n\n{{int:config-profile-fishbowl}} onaylanmış kullanıcıların değişikliklerine izin verir ama herkes sayfaları ve sayfa geçmişlerini görebilir.\n\n{{int:config-profile-private}} sadece onaylanmış kullanıcıları değişiklik yapma ve sayfaları görme imkânı tanır.\n\nDaha karmaşık kullanıcı hakkı ayarları, yüklemeden sonra görülebilir; [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights ilgili kılavuza] bakınız.", "config-license": "Telif Hakkı ve Lisans", + "config-license-none": "Lisans altbilgisi yok", + "config-license-cc-by-sa": "Creative Commons Attribution-ShareAlike", + "config-license-cc-by": "Creative Commons Attribution", + "config-license-cc-by-nc-sa": "Creative Commons Attribution-NonCommercial-ShareAlike", + "config-license-cc-0": "Creative Commons Zero (Kamu Malı)", "config-license-gfdl": "GNU Free Documentation License 1.3 veya üstü", "config-license-pd": "Kamu Malı", "config-license-cc-choose": "Özel bir Creative Commons lisansı seçin", diff --git a/includes/installer/i18n/uk.json b/includes/installer/i18n/uk.json index 54339c3b3d..a5b630a3fd 100644 --- a/includes/installer/i18n/uk.json +++ b/includes/installer/i18n/uk.json @@ -12,7 +12,8 @@ "아라", "Amire80", "Piramidion", - "Macofe" + "Macofe", + "Movses" ] }, "config-desc": "Інсталятор MediaWiki", @@ -314,6 +315,7 @@ "config-install-mainpage-failed": "Не вдається вставити головну сторінку: $1", "config-install-done": "Вітаємо!\nВи успішно встановили MediaWiki.\n\nІнсталятор згенерував файл LocalSettings.php, який містить усі Ваші налаштування.\n\nВам необхідно завантажити його і помістити у кореневу папку Вашої вікі (туди ж, де index.php). Завантаження мало початись автоматично.\n\nЯкщо завантаження не почалось або Ви його скасували, можете заново його почати, натиснувши на посилання внизу:\n\n$3\n\nПримітка: Якщо Ви не зробите цього зараз, цей файл не буде доступним пізніше, коли Ви вийдете з встановлення, не скачавши його.\n\nПісля виконання дій, описаних вище, Ви зможете [$2 увійти у свою вікі].", "config-install-done-path": "Вітаємо!\nВи встановили Медіавікі.\n\nІнсталятор створив файл LocalSettings.php.\nУ ньому містяться всі Ваші налаштування.\n\nВам потрібно завантажити його й помістити в $4. Завантаження повинно було автоматично розпочатись.\n\nЯкщо завантаження не було запропоновано, або Ви його скасували, Ви можете перезапустити завантаження натиснувши на посилання нижче:\n\n$3\n\nЗверніть увагу: Якщо Ви не зробите це зараз, цей згенерований файл налаштувань не буде доступним для Вас пізніше якщо Ви вийдете зі встановлення не завантаживши його.\n\nКоли це було зроблено Ви можете [$2 зайти до своєї вікі].", + "config-install-success": "Mediawiki успішно встановлено. Зараз ви можете перейти до <$1$2>, щоб переглянути свою вікі. Якщо у вас є питання, ознайомтеся з нашим FAQ: або використовуйте один з форумів підтримки, які вказано на цій сторінці.", "config-download-localsettings": "Завантажити LocalSettings.php", "config-help": "допомога", "config-help-tooltip": "натисніть, щоб розгорнути", diff --git a/includes/installer/i18n/zh-hans.json b/includes/installer/i18n/zh-hans.json index fab5eef95a..f5fa9f2470 100644 --- a/includes/installer/i18n/zh-hans.json +++ b/includes/installer/i18n/zh-hans.json @@ -324,6 +324,7 @@ "config-install-mainpage-failed": "无法插入首页:$1", "config-install-done": "恭喜!\n您已经安装了MediaWiki。\n\n安装程序已经生成了LocalSettings.php文件,其中包含了您所有的配置。\n\n您需要下载该文件,并将其放在您wiki的根目录(index.php的同级目录)中。稍后下载将自动开始。\n\n如果浏览器没有提示您下载,或者您取消了下载,您可以点击下面的链接重新开始下载:\n\n$3\n\n注意:如果您现在不完成本步骤,而是没有下载便退出了安装过程,此后您将无法获得自动生成的配置文件。\n\n当本步骤完成后,您可以[$2 进入您的wiki]。", "config-install-done-path": "祝贺!您已经安装了MediaWiki。\n\n安装程序已经生成了LocalSettings.php文件。它包含您所有的配置。\n\n您需要下载该文件,并将其放在$4。下载应已自动开始。\n\n如果没有提供下载,或者您取消了下载,您可以点击下面的链接重新开始下载:\n\n$3\n\n注意:如果您现在不完成本步骤,而是没有下载便退出了安装过程,此后您将无法获得自动生成的配置文件。\n\n当本步骤完成后,您可以[$2 进入您的wiki]。", + "config-install-success": "MediaWiki已成功安装。您现在可以访问<$1$2>以查看您的wiki。如果您有问题,请阅览我们的常见问题列表:或使用在该页面上链接的支持论坛之一。", "config-download-localsettings": "下载LocalSettings.php", "config-help": "帮助", "config-help-tooltip": "单击展开", diff --git a/includes/installer/i18n/zh-hant.json b/includes/installer/i18n/zh-hant.json index 96f0ef136b..b00320f399 100644 --- a/includes/installer/i18n/zh-hant.json +++ b/includes/installer/i18n/zh-hant.json @@ -20,7 +20,8 @@ "Winstonyin", "Wehwei", "Wwycheuk", - "蘭斯特" + "蘭斯特", + "Kly" ] }, "config-desc": "MediaWiki 安裝程式", @@ -38,7 +39,7 @@ "config-no-session": "您的連線階段資料遺失!\n請檢查 php.ini 設定檔並確認 session.save_path 所設定的目錄是否合適。", "config-your-language": "您的語言:", "config-your-language-help": "請選擇接下來安裝程序中要使用的語言。", - "config-wiki-language": "Wiki 語言:", + "config-wiki-language": "wiki 語言:", "config-wiki-language-help": "選擇將要安裝的 Wiki 多數情況主要使用的語言。", "config-back": "← 返回", "config-continue": "繼續 →", @@ -56,7 +57,7 @@ "config-page-releasenotes": "發佈說明", "config-page-copying": "複製", "config-page-upgradedoc": "升級", - "config-page-existingwiki": "現有 Wiki", + "config-page-existingwiki": "現有的 wiki", "config-help-restart": "是否要清除所有已輸入且儲存的資料,並重新開始安裝程序嗎?", "config-restart": "是的,重新開始", "config-welcome": "=== 環境檢查 ===\n現在會做基本的檢查,檢查環境是否符合 MediaWiki 安裝所需。\n若您要尋求如何完成安裝的協助,請記得提供以下訊息。", @@ -96,12 +97,13 @@ "config-no-cli-uploads-check": "警告:透過指令介面安不會檢查您預設的上傳目錄 ($1) 是否有可任意執行 Script 的安全性漏洞。", "config-brokenlibxml": "您的系統使用了可能造成 MediaWiki 或其他網頁應用程式資料損毀問題的 PHP 與 limbxml2 版本。\n請升級 libxml2 2.7.3 或更新的版本 ([https://bugs.php.net/bug.php?id=45996 PHP 問題報告])。\n安裝已中止。", "config-suhosin-max-value-length": "Suhosin 已安裝並且限制 GET 參數的長度 length 為 $1 位元組。\nMediaWiki 的 ResourceLoader 元件可以在此限制下正常運作,但仍會降低執行的效能。\n如果可能的情況下,您應該設定 php.ini 設定檔中的項目 suhosin.get.max_value_length 為 1024 或者更高的數值,並且將\nLocalSettings.php 中的設定項目 $wgResourceLoaderMaxQueryLength 設為相同的數值。", + "config-using-32bit": "警告:您的系統似乎是 32 位元系統,[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit 不推薦]您使用。", "config-db-type": "資料庫類型:", "config-db-host": "資料庫主機:", "config-db-host-help": "如果您的資料庫安裝在其他伺服器上,請在此輸入該主機的名稱或 IP 位址。\n\n如果您使用共用的網頁主機,您的主機提供商應會在說明文件上告訴您正確的主機名稱。\n\n如果您安裝在 Windows 伺服器並且使用 MySQL,伺服器名稱可能無法使用使用 \"localhost\"。若確實無法使用,請改嘗試使用本機的 IP 位址 \"127.0.0.1\"。\n\n如果您使用 PostgreSQL,將此欄位空白以使用 Unix socket 來連線。", "config-db-host-oracle": "資料庫的 TNS:", "config-db-host-oracle-help": "請輸入有效的 [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm 本地連線名稱],並確認安裝程式可以讀取 tnsnames.ora 檔案。
如果您使用的客戶端程式庫為 10g 或者更新的版本,您也可使用 [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm 簡易連線] 的命名方法進行連線。", - "config-db-wiki-settings": "此 Wiki 的 ID", + "config-db-wiki-settings": "識別此 wiki", "config-db-name": "資料庫名稱:", "config-db-name-help": "請輸入一個可以辨識您的 Wiki 的名稱,\n請勿包含空格。\n\n如果您使用的是共用的網頁主機,您的主機提供商會給您一個指定的資料庫名稱,或者讓您透過管理介面建立資料庫。", "config-db-name-oracle": "資料庫 Schema:", @@ -187,12 +189,12 @@ "config-mssql-web-auth": "請選擇一般操作中要用來連線資料庫使用的身份驗證類型。\n若您選擇 \"{{int:config-mssql-windowsauth}}\",不論網頁伺服器是使用何種身份執行都會使用這組驗證資料。", "config-mssql-sqlauth": "SQL Server 身份驗證", "config-mssql-windowsauth": "Windows 身份驗證", - "config-site-name": "Wiki 的名稱:", + "config-site-name": "wiki 的名稱:", "config-site-name-help": "您所填入的內容會出現在瀏覽器的標題列以及各種其他地方。", "config-site-name-blank": "請輸入網站名稱。", "config-project-namespace": "專案命名空間:", "config-ns-generic": "專案", - "config-ns-site-name": "同 Wiki 名稱:$1", + "config-ns-site-name": "與 wiki 名稱一致:$1", "config-ns-other": "其他 (請註明)", "config-ns-other-default": "我的 wiki", "config-project-namespace-help": "許多 Wiki 以維基百科 (Wikipedia) 做為範例將政策頁面從內容頁面抽離,放置在 \"'''專案命名空間'''\" 中。\n所有在此命名空間裡的頁面都會有特定的字首,您可以在此處設定。\n通常這些字首是由該 Wiki 的名稱所衍伸出來,但無法使用標點符號,如 \"#\" 或 \":\"。", @@ -221,7 +223,7 @@ "config-optional-continue": "多問我一些問題吧。", "config-optional-skip": "我已經不耐煩了,請趕緊安裝 Wiki。", "config-profile": "使用者權限基本資料:", - "config-profile-wiki": "開放式 Wiki", + "config-profile-wiki": "開放式 wiki", "config-profile-no-anon": "需要註冊帳號", "config-profile-fishbowl": "僅授權的編輯者", "config-profile-private": "私人 wiki", @@ -321,6 +323,7 @@ "config-install-mainpage-failed": "無法插入首頁: $1", "config-install-done": "恭喜!\n您已經成功安裝MediaWiki。\n\n安裝程式已自動產生LocalSettings.php檔案,\n該檔案中包含了您所有的設定項目。\n\n您需要下載該檔案,並將其放置在您的Wiki的根目錄(index.php所在的目錄)中,下載應已自動開始。\n\n若瀏覽器沒有提示您下載,或者您取消了下載,您可以點選下方連結重新下載:\n\n$3\n\n注意:如果您現在不下載此檔案,稍後結束安裝程式之後將無法再下載設定檔。\n\n當您完成本步驟後,您可以[$2 進入您的Wiki]。", "config-install-done-path": "恭喜!\n您已經成功安裝MediaWiki。\n\n安裝程式已自動產生LocalSettings.php檔案,\n該檔案中包含了您所有的設定項目。\n\n您需要下載該檔案,並將其放置在$4中,下載應已自動開始。\n\n若瀏覽器沒有提示您下載,或者您取消了下載,您可以點選下方連結重新下載:\n\n$3\n\n注意:如果您現在不下載此檔案,稍後結束安裝程式之後將無法再下載設定檔。\n\n當您完成本步驟後,您可以[$2 進入您的Wiki]。", + "config-install-success": "MediaWiki 已安裝成功。您現在可以在 <$1$2> 上檢視您的 wiki。若您有任何問題,請閱讀常見問題清單:,或是利用在頁面上所連結的支援論壇之一。", "config-download-localsettings": "下載 LocalSettings.php", "config-help": "說明", "config-help-tooltip": "點選以展開", diff --git a/includes/interwiki/ClassicInterwikiLookup.php b/includes/interwiki/ClassicInterwikiLookup.php index d9c04240c8..d5103da977 100644 --- a/includes/interwiki/ClassicInterwikiLookup.php +++ b/includes/interwiki/ClassicInterwikiLookup.php @@ -1,6 +1,4 @@ maxPartitionsTry; $i > 0 && count( $jobsLeft ); --$i ) { - // @codingStandardsIgnoreEnd try { $partitionRing->getLiveRing(); } catch ( UnexpectedValueException $e ) { diff --git a/includes/jobqueue/JobSpecification.php b/includes/jobqueue/JobSpecification.php index d844795143..b62b83c666 100644 --- a/includes/jobqueue/JobSpecification.php +++ b/includes/jobqueue/JobSpecification.php @@ -18,7 +18,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup JobQueue */ /** diff --git a/includes/jobqueue/aggregator/JobQueueAggregator.php b/includes/jobqueue/aggregator/JobQueueAggregator.php index f26beee4bd..433de93af7 100644 --- a/includes/jobqueue/aggregator/JobQueueAggregator.php +++ b/includes/jobqueue/aggregator/JobQueueAggregator.php @@ -158,6 +158,9 @@ abstract class JobQueueAggregator { } } +/** + * @ingroup JobQueue + */ class JobQueueAggregatorNull extends JobQueueAggregator { protected function doNotifyQueueEmpty( $wiki, $type ) { return true; diff --git a/includes/jobqueue/jobs/ClearUserWatchlistJob.php b/includes/jobqueue/jobs/ClearUserWatchlistJob.php index 17c4b665e2..3e8b2ad3e4 100644 --- a/includes/jobqueue/jobs/ClearUserWatchlistJob.php +++ b/includes/jobqueue/jobs/ClearUserWatchlistJob.php @@ -28,15 +28,10 @@ class ClearUserWatchlistJob extends Job { /** * @param Title|null $title Not used by this job. * @param array $params - * - batchSize, Number of watchlist entries to remove at once. * - userId, The ID for the user whose watchlist is being cleared. * - maxWatchlistId, The maximum wl_id at the time the job was first created, */ public function __construct( Title $title = null, array $params ) { - if ( !array_key_exists( 'batchSize', $params ) ) { - $params['batchSize'] = 1000; - } - parent::__construct( 'clearUserWatchlist', SpecialPage::getTitleFor( 'EditWatchlist', 'clear' ), @@ -47,8 +42,10 @@ class ClearUserWatchlistJob extends Job { } public function run() { + global $wgUpdateRowsPerQuery; $userId = $this->params['userId']; $maxWatchlistId = $this->params['maxWatchlistId']; + $batchSize = $wgUpdateRowsPerQuery; $loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer(); $dbw = $loadBalancer->getConnection( DB_MASTER ); @@ -86,7 +83,7 @@ class ClearUserWatchlistJob extends Job { __METHOD__, [ 'ORDER BY' => 'wl_id ASC', - 'LIMIT' => $this->params['batchSize'], + 'LIMIT' => $batchSize, ] ); @@ -101,7 +98,9 @@ class ClearUserWatchlistJob extends Job { $lbf->commitMasterChanges( __METHOD__ ); unset( $scopedLock ); - if ( count( $watchlistIds ) == $this->params['batchSize'] ) { + if ( count( $watchlistIds ) === (int)$batchSize ) { + // Until we get less results than the limit, recursively push + // the same job again. JobQueueGroup::singleton()->push( new self( $this->getTitle(), $this->getParams() ) ); } diff --git a/includes/jobqueue/jobs/DeleteLinksJob.php b/includes/jobqueue/jobs/DeleteLinksJob.php index 5c0f89f73f..d0969e4631 100644 --- a/includes/jobqueue/jobs/DeleteLinksJob.php +++ b/includes/jobqueue/jobs/DeleteLinksJob.php @@ -20,7 +20,8 @@ * @file * @ingroup JobQueue */ -use \MediaWiki\MediaWikiServices; + +use MediaWiki\MediaWikiServices; /** * Job to prune link tables for pages that were deleted diff --git a/includes/jobqueue/jobs/EnqueueJob.php b/includes/jobqueue/jobs/EnqueueJob.php index 5ffb01b45a..ea7a8d7801 100644 --- a/includes/jobqueue/jobs/EnqueueJob.php +++ b/includes/jobqueue/jobs/EnqueueJob.php @@ -24,11 +24,10 @@ /** * Router job that takes jobs and enqueues them to their proper queues * - * This can be used for several things: - * - a) Making multi-job enqueues more robust by atomically enqueueing - * a single job that pushes the actual jobs (with retry logic) - * - b) Masking the latency of pushing jobs to different queues/wikis - * - c) Low-latency enqueues to push jobs from warm to hot datacenters + * This can be used for getting sets of multiple jobs or sets of jobs intended for multiple + * queues to be inserted more robustly. This is a single job that, upon running, enqueues the + * wrapped jobs. If some of those fail to enqueue then the EnqueueJob will be retried. Due to + * the possibility of duplicate enqueues, the wrapped jobs should be idempotent. * * @ingroup JobQueue * @since 1.25 diff --git a/includes/libs/CSSMin.php b/includes/libs/CSSMin.php index ee88d0d2b5..f2c7ed29f0 100644 --- a/includes/libs/CSSMin.php +++ b/includes/libs/CSSMin.php @@ -29,8 +29,6 @@ */ class CSSMin { - /* Constants */ - /** @var string Strip marker for comments. **/ const PLACEHOLDER = "\x7fPLACEHOLDER\x7f"; @@ -42,8 +40,6 @@ class CSSMin { const EMBED_REGEX = '\/\*\s*\@embed\s*\*\/'; const COMMENT_REGEX = '\/\*.*?\*\/'; - /* Protected Static Members */ - /** @var array List of common image files extensions and MIME-types */ protected static $mimeTypes = [ 'gif' => 'image/gif', @@ -57,8 +53,6 @@ class CSSMin { 'svg' => 'image/svg+xml', ]; - /* Static Methods */ - /** * Get a list of local files referenced in a stylesheet (includes non-existent files). * @@ -138,6 +132,9 @@ class CSSMin { */ public static function encodeStringAsDataURI( $contents, $type, $ie8Compat = true ) { // Try #1: Non-encoded data URI + + // Remove XML declaration, it's not needed with data URI usage + $contents = preg_replace( "/<\\?xml.*?\\?>/", '', $contents ); // The regular expression matches ASCII whitespace and printable characters. if ( preg_match( '/^[\r\n\t\x20-\x7e]+$/', $contents ) ) { // Do not base64-encode non-binary files (sane SVGs). @@ -149,7 +146,15 @@ class CSSMin { '%2F' => '/', // Unencode slashes '%3A' => ':', // Unencode colons '%3D' => '=', // Unencode equals signs + '%0A' => ' ', // Change newlines to spaces + '%0D' => ' ', // Change carriage returns to spaces + '%09' => ' ', // Change tabs to spaces ] ); + // Consolidate runs of multiple spaces in a row + $encoded = preg_replace( '/ {2,}/', ' ', $encoded ); + // Remove leading and trailing spaces + $encoded = preg_replace( '/^ | $/', '', $encoded ); + $uri = 'data:' . $type . ',' . $encoded; if ( !$ie8Compat || strlen( $uri ) < self::DATA_URI_SIZE_LIMIT ) { return $uri; diff --git a/includes/libs/IEUrlExtension.php b/includes/libs/IEUrlExtension.php index 2d1c58b66a..0d969fb270 100644 --- a/includes/libs/IEUrlExtension.php +++ b/includes/libs/IEUrlExtension.php @@ -186,7 +186,7 @@ class IEUrlExtension { * - if we find a possible extension followed by a dot or another illegal * character, we ignore it and continue searching * - * @param string $url URL + * @param string $url * @return mixed Detected extension (string), or false if none found */ public static function findIE6Extension( $url ) { diff --git a/includes/libs/IP.php b/includes/libs/IP.php index 1c48f49d6b..f95bb1ebde 100644 --- a/includes/libs/IP.php +++ b/includes/libs/IP.php @@ -21,7 +21,7 @@ * @author Antoine Musso "" */ -use IPSet\IPSet; +use Wikimedia\IPSet; // Some regex definition to "play" with IP address and IP address ranges diff --git a/includes/libs/JavaScriptMinifier.php b/includes/libs/JavaScriptMinifier.php index 141a5153d4..a1a93d2b46 100644 --- a/includes/libs/JavaScriptMinifier.php +++ b/includes/libs/JavaScriptMinifier.php @@ -1,5 +1,4 @@ true, '"' => true, '%' => true, @@ -109,10 +106,10 @@ class JavaScriptMinifier { '|' => true, '}' => true, '~' => true - ); + ]; // $tokenTypes : maps keywords and operators to their corresponding token type - $tokenTypes = array( + $tokenTypes = [ '!' => self::TYPE_UN_OP, '~' => self::TYPE_UN_OP, 'delete' => self::TYPE_UN_OP, @@ -184,13 +181,13 @@ class JavaScriptMinifier { 'try' => self::TYPE_DO, 'var' => self::TYPE_DO, 'function' => self::TYPE_FUNC - ); + ]; // $goto : This is the main table for our state machine. For every state/token pair // the following state is defined. When no rule exists for a given pair, // the state is left unchanged. - $goto = array( - self::STATEMENT => array( + $goto = [ + self::STATEMENT => [ self::TYPE_UN_OP => self::EXPRESSION, self::TYPE_INCR_OP => self::EXPRESSION, self::TYPE_ADD_OP => self::EXPRESSION, @@ -199,29 +196,29 @@ class JavaScriptMinifier { self::TYPE_IF => self::CONDITION, self::TYPE_FUNC => self::CONDITION, self::TYPE_LITERAL => self::EXPRESSION_OP - ), - self::CONDITION => array( + ], + self::CONDITION => [ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION - ), - self::PROPERTY_ASSIGNMENT => array( + ], + self::PROPERTY_ASSIGNMENT => [ self::TYPE_COLON => self::PROPERTY_EXPRESSION, self::TYPE_BRACE_OPEN => self::STATEMENT - ), - self::EXPRESSION => array( + ], + self::EXPRESSION => [ self::TYPE_SEMICOLON => self::STATEMENT, self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION, self::TYPE_FUNC => self::EXPRESSION_FUNC, self::TYPE_LITERAL => self::EXPRESSION_OP - ), - self::EXPRESSION_NO_NL => array( + ], + self::EXPRESSION_NO_NL => [ self::TYPE_SEMICOLON => self::STATEMENT, self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION, self::TYPE_FUNC => self::EXPRESSION_FUNC, self::TYPE_LITERAL => self::EXPRESSION_OP - ), - self::EXPRESSION_OP => array( + ], + self::EXPRESSION_OP => [ self::TYPE_BIN_OP => self::EXPRESSION, self::TYPE_ADD_OP => self::EXPRESSION, self::TYPE_HOOK => self::EXPRESSION_TERNARY, @@ -229,33 +226,33 @@ class JavaScriptMinifier { self::TYPE_COMMA => self::EXPRESSION, self::TYPE_SEMICOLON => self::STATEMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION - ), - self::EXPRESSION_FUNC => array( + ], + self::EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::STATEMENT - ), - self::EXPRESSION_TERNARY => array( + ], + self::EXPRESSION_TERNARY => [ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION, self::TYPE_FUNC => self::EXPRESSION_TERNARY_FUNC, self::TYPE_LITERAL => self::EXPRESSION_TERNARY_OP - ), - self::EXPRESSION_TERNARY_OP => array( + ], + self::EXPRESSION_TERNARY_OP => [ self::TYPE_BIN_OP => self::EXPRESSION_TERNARY, self::TYPE_ADD_OP => self::EXPRESSION_TERNARY, self::TYPE_HOOK => self::EXPRESSION_TERNARY, self::TYPE_COMMA => self::EXPRESSION_TERNARY, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION - ), - self::EXPRESSION_TERNARY_FUNC => array( + ], + self::EXPRESSION_TERNARY_FUNC => [ self::TYPE_BRACE_OPEN => self::STATEMENT - ), - self::PAREN_EXPRESSION => array( + ], + self::PAREN_EXPRESSION => [ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION, self::TYPE_FUNC => self::PAREN_EXPRESSION_FUNC, self::TYPE_LITERAL => self::PAREN_EXPRESSION_OP - ), - self::PAREN_EXPRESSION_OP => array( + ], + self::PAREN_EXPRESSION_OP => [ self::TYPE_BIN_OP => self::PAREN_EXPRESSION, self::TYPE_ADD_OP => self::PAREN_EXPRESSION, self::TYPE_HOOK => self::PAREN_EXPRESSION, @@ -263,107 +260,107 @@ class JavaScriptMinifier { self::TYPE_COMMA => self::PAREN_EXPRESSION, self::TYPE_SEMICOLON => self::PAREN_EXPRESSION, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION - ), - self::PAREN_EXPRESSION_FUNC => array( + ], + self::PAREN_EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::STATEMENT - ), - self::PROPERTY_EXPRESSION => array( + ], + self::PROPERTY_EXPRESSION => [ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION, self::TYPE_FUNC => self::PROPERTY_EXPRESSION_FUNC, self::TYPE_LITERAL => self::PROPERTY_EXPRESSION_OP - ), - self::PROPERTY_EXPRESSION_OP => array( + ], + self::PROPERTY_EXPRESSION_OP => [ self::TYPE_BIN_OP => self::PROPERTY_EXPRESSION, self::TYPE_ADD_OP => self::PROPERTY_EXPRESSION, self::TYPE_HOOK => self::PROPERTY_EXPRESSION, self::TYPE_COMMA => self::PROPERTY_ASSIGNMENT, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION - ), - self::PROPERTY_EXPRESSION_FUNC => array( + ], + self::PROPERTY_EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::STATEMENT - ) - ); + ] + ]; // $push : This table contains the rules for when to push a state onto the stack. // The pushed state is the state to return to when the corresponding // closing token is found - $push = array( - self::STATEMENT => array( + $push = [ + self::STATEMENT => [ self::TYPE_BRACE_OPEN => self::STATEMENT, self::TYPE_PAREN_OPEN => self::EXPRESSION_OP - ), - self::CONDITION => array( + ], + self::CONDITION => [ self::TYPE_PAREN_OPEN => self::STATEMENT - ), - self::PROPERTY_ASSIGNMENT => array( + ], + self::PROPERTY_ASSIGNMENT => [ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT - ), - self::EXPRESSION => array( + ], + self::EXPRESSION => [ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP, self::TYPE_PAREN_OPEN => self::EXPRESSION_OP - ), - self::EXPRESSION_NO_NL => array( + ], + self::EXPRESSION_NO_NL => [ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP, self::TYPE_PAREN_OPEN => self::EXPRESSION_OP - ), - self::EXPRESSION_OP => array( + ], + self::EXPRESSION_OP => [ self::TYPE_HOOK => self::EXPRESSION, self::TYPE_PAREN_OPEN => self::EXPRESSION_OP - ), - self::EXPRESSION_FUNC => array( + ], + self::EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP - ), - self::EXPRESSION_TERNARY => array( + ], + self::EXPRESSION_TERNARY => [ self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP, self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP - ), - self::EXPRESSION_TERNARY_OP => array( + ], + self::EXPRESSION_TERNARY_OP => [ self::TYPE_HOOK => self::EXPRESSION_TERNARY, self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP - ), - self::EXPRESSION_TERNARY_FUNC => array( + ], + self::EXPRESSION_TERNARY_FUNC => [ self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP - ), - self::PAREN_EXPRESSION => array( + ], + self::PAREN_EXPRESSION => [ self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP, self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP - ), - self::PAREN_EXPRESSION_OP => array( + ], + self::PAREN_EXPRESSION_OP => [ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP - ), - self::PAREN_EXPRESSION_FUNC => array( + ], + self::PAREN_EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP - ), - self::PROPERTY_EXPRESSION => array( + ], + self::PROPERTY_EXPRESSION => [ self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP, self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP - ), - self::PROPERTY_EXPRESSION_OP => array( + ], + self::PROPERTY_EXPRESSION_OP => [ self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP - ), - self::PROPERTY_EXPRESSION_FUNC => array( + ], + self::PROPERTY_EXPRESSION_FUNC => [ self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP - ) - ); + ] + ]; // $pop : Rules for when to pop a state from the stack - $pop = array( - self::STATEMENT => array( self::TYPE_BRACE_CLOSE => true ), - self::PROPERTY_ASSIGNMENT => array( self::TYPE_BRACE_CLOSE => true ), - self::EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ), - self::EXPRESSION_NO_NL => array( self::TYPE_BRACE_CLOSE => true ), - self::EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true ), - self::EXPRESSION_TERNARY_OP => array( self::TYPE_COLON => true ), - self::PAREN_EXPRESSION => array( self::TYPE_PAREN_CLOSE => true ), - self::PAREN_EXPRESSION_OP => array( self::TYPE_PAREN_CLOSE => true ), - self::PROPERTY_EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ), - self::PROPERTY_EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true ) - ); + $pop = [ + self::STATEMENT => [ self::TYPE_BRACE_CLOSE => true ], + self::PROPERTY_ASSIGNMENT => [ self::TYPE_BRACE_CLOSE => true ], + self::EXPRESSION => [ self::TYPE_BRACE_CLOSE => true ], + self::EXPRESSION_NO_NL => [ self::TYPE_BRACE_CLOSE => true ], + self::EXPRESSION_OP => [ self::TYPE_BRACE_CLOSE => true ], + self::EXPRESSION_TERNARY_OP => [ self::TYPE_COLON => true ], + self::PAREN_EXPRESSION => [ self::TYPE_PAREN_CLOSE => true ], + self::PAREN_EXPRESSION_OP => [ self::TYPE_PAREN_CLOSE => true ], + self::PROPERTY_EXPRESSION => [ self::TYPE_BRACE_CLOSE => true ], + self::PROPERTY_EXPRESSION_OP => [ self::TYPE_BRACE_CLOSE => true ] + ]; // $semicolon : Rules for when a semicolon insertion is appropriate - $semicolon = array( - self::EXPRESSION_NO_NL => array( + $semicolon = [ + self::EXPRESSION_NO_NL => [ self::TYPE_UN_OP => true, self::TYPE_INCR_OP => true, self::TYPE_ADD_OP => true, @@ -374,8 +371,8 @@ class JavaScriptMinifier { self::TYPE_DO => true, self::TYPE_FUNC => true, self::TYPE_LITERAL => true - ), - self::EXPRESSION_OP => array( + ], + self::EXPRESSION_OP => [ self::TYPE_UN_OP => true, self::TYPE_INCR_OP => true, self::TYPE_BRACE_OPEN => true, @@ -384,33 +381,16 @@ class JavaScriptMinifier { self::TYPE_DO => true, self::TYPE_FUNC => true, self::TYPE_LITERAL => true - ) - ); - - // Rules for when newlines should be inserted if - // $statementsOnOwnLine is enabled. - // $newlineBefore is checked before switching state, - // $newlineAfter is checked after - $newlineBefore = array( - self::STATEMENT => array( - self::TYPE_BRACE_CLOSE => true, - ), - ); - $newlineAfter = array( - self::STATEMENT => array( - self::TYPE_BRACE_OPEN => true, - self::TYPE_PAREN_CLOSE => true, - self::TYPE_SEMICOLON => true, - ), - ); + ] + ]; // $divStates : Contains all states that can be followed by a division operator - $divStates = array( + $divStates = [ self::EXPRESSION_OP => true, self::EXPRESSION_TERNARY_OP => true, self::PAREN_EXPRESSION_OP => true, self::PROPERTY_EXPRESSION_OP => true - ); + ]; // Here's where the minifying takes place: Loop through the input, looking for tokens // and output them to $out, taking actions to the above defined rules when appropriate. @@ -420,24 +400,24 @@ class JavaScriptMinifier { $lineLength = 0; $newlineFound = true; $state = self::STATEMENT; - $stack = array(); + $stack = []; $last = ';'; // Pretend that we have seen a semicolon yet - while( $pos < $length ) { + while ( $pos < $length ) { // First, skip over any whitespace and multiline comments, recording whether we // found any newline character $skip = strspn( $s, " \t\n\r\xb\xc", $pos ); - if( !$skip ) { + if ( !$skip ) { $ch = $s[$pos]; - if( $ch === '/' && substr( $s, $pos, 2 ) === '/*' ) { + if ( $ch === '/' && substr( $s, $pos, 2 ) === '/*' ) { // Multiline comment. Search for the end token or EOT. $end = strpos( $s, '*/', $pos + 2 ); $skip = $end === false ? $length - $pos : $end - $pos + 2; } } - if( $skip ) { + if ( $skip ) { // The semicolon insertion mechanism needs to know whether there was a newline // between two tokens, so record it now. - if( !$newlineFound && strcspn( $s, "\r\n", $pos, $skip ) !== $skip ) { + if ( !$newlineFound && strcspn( $s, "\r\n", $pos, $skip ) !== $skip ) { $newlineFound = true; } $pos += $skip; @@ -446,7 +426,7 @@ class JavaScriptMinifier { // Handle C++-style comments and html comments, which are treated as single line // comments by the browser, regardless of whether the end tag is on the same line. // Handle --> the same way, but only if it's at the beginning of the line - if( ( $ch === '/' && substr( $s, $pos, 2 ) === '//' ) + if ( ( $ch === '/' && substr( $s, $pos, 2 ) === '//' ) || ( $ch === '<' && substr( $s, $pos, 4 ) === '' ) ) { @@ -454,65 +434,106 @@ class JavaScriptMinifier { continue; } - // Find out which kind of token we're handling. $end will point past the end of it. + // Find out which kind of token we're handling. + // Note: $end must point past the end of the current token + // so that `substr($s, $pos, $end - $pos)` would be the entire token. + // In order words, $end will be the offset of the last relevant character + // in the stream + 1, or simply put: The offset of the first character + // of any next token in the stream. $end = $pos + 1; // Handle string literals - if( $ch === "'" || $ch === '"' ) { + if ( $ch === "'" || $ch === '"' ) { // Search to the end of the string literal, skipping over backslash escapes $search = $ch . '\\'; do{ + // Speculatively add 2 to the end so that if we see a backslash, + // the next iteration will start 2 characters further (one for the + // backslash, one for the escaped character). + // We'll correct this outside the loop. $end += strcspn( $s, $search, $end ) + 2; - } while( $end - 2 < $length && $s[$end - 2] === '\\' ); + // If the last character in our search for a quote or a backlash + // matched a backslash and we haven't reached the end, keep searching.. + } while ( $end - 2 < $length && $s[$end - 2] === '\\' ); + // Correction (1): Undo speculative add, keep only one (end of string literal) $end--; + if ( $end > $length ) { + // Correction (2): Loop wrongly assumed an end quote ended the search, + // but search ended because we've reached the end. Correct $end. + // TODO: This is invalid and should throw. + $end--; + } // We have to distinguish between regexp literals and division operators // A division operator is only possible in certain states - } elseif( $ch === '/' && !isset( $divStates[$state] ) ) { - // Regexp literal, search to the end, skipping over backslash escapes and - // character classes - for( ; ; ) { + } elseif ( $ch === '/' && !isset( $divStates[$state] ) ) { + // Regexp literal + for ( ; ; ) { + // Search until we find "/" (end of regexp), "\" (backslash escapes), + // or "[" (start of character classes). do{ + // Speculatively add 2 to ensure next iteration skips + // over backslash and escaped character. + // We'll correct this outside the loop. $end += strcspn( $s, '/[\\', $end ) + 2; - } while( $end - 2 < $length && $s[$end - 2] === '\\' ); + // If backslash escape, keep searching... + } while ( $end - 2 < $length && $s[$end - 2] === '\\' ); + // Correction (1): Undo speculative add, keep only one (end of regexp) $end--; - if( $end - 1 >= $length || $s[$end - 1] === '/' ) { + if ( $end > $length ) { + // Correction (2): Loop wrongly assumed end slash was seen + // String ended without end of regexp. Correct $end. + // TODO: This is invalid and should throw. + $end--; + break; + } + if ( $s[$end - 1] === '/' ) { break; } + // (Implicit else), we must've found the start of a char class, + // skip until we find "]" (end of char class), or "\" (backslash escape) do{ + // Speculatively add 2 for backslash escape. + // We'll substract one outside the loop. $end += strcspn( $s, ']\\', $end ) + 2; - } while( $end - 2 < $length && $s[$end - 2] === '\\' ); + // If backslash escape, keep searching... + } while ( $end - 2 < $length && $s[$end - 2] === '\\' ); + // Correction (1): Undo speculative add, keep only one (end of regexp) $end--; - }; + } // Search past the regexp modifiers (gi) - while( $end < $length && ctype_alpha( $s[$end] ) ) { + while ( $end < $length && ctype_alpha( $s[$end] ) ) { $end++; } - } elseif( + } elseif ( $ch === '0' - && ($pos + 1 < $length) && ($s[$pos + 1] === 'x' || $s[$pos + 1] === 'X' ) + && ( $pos + 1 < $length ) && ( $s[$pos + 1] === 'x' || $s[$pos + 1] === 'X' ) ) { // Hex numeric literal $end++; // x or X $len = strspn( $s, '0123456789ABCDEFabcdef', $end ); if ( !$len ) { - return self::parseError($s, $pos, 'Expected a hexadecimal number but found ' . substr( $s, $pos, 5 ) . '...' ); + return self::parseError( + $s, + $pos, + 'Expected a hexadecimal number but found ' . substr( $s, $pos, 5 ) . '...' + ); } $end += $len; - } elseif( + } elseif ( ctype_digit( $ch ) || ( $ch === '.' && $pos + 1 < $length && ctype_digit( $s[$pos + 1] ) ) ) { $end += strspn( $s, '0123456789', $end ); $decimal = strspn( $s, '.', $end ); - if ($decimal) { + if ( $decimal ) { if ( $decimal > 2 ) { - return self::parseError($s, $end, 'The number has too many decimal points' ); + return self::parseError( $s, $end, 'The number has too many decimal points' ); } $end += strspn( $s, '0123456789', $end + 1 ) + $decimal; } $exponent = strspn( $s, 'eE', $end ); - if( $exponent ) { + if ( $exponent ) { if ( $exponent > 1 ) { - return self::parseError($s, $end, 'Number with several E' ); + return self::parseError( $s, $end, 'Number with several E' ); } $end++; @@ -520,13 +541,17 @@ class JavaScriptMinifier { $end += strspn( $s, '-+', $end ); $len = strspn( $s, '0123456789', $end ); if ( !$len ) { - return self::parseError($s, $pos, 'No decimal digits after e, how many zeroes should be added?' ); + return self::parseError( + $s, + $pos, + 'No decimal digits after e, how many zeroes should be added?' + ); } $end += $len; } - } elseif( isset( $opChars[$ch] ) ) { + } elseif ( isset( $opChars[$ch] ) ) { // Punctuation character. Search for the longest matching operator. - while( + while ( $end < $length && isset( $tokenTypes[substr( $s, $pos, $end - $pos + 1 )] ) ) { @@ -542,26 +567,25 @@ class JavaScriptMinifier { $token = substr( $s, $pos, $end - $pos ); // so $end - $pos == strlen( $token ) $type = isset( $tokenTypes[$token] ) ? $tokenTypes[$token] : self::TYPE_LITERAL; - if( $newlineFound && isset( $semicolon[$state][$type] ) ) { + if ( $newlineFound && isset( $semicolon[$state][$type] ) ) { // This token triggers the semicolon insertion mechanism of javascript. While we // could add the ; token here ourselves, keeping the newline has a few advantages. $out .= "\n"; $state = self::STATEMENT; $lineLength = 0; - } elseif( $maxLineLength > 0 && $lineLength + $end - $pos > $maxLineLength && - !isset( $semicolon[$state][$type] ) && $type !== self::TYPE_INCR_OP ) - { + } elseif ( $lineLength + $end - $pos > self::MAX_LINE_LENGTH && + !isset( $semicolon[$state][$type] ) && $type !== self::TYPE_INCR_OP ) { // This line would get too long if we added $token, so add a newline first. // Only do this if it won't trigger semicolon insertion and if it won't // put a postfix increment operator on its own line, which is illegal in js. $out .= "\n"; $lineLength = 0; // Check, whether we have to separate the token from the last one with whitespace - } elseif( !isset( $opChars[$last] ) && !isset( $opChars[$ch] ) ) { + } elseif ( !isset( $opChars[$last] ) && !isset( $opChars[$ch] ) ) { $out .= ' '; $lineLength++; // Don't accidentally create ++, -- or // tokens - } elseif( $last === $ch && ( $ch === '+' || $ch === '-' || $ch === '/' ) ) { + } elseif ( $last === $ch && ( $ch === '+' || $ch === '-' || $ch === '/' ) ) { $out .= ' '; $lineLength++; } @@ -580,35 +604,20 @@ class JavaScriptMinifier { $pos = $end; $newlineFound = false; - // Output a newline after the token if required - // This is checked before AND after switching state - $newlineAdded = false; - if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineBefore[$state][$type] ) ) { - $out .= "\n"; - $lineLength = 0; - $newlineAdded = true; - } - // Now that we have output our token, transition into the new state. - if( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) { + if ( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) { $stack[] = $push[$state][$type]; } - if( $stack && isset( $pop[$state][$type] ) ) { + if ( $stack && isset( $pop[$state][$type] ) ) { $state = array_pop( $stack ); - } elseif( isset( $goto[$state][$type] ) ) { + } elseif ( isset( $goto[$state][$type] ) ) { $state = $goto[$state][$type]; } - - // Check for newline insertion again - if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineAfter[$state][$type] ) ) { - $out .= "\n"; - $lineLength = 0; - } } return $out; } - static function parseError($fullJavascript, $position, $errorMsg) { + static function parseError( $fullJavascript, $position, $errorMsg ) { // TODO: Handle the error: trigger_error, throw exception, return false... return false; } diff --git a/includes/libs/MWMessagePack.php b/includes/libs/MWMessagePack.php index a9da3660b0..be7e93d53e 100644 --- a/includes/libs/MWMessagePack.php +++ b/includes/libs/MWMessagePack.php @@ -53,137 +53,137 @@ class MWMessagePack { } switch ( gettype( $value ) ) { - case 'NULL': - return "\xC0"; + case 'NULL': + return "\xC0"; - case 'boolean': - return $value ? "\xC3" : "\xC2"; + case 'boolean': + return $value ? "\xC3" : "\xC2"; - case 'double': - case 'float': - return self::$bigendian - ? "\xCB" . pack( 'd', $value ) - : "\xCB" . strrev( pack( 'd', $value ) ); + case 'double': + case 'float': + return self::$bigendian + ? "\xCB" . pack( 'd', $value ) + : "\xCB" . strrev( pack( 'd', $value ) ); - case 'string': - $length = strlen( $value ); - if ( $length < 32 ) { - return pack( 'Ca*', 0xA0 | $length, $value ); - } elseif ( $length <= 0xFFFF ) { - return pack( 'Cna*', 0xDA, $length, $value ); - } elseif ( $length <= 0xFFFFFFFF ) { - return pack( 'CNa*', 0xDB, $length, $value ); - } - throw new InvalidArgumentException( __METHOD__ - . ": string too long (length: $length; max: 4294967295)" ); - - case 'integer': - if ( $value >= 0 ) { - if ( $value <= 0x7F ) { - // positive fixnum - return chr( $value ); - } - if ( $value <= 0xFF ) { - // uint8 - return pack( 'CC', 0xCC, $value ); - } - if ( $value <= 0xFFFF ) { - // uint16 - return pack( 'Cn', 0xCD, $value ); - } - if ( $value <= 0xFFFFFFFF ) { - // uint32 - return pack( 'CN', 0xCE, $value ); - } - if ( $value <= 0xFFFFFFFFFFFFFFFF ) { - // uint64 - $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32; - $lo = $value & 0xFFFFFFFF; - return self::$bigendian - ? pack( 'CNN', 0xCF, $lo, $hi ) - : pack( 'CNN', 0xCF, $hi, $lo ); - } - } else { - if ( $value >= -32 ) { - // negative fixnum - return pack( 'c', $value ); - } - if ( $value >= -0x80 ) { - // int8 - return pack( 'Cc', 0xD0, $value ); - } - if ( $value >= -0x8000 ) { - // int16 - $p = pack( 's', $value ); - return self::$bigendian - ? pack( 'Ca2', 0xD1, $p ) - : pack( 'Ca2', 0xD1, strrev( $p ) ); - } - if ( $value >= -0x80000000 ) { - // int32 - $p = pack( 'l', $value ); - return self::$bigendian - ? pack( 'Ca4', 0xD2, $p ) - : pack( 'Ca4', 0xD2, strrev( $p ) ); - } - if ( $value >= -0x8000000000000000 ) { - // int64 - // pack() does not support 64-bit ints either so pack into two 32-bits - $p1 = pack( 'l', $value & 0xFFFFFFFF ); - $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF ); - return self::$bigendian - ? pack( 'Ca4a4', 0xD3, $p1, $p2 ) - : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) ); + case 'string': + $length = strlen( $value ); + if ( $length < 32 ) { + return pack( 'Ca*', 0xA0 | $length, $value ); + } elseif ( $length <= 0xFFFF ) { + return pack( 'Cna*', 0xDA, $length, $value ); + } elseif ( $length <= 0xFFFFFFFF ) { + return pack( 'CNa*', 0xDB, $length, $value ); } - } - throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" ); - - case 'array': - $buffer = ''; - $length = count( $value ); - if ( $length > 0xFFFFFFFF ) { throw new InvalidArgumentException( __METHOD__ - . ": array too long (length: $length, max: 4294967295)" ); - } + . ": string too long (length: $length; max: 4294967295)" ); - $index = 0; - foreach ( $value as $k => $v ) { - if ( $index !== $k || $index === $length ) { - break; + case 'integer': + if ( $value >= 0 ) { + if ( $value <= 0x7F ) { + // positive fixnum + return chr( $value ); + } + if ( $value <= 0xFF ) { + // uint8 + return pack( 'CC', 0xCC, $value ); + } + if ( $value <= 0xFFFF ) { + // uint16 + return pack( 'Cn', 0xCD, $value ); + } + if ( $value <= 0xFFFFFFFF ) { + // uint32 + return pack( 'CN', 0xCE, $value ); + } + if ( $value <= 0xFFFFFFFFFFFFFFFF ) { + // uint64 + $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32; + $lo = $value & 0xFFFFFFFF; + return self::$bigendian + ? pack( 'CNN', 0xCF, $lo, $hi ) + : pack( 'CNN', 0xCF, $hi, $lo ); + } } else { - $index++; + if ( $value >= -32 ) { + // negative fixnum + return pack( 'c', $value ); + } + if ( $value >= -0x80 ) { + // int8 + return pack( 'Cc', 0xD0, $value ); + } + if ( $value >= -0x8000 ) { + // int16 + $p = pack( 's', $value ); + return self::$bigendian + ? pack( 'Ca2', 0xD1, $p ) + : pack( 'Ca2', 0xD1, strrev( $p ) ); + } + if ( $value >= -0x80000000 ) { + // int32 + $p = pack( 'l', $value ); + return self::$bigendian + ? pack( 'Ca4', 0xD2, $p ) + : pack( 'Ca4', 0xD2, strrev( $p ) ); + } + if ( $value >= -0x8000000000000000 ) { + // int64 + // pack() does not support 64-bit ints either so pack into two 32-bits + $p1 = pack( 'l', $value & 0xFFFFFFFF ); + $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF ); + return self::$bigendian + ? pack( 'Ca4a4', 0xD3, $p1, $p2 ) + : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) ); + } } - } - $associative = $index !== $length; + throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" ); - if ( $associative ) { - if ( $length < 16 ) { - $buffer .= pack( 'C', 0x80 | $length ); - } elseif ( $length <= 0xFFFF ) { - $buffer .= pack( 'Cn', 0xDE, $length ); - } else { - $buffer .= pack( 'CN', 0xDF, $length ); + case 'array': + $buffer = ''; + $length = count( $value ); + if ( $length > 0xFFFFFFFF ) { + throw new InvalidArgumentException( __METHOD__ + . ": array too long (length: $length, max: 4294967295)" ); } + + $index = 0; foreach ( $value as $k => $v ) { - $buffer .= self::pack( $k ); - $buffer .= self::pack( $v ); + if ( $index !== $k || $index === $length ) { + break; + } else { + $index++; + } } - } else { - if ( $length < 16 ) { - $buffer .= pack( 'C', 0x90 | $length ); - } elseif ( $length <= 0xFFFF ) { - $buffer .= pack( 'Cn', 0xDC, $length ); + $associative = $index !== $length; + + if ( $associative ) { + if ( $length < 16 ) { + $buffer .= pack( 'C', 0x80 | $length ); + } elseif ( $length <= 0xFFFF ) { + $buffer .= pack( 'Cn', 0xDE, $length ); + } else { + $buffer .= pack( 'CN', 0xDF, $length ); + } + foreach ( $value as $k => $v ) { + $buffer .= self::pack( $k ); + $buffer .= self::pack( $v ); + } } else { - $buffer .= pack( 'CN', 0xDD, $length ); - } - foreach ( $value as $v ) { - $buffer .= self::pack( $v ); + if ( $length < 16 ) { + $buffer .= pack( 'C', 0x90 | $length ); + } elseif ( $length <= 0xFFFF ) { + $buffer .= pack( 'Cn', 0xDC, $length ); + } else { + $buffer .= pack( 'CN', 0xDD, $length ); + } + foreach ( $value as $v ) { + $buffer .= self::pack( $v ); + } } - } - return $buffer; + return $buffer; - default: - throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) ); + default: + throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) ); } } } diff --git a/includes/libs/StatusValue.php b/includes/libs/StatusValue.php index f9dcc1b52e..6f348c2b96 100644 --- a/includes/libs/StatusValue.php +++ b/includes/libs/StatusValue.php @@ -214,7 +214,7 @@ class StatusValue { /** * Merge another status object into this one * - * @param StatusValue $other Other StatusValue object + * @param StatusValue $other * @param bool $overwriteValue Whether to override the "value" member */ public function merge( $other, $overwriteValue = false ) { diff --git a/includes/libs/XhprofData.php b/includes/libs/XhprofData.php index 0be4ff6ad8..5af22ed5b2 100644 --- a/includes/libs/XhprofData.php +++ b/includes/libs/XhprofData.php @@ -18,7 +18,7 @@ * @file */ -use RunningStat\RunningStat; +use Wikimedia\RunningStat; /** * Convenience class for working with XHProf profiling data @@ -209,14 +209,14 @@ class XhprofData { foreach ( $this->inclusive as $func => $stats ) { foreach ( $stats as $name => $value ) { if ( $value instanceof RunningStat ) { - $total = $value->m1 * $value->n; + $total = $value->getMean() * $value->getCount(); $percent = ( isset( $main[$name] ) && $main[$name] ) ? 100 * $total / $main[$name] : 0; $this->inclusive[$func][$name] = [ 'total' => $total, 'min' => $value->min, - 'mean' => $value->m1, + 'mean' => $value->getMean(), 'max' => $value->max, 'variance' => $value->m2, 'percent' => $percent, diff --git a/includes/libs/filebackend/FileBackend.php b/includes/libs/filebackend/FileBackend.php index 51308c1371..08f960a646 100644 --- a/includes/libs/filebackend/FileBackend.php +++ b/includes/libs/filebackend/FileBackend.php @@ -175,7 +175,7 @@ abstract class FileBackend implements LoggerAwareInterface { : new NullLockManager( [] ); $this->fileJournal = isset( $config['fileJournal'] ) ? $config['fileJournal'] - : FileJournal::factory( [ 'class' => 'NullFileJournal' ], $this->name ); + : FileJournal::factory( [ 'class' => NullFileJournal::class ], $this->name ); $this->readOnly = isset( $config['readOnly'] ) ? (string)$config['readOnly'] : ''; @@ -1597,7 +1597,7 @@ abstract class FileBackend implements LoggerAwareInterface { final protected function newStatus() { $args = func_get_args(); if ( count( $args ) ) { - $sv = call_user_func_array( [ 'StatusValue', 'newFatal' ], $args ); + $sv = call_user_func_array( [ StatusValue::class, 'newFatal' ], $args ); } else { $sv = StatusValue::newGood(); } diff --git a/includes/libs/filebackend/FileBackendMultiWrite.php b/includes/libs/filebackend/FileBackendMultiWrite.php index f8ca7e5aef..9c367af5ad 100644 --- a/includes/libs/filebackend/FileBackendMultiWrite.php +++ b/includes/libs/filebackend/FileBackendMultiWrite.php @@ -87,6 +87,9 @@ class FileBackendMultiWrite extends FileBackend { * This will apply such updates post-send for web requests. Note that * any checks from "syncChecks" are still synchronous. * + * Bogus warning + * @suppress PhanAccessMethodProtected + * * @param array $config * @throws FileBackendError */ diff --git a/includes/libs/filebackend/FileBackendStore.php b/includes/libs/filebackend/FileBackendStore.php index b8eec3f01d..da8b4ce9da 100644 --- a/includes/libs/filebackend/FileBackendStore.php +++ b/includes/libs/filebackend/FileBackendStore.php @@ -1008,13 +1008,13 @@ abstract class FileBackendStore extends FileBackend { */ final public function getOperationsInternal( array $ops ) { $supportedOps = [ - 'store' => 'StoreFileOp', - 'copy' => 'CopyFileOp', - 'move' => 'MoveFileOp', - 'delete' => 'DeleteFileOp', - 'create' => 'CreateFileOp', - 'describe' => 'DescribeFileOp', - 'null' => 'NullFileOp' + 'store' => StoreFileOp::class, + 'copy' => CopyFileOp::class, + 'move' => MoveFileOp::class, + 'delete' => DeleteFileOp::class, + 'create' => CreateFileOp::class, + 'describe' => DescribeFileOp::class, + 'null' => NullFileOp::class ]; $performOps = []; // array of FileOp objects diff --git a/includes/libs/jsminplus.php b/includes/libs/jsminplus.php index 7feac7d11a..e3c2d75863 100644 --- a/includes/libs/jsminplus.php +++ b/includes/libs/jsminplus.php @@ -1,5 +1,5 @@ domain = isset( $config['domain'] ) ? $config['domain'] : 'global'; if ( isset( $config['lockTTL'] ) ) { $this->lockTTL = max( 5, $config['lockTTL'] ); - } elseif ( PHP_SAPI === 'cli' ) { + } elseif ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ) { $this->lockTTL = 3600; } else { $met = ini_get( 'max_execution_time' ); // this is 0 in CLI mode diff --git a/includes/libs/lockmanager/MemcLockManager.php b/includes/libs/lockmanager/MemcLockManager.php index aecdf60cda..6274d60518 100644 --- a/includes/libs/lockmanager/MemcLockManager.php +++ b/includes/libs/lockmanager/MemcLockManager.php @@ -69,10 +69,10 @@ class MemcLockManager extends QuorumLockManager { $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive $memcConfig = isset( $config['memcConfig'] ) ? $config['memcConfig'] : []; - $memcConfig += [ 'class' => 'MemcachedPhpBagOStuff' ]; // default + $memcConfig += [ 'class' => MemcachedPhpBagOStuff::class ]; // default $class = $memcConfig['class']; - if ( !is_subclass_of( $class, 'MemcachedBagOStuff' ) ) { + if ( !is_subclass_of( $class, MemcachedBagOStuff::class ) ) { throw new InvalidArgumentException( "$class is not of type MemcachedBagOStuff." ); } diff --git a/includes/libs/lockmanager/ScopedLock.php b/includes/libs/lockmanager/ScopedLock.php index 2ad8ac87b5..6261335ea3 100644 --- a/includes/libs/lockmanager/ScopedLock.php +++ b/includes/libs/lockmanager/ScopedLock.php @@ -70,7 +70,7 @@ class ScopedLock { public static function factory( LockManager $manager, array $paths, $type, StatusValue $status, $timeout = 0 ) { - $pathsByType = is_integer( $type ) ? [ $type => $paths ] : $paths; + $pathsByType = is_int( $type ) ? [ $type => $paths ] : $paths; $lockStatus = $manager->lockByType( $pathsByType, $timeout ); $status->merge( $lockStatus ); if ( $lockStatus->isOK() ) { diff --git a/includes/libs/mime/XmlTypeCheck.php b/includes/libs/mime/XmlTypeCheck.php index ea7f9a6ca7..9770515ec0 100644 --- a/includes/libs/mime/XmlTypeCheck.php +++ b/includes/libs/mime/XmlTypeCheck.php @@ -294,7 +294,7 @@ class XmlTypeCheck { /** * @param string $name element or attribute name, maybe with a full or short prefix - * @param string $namespaceURI the namespaceURI + * @param string $namespaceURI * @return string the name prefixed with namespaceURI */ private function expandNS( $name, $namespaceURI ) { @@ -376,7 +376,7 @@ class XmlTypeCheck { if ( !$externalCallback && !$generalCallback && !$checkIfSafe ) { return; } - $dtd = $reader->readOuterXML(); + $dtd = $reader->readOuterXml(); $callbackReturn = false; if ( $generalCallback ) { @@ -479,23 +479,23 @@ class XmlTypeCheck { continue; } switch ( $field ) { - case 'typepublic': - case 'typesystem': - $parsed['type'] = $value; - break; - case 'pubquote': - case 'pubapos': - $parsed['publicid'] = $value; - break; - case 'pubsysquote': - case 'pubsysapos': - case 'sysquote': - case 'sysapos': - $parsed['systemid'] = $value; - break; - case 'internal': - $parsed['internal'] = $value; - break; + case 'typepublic': + case 'typesystem': + $parsed['type'] = $value; + break; + case 'pubquote': + case 'pubapos': + $parsed['publicid'] = $value; + break; + case 'pubsysquote': + case 'pubsysapos': + case 'sysquote': + case 'sysapos': + $parsed['systemid'] = $value; + break; + case 'internal': + $parsed['internal'] = $value; + break; } } return $parsed; diff --git a/includes/libs/objectcache/MemcachedClient.php b/includes/libs/objectcache/MemcachedClient.php index 5cb49a9972..b937736d4f 100644 --- a/includes/libs/objectcache/MemcachedClient.php +++ b/includes/libs/objectcache/MemcachedClient.php @@ -1,5 +1,5 @@ = 2.6.12 * - * @note: avoid use of Redis::MULTI transactions for twemproxy support + * @note Avoid use of Redis::MULTI transactions for twemproxy support + * + * @ingroup Cache + * @ingroup Redis */ class RedisBagOStuff extends BagOStuff { /** @var RedisConnectionPool */ diff --git a/includes/libs/objectcache/WANObjectCache.php b/includes/libs/objectcache/WANObjectCache.php index db27e42e1e..08424c9c8a 100644 --- a/includes/libs/objectcache/WANObjectCache.php +++ b/includes/libs/objectcache/WANObjectCache.php @@ -91,6 +91,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { protected $logger; /** @var StatsdDataFactoryInterface */ protected $stats; + /** @var bool Whether to use "interim" caching while keys are tombstoned */ + protected $useInterimHoldOffCaching = true; + /** @var callable|null Function that takes a WAN cache callback and runs it later */ + protected $asyncHandler; /** @var int ERR_* constant for the "last error" registry */ protected $lastRelayError = self::ERR_NONE; @@ -189,6 +193,13 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * - relayers : Map of (action => EventRelayer object). Actions include "purge". * - logger : LoggerInterface object * - stats : LoggerInterface object + * - asyncHandler : A function that takes a callback and runs it later. If supplied, + * whenever a preemptive refresh would be triggered in getWithSetCallback(), the + * current cache value is still used instead. However, the async-handler function + * receives a WAN cache callback that, when run, will execute the value generation + * callback supplied by the getWithSetCallback() caller. The result will be saved + * as normal. The handler is expected to call the WAN cache callback at an opportune + * time (e.g. HTTP post-send), though generally within a few 100ms. [optional] */ public function __construct( array $params ) { $this->cache = $params['cache']; @@ -200,8 +211,12 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { : new EventRelayerNull( [] ); $this->setLogger( isset( $params['logger'] ) ? $params['logger'] : new NullLogger() ); $this->stats = isset( $params['stats'] ) ? $params['stats'] : new NullStatsdDataFactory(); + $this->asyncHandler = isset( $params['asyncHandler'] ) ? $params['asyncHandler'] : null; } + /** + * @param LoggerInterface $logger + */ public function setLogger( LoggerInterface $logger ) { $this->logger = $logger; } @@ -213,8 +228,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { */ public static function newEmpty() { return new static( [ - 'cache' => new EmptyBagOStuff(), - 'pool' => 'empty' + 'cache' => new EmptyBagOStuff() ] ); } @@ -375,13 +389,13 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { $purgeValues = []; foreach ( $timeKeys as $timeKey ) { $purge = isset( $wrappedValues[$timeKey] ) - ? self::parsePurgeValue( $wrappedValues[$timeKey] ) + ? $this->parsePurgeValue( $wrappedValues[$timeKey] ) : false; if ( $purge === false ) { // Key is not set or invalid; regenerate $newVal = $this->makePurgeValue( $now, self::HOLDOFF_TTL ); $this->cache->add( $timeKey, $newVal, self::CHECK_KEY_TTL ); - $purge = self::parsePurgeValue( $newVal ); + $purge = $this->parsePurgeValue( $newVal ); } $purgeValues[] = $purge; } @@ -405,6 +419,12 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * * Setting 'lag' and 'since' help avoids keys getting stuck in stale states. * + * Be aware that this does not update the process cache for getWithSetCallback() + * callers. Keys accessed via that method are not generally meant to also be set + * using this primitive method. + * + * Do not use this method on versioned keys accessed via getWithSetCallback(). + * * Example usage: * @code * $dbr = wfGetDB( DB_REPLICA ); @@ -521,6 +541,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * * Note that set() can also be lag-aware and lower the TTL if it's high. * + * Be aware that this does not clear the process cache. Even if it did, callbacks + * used by getWithSetCallback() might still return stale data in the case of either + * uncommitted or not-yet-replicated changes (callback generally use replica DBs). + * * 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 upon purge relay. @@ -589,25 +613,102 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * Note that "check" keys won't collide with other regular keys. * * @param string $key - * @return float UNIX timestamp of the check key + * @return float UNIX timestamp */ final public function getCheckKeyTime( $key ) { - $key = self::TIME_KEY_PREFIX . $key; + return $this->getMultiCheckKeyTime( [ $key ] )[$key]; + } - $purge = self::parsePurgeValue( $this->cache->get( $key ) ); - if ( $purge !== false ) { - $time = $purge[self::FLD_TIME]; - } else { - // Casting assures identical floats for the next getCheckKeyTime() calls - $now = (string)$this->getCurrentTime(); - $this->cache->add( $key, - $this->makePurgeValue( $now, self::HOLDOFF_TTL ), - self::CHECK_KEY_TTL - ); - $time = (float)$now; + /** + * Fetch the values of each timestamp "check" key + * + * This works like getCheckKeyTime() except it takes a list of keys + * and returns a map of timestamps instead of just that of one key + * + * This might be useful if both: + * - a) a class of entities each depend on hundreds of other entities + * - b) these other entities are depended upon by millions of entities + * + * The later entities can each use a "check" key to invalidate their dependee entities. + * However, it is expensive for the former entities to verify against all of the relevant + * "check" keys during each getWithSetCallback() call. A less expensive approach is to do + * these verifications only after a "time-till-verify" (TTV) has passed. This is a middle + * ground between using blind TTLs and using constant verification. The adaptiveTTL() method + * can be used to dynamically adjust the TTV. Also, the initial TTV can make use of the + * last-modified times of the dependant entities (either from the DB or the "check" keys). + * + * Example usage: + * @code + * $value = $cache->getWithSetCallback( + * $cache->makeGlobalKey( 'wikibase-item', $id ), + * self::INITIAL_TTV, // initial time-till-verify + * function ( $oldValue, &$ttv, &$setOpts, $oldAsOf ) use ( $checkKeys, $cache ) { + * $now = microtime( true ); + * // Use $oldValue if it passes max ultimate age and "check" key comparisons + * if ( $oldValue && + * $oldAsOf > max( $cache->getMultiCheckKeyTime( $checkKeys ) ) && + * ( $now - $oldValue['ctime'] ) <= self::MAX_CACHE_AGE + * ) { + * // Increase time-till-verify by 50% of last time to reduce overhead + * $ttv = $cache->adaptiveTTL( $oldAsOf, self::MAX_TTV, self::MIN_TTV, 1.5 ); + * // Unlike $oldAsOf, "ctime" is the ultimate age of the cached data + * return $oldValue; + * } + * + * $mtimes = []; // dependency last-modified times; passed by reference + * $value = [ 'data' => $this->fetchEntityData( $mtimes ), 'ctime' => $now ]; + * // Guess time-till-change among the dependencies, e.g. 1/(total change rate) + * $ttc = 1 / array_sum( array_map( + * function ( $mtime ) use ( $now ) { + * return 1 / ( $mtime ? ( $now - $mtime ) : 900 ); + * }, + * $mtimes + * ) ); + * // The time-to-verify should not be overly pessimistic nor optimistic + * $ttv = min( max( $ttc, self::MIN_TTV ), self::MAX_TTV ); + * + * return $value; + * }, + * [ 'staleTTL' => $cache::TTL_DAY ] // keep around to verify and re-save + * ); + * @endcode + * + * @see WANObjectCache::getCheckKeyTime() + * @see WANObjectCache::getWithSetCallback() + * + * @param array $keys + * @return float[] Map of (key => UNIX timestamp) + * @since 1.31 + */ + final public function getMultiCheckKeyTime( array $keys ) { + $rawKeys = []; + foreach ( $keys as $key ) { + $rawKeys[$key] = self::TIME_KEY_PREFIX . $key; } - return $time; + $rawValues = $this->cache->getMulti( $rawKeys ); + $rawValues += array_fill_keys( $rawKeys, false ); + + $times = []; + foreach ( $rawKeys as $key => $rawKey ) { + $purge = $this->parsePurgeValue( $rawValues[$rawKey] ); + if ( $purge !== false ) { + $time = $purge[self::FLD_TIME]; + } else { + // Casting assures identical floats for the next getCheckKeyTime() calls + $now = (string)$this->getCurrentTime(); + $this->cache->add( + $rawKey, + $this->makePurgeValue( $now, self::HOLDOFF_TTL ), + self::CHECK_KEY_TTL + ); + $time = (float)$now; + } + + $times[$key] = $time; + } + + return $times; } /** @@ -812,6 +913,40 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * ); * @endcode * + * Example usage (key holding an LRU subkey:value map; this can avoid flooding cache with + * keys for an unlimited set of (constraint,situation) pairs, thereby avoiding elevated + * cache evictions and wasted memory): + * @code + * $catSituationTolerabilityCache = $this->cache->getWithSetCallback( + * // Group by constraint ID/hash, cat family ID/hash, or something else useful + * $this->cache->makeKey( 'cat-situation-tolerablity-checks', $groupKey ), + * WANObjectCache::TTL_DAY, // rarely used groups should fade away + * // The $scenarioKey format is $constraintId: + * function ( $cacheMap ) use ( $scenarioKey, $constraintId, $situation ) { + * $lruCache = MapCacheLRU::newFromArray( $cacheMap ?: [], self::CACHE_SIZE ); + * $result = $lruCache->get( $scenarioKey ); // triggers LRU bump if present + * if ( $result === null || $this->isScenarioResultExpired( $result ) ) { + * $result = $this->checkScenarioTolerability( $constraintId, $situation ); + * $lruCache->set( $scenarioKey, $result, 3 / 8 ); + * } + * // Save the new LRU cache map and reset the map's TTL + * return $lruCache->toArray(); + * }, + * [ + * // Once map is > 1 sec old, consider refreshing + * 'ageNew' => 1, + * // Update within 5 seconds after "ageNew" given a 1hz cache check rate + * 'hotTTR' => 5, + * // Avoid querying cache servers multiple times in a request; this also means + * // that a request can only alter the value of any given constraint key once + * 'pcTTL' => WANObjectCache::TTL_PROC_LONG + * ] + * ); + * $tolerability = isset( $catSituationTolerabilityCache[$scenarioKey] ) + * ? $catSituationTolerabilityCache[$scenarioKey] + * : $this->checkScenarioTolerability( $constraintId, $situation ); + * @endcode + * * @see WANObjectCache::get() * @see WANObjectCache::set() * @@ -888,6 +1023,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * Default: WANObjectCache::STALE_TTL_NONE * @return mixed Value found or written to the key * @note Options added in 1.28: version, busyValue, hotTTR, ageNew, pcGroup, minAsOf + * @note Options added in 1.31: staleTTL, graceTTL * @note Callable type hints are not used to avoid class-autoloading */ final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) { @@ -1000,12 +1136,27 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { if ( $value !== false && $this->isAliveOrInGracePeriod( $curTTL, $graceTTL ) && $this->isValid( $value, $versioned, $asOf, $minTime ) - && !$this->worthRefreshExpiring( $curTTL, $lowTTL ) - && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime ) ) { - $this->stats->increment( "wanobjectcache.$kClass.hit.good" ); + $preemptiveRefresh = ( + $this->worthRefreshExpiring( $curTTL, $lowTTL ) || + $this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime ) + ); - return $value; + if ( !$preemptiveRefresh ) { + $this->stats->increment( "wanobjectcache.$kClass.hit.good" ); + + return $value; + } elseif ( $this->asyncHandler ) { + // Update the cache value later, such during post-send of an HTTP request + $func = $this->asyncHandler; + $func( function () use ( $key, $ttl, $callback, $opts, $asOf ) { + $opts['minAsOf'] = INF; // force a refresh + $this->doGetWithSetCallback( $key, $ttl, $callback, $opts, $asOf ); + } ); + $this->stats->increment( "wanobjectcache.$kClass.hit.refresh" ); + + return $value; + } } // A deleted key with a negative TTL left must be tombstoned @@ -1100,10 +1251,14 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @param string $key * @param bool $versioned * @param float $minTime - * @param mixed $asOf + * @param mixed &$asOf * @return mixed */ protected function getInterimValue( $key, $versioned, $minTime, &$asOf ) { + if ( !$this->useInterimHoldOffCaching ) { + return false; // disabled + } + $wrapped = $this->cache->get( self::INTERIM_KEY_PREFIX . $key ); list( $value ) = $this->unwrap( $wrapped, $this->getCurrentTime() ); if ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) { @@ -1232,8 +1387,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * This works the same as getWithSetCallback() except: * - a) The $keys argument expects the result of WANObjectCache::makeMultiKeys() * - b) The $callback argument expects a callback returning a map of (ID => new value) - * for all entity IDs in $regenById and it takes the following arguments: - * - $ids: a list of entity IDs to regenerate + * for all entity IDs in $ids and it takes the following arguments: + * - $ids: a list of entity IDs that require cache regeneration * - &$ttls: a reference to the (entity ID => new TTL) map * - &$setOpts: a reference to options for set() which can be altered * - c) The return value is a map of (cache key => value) in the order of $keyedIds @@ -1367,7 +1522,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @return bool Success * @since 1.28 */ - public function reap( $key, $purgeTimestamp, &$isStale = false ) { + final public function reap( $key, $purgeTimestamp, &$isStale = false ) { $minAsOf = $purgeTimestamp + self::HOLDOFF_TTL; $wrapped = $this->cache->get( self::VALUE_KEY_PREFIX . $key ); if ( is_array( $wrapped ) && $wrapped[self::FLD_TIME] < $minAsOf ) { @@ -1396,7 +1551,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @return bool Success * @since 1.28 */ - public function reapCheckKey( $key, $purgeTimestamp, &$isStale = false ) { + final public function reapCheckKey( $key, $purgeTimestamp, &$isStale = false ) { $purge = $this->parsePurgeValue( $this->cache->get( self::TIME_KEY_PREFIX . $key ) ); if ( $purge && $purge[self::FLD_TIME] < $purgeTimestamp ) { $isStale = true; @@ -1442,7 +1597,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @return ArrayIterator Iterator yielding (cache key => entity ID) in $entities order * @since 1.28 */ - public function makeMultiKeys( array $entities, callable $keyFunc ) { + final public function makeMultiKeys( array $entities, callable $keyFunc ) { $map = []; foreach ( $entities as $entity ) { $map[$keyFunc( $entity, $this )] = $entity; @@ -1495,6 +1650,30 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { $this->processCaches = []; } + /** + * Enable or disable the use of brief caching for tombstoned keys + * + * When a key is purged via delete(), there normally is a period where caching + * is hold-off limited to an extremely short time. This method will disable that + * caching, forcing the callback to run for any of: + * - WANObjectCache::getWithSetCallback() + * - WANObjectCache::getMultiWithSetCallback() + * - WANObjectCache::getMultiWithUnionSetCallback() + * + * This is useful when both: + * - a) the database used by the callback is known to be up-to-date enough + * for some particular purpose (e.g. replica DB has applied transaction X) + * - b) the caller needs to exploit that fact, and therefore needs to avoid the + * use of inherently volatile and possibly stale interim keys + * + * @see WANObjectCache::delete() + * @param bool $enabled Whether to enable interim caching + * @since 1.31 + */ + final public function useInterimHoldOffCaching( $enabled ) { + $this->useInterimHoldOffCaching = $enabled; + } + /** * @param int $flag ATTR_* class constant * @return int QOS_* class constant @@ -1546,7 +1725,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * $ttl = ( $newList === $oldValue ) * // No change: cache for 150% of the age of $oldValue * ? $cache->adaptiveTTL( $oldAsOf, $maxTTL, $minTTL, 1.5 ) - * // Changed: cache for %50 of the age of $oldValue + * // Changed: cache for 50% of the age of $oldValue * : $cache->adaptiveTTL( $oldAsOf, $maxTTL, $minTTL, .5 ); * } * @@ -1585,7 +1764,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @return int Number of warmup key cache misses last round * @since 1.30 */ - public function getWarmupKeyMisses() { + final public function getWarmupKeyMisses() { return $this->warmupKeyMisses; } @@ -1792,7 +1971,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { */ protected function unwrap( $wrapped, $now ) { // Check if the value is a tombstone - $purge = self::parsePurgeValue( $wrapped ); + $purge = $this->parsePurgeValue( $wrapped ); if ( $purge !== false ) { // Purged values should always have a negative current $ttl $curTTL = min( $purge[self::FLD_TIME] - $now, self::TINY_NEGATIVE ); @@ -1860,7 +2039,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @return array|bool Array containing a UNIX timestamp (float) and holdoff period (integer), * or false if value isn't a valid purge value */ - protected static function parsePurgeValue( $value ) { + protected function parsePurgeValue( $value ) { if ( !is_string( $value ) ) { return false; } diff --git a/includes/libs/rdbms/ChronologyProtector.php b/includes/libs/rdbms/ChronologyProtector.php index 8121654e33..4fcd88599c 100644 --- a/includes/libs/rdbms/ChronologyProtector.php +++ b/includes/libs/rdbms/ChronologyProtector.php @@ -43,10 +43,10 @@ class ChronologyProtector implements LoggerAwareInterface { protected $key; /** @var string Hash of client parameters */ protected $clientId; - /** @var float|null Minimum UNIX timestamp of 1+ expected startup positions */ - protected $waitForPosTime; + /** @var int|null Expected minimum index of the last write to the position store */ + protected $waitForPosIndex; /** @var int Max seconds to wait on positions to appear */ - protected $waitForPosTimeout = self::POS_WAIT_TIMEOUT; + protected $waitForPosStoreTimeout = self::POS_STORE_WAIT_TIMEOUT; /** @var bool Whether to no-op all method calls */ protected $enabled = true; /** @var bool Whether to check and wait on positions */ @@ -64,19 +64,19 @@ class ChronologyProtector implements LoggerAwareInterface { /** @var int Seconds to store positions */ const POSITION_TTL = 60; /** @var int Max time to wait for positions to appear */ - const POS_WAIT_TIMEOUT = 5; + const POS_STORE_WAIT_TIMEOUT = 5; /** * @param BagOStuff $store - * @param array $client Map of (ip: , agent: ) - * @param float $posTime UNIX timestamp + * @param array[] $client Map of (ip: , agent: ) + * @param int|null $posIndex Write counter index [optional] * @since 1.27 */ - public function __construct( BagOStuff $store, array $client, $posTime = null ) { + public function __construct( BagOStuff $store, array $client, $posIndex = null ) { $this->store = $store; $this->clientId = md5( $client['ip'] . "\n" . $client['agent'] ); $this->key = $store->makeGlobalKey( __CLASS__, $this->clientId, 'v1' ); - $this->waitForPosTime = $posTime; + $this->waitForPosIndex = $posIndex; $this->logger = new NullLogger(); } @@ -147,8 +147,10 @@ class ChronologyProtector implements LoggerAwareInterface { $masterName = $lb->getServerName( $lb->getWriterIndex() ); if ( $lb->getServerCount() > 1 ) { $pos = $lb->getMasterPos(); - $this->logger->info( __METHOD__ . ": LB for '$masterName' has pos $pos\n" ); - $this->shutdownPositions[$masterName] = $pos; + if ( $pos ) { + $this->logger->info( __METHOD__ . ": LB for '$masterName' has pos $pos\n" ); + $this->shutdownPositions[$masterName] = $pos; + } } else { $this->logger->info( __METHOD__ . ": DB '$masterName' touched\n" ); } @@ -161,9 +163,10 @@ class ChronologyProtector implements LoggerAwareInterface { * * @param callable|null $workCallback Work to do instead of waiting on syncing positions * @param string $mode One of (sync, async); whether to wait on remote datacenters + * @param int|null &$cpIndex DB position key write counter; incremented on update * @return DBMasterPos[] Empty on success; returns the (db name => position) map on failure */ - public function shutdown( callable $workCallback = null, $mode = 'sync' ) { + public function shutdown( callable $workCallback = null, $mode = 'sync', &$cpIndex = null ) { if ( !$this->enabled ) { return []; } @@ -198,13 +201,18 @@ class ChronologyProtector implements LoggerAwareInterface { } $ok = $store->set( $this->key, - self::mergePositions( $store->get( $this->key ), $this->shutdownPositions ), + $this->mergePositions( + $store->get( $this->key ), + $this->shutdownPositions, + $cpIndex + ), self::POSITION_TTL, ( $mode === 'sync' ) ? $store::WRITE_SYNC : 0 ); $store->unlock( $this->key ); } else { $ok = false; + $cpIndex = null; // nothing saved } if ( !$ok ) { @@ -254,28 +262,36 @@ class ChronologyProtector implements LoggerAwareInterface { $this->initialized = true; if ( $this->wait ) { - // If there is an expectation to see master positions with a certain min - // timestamp, then block until they appear, or until a timeout is reached. - if ( $this->waitForPosTime > 0.0 ) { + // If there is an expectation to see master positions from a certain write + // index or higher, then block until it appears, or until a timeout is reached. + // Since the write index restarts each time the key is created, it is possible that + // a lagged store has a matching key write index. However, in that case, it should + // already be expired and thus treated as non-existing, maintaining correctness. + if ( $this->waitForPosIndex > 0 ) { $data = null; $loop = new WaitConditionLoop( function () use ( &$data ) { $data = $this->store->get( $this->key ); + if ( !is_array( $data ) ) { + return WaitConditionLoop::CONDITION_CONTINUE; // not found yet + } elseif ( !isset( $data['writeIndex'] ) ) { + return WaitConditionLoop::CONDITION_REACHED; // b/c + } - return ( self::minPosTime( $data ) >= $this->waitForPosTime ) + return ( $data['writeIndex'] >= $this->waitForPosIndex ) ? WaitConditionLoop::CONDITION_REACHED : WaitConditionLoop::CONDITION_CONTINUE; }, - $this->waitForPosTimeout + $this->waitForPosStoreTimeout ); $result = $loop->invoke(); $waitedMs = $loop->getLastWaitTime() * 1e3; if ( $result == $loop::CONDITION_REACHED ) { - $msg = "expected and found pos time {$this->waitForPosTime} ({$waitedMs}ms)"; + $msg = "expected and found pos index {$this->waitForPosIndex} ({$waitedMs}ms)"; $this->logger->debug( $msg ); } else { - $msg = "expected but missed pos time {$this->waitForPosTime} ({$waitedMs}ms)"; + $msg = "expected but missed pos index {$this->waitForPosIndex} ({$waitedMs}ms)"; $this->logger->info( $msg ); } } else { @@ -290,48 +306,31 @@ class ChronologyProtector implements LoggerAwareInterface { } } - /** - * @param array|bool $data - * @return float|null - */ - private static function minPosTime( $data ) { - if ( !isset( $data['positions'] ) ) { - return null; - } - - $min = null; - foreach ( $data['positions'] as $pos ) { - if ( $pos instanceof DBMasterPos ) { - $min = $min ? min( $pos->asOfTime(), $min ) : $pos->asOfTime(); - } - } - - return $min; - } - /** * @param array|bool $curValue * @param DBMasterPos[] $shutdownPositions + * @param int|null &$cpIndex * @return array */ - private static function mergePositions( $curValue, array $shutdownPositions ) { + protected function mergePositions( $curValue, array $shutdownPositions, &$cpIndex = null ) { /** @var DBMasterPos[] $curPositions */ - if ( $curValue === false ) { - $curPositions = $shutdownPositions; - } else { - $curPositions = $curValue['positions']; - // Use the newest positions for each DB master - foreach ( $shutdownPositions as $db => $pos ) { - if ( - !isset( $curPositions[$db] ) || - !( $curPositions[$db] instanceof DBMasterPos ) || - $pos->asOfTime() > $curPositions[$db]->asOfTime() - ) { - $curPositions[$db] = $pos; - } + $curPositions = isset( $curValue['positions'] ) ? $curValue['positions'] : []; + // Use the newest positions for each DB master + foreach ( $shutdownPositions as $db => $pos ) { + if ( + !isset( $curPositions[$db] ) || + !( $curPositions[$db] instanceof DBMasterPos ) || + $pos->asOfTime() > $curPositions[$db]->asOfTime() + ) { + $curPositions[$db] = $pos; } } - return [ 'positions' => $curPositions ]; + $cpIndex = isset( $curValue['writeIndex'] ) ? $curValue['writeIndex'] : 0; + + return [ + 'positions' => $curPositions, + 'writeIndex' => ++$cpIndex + ]; } } diff --git a/includes/libs/rdbms/TransactionProfiler.php b/includes/libs/rdbms/TransactionProfiler.php index 57a12a4463..a828cd3f1c 100644 --- a/includes/libs/rdbms/TransactionProfiler.php +++ b/includes/libs/rdbms/TransactionProfiler.php @@ -82,7 +82,7 @@ class TransactionProfiler implements LoggerAwareInterface { } /** - * @param bool $value New value + * @param bool $value * @return bool Old value * @since 1.28 */ diff --git a/includes/libs/rdbms/connectionmanager/ConnectionManager.php b/includes/libs/rdbms/connectionmanager/ConnectionManager.php index 212ff315a8..4a497b088b 100644 --- a/includes/libs/rdbms/connectionmanager/ConnectionManager.php +++ b/includes/libs/rdbms/connectionmanager/ConnectionManager.php @@ -1,4 +1,23 @@ [ 'mysqli', 'mysql' ], - 'postgres' => [], - 'sqlite' => [], - 'oracle' => [], - 'mssql' => [], - ]; - static $classAliases = [ - 'DatabaseMssql' => DatabaseMssql::class, - 'DatabaseMysql' => DatabaseMysql::class, - 'DatabaseMysqli' => DatabaseMysqli::class, - 'DatabaseSqlite' => DatabaseSqlite::class, - 'DatabasePostgres' => DatabasePostgres::class + // For database types with built-in support, the below maps type to IDatabase + // implementations. For types with multipe driver implementations (PHP extensions), + // an array can be used, keyed by extension name. In case of an array, the + // optional 'driver' parameter can be used to force a specific driver. Otherwise, + // we auto-detect the first available driver. For types without built-in support, + // an class named "Database" us used, eg. DatabaseFoo for type 'foo'. + static $builtinTypes = [ + 'mssql' => DatabaseMssql::class, + 'mysql' => [ 'mysqli' => DatabaseMysqli::class ], + 'sqlite' => DatabaseSqlite::class, + 'postgres' => DatabasePostgres::class, ]; - $driver = false; $dbType = strtolower( $dbType ); - if ( isset( $canonicalDBTypes[$dbType] ) && $canonicalDBTypes[$dbType] ) { - $possibleDrivers = $canonicalDBTypes[$dbType]; - if ( !empty( $p['driver'] ) ) { - if ( in_array( $p['driver'], $possibleDrivers ) ) { - $driver = $p['driver']; - } else { - throw new InvalidArgumentException( __METHOD__ . - " type '$dbType' does not support driver '{$p['driver']}'" ); - } + $class = false; + if ( isset( $builtinTypes[$dbType] ) ) { + $possibleDrivers = $builtinTypes[$dbType]; + if ( is_string( $possibleDrivers ) ) { + $class = $possibleDrivers; } else { - foreach ( $possibleDrivers as $posDriver ) { - if ( extension_loaded( $posDriver ) ) { - $driver = $posDriver; - break; + if ( !empty( $p['driver'] ) ) { + if ( !isset( $possibleDrivers[$p['driver']] ) ) { + throw new InvalidArgumentException( __METHOD__ . + " type '$dbType' does not support driver '{$p['driver']}'" ); + } else { + $class = $possibleDrivers[$p['driver']]; + } + } else { + foreach ( $possibleDrivers as $posDriver => $possibleClass ) { + if ( extension_loaded( $posDriver ) ) { + $class = $possibleClass; + break; + } } } } } else { - $driver = $dbType; + $class = 'Database' . ucfirst( $dbType ); } - if ( $driver === false || $driver === '' ) { + if ( $class === false ) { throw new InvalidArgumentException( __METHOD__ . " no viable database extension found for type '$dbType'" ); } - $class = 'Database' . ucfirst( $driver ); - if ( isset( $classAliases[$class] ) ) { - $class = $classAliases[$class]; - } - if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) { // Resolve some defaults for b/c $p['host'] = isset( $p['host'] ) ? $p['host'] : false; @@ -394,7 +393,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $p['variables'] = isset( $p['variables'] ) ? $p['variables'] : []; $p['tablePrefix'] = isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : ''; $p['schema'] = isset( $p['schema'] ) ? $p['schema'] : ''; - $p['cliMode'] = isset( $p['cliMode'] ) ? $p['cliMode'] : ( PHP_SAPI === 'cli' ); + $p['cliMode'] = isset( $p['cliMode'] ) + ? $p['cliMode'] + : ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ); $p['agent'] = isset( $p['agent'] ) ? $p['agent'] : ''; if ( !isset( $p['connLogger'] ) ) { $p['connLogger'] = new \Psr\Log\NullLogger(); @@ -908,6 +909,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } if ( $isWrite ) { + if ( $this->getLBInfo( 'replica' ) === true ) { + throw new DBError( + $this, + 'Write operations are not allowed on replica database connections.' + ); + } # In theory, non-persistent writes are allowed in read-only mode, but due to things # like https://bugs.mysql.com/bug.php?id=33669 that might not work anyway... $reason = $this->getReadOnlyReason(); @@ -997,8 +1004,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } /** - * Helper method for query() that handles profiling and logging and sends - * the query to doQuery() + * Wrapper for query() that also handles profiling, logging, and affected row count updates * * @param string $sql Original SQL query * @param string $commentedSql SQL query with debugging/trace comment @@ -1024,7 +1030,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $this->profiler ) { call_user_func( [ $this->profiler, 'profileIn' ], $queryProf ); } + $this->affectedRowCount = null; $ret = $this->doQuery( $commentedSql ); + $this->affectedRowCount = $this->affectedRows(); if ( $this->profiler ) { call_user_func( [ $this->profiler, 'profileOut' ], $queryProf ); } @@ -2233,51 +2241,49 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) { - $quotedTable = $this->tableName( $table ); - if ( count( $rows ) == 0 ) { return; } - # Single row case + // Single row case if ( !is_array( reset( $rows ) ) ) { $rows = [ $rows ]; } - // @FXIME: this is not atomic, but a trx would break affectedRows() + $affectedRowCount = 0; foreach ( $rows as $row ) { - # Delete rows which collide - if ( $uniqueIndexes ) { - $sql = "DELETE FROM $quotedTable WHERE "; - $first = true; - foreach ( $uniqueIndexes as $index ) { - if ( $first ) { - $first = false; - $sql .= '( '; - } else { - $sql .= ' ) OR ( '; - } - if ( is_array( $index ) ) { - $first2 = true; - foreach ( $index as $col ) { - if ( $first2 ) { - $first2 = false; - } else { - $sql .= ' AND '; - } - $sql .= $col . '=' . $this->addQuotes( $row[$col] ); - } - } else { - $sql .= $index . '=' . $this->addQuotes( $row[$index] ); - } + // Delete rows which collide with this one + $indexWhereClauses = []; + foreach ( $uniqueIndexes as $index ) { + $indexColumns = (array)$index; + $indexRowValues = array_intersect_key( $row, array_flip( $indexColumns ) ); + if ( count( $indexRowValues ) != count( $indexColumns ) ) { + throw new DBUnexpectedError( + $this, + 'New record does not provide all values for unique key (' . + implode( ', ', $indexColumns ) . ')' + ); + } elseif ( in_array( null, $indexRowValues, true ) ) { + throw new DBUnexpectedError( + $this, + 'New record has a null value for unique key (' . + implode( ', ', $indexColumns ) . ')' + ); } - $sql .= ' )'; - $this->query( $sql, $fname ); + $indexWhereClauses[] = $this->makeList( $indexRowValues, LIST_AND ); } - # Now insert the row + if ( $indexWhereClauses ) { + $this->delete( $table, $this->makeList( $indexWhereClauses, LIST_OR ), $fname ); + $affectedRowCount += $this->affectedRows(); + } + + // Now insert the row $this->insert( $table, $row, $fname ); + $affectedRowCount += $this->affectedRows(); } + + $this->affectedRowCount = $affectedRowCount; } /** @@ -2342,6 +2348,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $where = false; } + $affectedRowCount = 0; $useTrx = !$this->mTrxLevel; if ( $useTrx ) { $this->begin( $fname, self::TRANSACTION_INTERNAL ); @@ -2350,11 +2357,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware # Update any existing conflicting row(s) if ( $where !== false ) { $ok = $this->update( $table, $set, $where, $fname ); + $affectedRowCount += $this->affectedRows(); } else { $ok = true; } # Now insert any non-conflicting row(s) $ok = $this->insert( $table, $rows, $fname, [ 'IGNORE' ] ) && $ok; + $affectedRowCount += $this->affectedRows(); } catch ( Exception $e ) { if ( $useTrx ) { $this->rollback( $fname, self::FLUSHING_INTERNAL ); @@ -2364,6 +2373,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $useTrx ) { $this->commit( $fname, self::FLUSHING_INTERNAL ); } + $this->affectedRowCount = $affectedRowCount; return $ok; } @@ -3182,6 +3192,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } + public function affectedRows() { + return ( $this->affectedRowCount === null ) + ? $this->fetchAffectedRowCount() // default to driver value + : $this->affectedRowCount; + } + + /** + * @return int Number of retrieved rows according to the driver + */ + abstract protected function fetchAffectedRowCount(); + /** * Take the result from a query, and wrap it in a ResultWrapper if * necessary. Boolean values are passed through as is, to indicate success @@ -3294,14 +3315,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @see WANObjectCache::getWithSetCallback() * * @param IDatabase $db1 - * @param IDatabase $dbs,... + * @param IDatabase $db2 [optional] * @return array Map of values: * - lag: highest lag of any of the DBs or false on error (e.g. replication stopped) * - since: oldest UNIX timestamp of any of the DB lag estimates * - pending: whether any of the DBs have uncommitted changes + * @throws DBError * @since 1.27 */ - public static function getCacheSetOptions( IDatabase $db1 ) { + public static function getCacheSetOptions( IDatabase $db1, IDatabase $db2 = null ) { $res = [ 'lag' => 0, 'since' => INF, 'pending' => false ]; foreach ( func_get_args() as $db ) { /** @var IDatabase $db */ @@ -3383,6 +3405,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $fname = __METHOD__, callable $inputCallback = null ) { + $delimiterReset = new ScopedCallback( + function ( $delimiter ) { + $this->delimiter = $delimiter; + }, + [ $this->delimiter ] + ); $cmd = ''; while ( !feof( $fp ) ) { @@ -3411,7 +3439,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $done || feof( $fp ) ) { $cmd = $this->replaceVars( $cmd ); - if ( !$inputCallback || call_user_func( $inputCallback, $cmd ) ) { + if ( $inputCallback ) { + $callbackResult = call_user_func( $inputCallback, $cmd ); + + if ( is_string( $callbackResult ) || !$callbackResult ) { + $cmd = $callbackResult; + } + } + + if ( $cmd ) { $res = $this->query( $cmd, $fname ); if ( $resultCallback ) { @@ -3428,6 +3464,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } + ScopedCallback::consume( $delimiterReset ); return true; } diff --git a/includes/libs/rdbms/database/DatabaseMssql.php b/includes/libs/rdbms/database/DatabaseMssql.php index 53beb65f9a..832ed9e11e 100644 --- a/includes/libs/rdbms/database/DatabaseMssql.php +++ b/includes/libs/rdbms/database/DatabaseMssql.php @@ -353,7 +353,7 @@ class DatabaseMssql extends Database { /** * @return int */ - public function affectedRows() { + protected function fetchAffectedRowCount() { return $this->mAffectedRows; } diff --git a/includes/libs/rdbms/database/DatabaseMysql.php b/includes/libs/rdbms/database/DatabaseMysql.php deleted file mode 100644 index 58b092669b..0000000000 --- a/includes/libs/rdbms/database/DatabaseMysql.php +++ /dev/null @@ -1,210 +0,0 @@ -getBindingHandle(); - - if ( $this->bufferResults() ) { - $ret = mysql_query( $sql, $conn ); - } else { - $ret = mysql_unbuffered_query( $sql, $conn ); - } - - return $ret; - } - - /** - * @param string $realServer - * @return bool|resource MySQL Database connection or false on failure to connect - * @throws DBConnectionError - */ - protected function mysqlConnect( $realServer ) { - # Avoid a suppressed fatal error, which is very hard to track down - if ( !extension_loaded( 'mysql' ) ) { - throw new DBConnectionError( - $this, - "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" - ); - } - - $connFlags = 0; - if ( $this->mFlags & self::DBO_SSL ) { - $connFlags |= MYSQL_CLIENT_SSL; - } - if ( $this->mFlags & self::DBO_COMPRESS ) { - $connFlags |= MYSQL_CLIENT_COMPRESS; - } - - if ( ini_get( 'mysql.connect_timeout' ) <= 3 ) { - $numAttempts = 2; - } else { - $numAttempts = 1; - } - - $conn = false; - - # The kernel's default SYN retransmission period is far too slow for us, - # so we use a short timeout plus a manual retry. Retrying means that a small - # but finite rate of SYN packet loss won't cause user-visible errors. - for ( $i = 0; $i < $numAttempts && !$conn; $i++ ) { - if ( $i > 1 ) { - usleep( 1000 ); - } - if ( $this->mFlags & self::DBO_PERSISTENT ) { - $conn = mysql_pconnect( $realServer, $this->mUser, $this->mPassword, $connFlags ); - } else { - # Create a new connection... - $conn = mysql_connect( $realServer, $this->mUser, $this->mPassword, true, $connFlags ); - } - } - - return $conn; - } - - /** - * @param string $charset - * @return bool - */ - protected function mysqlSetCharset( $charset ) { - $conn = $this->getBindingHandle(); - - if ( function_exists( 'mysql_set_charset' ) ) { - return mysql_set_charset( $charset, $conn ); - } else { - return $this->query( 'SET NAMES ' . $charset, __METHOD__ ); - } - } - - /** - * @return bool - */ - protected function closeConnection() { - $conn = $this->getBindingHandle(); - - return mysql_close( $conn ); - } - - /** - * @return int - */ - function insertId() { - $conn = $this->getBindingHandle(); - - return mysql_insert_id( $conn ); - } - - /** - * @return int - */ - function lastErrno() { - if ( $this->mConn ) { - return mysql_errno( $this->mConn ); - } else { - return mysql_errno(); - } - } - - /** - * @return int - */ - function affectedRows() { - $conn = $this->getBindingHandle(); - - return mysql_affected_rows( $conn ); - } - - /** - * @param string $db - * @return bool - */ - function selectDB( $db ) { - $conn = $this->getBindingHandle(); - - $this->mDBname = $db; - - return mysql_select_db( $db, $conn ); - } - - protected function mysqlFreeResult( $res ) { - return mysql_free_result( $res ); - } - - protected function mysqlFetchObject( $res ) { - return mysql_fetch_object( $res ); - } - - protected function mysqlFetchArray( $res ) { - return mysql_fetch_array( $res ); - } - - protected function mysqlNumRows( $res ) { - return mysql_num_rows( $res ); - } - - protected function mysqlNumFields( $res ) { - return mysql_num_fields( $res ); - } - - protected function mysqlFetchField( $res, $n ) { - return mysql_fetch_field( $res, $n ); - } - - protected function mysqlFieldName( $res, $n ) { - return mysql_field_name( $res, $n ); - } - - protected function mysqlFieldType( $res, $n ) { - return mysql_field_type( $res, $n ); - } - - protected function mysqlDataSeek( $res, $row ) { - return mysql_data_seek( $res, $row ); - } - - protected function mysqlError( $conn = null ) { - return ( $conn !== null ) ? mysql_error( $conn ) : mysql_error(); // avoid warning - } - - protected function mysqlRealEscapeString( $s ) { - $conn = $this->getBindingHandle(); - - return mysql_real_escape_string( (string)$s, $conn ); - } -} - -class_alias( DatabaseMysql::class, 'DatabaseMysql' ); diff --git a/includes/libs/rdbms/database/DatabaseMysqlBase.php b/includes/libs/rdbms/database/DatabaseMysqlBase.php index e0ff475959..6a545ceb2d 100644 --- a/includes/libs/rdbms/database/DatabaseMysqlBase.php +++ b/includes/libs/rdbms/database/DatabaseMysqlBase.php @@ -63,6 +63,8 @@ abstract class DatabaseMysqlBase extends Database { /** @var string|null */ private $serverVersion = null; + /** @var bool|null */ + private $insertSelectIsSafe = null; /** * Additional $params include: @@ -75,6 +77,7 @@ abstract class DatabaseMysqlBase extends Database { * ID of this server's master will be used. Set the "conds" field to * override the query conditions, e.g. ['shard' => 's1']. * - useGTIDs : use GTID methods like MASTER_GTID_WAIT() when possible. + * - insertSelectIsSafe : force that native INSERT SELECT is or is not safe [default: null] * - sslKeyPath : path to key file [default: null] * - sslCertPath : path to certificate file [default: null] * - sslCAFile: path to a single certificate authority PEM file [default: null] @@ -98,6 +101,8 @@ abstract class DatabaseMysqlBase extends Database { } $this->sqlMode = isset( $params['sqlMode'] ) ? $params['sqlMode'] : ''; $this->utf8Mode = !empty( $params['utf8Mode'] ); + $this->insertSelectIsSafe = isset( $params['insertSelectIsSafe'] ) + ? (bool)$params['insertSelectIsSafe'] : null; parent::__construct( $params ); } @@ -501,6 +506,56 @@ abstract class DatabaseMysqlBase extends Database { return $this->nativeReplace( $table, $rows, $fname ); } + protected function nativeInsertSelect( + $destTable, $srcTable, $varMap, $conds, + $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = [] + ) { + if ( $this->insertSelectIsSafe === null ) { + // In MySQL, an INSERT SELECT is only replication safe with row-based + // replication or if innodb_autoinc_lock_mode is 0. When those + // conditions aren't met, use non-native mode. + // While we could try to determine if the insert is safe anyway by + // checking if the target table has an auto-increment column that + // isn't set in $varMap, that seems unlikely to be worth the extra + // complexity. + $row = $this->selectRow( + false, + [ + 'innodb_autoinc_lock_mode' => '@@innodb_autoinc_lock_mode', + 'binlog_format' => '@@binlog_format', + ], + [], + __METHOD__ + ); + $this->insertSelectIsSafe = $row->binlog_format === 'ROW' || + (int)$row->innodb_autoinc_lock_mode === 0; + } + + if ( !$this->insertSelectIsSafe ) { + return $this->nonNativeInsertSelect( + $destTable, + $srcTable, + $varMap, + $conds, + $fname, + $insertOptions, + $selectOptions, + $selectJoinConds + ); + } else { + return parent::nativeInsertSelect( + $destTable, + $srcTable, + $varMap, + $conds, + $fname, + $insertOptions, + $selectOptions, + $selectJoinConds + ); + } + } + /** * Estimate rows in dataset * Returns estimated count, based on EXPLAIN output @@ -834,8 +889,10 @@ abstract class DatabaseMysqlBase extends Database { return 0; // already reached this point for sure } + $useGTID = ( $this->useGTIDs && $pos->gtids ); + // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set - if ( $this->useGTIDs && $pos->gtids ) { + if ( $useGTID ) { // Wait on the GTID set (MariaDB only) $gtidArg = $this->addQuotes( implode( ',', $pos->gtids ) ); $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" ); @@ -855,14 +912,17 @@ abstract class DatabaseMysqlBase extends Database { // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual $status = ( $row[0] !== null ) ? intval( $row[0] ) : null; if ( $status === null ) { - // T126436: jobs programmed to wait on master positions might be referencing binlogs - // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try - // to detect this and treat the replica DB as having reached the position; a proper master - // switchover already requires that the new master be caught up before the switch. - $replicationPos = $this->getReplicaPos(); - if ( $replicationPos && !$replicationPos->channelsMatch( $pos ) ) { - $this->lastKnownReplicaPos = $replicationPos; - $status = 0; + if ( !$useGTID ) { + // T126436: jobs programmed to wait on master positions might be referencing + // binlogs with an old master hostname; this makes MASTER_POS_WAIT() return null. + // Try to detect this case and treat the replica DB as having reached the given + // position (any master switchover already requires that the new master be caught + // up before the switch). + $replicationPos = $this->getReplicaPos(); + if ( $replicationPos && !$replicationPos->channelsMatch( $pos ) ) { + $this->lastKnownReplicaPos = $replicationPos; + $status = 0; + } } } elseif ( $status >= 0 ) { // Remember that this position was reached to save queries next time @@ -1044,7 +1104,7 @@ abstract class DatabaseMysqlBase extends Database { return true; } - $this->queryLogger->warning( __METHOD__ . " failed to acquire lock '{lockname}'", + $this->queryLogger->info( __METHOD__ . " failed to acquire lock '{lockname}'", [ 'lockname' => $lockName ] ); return false; diff --git a/includes/libs/rdbms/database/DatabaseMysqli.php b/includes/libs/rdbms/database/DatabaseMysqli.php index c1a56988d5..09ea66cac8 100644 --- a/includes/libs/rdbms/database/DatabaseMysqli.php +++ b/includes/libs/rdbms/database/DatabaseMysqli.php @@ -172,7 +172,7 @@ class DatabaseMysqli extends DatabaseMysqlBase { /** * @return int */ - function affectedRows() { + protected function fetchAffectedRowCount() { $conn = $this->getBindingHandle(); return $conn->affected_rows; diff --git a/includes/libs/rdbms/database/DatabasePostgres.php b/includes/libs/rdbms/database/DatabasePostgres.php index 8c21d726b0..5bf845b1af 100644 --- a/includes/libs/rdbms/database/DatabasePostgres.php +++ b/includes/libs/rdbms/database/DatabasePostgres.php @@ -384,7 +384,7 @@ class DatabasePostgres extends Database { } } - public function affectedRows() { + protected function fetchAffectedRowCount() { if ( !is_null( $this->mAffectedRows ) ) { // Forced result for simulated queries return $this->mAffectedRows; diff --git a/includes/libs/rdbms/database/DatabaseSqlite.php b/includes/libs/rdbms/database/DatabaseSqlite.php index 2b0660707c..01772cf809 100644 --- a/includes/libs/rdbms/database/DatabaseSqlite.php +++ b/includes/libs/rdbms/database/DatabaseSqlite.php @@ -56,6 +56,9 @@ class DatabaseSqlite extends Database { /** @var FSLockManager (hopefully on the same server as the DB) */ protected $lockMgr; + /** @var array List of shared database already attached to this connection */ + private $alreadyAttached = []; + /** * Additional params include: * - dbDirectory : directory containing the DB and the lock file directory @@ -82,16 +85,7 @@ class DatabaseSqlite extends Database { parent::__construct( $p ); // Super doesn't open when $user is false, but we can work with $dbName if ( $p['dbname'] && !$this->isOpen() ) { - if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) { - $done = []; - foreach ( $this->tableAliases as $params ) { - if ( isset( $done[$params['dbname']] ) ) { - continue; - } - $this->attachDatabase( $params['dbname'] ); - $done[$params['dbname']] = 1; - } - } + $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ); } } @@ -302,6 +296,14 @@ class DatabaseSqlite extends Database { return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql ); } + protected function isTransactableQuery( $sql ) { + return parent::isTransactableQuery( $sql ) && !in_array( + $this->getQueryVerb( $sql ), + [ 'ATTACH', 'PRAGMA' ], + true + ); + } + /** * SQLite doesn't allow buffered results or data seeking etc, so we'll use fetchAll as the result * @@ -494,7 +496,7 @@ class DatabaseSqlite extends Database { /** * @return int */ - function affectedRows() { + protected function fetchAffectedRowCount() { return $this->mAffectedRows; } @@ -1033,6 +1035,17 @@ class DatabaseSqlite extends Database { return $this->query( $sql, $fName ); } + public function setTableAliases( array $aliases ) { + parent::setTableAliases( $aliases ); + foreach ( $this->tableAliases as $params ) { + if ( isset( $this->alreadyAttached[$params['dbname']] ) ) { + continue; + } + $this->attachDatabase( $params['dbname'] ); + $this->alreadyAttached[$params['dbname']] = true; + } + } + protected function requiresDatabaseUser() { return false; // just a file } diff --git a/includes/libs/rdbms/database/IDatabase.php b/includes/libs/rdbms/database/IDatabase.php index bbf88dc8b5..0964dd55fe 100644 --- a/includes/libs/rdbms/database/IDatabase.php +++ b/includes/libs/rdbms/database/IDatabase.php @@ -1,10 +1,5 @@ [ 'LEFT JOIN', 'page_latest=rev_id' ] ] * * @return IResultWrapper Resulting rows - * @throws DBQueryError + * @throws DBError */ public function select( $table, $vars, $conds = '', $fname = __METHOD__, @@ -799,7 +797,7 @@ interface IDatabase { * @param array|string $join_conds Join conditions * * @return stdClass|bool - * @throws DBQueryError + * @throws DBError */ public function selectRow( $table, $vars, $conds, $fname = __METHOD__, $options = [], $join_conds = [] @@ -824,7 +822,7 @@ interface IDatabase { * @param string $fname Function name for profiling * @param array $options Options for select * @return int Row count - * @throws DBQueryError + * @throws DBError */ public function estimateRowCount( $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [] @@ -846,7 +844,7 @@ interface IDatabase { * @param array $options Options for select * @param array $join_conds Join conditions (since 1.27) * @return int Row count - * @throws DBQueryError + * @throws DBError */ public function selectRowCount( $tables, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = [] @@ -859,6 +857,7 @@ interface IDatabase { * @param string $field Filed to check on that table * @param string $fname Calling function name (optional) * @return bool Whether $table has filed $field + * @throws DBError */ public function fieldExists( $table, $field, $fname = __METHOD__ ); @@ -871,6 +870,7 @@ interface IDatabase { * @param string $index * @param string $fname * @return bool|null + * @throws DBError */ public function indexExists( $table, $index, $fname = __METHOD__ ); @@ -880,6 +880,7 @@ interface IDatabase { * @param string $table * @param string $fname * @return bool + * @throws DBError */ public function tableExists( $table, $fname = __METHOD__ ); @@ -925,6 +926,7 @@ interface IDatabase { * @param array $options Array of options * * @return bool + * @throws DBError */ public function insert( $table, $a, $fname = __METHOD__, $options = [] ); @@ -947,6 +949,7 @@ interface IDatabase { * - IGNORE: Ignore unique key conflicts * - LOW_PRIORITY: MySQL-specific, see MySQL manual. * @return bool + * @throws DBError */ public function update( $table, $values, $conds, $fname = __METHOD__, $options = [] ); @@ -1167,6 +1170,7 @@ interface IDatabase { * @param array $rows Can be either a single row to insert, or multiple rows, * in the same format as for IDatabase::insert() * @param string $fname Calling function name (use __METHOD__) for logs/profiling + * @throws DBError */ public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ); @@ -1203,7 +1207,7 @@ interface IDatabase { * Values with integer keys form unquoted SET statements, which can be used for * things like "field = field + 1" or similar computed values. * @param string $fname Calling function name (use __METHOD__) for logs/profiling - * @throws Exception + * @throws DBError * @return bool */ public function upsert( @@ -1228,7 +1232,7 @@ interface IDatabase { * @param array $conds Condition array of field names mapped to variables, * ANDed together in the WHERE clause * @param string $fname Calling function name (use __METHOD__) for logs/profiling - * @throws DBUnexpectedError + * @throws DBError */ public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__ @@ -1243,6 +1247,7 @@ interface IDatabase { * @param string $fname Name of the calling function * @throws DBUnexpectedError * @return bool|IResultWrapper + * @throws DBError */ public function delete( $table, $conds, $fname = __METHOD__ ); @@ -1250,6 +1255,11 @@ interface IDatabase { * INSERT SELECT wrapper. Takes data from a SELECT query and inserts it * into another table. * + * @warning If the insert will use an auto-increment or sequence to + * determine the value of a column, this may break replication on + * databases using statement-based replication if the SELECT is not + * deterministically ordered. + * * @param string $destTable The table name to insert into * @param string|array $srcTable May be either a table name, or an array of table names * to include in a join. @@ -1273,6 +1283,7 @@ interface IDatabase { * IDatabase::select() for details. * * @return bool + * @throws DBError */ public function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__, @@ -1354,6 +1365,7 @@ interface IDatabase { * Determines how long the server has been up * * @return int + * @throws DBError */ public function getServerUptime(); @@ -1394,13 +1406,15 @@ interface IDatabase { * @return int|null Zero if the replica DB was past that position already, * greater than zero if we waited for some period of time, less than * zero if it timed out, and null on error + * @throws DBError */ public function masterPosWait( DBMasterPos $pos, $timeout ); /** * Get the replication position of this replica DB * - * @return DBMasterPos|bool False if this is not a replica DB. + * @return DBMasterPos|bool False if this is not a replica DB + * @throws DBError */ public function getReplicaPos(); @@ -1408,6 +1422,7 @@ interface IDatabase { * Get the position of this master * * @return DBMasterPos|bool False if this is not a master + * @throws DBError */ public function getMasterPos(); @@ -1596,7 +1611,7 @@ interface IDatabase { * Only set the flush flag if you are sure that these warnings are not applicable, * and no explicit transactions are open. * - * @throws DBUnexpectedError + * @throws DBError */ public function commit( $fname = __METHOD__, $flush = '' ); @@ -1617,7 +1632,7 @@ interface IDatabase { * constant to disable warnings about calling rollback when no transaction is in * progress. This will silently break any ongoing explicit transaction. Only set the * flush flag if you are sure that it is safe to ignore these warnings in your context. - * @throws DBUnexpectedError + * @throws DBError * @since 1.23 Added $flush parameter */ public function rollback( $fname = __METHOD__, $flush = '' ); @@ -1631,7 +1646,7 @@ interface IDatabase { * useful to call on a replica DB after waiting on replication to catch up to the master. * * @param string $fname Calling function name - * @throws DBUnexpectedError + * @throws DBError * @since 1.28 */ public function flushSnapshot( $fname = __METHOD__ ); @@ -1690,6 +1705,7 @@ interface IDatabase { * instead. * * @return int|bool Database replication lag in seconds or false on error + * @throws DBError */ public function getLag(); @@ -1704,6 +1720,7 @@ interface IDatabase { * indication of the staleness of subsequent reads. * * @return array ('lag': seconds or false on error, 'since': UNIX timestamp of BEGIN) + * @throws DBError * @since 1.27 */ public function getSessionLagStatus(); @@ -1745,6 +1762,7 @@ interface IDatabase { * * @param array $options * @return void + * @throws DBError */ public function setSessionOptions( array $options ); @@ -1763,6 +1781,7 @@ interface IDatabase { * @param string $lockName Name of lock to poll * @param string $method Name of method calling us * @return bool + * @throws DBError * @since 1.20 */ public function lockIsFree( $lockName, $method ); @@ -1776,6 +1795,7 @@ interface IDatabase { * @param string $method Name of the calling method * @param int $timeout Acquisition timeout in seconds * @return bool + * @throws DBError */ public function lock( $lockName, $method, $timeout = 5 ); @@ -1788,8 +1808,10 @@ interface IDatabase { * @param string $method Name of the calling method * * @return int Returns 1 if the lock was released, 0 if the lock was not established - * by this thread (in which case the lock is not released), and NULL if the named - * lock did not exist + * by this thread (in which case the lock is not released), and NULL if the named lock + * did not exist + * + * @throws DBError */ public function unlock( $lockName, $method ); @@ -1811,7 +1833,7 @@ interface IDatabase { * @param string $fname Name of the calling method * @param int $timeout Acquisition timeout in seconds * @return ScopedCallback|null - * @throws DBUnexpectedError + * @throws DBError * @since 1.27 */ public function getScopedLockAndFlush( $lockKey, $fname, $timeout ); diff --git a/includes/libs/rdbms/database/IMaintainableDatabase.php b/includes/libs/rdbms/database/IMaintainableDatabase.php index fbc2774b05..66012dae43 100644 --- a/includes/libs/rdbms/database/IMaintainableDatabase.php +++ b/includes/libs/rdbms/database/IMaintainableDatabase.php @@ -20,7 +20,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Database */ namespace Wikimedia\Rdbms; diff --git a/includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php b/includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php index 298ec61934..4b79044655 100644 --- a/includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php +++ b/includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php @@ -15,7 +15,7 @@ class MssqlResultWrapper extends ResultWrapper { $res = $this->result; if ( $this->mSeekTo !== null ) { - $result = sqlsrv_fetch_object( $res, 'stdClass', [], + $result = sqlsrv_fetch_object( $res, stdClass::class, [], SQLSRV_SCROLL_ABSOLUTE, $this->mSeekTo ); $this->mSeekTo = null; } else { diff --git a/includes/libs/rdbms/exception/DBError.php b/includes/libs/rdbms/exception/DBError.php index 2f7499bc64..50238003a2 100644 --- a/includes/libs/rdbms/exception/DBError.php +++ b/includes/libs/rdbms/exception/DBError.php @@ -21,13 +21,13 @@ namespace Wikimedia\Rdbms; -use Exception; +use RuntimeException; /** * Database error base class * @ingroup Database */ -class DBError extends Exception { +class DBError extends RuntimeException { /** @var IDatabase|null */ public $db; diff --git a/includes/libs/rdbms/exception/DBExpectedError.php b/includes/libs/rdbms/exception/DBExpectedError.php index cae7f3e1a6..406d82c139 100644 --- a/includes/libs/rdbms/exception/DBExpectedError.php +++ b/includes/libs/rdbms/exception/DBExpectedError.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Database */ namespace Wikimedia\Rdbms; diff --git a/includes/libs/rdbms/lbfactory/ILBFactory.php b/includes/libs/rdbms/lbfactory/ILBFactory.php index f6d080e4f0..98108a7df2 100644 --- a/includes/libs/rdbms/lbfactory/ILBFactory.php +++ b/includes/libs/rdbms/lbfactory/ILBFactory.php @@ -140,9 +140,10 @@ interface ILBFactory { * Prepare all tracked load balancers for shutdown * @param int $mode One of the class SHUTDOWN_* constants * @param callable|null $workCallback Work to mask ChronologyProtector writes + * @param int|null &$cpIndex Position key write counter for ChronologyProtector */ public function shutdown( - $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback = null + $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback = null, &$cpIndex = null ); /** @@ -304,7 +305,7 @@ interface ILBFactory { public function setAgentName( $agent ); /** - * Append ?cpPosTime parameter to a URL for ChronologyProtector purposes if needed + * Append ?cpPosIndex parameter to a URL for ChronologyProtector purposes if needed * * Note that unlike cookies, this works accross domains * @@ -312,13 +313,14 @@ interface ILBFactory { * @param float $time UNIX timestamp just before shutdown() was called * @return string */ - public function appendPreShutdownTimeAsQuery( $url, $time ); + public function appendShutdownCPIndexAsQuery( $url, $time ); /** * @param array $info Map of fields, including: * - IPAddress : IP address * - UserAgent : User-Agent HTTP header * - ChronologyProtection : cookie/header value specifying ChronologyProtector usage + * - ChronologyPositionIndex: timestamp used to get up-to-date DB positions for the agent */ public function setRequestInfo( array $info ); } diff --git a/includes/libs/rdbms/lbfactory/LBFactory.php b/includes/libs/rdbms/lbfactory/LBFactory.php index c891fb6ba7..2324553016 100644 --- a/includes/libs/rdbms/lbfactory/LBFactory.php +++ b/includes/libs/rdbms/lbfactory/LBFactory.php @@ -115,7 +115,8 @@ abstract class LBFactory implements ILBFactory { $this->requestInfo = [ 'IPAddress' => isset( $_SERVER[ 'REMOTE_ADDR' ] ) ? $_SERVER[ 'REMOTE_ADDR' ] : '', 'UserAgent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '', - 'ChronologyProtection' => 'true' + 'ChronologyProtection' => 'true', + 'ChronologyPositionIndex' => isset( $_GET['cpPosIndex'] ) ? $_GET['cpPosIndex'] : null ]; $this->cliMode = isset( $conf['cliMode'] ) ? $conf['cliMode'] : PHP_SAPI === 'cli'; @@ -131,13 +132,13 @@ abstract class LBFactory implements ILBFactory { } public function shutdown( - $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback = null + $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback = null, &$cpIndex = null ) { $chronProt = $this->getChronologyProtector(); if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) { - $this->shutdownChronologyProtector( $chronProt, $workCallback, 'sync' ); + $this->shutdownChronologyProtector( $chronProt, $workCallback, 'sync', $cpIndex ); } elseif ( $mode === self::SHUTDOWN_CHRONPROT_ASYNC ) { - $this->shutdownChronologyProtector( $chronProt, null, 'async' ); + $this->shutdownChronologyProtector( $chronProt, null, 'async', $cpIndex ); } $this->commitMasterChanges( __METHOD__ ); // sanity @@ -357,7 +358,7 @@ abstract class LBFactory implements ILBFactory { $failed = []; foreach ( $lbs as $i => $lb ) { if ( $masterPositions[$i] ) { - // The DBMS may not support getMasterPos() + // The RDBMS may not support getMasterPos() if ( !$lb->waitForAll( $masterPositions[$i], $opts['timeout'] ) ) { $failed[] = $lb->getServerName( $lb->getWriterIndex() ); } @@ -440,7 +441,7 @@ abstract class LBFactory implements ILBFactory { 'ip' => $this->requestInfo['IPAddress'], 'agent' => $this->requestInfo['UserAgent'], ], - isset( $_GET['cpPosTime'] ) ? $_GET['cpPosTime'] : null + $this->requestInfo['ChronologyPositionIndex'] ); $this->chronProt->setLogger( $this->replLogger ); @@ -464,9 +465,10 @@ abstract class LBFactory implements ILBFactory { * @param ChronologyProtector $cp * @param callable|null $workCallback Work to do instead of waiting on syncing positions * @param string $mode One of (sync, async); whether to wait on remote datacenters + * @param int|null &$cpIndex DB position key write counter; incremented on update */ protected function shutdownChronologyProtector( - ChronologyProtector $cp, $workCallback, $mode + ChronologyProtector $cp, $workCallback, $mode, &$cpIndex = null ) { // Record all the master positions needed $this->forEachLB( function ( ILoadBalancer $lb ) use ( $cp ) { @@ -474,7 +476,7 @@ abstract class LBFactory implements ILBFactory { } ); // Write them to the persistent stash. Try to do something useful by running $work // while ChronologyProtector waits for the stash write to replicate to all DCs. - $unsavedPositions = $cp->shutdown( $workCallback, $mode ); + $unsavedPositions = $cp->shutdown( $workCallback, $mode, $cpIndex ); if ( $unsavedPositions && $workCallback ) { // Invoke callback in case it did not cache the result yet $workCallback(); // work now to block for less time in waitForAll() @@ -543,7 +545,7 @@ abstract class LBFactory implements ILBFactory { $this->agent = $agent; } - public function appendPreShutdownTimeAsQuery( $url, $time ) { + public function appendShutdownCPIndexAsQuery( $url, $index ) { $usedCluster = 0; $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$usedCluster ) { $usedCluster |= ( $lb->getServerCount() > 1 ); @@ -553,7 +555,7 @@ abstract class LBFactory implements ILBFactory { return $url; // no master/replica clusters touched } - return strpos( $url, '?' ) === false ? "$url?cpPosTime=$time" : "$url&cpPosTime=$time"; + return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index"; } public function setRequestInfo( array $info ) { diff --git a/includes/libs/rdbms/loadbalancer/ILoadBalancer.php b/includes/libs/rdbms/loadbalancer/ILoadBalancer.php index 86c43350a0..e246b79f80 100644 --- a/includes/libs/rdbms/loadbalancer/ILoadBalancer.php +++ b/includes/libs/rdbms/loadbalancer/ILoadBalancer.php @@ -309,25 +309,6 @@ interface ILoadBalancer { */ public function getServerType( $i ); - /** - * Return the server info structure for a given index, or false if the index is invalid. - * @param int $i - * @return array|bool - * - * @deprecated Since 1.30, no alternative - */ - public function getServerInfo( $i ); - - /** - * 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 - * - * @deprecated Since 1.30, construct new object - */ - public function setServerInfo( $i, array $serverInfo ); - /** * Get the current master position for chronology control purposes * @return DBMasterPos|bool Returns false if not applicable diff --git a/includes/libs/rdbms/loadbalancer/LoadBalancer.php b/includes/libs/rdbms/loadbalancer/LoadBalancer.php index a67e6e913d..ee3c86f1ee 100644 --- a/includes/libs/rdbms/loadbalancer/LoadBalancer.php +++ b/includes/libs/rdbms/loadbalancer/LoadBalancer.php @@ -18,7 +18,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Database */ namespace Wikimedia\Rdbms; @@ -147,17 +146,10 @@ class LoadBalancer implements ILoadBalancer { } } - $this->localDomain = isset( $params['localDomain'] ) + $localDomain = isset( $params['localDomain'] ) ? DatabaseDomain::newFromId( $params['localDomain'] ) : DatabaseDomain::newUnspecified(); - // In case a caller assumes that the domain ID is simply -, which is almost - // always true, gracefully handle the case when they fail to account for escaping. - if ( $this->localDomain->getTablePrefix() != '' ) { - $this->localDomainIdAlias = - $this->localDomain->getDatabase() . '-' . $this->localDomain->getTablePrefix(); - } else { - $this->localDomainIdAlias = $this->localDomain->getDatabase(); - } + $this->setLocalDomain( $localDomain ); $this->mWaitTimeout = isset( $params['waitTimeout'] ) ? $params['waitTimeout'] : 10; @@ -233,7 +225,9 @@ class LoadBalancer implements ILoadBalancer { $this->host = isset( $params['hostname'] ) ? $params['hostname'] : ( gethostname() ?: 'unknown' ); - $this->cliMode = isset( $params['cliMode'] ) ? $params['cliMode'] : PHP_SAPI === 'cli'; + $this->cliMode = isset( $params['cliMode'] ) + ? $params['cliMode'] + : ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ); $this->agent = isset( $params['agent'] ) ? $params['agent'] : ''; if ( isset( $params['chronologyProtector'] ) ) { @@ -241,6 +235,17 @@ class LoadBalancer implements ILoadBalancer { } } + /** + * Get the local (and default) database domain ID of connection handles + * + * @see DatabaseDomain + * @return string Database domain ID; this specifies DB name, schema, and table prefix + * @since 1.31 + */ + public function getLocalDomainID() { + return $this->localDomain->getId(); + } + /** * Get a LoadMonitor instance * @@ -506,6 +511,8 @@ class LoadBalancer implements ILoadBalancer { } public function waitForAll( $pos, $timeout = null ) { + $timeout = $timeout ?: $this->mWaitTimeout; + $oldPos = $this->mWaitForPos; try { $this->mWaitForPos = $pos; @@ -514,7 +521,12 @@ class LoadBalancer implements ILoadBalancer { $ok = true; for ( $i = 1; $i < $serverCount; $i++ ) { if ( $this->mLoads[$i] > 0 ) { - $ok = $this->doWait( $i, true, $timeout ) && $ok; + $start = microtime( true ); + $ok = $this->doWait( $i, true, max( 1, (int)$timeout ) ) && $ok; + $timeout -= ( microtime( true ) - $start ); + if ( $timeout <= 0 ) { + break; // timeout reached + } } } } finally { @@ -809,7 +821,11 @@ class LoadBalancer implements ILoadBalancer { $server = $this->mServers[$i]; $server['serverIndex'] = $i; $server['autoCommitOnly'] = $autoCommit; - $conn = $this->reallyOpenConnection( $server, false ); + if ( $this->localDomain->getDatabase() !== null ) { + // Use the local domain table prefix if the local domain is specified + $server['tablePrefix'] = $this->localDomain->getTablePrefix(); + } + $conn = $this->reallyOpenConnection( $server, $this->localDomain->getDatabase() ); $host = $this->getServerName( $i ); if ( $conn->isOpen() ) { $this->connLogger->debug( "Connected to database $i at '$host'." ); @@ -887,8 +903,6 @@ class LoadBalancer implements ILoadBalancer { // Reuse a free connection from another domain $conn = reset( $this->mConns[$connFreeKey][$i] ); $oldDomain = key( $this->mConns[$connFreeKey][$i] ); - // The empty string as a DB name means "don't care". - // DatabaseMysqlBase::open() already handle this on connection. if ( strlen( $dbName ) && !$conn->selectDB( $dbName ) ) { $this->mLastError = "Error selecting database '$dbName' on server " . $conn->getServer() . " from client host {$this->host}"; @@ -897,7 +911,8 @@ class LoadBalancer implements ILoadBalancer { } else { $conn->tablePrefix( $prefix ); unset( $this->mConns[$connFreeKey][$i][$oldDomain] ); - $this->mConns[$connInUseKey][$i][$domain] = $conn; + // Note that if $domain is an empty string, getDomainID() might not match it + $this->mConns[$connInUseKey][$i][$conn->getDomainId()] = $conn; $this->connLogger->debug( __METHOD__ . ": reusing free connection from $oldDomain for $domain" ); } @@ -917,8 +932,9 @@ class LoadBalancer implements ILoadBalancer { $this->errorConnection = $conn; $conn = false; } else { - $conn->tablePrefix( $prefix ); - $this->mConns[$connInUseKey][$i][$domain] = $conn; + $conn->tablePrefix( $prefix ); // as specified + // Note that if $domain is an empty string, getDomainID() might not match it + $this->mConns[$connInUseKey][$i][$conn->getDomainID()] = $conn; $this->connLogger->debug( __METHOD__ . ": opened new connection for $i/$domain" ); } } @@ -940,7 +956,7 @@ class LoadBalancer implements ILoadBalancer { * @return bool */ private function isOpen( $index ) { - if ( !is_integer( $index ) ) { + if ( !is_int( $index ) ) { return false; } @@ -948,22 +964,22 @@ class LoadBalancer implements ILoadBalancer { } /** - * Really opens a connection. Uncached. + * Open a new network connection to a server (uncached) + * * Returns a Database object whether or not the connection was successful. - * @access private * * @param array $server - * @param string|bool $dbNameOverride Use "" to not select any database + * @param string|null $dbNameOverride Use "" to not select any database * @return Database * @throws DBAccessError * @throws InvalidArgumentException */ - protected function reallyOpenConnection( array $server, $dbNameOverride = false ) { + protected function reallyOpenConnection( array $server, $dbNameOverride ) { if ( $this->disabled ) { throw new DBAccessError(); } - if ( $dbNameOverride !== false ) { + if ( $dbNameOverride !== null ) { $server['dbname'] = $dbNameOverride; } @@ -1081,26 +1097,6 @@ class LoadBalancer implements ILoadBalancer { return isset( $this->mServers[$i]['type'] ) ? $this->mServers[$i]['type'] : 'unknown'; } - /** - * @deprecated Since 1.30, no alternative - */ - public function getServerInfo( $i ) { - wfDeprecated( __METHOD__, '1.30' ); - if ( isset( $this->mServers[$i] ) ) { - return $this->mServers[$i]; - } else { - return false; - } - } - - /** - * @deprecated Since 1.30, construct new object - */ - public function setServerInfo( $i, array $serverInfo ) { - wfDeprecated( __METHOD__, '1.30' ); - $this->mServers[$i] = $serverInfo; - } - public function getMasterPos() { # If this entire request was served from a replica DB without opening a connection to the # master (however unlikely that may be), then we can fetch the position from the replica DB. @@ -1699,17 +1695,35 @@ class LoadBalancer implements ILoadBalancer { "Foreign domain connections are still in use ($domains)." ); } - $this->localDomain = new DatabaseDomain( + $oldDomain = $this->localDomain->getId(); + $this->setLocalDomain( new DatabaseDomain( $this->localDomain->getDatabase(), null, $prefix - ); + ) ); - $this->forEachOpenConnection( function ( IDatabase $db ) use ( $prefix ) { - $db->tablePrefix( $prefix ); + $this->forEachOpenConnection( function ( IDatabase $db ) use ( $prefix, $oldDomain ) { + if ( !$db->getLBInfo( 'foreign' ) ) { + $db->tablePrefix( $prefix ); + } } ); } + /** + * @param DatabaseDomain $domain + */ + private function setLocalDomain( DatabaseDomain $domain ) { + $this->localDomain = $domain; + // In case a caller assumes that the domain ID is simply -, which is almost + // always true, gracefully handle the case when they fail to account for escaping. + if ( $this->localDomain->getTablePrefix() != '' ) { + $this->localDomainIdAlias = + $this->localDomain->getDatabase() . '-' . $this->localDomain->getTablePrefix(); + } else { + $this->localDomainIdAlias = $this->localDomain->getDatabase(); + } + } + /** * Make PHP ignore user aborts/disconnects until the returned * value leaves scope. This returns null and does nothing in CLI mode. diff --git a/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php b/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php index 79d250f6a0..b5e1a808bc 100644 --- a/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php +++ b/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php @@ -72,9 +72,9 @@ class LoadBalancerSingle extends LoadBalancer { return new static( [ 'connection' => $db ] + $params ); } - protected function reallyOpenConnection( array $server, $dbNameOverride = false ) { + protected function reallyOpenConnection( array $server, $dbNameOverride ) { return $this->db; } } -class_alias( 'Wikimedia\Rdbms\LoadBalancerSingle', 'LoadBalancerSingle' ); +class_alias( LoadBalancerSingle::class, 'LoadBalancerSingle' ); diff --git a/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php b/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php index f8ad329bb0..98cff6d77a 100644 --- a/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php +++ b/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php @@ -46,7 +46,7 @@ class LoadMonitorMySQL extends LoadMonitor { protected function getWeightScale( $index, IDatabase $conn = null ) { if ( !$conn ) { - return 0.0; + return parent::getWeightScale( $index, $conn ); } $weight = 1.0; diff --git a/includes/libs/stats/BufferingStatsdDataFactory.php b/includes/libs/stats/BufferingStatsdDataFactory.php index d75d9c0b1e..06915b2dd2 100644 --- a/includes/libs/stats/BufferingStatsdDataFactory.php +++ b/includes/libs/stats/BufferingStatsdDataFactory.php @@ -99,27 +99,22 @@ class BufferingStatsdDataFactory extends StatsdDataFactory implements IBuffering return $this->buffer; } - /** - * Check whether this data factory has any data. - * @return bool - */ public function hasData() { return !empty( $this->buffer ); } - /** - * Return data from the factory. - * @return StatsdData[] - */ public function getData() { return $this->buffer; } - /** - * Set collection enable status. - * @param bool $enabled Will collection be enabled? - * @return void - */ + public function clearData() { + $this->buffer = []; + } + + public function getDataCount() { + return count( $this->buffer ); + } + public function setEnabled( $enabled ) { $this->enabled = $enabled; } diff --git a/includes/libs/stats/IBufferingStatsdDataFactory.php b/includes/libs/stats/IBufferingStatsdDataFactory.php index f77b26cefb..77b4c3528a 100644 --- a/includes/libs/stats/IBufferingStatsdDataFactory.php +++ b/includes/libs/stats/IBufferingStatsdDataFactory.php @@ -9,22 +9,34 @@ use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface; */ interface IBufferingStatsdDataFactory extends StatsdDataFactoryInterface { /** - * Check whether this data factory has any data. + * Check whether this data factory has any buffered data. * @return bool */ public function hasData(); /** - * Return data from the factory. + * Return the buffered data from the factory. * @return StatsdData[] */ public function getData(); + /** + * Clear all buffered data from the factory + * @since 1.31 + */ + public function clearData(); + + /** + * Return the number of buffered statsd data entries + * @return int + * @since 1.31 + */ + public function getDataCount(); + /** * Set collection enable status. * @param bool $enabled Will collection be enabled? * @return void */ public function setEnabled( $enabled ); - } diff --git a/includes/libs/stats/NullStatsdDataFactory.php b/includes/libs/stats/NullStatsdDataFactory.php index ed16311929..63de8f2f63 100644 --- a/includes/libs/stats/NullStatsdDataFactory.php +++ b/includes/libs/stats/NullStatsdDataFactory.php @@ -105,27 +105,22 @@ class NullStatsdDataFactory implements IBufferingStatsdDataFactory { return $data; } - /** - * Check whether this data factory has any data. - * @return bool - */ public function hasData() { return false; } - /** - * Return data from the factory. - * @return StatsdData[] - */ public function getData() { return []; } - /** - * Set collection enable status. - * @param bool $enabled Will collection be enabled? - * @return void - */ + public function clearData() { + // Nothing to do, always empty + } + + public function getDataCount() { + return 0; + } + public function setEnabled( $enabled ) { // Nothing to do, null factory is always disabled. } diff --git a/includes/libs/xmp/XMP.php b/includes/libs/xmp/XMP.php index 0cc14669a7..88e816a72a 100644 --- a/includes/libs/xmp/XMP.php +++ b/includes/libs/xmp/XMP.php @@ -129,11 +129,17 @@ class XMPReader implements LoggerAwareInterface { */ private $logger; + /** + * @var string + */ + private $filename; + /** * Primary job is to initialize the XMLParser * @param LoggerInterface|null $logger + * @param string $filename */ - function __construct( LoggerInterface $logger = null ) { + function __construct( LoggerInterface $logger = null, $filename = 'unknown' ) { if ( !function_exists( 'xml_parser_create_ns' ) ) { // this should already be checked by this point throw new RuntimeException( 'XMP support requires XML Parser' ); @@ -143,6 +149,7 @@ class XMPReader implements LoggerAwareInterface { } else { $this->setLogger( new NullLogger() ); } + $this->filename = $filename; $this->items = XMPInfo::getItems(); @@ -370,13 +377,15 @@ class XMPReader implements LoggerAwareInterface { $col = xml_get_current_column_number( $this->xmlParser ); $offset = xml_get_current_byte_index( $this->xmlParser ); - $this->logger->warning( + $this->logger->info( '{method} : Error reading XMP content: {error} ' . - '(line: {line} column: {column} byte offset: {offset})', + '(file: {file}, line: {line} column: {column} ' . + 'byte offset: {offset})', [ 'method' => __METHOD__, 'error_code' => $code, 'error' => $error, + 'file' => $this->filename, 'line' => $line, 'column' => $col, 'offset' => $offset, @@ -392,6 +401,7 @@ class XMPReader implements LoggerAwareInterface { [ 'method' => __METHOD__, 'exception' => $e, + 'file' => $this->filename, 'content' => $content, ] ); @@ -421,7 +431,11 @@ class XMPReader implements LoggerAwareInterface { ) { $this->logger->info( __METHOD__ . " Ignoring XMPExtended block due to wrong guid (guid= '{guid}')", - [ 'guid' => 'guid' ] ); + [ + 'guid' => $guid, + 'file' => $this->filename, + ] + ); return false; } @@ -433,7 +447,8 @@ class XMPReader implements LoggerAwareInterface { $len['offset'] > $len['length'] ) { $this->logger->info( - __METHOD__ . 'Error reading extended XMP block, invalid length or offset.' + __METHOD__ . 'Error reading extended XMP block, invalid length or offset.', + [ 'file' => $this->filename ] ); return false; @@ -451,7 +466,9 @@ class XMPReader implements LoggerAwareInterface { if ( $len['offset'] !== $this->extendedXMPOffset ) { $this->logger->info( __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was ' - . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')' ); + . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')', + [ 'file' => $this->filename ] + ); return false; } @@ -472,7 +489,10 @@ class XMPReader implements LoggerAwareInterface { $atEnd = false; } - $this->logger->debug( __METHOD__ . 'Parsing a XMPExtended block' ); + $this->logger->debug( + __METHOD__ . 'Parsing a XMPExtended block', + [ 'file' => $this->filename ] + ); return $this->parse( $actualContent, $atEnd ); } @@ -668,19 +688,28 @@ class XMPReader implements LoggerAwareInterface { if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) { // This can happen if all the members of the struct failed validation. - $this->logger->debug( __METHOD__ . " <$ns:$tag> has no valid members." ); + $this->logger->debug( + __METHOD__ . " <$ns:$tag> has no valid members.", + [ 'file' => $this->filename ] + ); } elseif ( is_callable( $validate ) ) { $val =& $this->results['xmp-' . $info['map_group']][$finalName]; call_user_func_array( $validate, [ $info, &$val, false ] ); if ( is_null( $val ) ) { // the idea being the validation function will unset the variable if // its invalid. - $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." ); + $this->logger->info( + __METHOD__ . " <$ns:$tag> failed validation.", + [ 'file' => $this->filename ] + ); unset( $this->results['xmp-' . $info['map_group']][$finalName] ); } } else { - $this->logger->warning( __METHOD__ . " Validation function for $finalName (" - . $validate[0] . '::' . $validate[1] . '()) is not callable.' ); + $this->logger->warning( + __METHOD__ . " Validation function for $finalName (" . + $validate[0] . '::' . $validate[1] . '()) is not callable.', + [ 'file' => $this->filename ] + ); } } @@ -719,7 +748,10 @@ class XMPReader implements LoggerAwareInterface { array_shift( $this->mode ); if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) { - $this->logger->debug( __METHOD__ . " Empty compund element $finalName." ); + $this->logger->debug( + __METHOD__ . " Empty compund element $finalName.", + [ 'file' => $this->filename ] + ); return; } @@ -787,7 +819,10 @@ class XMPReader implements LoggerAwareInterface { if ( $elm === self::NS_RDF . ' type' ) { // these aren't really supported properly yet. // However, it appears they almost never used. - $this->logger->info( __METHOD__ . ' encountered ' ); + $this->logger->info( + __METHOD__ . ' encountered ', + [ 'file' => $this->filename ] + ); } if ( strpos( $elm, ' ' ) === false ) { @@ -795,7 +830,10 @@ class XMPReader implements LoggerAwareInterface { // However, there is a bug in an adobe product // that forgets the namespace on some things. // (Luckily they are unimportant things). - $this->logger->info( __METHOD__ . " Encountered which has no namespace. Skipping." ); + $this->logger->info( + __METHOD__ . " Encountered which has no namespace. Skipping.", + [ 'file' => $this->filename ] + ); return; } @@ -841,7 +879,10 @@ class XMPReader implements LoggerAwareInterface { $this->endElementModeQDesc( $elm ); break; default: - $this->logger->warning( __METHOD__ . " no mode (elm = $elm)" ); + $this->logger->info( + __METHOD__ . " no mode (elm = $elm)", + [ 'file' => $this->filename ] + ); break; } } @@ -891,8 +932,11 @@ class XMPReader implements LoggerAwareInterface { array_unshift( $this->mode, self::MODE_LI ); } elseif ( $elm === self::NS_RDF . ' Bag' ) { # T29105 - $this->logger->info( __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending' - . ' it is a Seq, since some buggy software is known to screw this up.' ); + $this->logger->info( + __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending' . + ' it is a Seq, since some buggy software is known to screw this up.', + [ 'file' => $this->filename ] + ); array_unshift( $this->mode, self::MODE_LI ); } else { throw new RuntimeException( "Expected but got $elm." ); @@ -956,7 +1000,12 @@ class XMPReader implements LoggerAwareInterface { // something else we don't recognize, like a qualifier maybe. $this->logger->info( __METHOD__ . " Encountered element <{element}> where only expecting character data as value of {curitem}", - [ 'element' => $elm, 'curitem' => $this->curItem[0] ] ); + [ + 'element' => $elm, + 'curitem' => $this->curItem[0], + 'file' => $this->filename, + ] + ); array_unshift( $this->mode, self::MODE_IGNORE ); array_unshift( $this->curItem, $elm ); } @@ -1006,9 +1055,9 @@ class XMPReader implements LoggerAwareInterface { // a child of a struct), then something weird is // happening, so ignore this element and its children. - $this->logger->warning( + $this->logger->info( 'Encountered <{element}> outside of its expected parent. Ignoring.', - [ 'element' => "$ns:$tag" ] + [ 'element' => "$ns:$tag", 'file' => $this->filename ] ); array_unshift( $this->mode, self::MODE_IGNORE ); @@ -1031,7 +1080,7 @@ class XMPReader implements LoggerAwareInterface { } else { // This element is not on our list of allowed elements so ignore. $this->logger->debug( __METHOD__ . ' Ignoring unrecognized element <{element}>.', - [ 'element' => "$ns:$tag" ] ); + [ 'element' => "$ns:$tag", 'file' => $this->filename ] ); array_unshift( $this->mode, self::MODE_IGNORE ); array_unshift( $this->curItem, $ns . ' ' . $tag ); @@ -1208,12 +1257,18 @@ class XMPReader implements LoggerAwareInterface { // on page 25 of part 1 of the xmp standard. // Also it seems as if exiv2 and exiftool do not support // this either (That or I misunderstand the standard) - $this->logger->info( __METHOD__ . ' Encountered which isn\'t currently supported' ); + $this->logger->info( + __METHOD__ . ' Encountered which isn\'t currently supported', + [ 'file' => $this->filename ] + ); } if ( strpos( $elm, ' ' ) === false ) { // This probably shouldn't happen. - $this->logger->info( __METHOD__ . " Encountered <$elm> which has no namespace. Skipping." ); + $this->logger->info( + __METHOD__ . " Encountered <$elm> which has no namespace. Skipping.", + [ 'file' => $this->filename ] + ); return; } @@ -1263,7 +1318,7 @@ class XMPReader implements LoggerAwareInterface { } } - // @codingStandardsIgnoreStart Generic.Files.LineLength + // phpcs:disable Generic.Files.LineLength /** * Process attributes. * Simple values can be stored as either a tag or attribute @@ -1279,7 +1334,7 @@ class XMPReader implements LoggerAwareInterface { * @param array $attribs Array attribute=>value * @throws RuntimeException */ - // @codingStandardsIgnoreEnd + // phpcs:enable private function doAttribs( $attribs ) { // first check for rdf:parseType attribute, as that can change // how the attributes are interperted. @@ -1295,8 +1350,11 @@ class XMPReader implements LoggerAwareInterface { if ( strpos( $name, ' ' ) === false ) { // This shouldn't happen, but so far some old software forgets namespace // on rdf:about. - $this->logger->info( __METHOD__ . ' Encountered non-namespaced attribute: ' - . " $name=\"$val\". Skipping. " ); + $this->logger->info( + __METHOD__ . ' Encountered non-namespaced attribute: ' . + " $name=\"$val\". Skipping. ", + [ 'file' => $this->filename ] + ); continue; } list( $ns, $tag ) = explode( ' ', $name, 2 ); @@ -1313,7 +1371,10 @@ class XMPReader implements LoggerAwareInterface { } $this->saveValue( $ns, $tag, $val ); } else { - $this->logger->debug( __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." ); + $this->logger->debug( + __METHOD__ . " Ignoring unrecognized element <$ns:$tag>.", + [ 'file' => $this->filename ] + ); } } } @@ -1346,13 +1407,19 @@ class XMPReader implements LoggerAwareInterface { // the reasoning behind using &$val instead of using the return value // is to be consistent between here and validating structures. if ( is_null( $val ) ) { - $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." ); + $this->logger->info( + __METHOD__ . " <$ns:$tag> failed validation.", + [ 'file' => $this->filename ] + ); return; } } else { - $this->logger->warning( __METHOD__ . " Validation function for $finalName (" - . $validate[0] . '::' . $validate[1] . '()) is not callable.' ); + $this->logger->warning( + __METHOD__ . " Validation function for $finalName (" . + $validate[0] . '::' . $validate[1] . '()) is not callable.', + [ 'file' => $this->filename ] + ); } } diff --git a/includes/libs/xmp/XMPValidate.php b/includes/libs/xmp/XMPValidate.php index 76ae279f32..7aec28e635 100644 --- a/includes/libs/xmp/XMPValidate.php +++ b/includes/libs/xmp/XMPValidate.php @@ -262,14 +262,12 @@ class XMPValidate implements LoggerAwareInterface { return; } $res = []; - // @codingStandardsIgnoreStart Long line that cannot be broken if ( !preg_match( /* ahh! scary regex... */ + // phpcs:ignore Generic.Files.LineLength '/^([0-3]\d{3})(?:-([01]\d)(?:-([0-3]\d)(?:T([0-2]\d):([0-6]\d)(?::([0-6]\d)(?:\.\d+)?)?([-+]\d{2}:\d{2}|Z)?)?)?)?$/D', $val, $res ) ) { - // @codingStandardsIgnoreEnd - $this->logger->info( __METHOD__ . " Expected date but got $val" ); $val = null; } else { diff --git a/includes/linkeddata/PageDataRequestHandler.php b/includes/linkeddata/PageDataRequestHandler.php index 43cb44c854..03ab8ea268 100644 --- a/includes/linkeddata/PageDataRequestHandler.php +++ b/includes/linkeddata/PageDataRequestHandler.php @@ -1,4 +1,22 @@ */ namespace MediaWiki\Linker; diff --git a/includes/linker/LinkRendererFactory.php b/includes/linker/LinkRendererFactory.php index b7c05c2fe8..240ea09be9 100644 --- a/includes/linker/LinkRendererFactory.php +++ b/includes/linker/LinkRendererFactory.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @license GPL-2.0+ * @author Kunal Mehta */ namespace MediaWiki\Linker; diff --git a/includes/linker/LinkTarget.php b/includes/linker/LinkTarget.php index 980a8bfcb8..56407aec36 100644 --- a/includes/linker/LinkTarget.php +++ b/includes/linker/LinkTarget.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @license GPL 2+ * @author Addshore */ namespace MediaWiki\Linker; diff --git a/includes/logging/LogEventsList.php b/includes/logging/LogEventsList.php index 00d3bd3315..93a81cff8e 100644 --- a/includes/logging/LogEventsList.php +++ b/includes/logging/LogEventsList.php @@ -98,8 +98,9 @@ class LogEventsList extends ContextSource { * @param string $user * @param string $page * @param string $pattern - * @param int $year Year - * @param int $month Month + * @param int|string $year Use 0 to start with no year preselected. + * @param int|string $month A month in the 1..12 range. Use 0 to start with no month + * preselected. * @param array $filter * @param string $tagFilter Tag to select by default * @param string $action @@ -426,7 +427,7 @@ class LogEventsList extends ContextSource { } /** - * @param stdClass $row Row + * @param stdClass $row * @return string */ private function getShowHideLinks( $row ) { @@ -496,7 +497,7 @@ class LogEventsList extends ContextSource { } /** - * @param stdClass $row Row + * @param stdClass $row * @param string|array $type * @param string|array $action * @param string $right @@ -521,7 +522,7 @@ class LogEventsList extends ContextSource { * Determine if the current user is allowed to view a particular * field of this log row, if it's marked as deleted. * - * @param stdClass $row Row + * @param stdClass $row * @param int $field * @param User $user User to check, or null to use $wgUser * @return bool @@ -558,7 +559,7 @@ class LogEventsList extends ContextSource { } /** - * @param stdClass $row Row + * @param stdClass $row * @param int $field One of DELETED_* bitfield constants * @return bool */ diff --git a/includes/logging/LogPage.php b/includes/logging/LogPage.php index e421209278..77d9aa21ba 100644 --- a/includes/logging/LogPage.php +++ b/includes/logging/LogPage.php @@ -319,7 +319,7 @@ class LogPage { * * @param string $action One of '', 'block', 'protect', 'rights', 'delete', * 'upload', 'move', 'move_redir' - * @param Title $target Title object + * @param Title $target * @param string $comment Description associated * @param array $params Parameters passed later to wfMessage function * @param null|int|User $doer The user doing the action. null for $wgUser diff --git a/includes/media/Bitmap.php b/includes/media/Bitmap.php index ac39e6f3d4..617a910295 100644 --- a/includes/media/Bitmap.php +++ b/includes/media/Bitmap.php @@ -112,14 +112,14 @@ class BitmapHandler extends TransformationalImageHandler { */ protected function imageMagickSubsampling( $pixelFormat ) { switch ( $pixelFormat ) { - case 'yuv444': - return [ '1x1', '1x1', '1x1' ]; - case 'yuv422': - return [ '2x1', '1x1', '1x1' ]; - case 'yuv420': - return [ '2x2', '1x1', '1x1' ]; - default: - throw new MWException( 'Invalid pixel format for JPEG output' ); + case 'yuv444': + return [ '1x1', '1x1', '1x1' ]; + case 'yuv422': + return [ '2x1', '1x1', '1x1' ]; + case 'yuv420': + return [ '2x2', '1x1', '1x1' ]; + default: + throw new MWException( 'Invalid pixel format for JPEG output' ); } } diff --git a/includes/media/BitmapMetadataHandler.php b/includes/media/BitmapMetadataHandler.php index 35c97518ea..9e0fc3db36 100644 --- a/includes/media/BitmapMetadataHandler.php +++ b/includes/media/BitmapMetadataHandler.php @@ -170,7 +170,7 @@ class BitmapMetadataHandler { } } if ( isset( $seg['XMP'] ) && $showXMP ) { - $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) ); + $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename ); $xmp->parse( $seg['XMP'] ); foreach ( $seg['XMP_ext'] as $xmpExt ) { /* Support for extended xmp in jpeg files @@ -205,7 +205,7 @@ class BitmapMetadataHandler { if ( isset( $array['text']['xmp']['x-default'] ) && $array['text']['xmp']['x-default'] !== '' && $showXMP ) { - $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) ); + $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename ); $xmp->parse( $array['text']['xmp']['x-default'] ); $xmpRes = $xmp->getResults(); foreach ( $xmpRes as $type => $xmpSection ) { @@ -238,7 +238,7 @@ class BitmapMetadataHandler { } if ( $baseArray['xmp'] !== '' && XMPReader::isSupported() ) { - $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) ); + $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename ); $xmp->parse( $baseArray['xmp'] ); $xmpRes = $xmp->getResults(); foreach ( $xmpRes as $type => $xmpSection ) { @@ -292,7 +292,7 @@ class BitmapMetadataHandler { * Read the first 2 bytes of a tiff file to figure out * Little Endian or Big Endian. Needed for exif stuff. * - * @param string $filename The filename + * @param string $filename * @return string 'BE' or 'LE' or false */ static function getTiffByteOrder( $filename ) { diff --git a/includes/media/Bitmap_ClientOnly.php b/includes/media/Bitmap_ClientOnly.php index 3ec87723e9..fa5b0a61c6 100644 --- a/includes/media/Bitmap_ClientOnly.php +++ b/includes/media/Bitmap_ClientOnly.php @@ -29,9 +29,8 @@ * * @ingroup Media */ -// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps +// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps class BitmapHandler_ClientOnly extends BitmapHandler { - // @codingStandardsIgnoreEnd /** * @param File $image diff --git a/includes/media/FormatMetadata.php b/includes/media/FormatMetadata.php index 666196585a..f683da2c02 100644 --- a/includes/media/FormatMetadata.php +++ b/includes/media/FormatMetadata.php @@ -740,8 +740,13 @@ class FormatMetadata extends ContextSource { case 'Software': if ( is_array( $val ) ) { - // if its a software, version array. - $val = $this->msg( 'exif-software-version-value', $val[0], $val[1] )->text(); + if ( count( $val ) > 1 ) { + // if its a software, version array. + $val = $this->msg( 'exif-software-version-value', $val[0], $val[1] )->text(); + } else { + // https://phabricator.wikimedia.org/T178130 + $val = $this->exifMsg( $tag, '', $val[0] ); + } } else { $val = $this->exifMsg( $tag, '', $val ); } @@ -1042,7 +1047,7 @@ class FormatMetadata extends ContextSource { if ( !is_array( $vals ) ) { return $vals; // do nothing if not an array; - } elseif ( count( $vals ) === 1 && $type !== 'lang' ) { + } elseif ( count( $vals ) === 1 && $type !== 'lang' && isset( $vals[0] ) ) { return $vals[0]; } elseif ( count( $vals ) === 0 ) { wfDebug( __METHOD__ . " metadata array with 0 elements!\n" ); diff --git a/includes/media/IPTC.php b/includes/media/IPTC.php index 343adc2088..894043a4e5 100644 --- a/includes/media/IPTC.php +++ b/includes/media/IPTC.php @@ -353,20 +353,20 @@ class IPTC { * @todo Potentially this should also capture the timezone offset. * @param array $date The date tag * @param array $time The time tag - * @param string $c The charset + * @param string $charset * @return string Date in EXIF format. */ - private static function timeHelper( $date, $time, $c ) { + private static function timeHelper( $date, $time, $charset ) { if ( count( $date ) === 1 ) { // the standard says this should always be 1 // just double checking. - list( $date ) = self::convIPTC( $date, $c ); + list( $date ) = self::convIPTC( $date, $charset ); } else { return null; } if ( count( $time ) === 1 ) { - list( $time ) = self::convIPTC( $time, $c ); + list( $time ) = self::convIPTC( $time, $charset ); $dateOnly = false; } else { $time = '000000+0000'; // placeholder @@ -420,7 +420,7 @@ class IPTC { /** * Helper function to convert charset for iptc values. * @param string|array $data The iptc string - * @param string $charset The charset + * @param string $charset * * @return string|array */ @@ -439,7 +439,7 @@ class IPTC { /** * Helper function of a helper function to convert charset for iptc values. * @param string|array $data The IPTC string - * @param string $charset The charset + * @param string $charset * * @return string */ diff --git a/includes/media/MediaHandler.php b/includes/media/MediaHandler.php index 8551a120a5..5dca24bcba 100644 --- a/includes/media/MediaHandler.php +++ b/includes/media/MediaHandler.php @@ -255,7 +255,7 @@ abstract class MediaHandler { * Get a MediaTransformOutput object representing the transformed output. Does not * actually do the transform. * - * @param File $image The image object + * @param File $image * @param string $dstPath Filesystem destination path * @param string $dstUrl Destination URL to use in output HTML * @param array $params Arbitrary set of parameters validated by $this->validateParam() @@ -269,7 +269,7 @@ abstract class MediaHandler { * Get a MediaTransformOutput object representing the transformed output. Does the * transform unless $flags contains self::TRANSFORM_LATER. * - * @param File $image The image object + * @param File $image * @param string $dstPath Filesystem destination path * @param string $dstUrl Destination URL to use in output HTML * @param array $params Arbitrary set of parameters validated by $this->validateParam() @@ -497,7 +497,7 @@ abstract class MediaHandler { * * This is used by the media handlers that use the FormatMetadata class * - * @param array $metadataArray Metadata array + * @param array $metadataArray * @param bool|IContextSource $context Context to use (optional) * @return array Array for use displaying metadata. */ diff --git a/includes/media/SVG.php b/includes/media/SVG.php index 2b138930d1..10be97a5cd 100644 --- a/includes/media/SVG.php +++ b/includes/media/SVG.php @@ -511,8 +511,6 @@ class SvgHandler extends ImageHandler { } elseif ( $name == 'lang' ) { // Validate $code if ( $value === '' || !Language::isValidCode( $value ) ) { - wfDebug( "Invalid user language code\n" ); - return false; } diff --git a/includes/media/WebP.php b/includes/media/WebP.php index e23989dfa8..e0af6def45 100644 --- a/includes/media/WebP.php +++ b/includes/media/WebP.php @@ -154,7 +154,7 @@ class WebPHandler extends BitmapHandler { /** * Decodes a lossy chunk header - * @param string $header Header string + * @param string $header First few bytes of the header, expected to be at least 18 bytes long * @return bool|array See WebPHandler::decodeHeader */ protected static function decodeLossyChunkHeader( $header ) { @@ -180,7 +180,7 @@ class WebPHandler extends BitmapHandler { /** * Decodes a lossless chunk header - * @param string $header Header string + * @param string $header First few bytes of the header, expected to be at least 13 bytes long * @return bool|array See WebPHandler::decodeHeader */ public static function decodeLosslessChunkHeader( $header ) { @@ -205,7 +205,7 @@ class WebPHandler extends BitmapHandler { /** * Decodes an extended chunk header - * @param string $header Header string + * @param string $header First few bytes of the header, expected to be at least 18 bytes long * @return bool|array See WebPHandler::decodeHeader */ public static function decodeExtendedChunkHeader( $header ) { diff --git a/includes/media/XCF.php b/includes/media/XCF.php index c41952408f..1b6c4c87ed 100644 --- a/includes/media/XCF.php +++ b/includes/media/XCF.php @@ -151,7 +151,7 @@ class XCFHandler extends BitmapHandler { * * @param File|FSFile $file The image object, or false if there isn't one. * Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!) - * @param string $filename The filename + * @param string $filename * @return string */ public function getMetadata( $file, $filename ) { @@ -162,18 +162,17 @@ class XCFHandler extends BitmapHandler { // Unclear from base media type if it has an alpha layer, // so just assume that it does since it "potentially" could. switch ( $header['base_type'] ) { - case 0: - $metadata['colorType'] = 'truecolour-alpha'; - break; - case 1: - $metadata['colorType'] = 'greyscale-alpha'; - break; - case 2: - $metadata['colorType'] = 'index-coloured'; - break; - default: - $metadata['colorType'] = 'unknown'; - + case 0: + $metadata['colorType'] = 'truecolour-alpha'; + break; + case 1: + $metadata['colorType'] = 'greyscale-alpha'; + break; + case 2: + $metadata['colorType'] = 'index-coloured'; + break; + default: + $metadata['colorType'] = 'unknown'; } } else { // Marker to prevent repeated attempted extraction diff --git a/includes/objectcache/ObjectCache.php b/includes/objectcache/ObjectCache.php index 6d6d3459d9..67d2346013 100644 --- a/includes/objectcache/ObjectCache.php +++ b/includes/objectcache/ObjectCache.php @@ -332,6 +332,8 @@ class ObjectCache { * @throws UnexpectedValueException */ public static function newWANCacheFromParams( array $params ) { + global $wgCommandLineMode; + $services = MediaWikiServices::getInstance(); $erGroup = $services->getEventRelayerGroup(); @@ -340,12 +342,17 @@ class ObjectCache { $params['channels'][$action] = $channel; } $params['cache'] = self::newFromParams( $params['store'] ); - $params['stats'] = $services->getStatsdDataFactory(); if ( isset( $params['loggroup'] ) ) { $params['logger'] = LoggerFactory::getInstance( $params['loggroup'] ); } else { $params['logger'] = LoggerFactory::getInstance( 'objectcache' ); } + if ( !$wgCommandLineMode ) { + // Send the statsd data post-send on HTTP requests; avoid in CLI mode (T181385) + $params['stats'] = $services->getStatsdDataFactory(); + // Let pre-emptive refreshes happen post-send on HTTP requests + $params['asyncHandler'] = [ DeferredUpdates::class, 'addCallableUpdate' ]; + } $class = $params['class']; return new $class( $params ); diff --git a/includes/objectcache/SqlBagOStuff.php b/includes/objectcache/SqlBagOStuff.php index 2cfd2a1d76..6691f73d2e 100644 --- a/includes/objectcache/SqlBagOStuff.php +++ b/includes/objectcache/SqlBagOStuff.php @@ -21,15 +21,15 @@ * @ingroup Cache */ +use MediaWiki\MediaWikiServices; use Wikimedia\Rdbms\Database; use Wikimedia\Rdbms\IDatabase; use Wikimedia\Rdbms\DBError; use Wikimedia\Rdbms\DBQueryError; use Wikimedia\Rdbms\DBConnectionError; -use \MediaWiki\MediaWikiServices; -use \Wikimedia\WaitConditionLoop; -use \Wikimedia\Rdbms\TransactionProfiler; use Wikimedia\Rdbms\LoadBalancer; +use Wikimedia\Rdbms\TransactionProfiler; +use Wikimedia\WaitConditionLoop; /** * Class to store objects in the database @@ -808,6 +808,9 @@ class SqlBagOStuff extends BagOStuff { // Main LB is used; wait for any replica DBs to catch up $masterPos = $lb->getMasterPos(); + if ( !$masterPos ) { + return true; // not applicable + } $loop = new WaitConditionLoop( function () use ( $lb, $masterPos ) { diff --git a/includes/page/CategoryPage.php b/includes/page/CategoryPage.php index 2d7e8f24fd..491726bedd 100644 --- a/includes/page/CategoryPage.php +++ b/includes/page/CategoryPage.php @@ -27,7 +27,7 @@ */ class CategoryPage extends Article { # Subclasses can change this to override the viewer class. - protected $mCategoryViewerClass = 'CategoryViewer'; + protected $mCategoryViewerClass = CategoryViewer::class; /** * @var WikiCategoryPage diff --git a/includes/page/ImagePage.php b/includes/page/ImagePage.php index 76ff41bc36..b5ff80594e 100644 --- a/includes/page/ImagePage.php +++ b/includes/page/ImagePage.php @@ -251,13 +251,14 @@ class ImagePage extends Article { protected function makeMetadataTable( $metadata ) { $r = "