'MediaWiki\\Auth\\Throttler' => __DIR__ . '/includes/auth/Throttler.php',
'MediaWiki\\Auth\\UserDataAuthenticationRequest' => __DIR__ . '/includes/auth/UserDataAuthenticationRequest.php',
'MediaWiki\\Auth\\UsernameAuthenticationRequest' => __DIR__ . '/includes/auth/UsernameAuthenticationRequest.php',
+ 'MediaWiki\\Config\\ConfigRepository' => __DIR__ . '/includes/config/ConfigRepository.php',
'MediaWiki\\DB\\PatchFileLocation' => __DIR__ . '/includes/db/PatchFileLocation.php',
'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
"zordius/lightncandy": "0.23"
},
"require-dev": {
+ "cache/integration-tests": "0.16.0",
"composer/spdx-licenses": "1.3.0",
"hamcrest/hamcrest-php": "^2.0",
"jakub-onderka/php-parallel-lint": "0.9.2",
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
- <style>
- /** This is just for coloring: */
- table { border: 1px solid #CC0; }
- td { border: 1px solid #CCC; }
-
- table {
- width: 100%;
- table-layout: fixed;
- }
-
- #first {
- width: 300px;
- }
- </style>
-</head>
-<body>
-
-<p>
-This play with table-layout:fixed; and applying the width to colgroup or col element. Firefox only recongize the width if it is applied on col element!</p>
-<p>
-On a perfect browser, both tables should look the same</p>
-
-<dl>
- <dt>colgroup</dt>
- <dd>300 px width is applied to the first colgroup element</dd>
-</dl>
-<div style="width: 400px;">
-<table>
- <colgroup id="first" /></colgroup>
- <colgroup id="second"/></colgroup>
- <colgroup id="third" /></colgroup>
- <tr>
- <td>Very long?</td>
- <td>#</td>
- <td>$</td>
- </tr>
-</table>
-</div>
-
-<dl>
- <dt>col</dt>
- <dd>Each colgroup has an additional col element. The first col element is applied the 300 px width</dd>
-</dl>
-
-<div style="width: 400px;">
-<table>
- <colgroup><col id="first" /></colgroup>
- <colgroup><col id="second"/></colgroup>
- <colgroup><col id="third" /></colgroup>
- <tr>
- <td>Very long?</td>
- <td>#</td>
- <td>$</td>
- </tr>
-</table>
-</div>
* @since 1.32
* @var int An appropriate combination of SCHEMA_COMPAT_XXX flags.
*/
-$wgMultiContentRevisionSchemaMigrationStage = MIGRATION_OLD;
+$wgMultiContentRevisionSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD;
/**
* Actor table schema migration stage.
function wfExpandIRI( $url ) {
return preg_replace_callback(
'/((?:%[89A-F][0-9A-F])+)/i',
- 'wfExpandIRI_callback',
+ function ( array $matches ) {
+ return urldecode( $matches[1] );
+ },
wfExpandUrl( $url )
);
}
-/**
- * Private callback for wfExpandIRI
- * @param array $matches
- * @return string
- */
-function wfExpandIRI_callback( $matches ) {
- return urldecode( $matches[1] );
-}
-
/**
* Make URL indexes, appropriate for the el_index field of externallinks.
*
use LinkCache;
use Wikimedia\Rdbms\LoadBalancer;
use MediaHandlerFactory;
+use MediaWiki\Config\ConfigRepository;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Linker\LinkRendererFactory;
use MediaWiki\Services\SalvageableService;
return $this->getService( 'OldRevisionImporter' );
}
+ /**
+ * @return ConfigRepository
+ */
+ public function getConfigRepository() {
+ return $this->getService( 'ConfigRepository' );
+ }
+
///////////////////////////////////////////////////////////////////////////
// NOTE: When adding a service getter here, don't forget to add a test
// case for it in MediaWikiServicesTest::provideGetters() and in
*/
use MediaWiki\Auth\AuthManager;
+use MediaWiki\Config\ConfigRepository;
use MediaWiki\Interwiki\ClassicInterwikiLookup;
use MediaWiki\Linker\LinkRendererFactory;
use MediaWiki\Logger\LoggerFactory;
return $factory;
},
+ 'ConfigRepository' => function ( MediaWikiServices $services ) {
+ return new ConfigRepository( $services->getConfigFactory() );
+ },
+
'MainConfig' => function ( MediaWikiServices $services ) {
// Use the 'main' config from the ConfigFactory service.
return $services->getConfigFactory()->makeConfig( 'main' );
* and does not rely on global state or the database.
*/
class Title implements LinkTarget {
- /** @var HashBagOStuff */
+ /** @var MapCacheLRU */
static private $titleCache = null;
/**
}
/**
- * @return HashBagOStuff
+ * @return MapCacheLRU
*/
private static function getTitleCache() {
if ( self::$titleCache == null ) {
- self::$titleCache = new HashBagOStuff( [ 'maxKeys' => self::CACHE_MAX ] );
+ self::$titleCache = new MapCacheLRU( self::CACHE_MAX );
}
return self::$titleCache;
}
* @return ApiFormatBase
*/
public function createPrinterByName( $format ) {
- $printer = $this->mModuleMgr->getModule( $format, 'format' );
+ $printer = $this->mModuleMgr->getModule( $format, 'format', /* $ignoreCache */ true );
if ( $printer === null ) {
$this->dieWithError(
[ 'apierror-unknownformat', wfEscapeWikiText( $format ) ], 'unknown_format'
"AttemptToCallNil",
"Movses",
"Stjn",
- "Edward Chernenko"
+ "Edward Chernenko",
+ "Vlad5250"
]
},
"apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Документация]]\n* [[mw:Special:MyLanguage/API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почтовая рассылка]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Новости API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Ошибки и запросы]\n</div>\n<strong>Статус:</strong> MediaWiki API — зрелый и стабильный интерфейс, активно поддерживаемый и улучшаемый. Мы стараемся избегать ломающих изменений, однако изредка они могут быть необходимы. Подпишитесь на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почтовую рассылку mediawiki-api-announce], чтобы быть в курсе обновлений.\n\n<strong>Ошибочные запросы:</strong> Если API получает запрос с ошибкой, вернётся заголовок HTTP с ключом «MediaWiki-API-Error», после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Ошибки и предупреждения]].\n\n<p class=\"mw-apisandbox-link\"><strong>Тестирование:</strong> для удобства тестирования API-запросов, см. [[Special:ApiSandbox]].</p>",
"apihelp-query+filearchive-example-simple": "Список всех удалённых файлов.",
"apihelp-query+filerepoinfo-summary": "Возвращает мета-информацию о файловых репозиториях, настроенных в вики.",
"apihelp-query+filerepoinfo-param-prop": "Какие свойства хранилища получить (доступность свойств может отличаться в разных вики).",
+ "apihelp-query+filerepoinfo-paramvalue-prop-rootUrl": "Корневой URL для изображений.",
+ "apihelp-query+filerepoinfo-paramvalue-prop-url": "URL путь публичной зоны.",
"apihelp-query+filerepoinfo-example-simple": "Получить информацию о файловых репозиториях.",
"apihelp-query+fileusage-summary": "Поиск всех страниц, использующих данный файл.",
"apihelp-query+fileusage-param-prop": "Какие свойства получить:",
--- /dev/null
+<?php
+/**
+ * Copyright 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Config;
+
+use MediaWiki\Services\SalvageableService;
+use Wikimedia\Assert\Assert;
+
+/**
+ * Object which holds currently registered configuration options.
+ *
+ * @since 1.32
+ */
+class ConfigRepository implements SalvageableService {
+ /** @var \ConfigFactory */
+ private $configFactory;
+
+ /** @var array */
+ private $configItems = [
+ 'private' => [],
+ 'public' => [],
+ ];
+
+ /**
+ * @param \ConfigFactory $configFactory
+ */
+ public function __construct( \ConfigFactory $configFactory ) {
+ $this->configFactory = $configFactory;
+ }
+
+ /**
+ * Returns true, if this repository contains a configuration with a specific name.
+ *
+ * @param string $name The name of the config to check the existence of
+ * @param bool $alsoPrivate If set to true, will check the private config options, too
+ * @return bool
+ */
+ public function has( $name, $alsoPrivate = false ) {
+ return isset( $this->configItems['public'][$name] ) ||
+ ( $alsoPrivate && isset( $this->configItems['private'][$name] ) );
+ }
+
+ /**
+ * Returns the ConfigItem with the given name, if there's one. Throws a ConfigException
+ * otherwise.
+ *
+ * @param string $name The name of the configuration option to get
+ * @return array
+ * @throws \ConfigException
+ */
+ public function get( $name ) {
+ if ( !$this->has( $name, true ) ) {
+ throw new \ConfigException( 'The configuration option ' . $name . ' does not exist.' );
+ }
+ if ( isset( $this->configItems['public'][$name] ) ) {
+ return $this->configItems['public'][$name];
+ }
+ return $this->configItems['private'][$name];
+ }
+
+ /**
+ * Returns an array of all configuration items saved in this ConfigRepository. This includes
+ * all configuration options, including the ones marked as private and public.
+ *
+ * Note: This function does not do any permission checks or something similar. You should not
+ * use this function, if the output will be available to the public audience! Use
+ * ConfigRepository::getPublic() instead.
+ *
+ * @return array
+ */
+ public function getAll() {
+ return array_merge( $this->configItems['private'], $this->configItems['public'] );
+ }
+
+ /**
+ * Returns an array of all public configuration options saved in this ConfigRepository.
+ *
+ * @return array
+ */
+ public function getPublic() {
+ return $this->configItems['public'];
+ }
+
+ /**
+ * Returns the current value of the configuration option. If no ConfigRegistry was provided
+ * when the config was added to the repository, the default value will be returned.
+ *
+ * @param string $name The name of the configuration option to get the value of
+ * @return mixed
+ * @throws \ConfigException
+ */
+ public function getValueOf( $name ) {
+ $config = $this->get( $name );
+ if ( !isset( $config['configregistry'] ) ) {
+ return $config['value'];
+ }
+
+ return $this->configFactory->makeConfig( $config['configregistry'] )->get( $name );
+ }
+
+ /**
+ * Returns the description of the given config option, This can be either a localized
+ * description, if one such, or the (maybe english only) description provided in the
+ * definition of the configuration. If both is not provided an empty string is returned.
+ *
+ * @param string $name The name of the configuration option to get the description of
+ * @return string HTML-escaped string
+ */
+ public function getDescriptionOf( $name ) {
+ $config = $this->get( $name );
+ if ( isset( $config['descriptionmsg'] ) ) {
+ return wfMessage( $config['descriptionmsg'] )->escaped();
+ }
+ if ( isset( $config['description'] ) ) {
+ return htmlspecialchars( $config['description'] );
+ }
+ return '';
+ }
+
+ /**
+ * Adds the definition of a configuration to this repository.
+ *
+ * @param string $name the name of the config
+ * @param array $config Options of this config. Values are:
+ * - value: The default value of this configuration, required
+ * - providedby: The name of the provider of this config (an extension, core, ...), required
+ * - configregistry: The name of the config to retrieve the value with, required
+ * - public: whether this option is public or not, if not set, the option is considered as
+ * "private", optional
+ * - description: the not localized description of this config option, optional
+ * - descriptionmsg: The message key of the localized description of this configuration
+ * option, optional
+ * @throws \ConfigException
+ */
+ public function add( $name, array $config ) {
+ if ( $this->has( $name ) ) {
+ throw new \ConfigException( 'A configuration with the name ' . $name .
+ 'does already exist. It is provided by: ' .
+ $this->get( $name )['providedby'] );
+ }
+ if ( isset( $config['public'] ) && $config['public'] ) {
+ $this->configItems['public'][$name] = $config;
+ } else {
+ $this->configItems['private'][$name] = $config;
+ }
+ }
+
+ /**
+ * Returns true, if there're no elements in this instance, otherwise false.
+ *
+ * @param bool $includePrivate Whether configuration options, that are marked as private
+ * should be included in this check.
+ * @return bool
+ */
+ public function isEmpty( $includePrivate = false ) {
+ if ( $includePrivate ) {
+ return empty( $this->configItems['private'] ) &&
+ empty( $this->configItems[ 'public'] );
+ }
+ return empty( $this->configItems['public'] );
+ }
+
+ /**
+ * Re-uses existing Cache objects from $other. Cache objects are only re-used if the
+ * registered factory function for both is the same.
+ *
+ * @see SalvageableService::salvage()
+ *
+ * @param SalvageableService $other The object to salvage state from. $other must have the
+ * exact same type as $this.
+ */
+ public function salvage( SalvageableService $other ) {
+ Assert::parameterType( self::class, $other, '$other' );
+
+ /** @var ConfigRepository $other */
+ $otherCurrentObj = $other->current();
+ foreach ( $other->configItems['public'] as $name => $otherConfig ) {
+ if ( isset( $this->configItems['public'][$name] ) ) {
+ continue;
+ }
+
+ $this->add( $name, $otherConfig );
+
+ // recover the pointer of the other config repository
+ if ( $otherCurrentObj === $otherConfig ) {
+ end( $this->configItems['public'] );
+ }
+ }
+ foreach ( $other->configItems['private'] as $name => $otherConfig ) {
+ if ( isset( $this->configItems['private'][$name] ) ) {
+ continue;
+ }
+
+ $this->add( $name, $otherConfig );
+
+ // recover the pointer of the other config repository
+ if ( $otherCurrentObj === $otherConfig ) {
+ end( $this->configItems['private'] );
+ }
+ }
+
+ // disable $other
+ $other->configItems = [];
+ }
+}
if ( isset( $options['bypassCache'] ) ) {
$options['latest'] = $options['bypassCache']; // b/c
}
+ $options += [ 'time' => false ];
if ( !$this->reposInitialised ) {
$this->initialiseRepos();
}
+
$title = File::normalizeTitle( $title );
if ( !$title ) {
return false;
# Check the cache
$dbkey = $title->getDBkey();
+ $timeKey = is_string( $options['time'] ) ? $options['time'] : '';
if ( empty( $options['ignoreRedirect'] )
&& empty( $options['private'] )
&& empty( $options['latest'] )
) {
- $time = $options['time'] ?? '';
- if ( $this->cache->hasField( $dbkey, $time, 60 ) ) {
- return $this->cache->getField( $dbkey, $time );
+ if ( $this->cache->hasField( $dbkey, $timeKey, 60 ) ) {
+ return $this->cache->getField( $dbkey, $timeKey );
}
$useCache = true;
} else {
- $time = false;
$useCache = false;
}
$image = $image ?: false; // type sanity
# Cache file existence or non-existence
if ( $useCache && ( !$image || $image->isCacheable() ) ) {
- $this->cache->setField( $dbkey, $time, $image );
+ $this->cache->setField( $dbkey, $timeKey, $image );
}
return $image;
"config-sqlite-dir-help": "يخزن SQLite جميع البيانات في ملف واحد. \n\nيجب أن يكون الدليل الذي توفره قابلا للكتابة بواسطة خادم الويب أثناء التثبيت. \n\nيجب أن يكون <strong>غير</strong> متاحا عبر الويب؛ هذا هو سبب عدم وضعه في مكان ملفات PHP الخاصة بك. \n\nسيقوم المثبت بكتابة ملف <code>.htaccess</code> معه، ولكن إذا فشل ذلك، يمكن لشخص ما الوصول إلى قاعدة بياناتك الأولية، \nيتضمن ذلك بيانات المستخدم الأولية (عناوين البريد الإلكتروني وكلمات المرور المجزأة) بالإضافة إلى المراجعات المحذوفة والبيانات المحظورة الأخرى على الويكي. \n\nفكر في وضع قاعدة البيانات في مكان آخر تماما، على سبيل المثال في <code>/var/lib/mediawiki/yourwiki</code.",
"config-oracle-def-ts": "جدولية افتراضية:",
"config-oracle-temp-ts": "جدولية مؤقتة:",
- "config-type-mysql": "MySQL (أو متوافق)",
+ "config-type-mysql": "MariaDB أو MySQL أو متوافق",
"config-type-postgres": "بوستجر إس كيو إل",
"config-type-sqlite": "إس كيو لايت",
"config-type-oracle": "أوراكل",
"config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] هو نظام قاعدة بيانات خفيف مدعوم بشكل جيد. ([https://secure.php.net/manual/en/pdo.installation.php كيفية ترجمة PHP باستخدام دعم SQLite]، يستخدم PDO)",
"config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] هي قاعدة بيانات مؤسسة تجارية. ([https://secure.php.net/manual/en/oci8.installation.php كيفية تجميع PHP مع دعم OCI8])",
"config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] هي قاعدة بيانات مؤسسة تجارية لويندوز. ([https://secure.php.net/manual/en/sqlsrv.installation.php كيفية تجميع PHP مع دعم SQLSRV])",
- "config-header-mysql": "إعدادات MySQL",
+ "config-header-mysql": "إعدادات MariaDB/MySQL",
"config-header-postgres": "إعدادات PostgreSQL",
"config-header-sqlite": "إعدادات SQLite",
"config-header-oracle": "إعدادات أوراكل",
"config-db-web-create": "إنشئ حساب إذا لم يكن موجودا بالفعل",
"config-db-web-no-create-privs": "الحساب الذي حددته لتركيب ليس لديه امتيازات كافية لإنشاء حساب.\nالحساب الذي حددته هنا موجود بالفعل.",
"config-mysql-engine": "محرك التخزين",
- "config-mysql-innodb": "إنو دي بي",
+ "config-mysql-innodb": "InnoDB (مستحسن)",
"config-mysql-myisam": "ماي إسام",
"config-mysql-myisam-dep": "<strong>تحذير:</strong> لقد اخترت MyISAM كمحرك تخزين لـMySQL، والذي لا يُنصَح باستخدامه مع ميدياويكي; لأنه:\n* بالكاد يدعم التزامن بسبب قفل الجدول \n* أكثر عرضة للفساد من المحركات الأخرى\n* لا يقوم الكود الأساسي لميدياويكي بمعالجة MyISAM دائما كما يجب\n\nإذا كان تثبيت MySQL يدعم InnoDB، فمن المستحسن جدا أن تختاره بدلا منه، \nإذا كان تثبيت MySQL لا يدعم InnoDB، فربما حان الوقت للترقية.",
"config-mysql-only-myisam-dep": "<strong>تحذير:</strong> MyISAMهو محرك التخزين الوحيد المتاح لـMySQL على هذا الجهاز، ولا يُنصَح باستخدامه مع ميدياويكي; لأنه:\n* بالكاد يدعم التزامن بسبب قفل الجدول \n* أكثر عرضة للفساد من المحركات الأخرى\n* لا يقوم الكود الأساسي لميدياويكي بمعالجة MyISAM دائما كما يجب\n\nتثبيت MySQL لا يدعم InnoDB; ربما حان الوقت للترقية.",
"config-sqlite-dir-help": "SQLite lagrer alle data i en enkelt fil.\n\nMappen du oppgir må være skrivbar for nettjeneren under installasjonen.\n\nDen bør '''ikke''' være tilgjengelig fra nettet, dette er grunnen til at vi ikke legger det der PHP-filene dine er.\n\nInstallasjonsprogrammet vil skrive en <code>.htaccess</code>-fil sammen med det, men om det mislykkes kan noen få tilgang til din råe database. Dette inkluderer rå brukerdata (e-postadresser, hashede passord) samt slettede revisjoner og andre begrensede data på wikien.\n\nVurder å plassere databasen et helt annet sted, for eksempel i <code>/var/lib/mediawiki/yourwiki</code>.",
"config-oracle-def-ts": "Standard tabellrom:",
"config-oracle-temp-ts": "Midlertidig tabellrom:",
- "config-type-mysql": "MySQL (eller kompatibelt)",
+ "config-type-mysql": "MariaDB, MySQL eller kompatibel",
"config-type-postgres": "PostgreSQL",
"config-type-sqlite": "SQLite",
"config-type-oracle": "Oracle",
"config-type-mssql": "Microsoft SQLServer",
"config-support-info": "MediaWiki støtter følgende databasesystem:\n\n$1\n\nHvis du ikke ser databasesystemet du prøver å bruke i listen nedenfor, følg instruksjonene det er lenket til over for å aktivere støtte.",
- "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] er den foretrukne databasetypen for MediaWiki og har best støtte. MediaWiki fungerer også med [{{int:version-db-mariadb-url}} MariaDB] og [{{int:version-db-percona-url}} Percona Server], som begge er MySQL-kompatible. ([https://secure.php.net/manual/en/mysqli.installation.php Hvordan kompilere PHP med MySQL-støtte])",
+ "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] er den foretrukne databasetypen for MediaWiki og har best støtte. MediaWiki fungerer også med [{{int:version-db-mysql-url}} MySQL] og [{{int:version-db-percona-url}} Percona Server], som begge er MariaDB-kompatible. ([https://secure.php.net/manual/en/mysqli.installation.php Hvordan kompilere PHP med MySQL-støtte])",
"config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] er et populært åpen kildekode-databasesystem og et alternativ til MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Hvordan kompilere PHP med PostgreSQL-støtte])",
"config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] er et lettvekts-databasesystem som har veldig god støtte. ([http://www.php.net/manual/en/pdo.installation.php Hvordan kompilere PHP med SQLite-støtte], bruker PDO)",
"config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] er en kommersiell database for bedrifter. ([https://secure.php.net/manual/en/oci8.installation.php Hvordan kompilere PHP med OCI8-støtte])",
"config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] er et kommersielt databasesystem under Windows for bedrifter. ([https://secure.php.net/manual/en/sqlsrv.installation.php Hvordan kompilere PHP med SQLSRV-støtte])",
- "config-header-mysql": "MySQL-innstillinger",
+ "config-header-mysql": "MariadB/MySQL-innstillinger",
"config-header-postgres": "PostgreSQL-innstillinger",
"config-header-sqlite": "SQLite-innstillinger",
"config-header-oracle": "Oracle-innstillinger",
"config-db-web-create": "Opprett kontoen om den ikke finnes allerede",
"config-db-web-no-create-privs": "Kontoen du oppga for installasjonen har ikke nok privilegier til å opprette en konto.\nKontoen du oppgir her må finnes allerede.",
"config-mysql-engine": "Lagringsmotor:",
- "config-mysql-innodb": "InnoDB",
+ "config-mysql-innodb": "InnoDB (anbefalt)",
"config-mysql-myisam": "MyISAM",
"config-mysql-myisam-dep": "'''Advarsel:''' Du har valgt MyISAM som lagringsmotor for MySQL, noe som ikke er anbefalt for bruk med MediaWiki, fordi:\n* den knapt støtter samtidighet pga. tabell-låsing\n* den har større tilbøyelighet for å bli korrupt enn andre motorer\n* MediaWiki-koden håndterer ikke alltid MyISAM som den burde\n\nHvis din MySQL-installasjon støtter InnoDB, er det sterkt å anbefale at du i stedet velger den.\nHvis din MySQL-installasjon ikke støtter InnoDB, kan det være på tide med en oppgradering.",
"config-mysql-only-myisam-dep": "'''Advarsel:''' MyISAM er den eneste tilgjengelig lagringsmotoren for MySQL på denne maskinen, og det er ikke anbefalt brukt for MediaWiki, fordi:\n* den knapt støtter samtidighet pga. tabell-låsing\n* den har større tilbøyelighet for å bli korrupt enn andre motorer\n* MediaWiki-koden håndterer ikke alltid MyISAM som den burde\n\nHvis din MySQL-installasjon ikke støtter InnoDB, kan det være på tide med en oppgradering.",
$conf = $conf + $wgJobTypeConf['default'];
}
$conf['aggregator'] = JobQueueAggregator::singleton();
- if ( $this->readOnlyReason !== false ) {
+ if ( !isset( $conf['readOnlyReason'] ) ) {
$conf['readOnlyReason'] = $this->readOnlyReason;
}
$url = $match['file'][0];
// Skip fully-qualified and protocol-relative URLs and data URIs
- // Also skips the rare `behavior` property specifying application's default behavior
if (
substr( $url, 0, 2 ) === '//' ||
- parse_url( $url, PHP_URL_SCHEME ) ||
- substr( $url, 0, 9 ) === '#default#'
+ parse_url( $url, PHP_URL_SCHEME )
) {
break;
}
+ // Strip trailing anchors - T115436
+ $anchor = strpos( $url, '#' );
+ if ( $anchor !== false ) {
+ $url = substr( $url, 0, $anchor );
+
+ // '#some-anchors' is not a file
+ if ( $url === '' ) {
+ break;
+ }
+ }
+
$files[] = $path . $url;
}
}
// Pass thru fully-qualified and protocol-relative URLs and data URIs, as well as local URLs if
// we can't expand them.
- // Also skips the rare `behavior` property specifying application's default behavior
+ // Also skips anchors or the rare `behavior` property specifying application's default behavior
if (
self::isRemoteUrl( $url ) ||
self::isLocalUrl( $url ) ||
- substr( $url, 0, 9 ) === '#default#'
+ substr( $url, 0, 1 ) === '#'
) {
return $url;
}
*/
protected $credits = [];
+ /**
+ * @var array
+ */
+ protected $config = [];
+
/**
* Any thing else in the $info that hasn't
* already been processed
return [
'globals' => $this->globals,
+ 'config' => $this->config,
'defines' => $this->defines,
'callbacks' => $this->callbacks,
'credits' => $this->credits,
$value = "$dir/$value";
}
$this->addConfigGlobal( "$prefix$key", $value, $info['name'] );
+ $data['providedby'] = $info['name'];
+ if ( isset( $info['ConfigRegistry'][0] ) ) {
+ $data['configregistry'] = array_keys( $info['ConfigRegistry'] )[0];
+ }
+ $this->config[$key] = $data;
}
}
}
/**
* Bump whenever the registration cache needs resetting
*/
- const CACHE_VERSION = 6;
+ const CACHE_VERSION = 7;
/**
* Special key that defines the merge strategy
* @return array With following keys:
* 'globals' - variables to be set to $GLOBALS
* 'defines' - constants to define
+ * 'config' - configuration information
* 'callbacks' - functions to be executed by the registry
* 'credits' - metadata to be stored by registry
* 'attributes' - registration info which isn't a global variable
* Take a list of strings and build a locale-friendly comma-separated
* list, using the local comma-separator message.
* The last two strings are chained with an "and".
- * NOTE: This function will only work with standard numeric array keys (0, 1, 2…)
*
- * @param string[] $l
+ * @param string[] $list
* @return string
*/
- function listToText( array $l ) {
- $m = count( $l ) - 1;
- if ( $m < 0 ) {
+ public function listToText( array $list ) {
+ $itemCount = count( $list );
+ if ( $itemCount < 1 ) {
return '';
}
- if ( $m > 0 ) {
+ $text = array_pop( $list );
+ if ( $itemCount > 1 ) {
$and = $this->msg( 'and' )->escaped();
$space = $this->msg( 'word-separator' )->escaped();
- if ( $m > 1 ) {
+ $comma = '';
+ if ( $itemCount > 2 ) {
$comma = $this->msg( 'comma-separator' )->escaped();
}
+ $text = implode( $comma, $list ) . $and . $space . $text;
}
- $s = $l[$m];
- for ( $i = $m - 1; $i >= 0; $i-- ) {
- if ( $i == $m - 1 ) {
- $s = $l[$i] . $and . $space . $s;
- } else {
- $s = $l[$i] . $comma . $s;
- }
- }
- return $s;
+ return $text;
}
/**
--- /dev/null
+## normalize-ar.phpc
+
+Generated by `maintenance/language/generateNormalizerDataAr.php`.
+
+## normalize-ml.php
+
+Generated by `maintenance/language/generateNormalizerDataMl.php`.
<?php
-// File created by maintenance/generateNormalizerDataAr.php
+// File created by generateNormalizerDataAr.php
return [
'ﭐ' => 'ٱ',
'ﭑ' => 'ٱ',
<?php
-// File created by maintenance/generateNormalizerDataMl.php
+// File created by generateNormalizerDataMl.php
return [
'ണ്' => 'ൺ',
'ന്' => 'ൻ',
"diff-paragraph-moved-toold": "الفقرة تم نقلها. اضغط للذهاب للموقع القديم.",
"difference-missing-revision": "{{PLURAL:$2|مراجعة واحدة|$2 مراجعات}} لهذا الفرق ($1) {{PLURAL:$2|لم|لم}} يتم إيجادها.\n\nهذا يحدث عادة عن طريق اتباع وصلة فرق قديمة لصفحة تم حذفها.\nالتفاصيل يمكن إيجادها في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
"searchresults": "نتائج البحث",
+ "search-filter-title-prefix": "البحث فقط في الصفحات التي يبدأ عنوانها بـ \"$1\"",
+ "search-filter-title-prefix-reset": "البحث في جميع الصفحات",
"searchresults-title": "نتائج البحث عن \"$1\"",
"titlematches": "عنوان الصفحة يطابق",
"textmatches": "نص الصفحة يطابق",
"speciallogtitlelabel": "الهدف (عنوان أو {{ns:user}}:اسم المستخدم للمستخدم):",
"log": "سجلات",
"logeventslist-submit": "أظهر",
- "logeventslist-more-filters": "المزيد من المرشحات:",
+ "logeventslist-more-filters": "إظهار السجلات الإضافية:",
+ "logeventslist-patrol-log": "سجل الخفر",
+ "logeventslist-tag-log": "سجل الوسم",
"all-logs-page": "كل السجلات العامة",
"alllogstext": "عرض شامل لكل السجلات المتوفرة في {{SITENAME}}.\nباستطاعتك جعل القائمة أكثر تحديداً، وذلك باختيار نوع السجل واسم المستخدم (حساس لحالة الحروف)، أو الصفحة المتأثرة (أيضاً حساس لحالة الحروف).",
"logempty": "لا توجد مدخلات مطابقة في السجل.",
"uctop": "(حالية)",
"month": "من شهر (وأقدم):",
"year": "من سنة (وأقدم):",
+ "date": "من تاريخ (وأقدم).",
"sp-contributions-newbies": "اعرض مساهمات الحسابات الجديدة فقط",
"sp-contributions-newbies-sub": "للحسابات الجديدة",
"sp-contributions-newbies-title": "مساهمات المستخدم للحسابات الجديدة",
"difference-missing-revision": "{{PLURAL:$2|$2 вэрсія|$2 вэрсіі|$2 вэрсіяў}} з гэтымі адрозьненьнямі ($1) {{PLURAL:$2|не была|не былі}} знойдзеныя.\n\nЗвычайна гэта здараецца з-за пераходу па састарэлай спасылцы на старонку, якая была выдаленая.\nПадрабязнасьці можна знайсьці ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].",
"searchresults": "Вынікі пошуку",
"search-filter-title-prefix": "Шукаем толькі на старонках, назвы якіх пачынаюцца з «$1»",
+ "search-filter-title-prefix-reset": "Шукаць сярод усіх старонак",
"searchresults-title": "Вынікі пошуку для «$1»",
"titlematches": "Супадзеньні ў назвах старонак",
"textmatches": "Супадзеньні ў тэкстах старонак",
"rcfilters-other-review-tools": "Други инструменти за проверка",
"rcfilters-group-results-by-page": "Групиране на резултатите по страница",
"rcfilters-activefilters": "Активни филтри",
+ "rcfilters-activefilters-hide": "Скриване",
"rcfilters-advancedfilters": "Разширени филтри",
"rcfilters-limit-title": "Резултати за показване",
"rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|промяна|промени}}, $2",
"rcfilters-filter-humans-label": "Човек (не бот)",
"rcfilters-filter-humans-description": "Редакции, направени от редактори.",
"rcfilters-filtergroup-reviewstatus": "Проверка на статуса",
- "rcfilters-filter-reviewstatus-unpatrolled-label": "Ð\9dепаÑ\82Ñ\80Ñ\83лиÑ\80ано",
+ "rcfilters-filter-reviewstatus-unpatrolled-label": "Ð\9dепаÑ\82Ñ\80Ñ\83лиÑ\80ани",
"rcfilters-filter-reviewstatus-manual-label": "Ръчно патрулирани",
"rcfilters-filter-reviewstatus-auto-label": "Автоматично патрулирани",
"rcfilters-filtergroup-significance": "Значимост",
"rcfilters-filter-watchlist-notwatched-label": "Извън списъка за наблюдение",
"rcfilters-filter-watchlist-notwatched-description": "Всички, освен промените в страници от списъка за наблюдение.",
"rcfilters-filtergroup-watchlistactivity": "Активност по списъка за наблюдение",
- "rcfilters-filter-watchlistactivity-unseen-label": "Невидяни промени",
+ "rcfilters-filter-watchlistactivity-unseen-label": "Невидeни промени",
"rcfilters-filter-watchlistactivity-unseen-description": "Промени по страници, които не сте посетили откакто са настъпили промените.",
"rcfilters-filter-watchlistactivity-seen-label": "Видени промени",
"rcfilters-filter-watchlistactivity-seen-description": "Промени по страници, които сте посетили откакто са настъпили промените.",
"dellogpage": "Дневник на изтриванията",
"dellogpagetext": "Списък на последните изтривания.",
"deletionlog": "дневник на изтриванията",
+ "log-name-create": "Дневник на създадените страници",
+ "log-description-create": "По-долу е показан списък на последно създадените страници.",
"logentry-create-create": "$1 {{GENDER:$2|създаде}} страница $3",
"reverted": "Възвръщане към предишна версия",
"deletecomment": "Причина:",
"tag-filter-submit": "Филтриране",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Етикет|Етикети}}]]: $2)",
"tag-mw-contentmodelchange": "промяна на модела на съдържание",
+ "tag-mw-new-redirect": "Ново пренасочване",
+ "tag-mw-removed-redirect": "Премахнато пренасочване",
+ "tag-mw-blank": "Изтриване на съдържанието",
+ "tag-mw-replace": "Заменено",
"tag-mw-rollback": "Отмяна",
"tag-mw-undo": "Отмяна",
"tags-title": "Етикети",
"nextn": "âu $1 bĭk",
"shown-title": "Mūi hiĕk hiēng-sê $1{{PLURAL:$1|bĭk giék-guō}}",
"viewprevnext": "Káng ($1 {{int:pipe-separator}} $2) ($3)",
+ "searchmenu-exists": "cī siŏh bĭh wiki ī-gĭng ô „$1“ mìng-chĭng gì dèu-mŭk",
"searchprofile-articles": "Nô̤i-ṳ̀ng hiĕk",
"searchprofile-images": "Dŏ̤-mùi-tā̤",
"searchprofile-everything": "Sū-iū-nó̤h",
"dellogpage": "لۆگی سڕینەوە",
"dellogpagetext": "ئەوەی خوارەوە لیستێكە لە دوایین سڕینەوەکان",
"deletionlog": "لۆگی سڕینەوە",
+ "log-name-create": "لۆگی دروستکردنی پەڕە",
+ "logentry-create-create": "$1 پەڕەی $3ی دروست کرد",
"reverted": "گەڕێندراوە بۆ پێداچوونەوەی پێشووتر",
"deletecomment": "ھۆکار:",
"deleteotherreason": "ھۆکاری تر/زیاتر:",
"diff-paragraph-moved-toold": "Η παράγραφος αφαιρέθηκε. Πατήστε στο κουμπί για να πάτε σε προηγούμενη τοποθεσία.",
"difference-missing-revision": "{{PLURAL:$2|Μία αναθεώρηση|$2 αναθεωρήσεις}} αυτής της διαφοράς ($1) δεν {{PLURAL:$2|μπόρεσε να βρεθεί|μπόρεσαν να βρεθούν}}.\n\nΑυτό συνήθως προκαλείται από παλιό σύνδεσμο διαφοράς προς σελίδα που έχει διαγραφεί.\nΛεπτομέρειες θα βρείτε στο [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ημερολόγιο καταγραφής διαγραφών].",
"searchresults": "Αποτελέσματα αναζήτησης",
+ "search-filter-title-prefix-reset": "Αναζήτηση όλων των σελίδων",
"searchresults-title": "Αποτελέσματα αναζήτησης για \"$1\"",
"titlematches": "Τίτλοι άρθρων που ανταποκρίνονται",
"textmatches": "Κείμενα σελίδων που ανταποκρίνονται:",
"Truebamateo",
"La Mantis",
"Amaia",
- "Tiberius1701"
+ "Tiberius1701",
+ "Astroemi"
]
},
"tog-underline": "Subrayar los enlaces:",
"speciallogtitlelabel": "Objetivo (título o {{ns:user}}:nombre de usuario):",
"log": "Registros",
"logeventslist-submit": "Mostrar",
- "logeventslist-more-filters": "Más filtros:",
+ "logeventslist-more-filters": "Mostrar registros adicionales:",
"logeventslist-patrol-log": "Registro de revisiones",
"logeventslist-tag-log": "Registro de etiquetas",
"all-logs-page": "Todos los registros públicos",
"uctop": "(uusin)",
"month": "Alkaen kuukaudesta (ja aiemmin):",
"year": "Vuosi",
- "date": "Alkaen päiväydestä (ja aiemmin):",
+ "date": "Alkaen päivämäärästä (tai sitä aikaisemmasta):",
"sp-contributions-newbies": "Näytä uusien tulokkaiden muutokset",
"sp-contributions-newbies-sub": "Uusien käyttäjien muokkaukset",
"sp-contributions-newbies-title": "Uusien käyttäjien muokkaukset",
"rcfilters-filterlist-whatsthis": "Ciamar a dh’obraicheas iad seo?",
"rcfilters-highlightbutton-title": "Soillsich toraidhean",
"rcfilters-filterlist-noresults": "Cha do lorg sinn criathrag",
+ "rcfilters-filter-editsbyself-label": "Mùthaidhean a rinn thusa",
+ "rcfilters-filter-editsbyself-description": "Na mùthaidhean a rinn thu fhèin.",
+ "rcfilters-filter-editsbyother-label": "Mùthaidhean a rinn daoine eile",
+ "rcfilters-filter-editsbyother-description": "Gach mùthadh ach an fheadhainn agad fhèin.",
"rcfilters-filtergroup-userExpLevel": "Clàradh is eòlas a’ chleachdaiche",
"rcfilters-filter-user-experience-level-registered-label": "Air clàradh a-steach",
+ "rcfilters-filter-user-experience-level-registered-description": "Deasaichean a rinn clàradh a-steach.",
"rcfilters-filter-user-experience-level-unregistered-label": "Gun chlàradh a-steach",
+ "rcfilters-filter-user-experience-level-unregistered-description": "Deasaichean nach do rinn clàradh a-steach.",
+ "rcfilters-filter-user-experience-level-newcomer-label": "Ùranaich",
"rcfilters-filter-user-experience-level-newcomer-description": "Deasaichean a chlàraich a-steach ach a rinn nas lugha na 10 deasachaidhean no aig a bheil nas lugha na 4 làithean de ghnìomhachd.",
+ "rcfilters-filter-user-experience-level-learner-label": "Luchd-ionnsachaidh",
"rcfilters-filter-user-experience-level-learner-description": "Deasaichean a rinn clàradh a-steach is aig a bheil eòlas eadar feadhainn air ùr-thighinn is feadhainn shàr-eòlach.",
+ "rcfilters-filter-user-experience-level-experienced-label": "Seann-eòlaich",
"rcfilters-filter-user-experience-level-experienced-description": "Deasaichean a chlàraich a-steach ach a rinn barrachd air 500 deasachadh is aig a bheil barrachd air 30 latha de ghnìomhachd.",
+ "rcfilters-filtergroup-automated": "Mùthaidhean fèin-obrachail",
+ "rcfilters-filter-bots-description": "Mùthaidhean a rinn innealan fèin-obrachail.",
+ "rcfilters-filter-humans-label": "Duine (chan e bot)",
+ "rcfilters-filter-humans-description": "Deasachaidhean a rinn deasaichean daonna.",
+ "rcfilters-filtergroup-significance": "Cudromachd",
+ "rcfilters-filter-minor-label": "Mùthaidhean beaga",
+ "rcfilters-filter-major-label": "Mùthaichean nach eil beag",
+ "rcfilters-filter-major-description": "Deasachaidhean ris nach eil comharra gur e deasachadh beag a tha ann.",
"rcfilters-filtergroup-watchlistactivity": "Gnìomhachd a’ chlàir-fhaire",
"rcfilters-filter-watchlistactivity-unseen-label": "Atharraichean gun choimhead",
"rcfilters-filter-watchlistactivity-unseen-description": "Atharraichean air duilleagan air nach do thadhail thu on a chaidh an atharrachadh.",
"rcfilters-filter-newpages-description": "Deasachadh a chruthaich duilleag ùr.",
"rcfilters-filter-logactions-label": "Gnìomhan logaichte",
"rcfilters-filtergroup-lastRevision": "Na mùthaidhean as ùire",
+ "rcfilters-filter-lastrevision-label": "Am mùthadh mu dheireadh",
"rcfilters-filter-lastrevision-description": "Dìreach an t-àtharrachadh as ùire air duilleag.",
"rcfilters-liveupdates-button": "Ùrachadh beò",
"rcfilters-liveupdates-button-title-off": "Seall atharraichean ùra fhad ’s a thathar gan dèanamh",
"rcfilters-watchlist-markseen-button": "Comharraich gun dug thu sùil air gach atharrachadh",
"rcfilters-watchlist-edit-watchlist-button": "Deasaich liosta nan duilleagan air a’ chlàr-fhaire agad",
+ "rcfilters-watchlist-showupdated": "Tha atharraichean air duilleagan nach do thadhail thu orra on a chaidh an atharrachadh ann an clò <strong>trom</strong> le comharran soladach.",
"rcnotefrom": "Chì thu {{PLURAL:$5|am mùthadh|na mùthaidhean|na mùthaidhean|na mùthaidhean}} o <strong>$3 $4</strong> (gu ruige <strong>$1</strong> dhiubh) gu h-ìosal.",
"rclistfrom": "Seall na mùthaidhean ùra a-mach o $3 $2",
"rcshowhideminor": "$1 mùthaidhean beaga",
"diff-paragraph-moved-toold": "문단이 이동되었습니다. 오래된 위치로 이동하려면 클릭하십시오.",
"difference-missing-revision": "문서 비교에서 {{PLURAL:$2|하나|$2개}}의 판($1)을 찾을 수 {{PLURAL:$2|없습니다}}.\n\n이 문제는 주로 삭제된 문서를 가리키는 오래된 문서 비교 링크로 인해 발생합니다.\n자세한 내용은 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 삭제 기록]에서 확인할 수 있습니다.",
"searchresults": "검색 결과",
+ "search-filter-title-prefix-reset": "모든 문서 검색",
"searchresults-title": "\"$1\"에 대한 검색 결과",
"titlematches": "문서 제목 일치",
"textmatches": "문서 내용 일치",
"speciallogtitlelabel": "대상 (문서 제목 또는 {{ns:user}}:사용자 이름으로 사용자 검색):",
"log": "기록 목록",
"logeventslist-submit": "보기",
- "logeventslist-more-filters": "더 많은 필터:",
+ "logeventslist-more-filters": "추가 기록 표시:",
"logeventslist-patrol-log": "점검 기록",
"logeventslist-tag-log": "태그 기록",
"all-logs-page": "모든 공개 기록",
"diff-paragraph-moved-toold": "Пасусот е преместен. Стиснете за да прејдете на старото место.",
"difference-missing-revision": "Не пронајдов {{PLURAL:$2|една преработка|$2 преработки}} од оваа разлика ($1).\n\nОва обично се должи на застарена врска за разлики што води кон избришана страница.\nПовеќе подробности ќе најдете во [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневникот на бришења].",
"searchresults": "Исход од пребарувањето",
+ "search-filter-title-prefix": "Пребарување по страници чиј наслов почнува со „$1“",
+ "search-filter-title-prefix-reset": "Пребарај по сите страници",
"searchresults-title": "Исход од пребарувањето на „$1“",
"titlematches": "Совпаднати наслови",
"textmatches": "Совпаднат текст во страниците",
"speciallogtitlelabel": "Цел (наслов или {{ns:user}}:корисничко име на корисникот):",
"log": "Дневници",
"logeventslist-submit": "Прикажи",
- "logeventslist-more-filters": "Повеќе филтри:",
+ "logeventslist-more-filters": "Прикажи повеќе дневници:",
"logeventslist-patrol-log": "Дневник на патролирања",
"logeventslist-tag-log": "Дневник на ознаки",
"all-logs-page": "Сите јавни дневници",
"movelogpagetext": "Ē-kha lia̍t-chhut hông soá-ūi ê ia̍h.",
"movereason": "Lí-iû:",
"revertmove": "hôe-tńg",
+ "delete_and_move_reason": "Thâi-ia̍h hō͘ \"[[$1]]\" thang sóa-ia̍h kòe--lâi",
"selfmove": "Goân piau-tê kap sin piau-tê sio-siâng; bô hoat-tō· sóa.",
"protectedpagemovewarning": "'''KÉNG-KÒ: Pún ia̍h só tiâu leh. Kan-taⁿ ū hêng-chèng te̍k-koân ê iōng-chiá (sysop) ē-sái soá tín-tāng.'''\nĒ-kha ū choè-kīn ê kì-lio̍k thang chham-khó:",
"export": "Su-chhut ia̍h",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|piau-chhiam}}]]: $2)",
"tag-mw-new-redirect": "Sin choán-ia̍h",
"tag-mw-changed-redirect-target": "Choán-ia̍h bo̍k-phiau kái-piàn",
+ "logentry-delete-delete_redir": "$1 ēng têng-siá lâi kā choán-ia̍h $3 {{GENDER:$2|thâi-tiāu}}",
"logentry-move-move": "$1 {{GENDER:$2|sóa}} $3 chit ia̍h khì $4",
"logentry-move-move_redir": "$1 iōng choán-ia̍h {{GENDER:$2|sóa}} ia̍h-bīn $3 kòe $4",
"logentry-newusers-create": "已經{{GENDER:$2|開好}}用者口座 $1",
"diff-paragraph-moved-toold": "Avsnittet ble flyttet. Klikk for å hoppe til den gamle plasseringen.",
"difference-missing-revision": "{{PLURAL:$2|En revisjon|$2 revisjoner}} av denne forskjellen ($1) {{PLURAL:$2|ble|ble}} ikke funnet.\n\nDette skyldes som regel at en gammel forskjell-lenke er fulgt til en side som er slettet.\nDetaljer kan finnes i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletteloggen].",
"searchresults": "Søkeresultater",
+ "search-filter-title-prefix": "Søker bare i sider der tittelen begynner med «$1»",
"search-filter-title-prefix-reset": "Søk i alle sider",
"searchresults-title": "Søkeresultater for «$1»",
"titlematches": "Artikkeltitler med treff på forespørselen",
"speciallogtitlelabel": "Mål (tittel eller {{ns:user}}:brukernavn for brukeren):",
"log": "Logger",
"logeventslist-submit": "Vis",
- "logeventslist-more-filters": "Flere filtre:",
+ "logeventslist-more-filters": "Vis flere logger:",
"logeventslist-patrol-log": "Patruljeringslogg",
"logeventslist-tag-log": "Merkelogg",
"all-logs-page": "Alle offentlige logger",
"diff-paragraph-moved-toold": "Akapit został przeniesiony. Kliknij aby przeskoczyć do jego poprzedniego położenia.",
"difference-missing-revision": "{{PLURAL:$2|Wersja|$2 wersje|$2 wersji}} #$1 strony \"{{PAGENAME}}\" nie {{PLURAL:$2|została znaleziona|zostały znalezione|zostało znalezionych}}.\n\nZazwyczaj jest to spowodowane przestarzałym linkiem do usuniętej strony. Powód usunięcia znajduje się w [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} rejestrze].",
"searchresults": "Wyniki wyszukiwania",
+ "search-filter-title-prefix": "Wyszukiwanie tylko na stronach, których tytuł zaczyna się od „$1”",
"searchresults-title": "Wyniki wyszukiwania „$1”",
"titlematches": "Znaleziono w tytułach",
"textmatches": "Znaleziono w treści stron",
"diff-paragraph-moved-toold": "O parágrafo foi movido. Clique para saltar para a posição anterior.",
"difference-missing-revision": "{{PLURAL:$2|Uma revisão|$2 revisões}} desta diferença ($1) não {{PLURAL:$2|foi encontrada|foram encontradas}}.\n\nIsto é geralmente causado por seguir um link de histórico desatualizado para uma página que foi eliminada.\nOs detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de eliminação].",
"searchresults": "Resultados da pesquisa",
+ "search-filter-title-prefix": "A pesquisar só nas páginas cujo título começa por \"$1\"",
+ "search-filter-title-prefix-reset": "Pesquisar em todas as páginas",
"searchresults-title": "Resultados da pesquisa por \"$1\"",
"titlematches": "Resultados nos títulos das páginas",
"textmatches": "Resultados nos textos das páginas",
"speciallogtitlelabel": "Alvo (título da página ou {{ns:user}}:'nomedeusuário' para usuários):",
"log": "Registros",
"logeventslist-submit": "Exibir",
- "logeventslist-more-filters": "Mais filtros:",
+ "logeventslist-more-filters": "Mostrar registos adicionais:",
"logeventslist-patrol-log": "Registro de edições patrulhadas",
"logeventslist-tag-log": "Registro de etiquetas",
"all-logs-page": "Todos os registros públicos",
"diff-paragraph-moved-toold": "Пункт был перемещен. Нажмите, чтобы перейти к старому местоположению.",
"difference-missing-revision": "Не {{PLURAL:$2|1=найдена|найдены}} {{PLURAL:$2|$2 версия|$2 версий|$2 версии|1=одна из версий}} для этого сравнения ($1).\n\nТакое обычно случается при переходе по устаревшей ссылке сравнения версий для страницы, которая была удалена.\nПодробности могут быть в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале удалений].",
"searchresults": "Результаты поиска",
+ "search-filter-title-prefix": "Искать только на страницах, название которых начинается с «$1»",
"search-filter-title-prefix-reset": "Искать все страницы",
"searchresults-title": "Поиск «$1»",
"titlematches": "Совпадения в названиях страниц",
"diff-paragraph-moved-toold": "Odstavek je bil premaknjen. Kliknite, da skočite na staro nahajališče.",
"difference-missing-revision": "{{PLURAL:$2|Ene redakcije|$2 redakcij}} razlike ($1) {{PLURAL:$2|nisem}} našel.\n\nPo navadi se to zgodi, ko sledite zastareli povezavi na razliko redakcij strani, ki jo je nekdo izbrisal.\nPodrobnosti lahko najdete v [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
"searchresults": "Izid iskanja",
+ "search-filter-title-prefix": "Išči samo na straneh, katerih naslovi se začnejo z \"$1\"",
+ "search-filter-title-prefix-reset": "Išči vse strani",
"searchresults-title": "Zadetki za povpraševanje »$1«",
"titlematches": "Ujemanje z naslovom članka",
"textmatches": "Ujemanje z besedilom članka",
"prefs-rc": "Zadnje spremembe",
"prefs-watchlist": "Spisek nadzorov",
"prefs-editwatchlist": "Uredi spisek nadzorov",
- "prefs-editwatchlist-label": "Uredite vnose na svojem spisku nadzorov:",
+ "prefs-editwatchlist-label": "Uredi vnose na svojem spisku nadzorov:",
"prefs-editwatchlist-edit": "Preglejte in odstranite naslove s svojega spiska nadzorov",
"prefs-editwatchlist-raw": "Uredite gol spisek nadzorov",
"prefs-editwatchlist-clear": "Počistite svoj spisek nadzorov",
"speciallogtitlelabel": "Cilj (naslov ali {{ns:user}}:uporabniškoime za uporabnika):",
"log": "Dnevniki",
"logeventslist-submit": "Prikaži",
- "logeventslist-more-filters": "Več filtrov:",
+ "logeventslist-more-filters": "Prikaži dodatne dnevnike:",
"logeventslist-patrol-log": "Dnevnik patrulje",
"logeventslist-tag-log": "Dnevnik oznak",
"all-logs-page": "Vsi javni dnevniki",
"diff-paragraph-moved-toold": "Абзац було переміщено. Натисніть щоб перестрибнути до старого розташування.",
"difference-missing-revision": "{{PLURAL:$2|$2 версія|$2 версії|$2 версій}} для цього порівняння ($1) не {{PLURAL:$2|1=знайдена|знайдені}}.\n\nІмовірно, ви перейшли за застарілим посиланням на порівняння версій вилученої сторінки.\nПодробиці можна дізнатися з [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журналу вилучень].",
"searchresults": "Результати пошуку",
+ "search-filter-title-prefix": "Лише пошук в сторінках, назви яких починаються з \"$1\"",
+ "search-filter-title-prefix-reset": "Пошук по всіх сторінках",
"searchresults-title": "Результати пошуку для «$1»",
"titlematches": "Збіги в назвах сторінок",
"textmatches": "Збіги в текстах сторінок",
"grouppage-suppress": "{{ns:project}}:Подавлювачі",
"right-read": "перегляд сторінок",
"right-edit": "редагування сторінок",
- "right-createpage": "створення сторінок (але не обговорень)",
+ "right-createpage": "створення сторінок (які не є обговореннями)",
"right-createtalk": "створення обговорень сторінок",
"right-createaccount": "створення нових облікових записів",
"right-autocreateaccount": "Автоматичний вхід в систему із зовнішнього облікового запису користувача",
"right-markbotedits": "позначення відкинутих редагувань як редагування бота",
"right-noratelimit": "нема обмежень за швидкістю",
"right-import": "імпорт сторінок з інших вікі",
- "right-importupload": "Імпорт сторінок через завантаження файлів",
+ "right-importupload": "імпорт сторінок через завантаження файлів",
"right-patrol": "позначення редагувань патрульованими",
"right-autopatrol": "автоматичне позначення редагувань патрульованими",
"right-patrolmarks": "Перегляд патрульованих сторінок у нових редагуваннях",
"speciallogtitlelabel": "Ціль (назва сторінки або {{ns:user}}:Ім'я_користувача):",
"log": "Журнали",
"logeventslist-submit": "Показати",
- "logeventslist-more-filters": "Ð\91Ñ\96лÑ\8cÑ\88е Ñ\84Ñ\96лÑ\8cÑ\82Ñ\80Ñ\96в:",
+ "logeventslist-more-filters": "Ð\9fоказаÑ\82и додаÑ\82ковÑ\96 жÑ\83Ñ\80нали:",
"logeventslist-patrol-log": "Журнал патрулювання",
"logeventslist-tag-log": "Журнал міток",
"all-logs-page": "Усі публічні журнали",
"WhitePhosphorus",
"A2093064",
"EagerLin",
- "Deathkon"
+ "Deathkon",
+ "RyRubyy"
]
},
"tog-underline": "链接下划线:",
"noemailcreate": "您需要提供一个有效的电子邮件地址",
"passwordsent": "用户\"$1\"的新密码已经寄往所登记的电子邮件地址。\n请在收到后再登录。",
"blocked-mailpassword": "您的IP地址被禁止编辑,为预防滥用,也不允许从该IP地址使用密码恢复功能。",
- "eauthentsent": "一封确认信已经发送至您设定的邮件地址。\n在任何其他邮件发送至您的账户前,您将不得不根据邮件中的指示,确认那个账户确实是您的。",
+ "eauthentsent": "一封确认信已经发送至您设定的邮件地址。\n在任何其他邮件发送至您的账户前,您将需要根据邮件中的指示,确认那个账户确实是您的。",
"throttled-mailpassword": "密码提醒已在最近$1小时内发送。为了安全起见,在每$1小时内只能发送一个密码提醒。",
"mailerror": "发送邮件错误:$1",
"acct_creation_throttle_hit": "使用您的IP地址访问本wiki的访客在过去$2中创建了{{PLURAL:$1|$1个账户}},达到了这段时间所允许的最大值。因此,使用该IP地址的访客现在不能再创建账户。",
*
* This data file is used after normalizing to NFC.
*
+ * Example usage:
+ *
+ * curl 'https://unicode.org/Public/6.0.0/ucd/UnicodeData.txt' > /tmp/UnicodeData.txt
+ * php generateNormalizerDataAr.php --unicode-data-file /tmp/UnicodeData.txt
+ *
* @ingroup MaintenanceLanguage
*/
class GenerateNormalizerDataAr extends Maintenance {
$args = array_merge( $args, $this->mArgs );
+ // Ignore SIGINT if possible, otherwise the wrapper terminates when the user presses
+ // ctrl-C to kill a query.
+ if ( function_exists( 'pcntl_signal' ) ) {
+ pcntl_signal( SIGINT, SIG_IGN );
+ }
+
$pipes = [];
$proc = proc_open( Shell::escape( $args ), $desc, $pipes );
if ( $proc === false ) {
display: block;
padding-top: 1em;
}
+
+ label {
+ // Workaround for Chrome browser bug (T199932)
+ // Override padding rule from FieldLayout
+ padding-left: 0 !important; /* stylelint-disable-line declaration-no-important */
+ }
}
.mw-rcfilters-ui-cell {
*/
private $normalizationFunctions = [];
+ /**
+ * Run disabled parser tests
+ * @var bool
+ */
+ private $runDisabled;
+
+ /**
+ * Run tests intended only for parsoid
+ * @var bool
+ */
+ private $runParsoid;
+
+ /**
+ * Disable parse on article insertion
+ * @var bool
+ */
+ private $disableSaveParse;
+
+ /**
+ * Reuse upload directory
+ * @var bool
+ */
+ private $keepUploads;
+
/**
* @param TestRecorder $recorder
* @param array $options
$this->runDisabled = !empty( $options['run-disabled'] );
$this->runParsoid = !empty( $options['run-parsoid'] );
+ $this->disableSaveParse = !empty( $options['disable-save-parse'] );
+
$this->tidySupport = new TidySupport( !empty( $options['use-tidy-config'] ) );
if ( !$this->tidySupport->isEnabled() ) {
$this->recorder->warning(
'site_stats', 'ipblocks', 'image', 'oldimage',
'recentchanges', 'watchlist', 'interwiki', 'logging', 'log_search',
'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo',
- 'archive', 'user_groups', 'page_props', 'category'
+ 'archive', 'user_groups', 'page_props', 'category',
+ 'slots', 'content', 'slot_roles', 'content_models',
];
if ( $wgCommentTableSchemaMigrationStage >= MIGRATION_WRITE_BOTH ) {
$this->checkSetupDone( 'setupDatabase' );
$this->dbClone->destroy();
- $this->databaseSetupDone = false;
if ( $this->useTemporaryTables ) {
if ( $this->db->getType() == 'sqlite' ) {
);
}
- // Use mock parser, to make debugging of actual parser tests simpler.
+ // Optionally use mock parser, to make debugging of actual parser tests simpler.
// But initialise the MessageCache clone first, don't let MessageCache
// get a reference to the mock object.
- MessageCache::singleton()->getParser();
- $restore = $this->executeSetupSnippets( [ 'wgParser' => new ParserTestMockParser ] );
+ if ( $this->disableSaveParse ) {
+ MessageCache::singleton()->getParser();
+ $restore = $this->executeSetupSnippets( [ 'wgParser' => new ParserTestMockParser ] );
+ } else {
+ $restore = false;
+ }
try {
$status = $page->doEditContent(
$newContent,
EDIT_NEW | EDIT_INTERNAL
);
} finally {
- $restore();
+ if ( $restore ) {
+ $restore();
+ }
}
if ( !$status->isOK() ) {
'be used.', false, true );
$this->addOption( 'run-disabled', 'run disabled tests' );
$this->addOption( 'run-parsoid', 'run parsoid tests (normally disabled)' );
+ $this->addOption( 'disable-save-parse', 'Don\'t run the parser when ' .
+ 'inserting articles into the database' );
$this->addOption( 'dwdiff', 'Use dwdiff to display diff output' );
$this->addOption( 'mark-ws', 'Mark whitespace in diffs by replacing it with symbols' );
$this->addOption( 'norm', 'Apply a comma-separated list of normalization functions to ' .
'keep-uploads' => $this->hasOption( 'keep-uploads' ),
'run-disabled' => $this->hasOption( 'run-disabled' ),
'run-parsoid' => $this->hasOption( 'run-parsoid' ),
+ 'disable-save-parse' => $this->hasOption( 'disable-save-parse' ),
'use-tidy-config' => $this->hasOption( 'use-tidy-config' ),
'file-backend' => $this->getOption( 'file-backend' ),
'upload-dir' => $this->getOption( 'upload-dir' ),
'ExternalStoreFactory' => [ 'ExternalStoreFactory', ExternalStoreFactory::class ],
'PreferencesFactory' => [ 'PreferencesFactory', PreferencesFactory::class ],
'ActorMigration' => [ 'ActorMigration', ActorMigration::class ],
+ 'ConfigRepository' => [ 'ConfigRepository', \MediaWiki\Config\ConfigRepository::class ],
];
}
],
];
}
+
+ public function testPrinterParameterValidationError() {
+ $api = $this->getNonInternalApiMain( [
+ 'action' => 'query', 'meta' => 'siteinfo', 'format' => 'json', 'formatversion' => 'bogus',
+ ] );
+
+ ob_start();
+ $api->execute();
+ $txt = ob_get_clean();
+
+ // Test that the actual output is valid JSON, not just the format of the ApiResult.
+ $data = FormatJson::decode( $txt, true );
+ $this->assertInternalType( 'array', $data );
+ $this->assertArrayHasKey( 'error', $data );
+ $this->assertArrayHasKey( 'code', $data['error'] );
+ $this->assertSame( 'unknown_formatversion', $data['error']['code'] );
+ }
}
] );
}
+ /**
+ * @dataProvider providesReferencedFiles
+ * @covers CSSMin::getLocalFileReferences
+ */
+ public function testGetLocalFileReferences( $input, $expected ) {
+ $output = CSSMin::getLocalFileReferences( $input, '/' );
+ $this->assertEquals(
+ $expected,
+ $output,
+ 'getLocalFileReferences() must find the local file properly'
+ );
+ }
+
+ public static function providesReferencedFiles() {
+ // input, array of expected local file names
+ return [
+ [ 'url("//example.org")', [] ],
+ [ 'url("https://example.org")', [] ],
+ [ 'url("#default#")', [] ],
+ [ 'url("WikiFont-Glyphs.svg#wikiglyph")', [ '/WikiFont-Glyphs.svg' ] ],
+ [ 'url("#some-anchor")', [] ],
+ ];
+ }
+
/**
* @dataProvider provideSerializeStringValue
* @covers CSSMin::serializeStringValue
[ 'foo { behavior: url(#default#bar); }', false, '/w/', false ],
'foo { behavior: url("#default#bar"); }',
],
+ [
+ 'Keeps anchors',
+ [ 'url(#other)', false, '/', false ],
+ 'url("#other")'
+ ],
+ [
+ 'Keeps anchors after a path',
+ [ 'url(images/file.svg#id)', false, '/', false ],
+ 'url("/images/file.svg#id")'
+ ],
];
}