{
"extends": "wikimedia",
"env": {
- "browser": true,
- "jquery": true
+ "browser": true
},
"globals": {
"require": false,
"module": false,
+ "mw": false,
+ "$": false,
"mediaWiki": false,
+ "jQuery": false,
"OO": false
},
"rules": {
* Updated jquery.i18n from 1.0.4 to 1.0.5.
* Updated wikimedia/timestamp from 1.0.0 to 2.0.0.
* Updated wikimedia/remex-html from 1.0.3 to 2.0.0.
+* Updated jquery from v3.2.1 to v3.3.1.
==== Removed external libraries ====
* …
"wikimedia/running-stat": "1.2.1",
"wikimedia/scoped-callback": "2.0.0",
"wikimedia/utfnormal": "2.0.0",
- "wikimedia/timestamp": "2.0.0",
+ "wikimedia/timestamp": "2.1.0",
"wikimedia/wait-condition-loop": "1.0.1",
"wikimedia/wrappedstring": "3.0.1",
"wikimedia/xmp-reader": "0.6.0",
use MediaWiki\Storage\BlobStore;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
* @return NameTableStore
*/
public function getChangeTagDefStore() {
- return $this->getService( 'ChangeTagDefStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getChangeTagDef();
}
/**
* @return NameTableStore
*/
public function getContentModelStore() {
- return $this->getService( 'ContentModelStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getContentModels();
}
/**
/**
* @since 1.32
+ * @return NameTableStoreFactory
+ */
+ public function getNameTableStoreFactory() {
+ return $this->getService( 'NameTableStoreFactory' );
+ }
+
+ /**
* @return OldRevisionImporter
*/
public function getOldRevisionImporter() {
* @return NameTableStore
*/
public function getSlotRoleStore() {
- return $this->getService( 'SlotRoleStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getSlotRoles();
}
/**
use MediaWiki\Storage\BlobStore;
use MediaWiki\Revision\RevisionRenderer;
use MediaWiki\Storage\BlobStoreFactory;
-use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
);
},
- 'ChangeTagDefStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'change_tag_def',
- 'ctd_id',
- 'ctd_name',
- null,
- false,
- function ( $insertFields ) {
- $insertFields['ctd_user_defined'] = 0;
- $insertFields['ctd_count'] = 0;
- return $insertFields;
- }
- );
- },
-
'CommentStore' => function ( MediaWikiServices $services ) : CommentStore {
return new CommentStore(
$services->getContentLanguage(),
return Language::factory( $services->getMainConfig()->get( 'LanguageCode' ) );
},
- 'ContentModelStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'content_models',
- 'model_id',
- 'model_name'
- /**
- * No strtolower normalization is added to the service as there are examples of
- * extensions that do not stick to this assumption.
- * - extensions/examples/DataPages define( 'CONTENT_MODEL_XML_DATA','XML_DATA' );
- * - extensions/Scribunto define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
- */
- );
- },
-
'CryptHKDF' => function ( MediaWikiServices $services ) : CryptHKDF {
$config = $services->getMainConfig();
return new MimeMagic( $params );
},
+ 'NameTableStoreFactory' => function ( MediaWikiServices $services ) : NameTableStoreFactory {
+ return new NameTableStoreFactory(
+ $services->getDBLoadBalancerFactory(),
+ $services->getMainWANObjectCache(),
+ LoggerFactory::getInstance( 'NameTableSqlStore' )
+ );
+ },
+
'OldRevisionImporter' => function ( MediaWikiServices $services ) : OldRevisionImporter {
return new ImportableOldRevisionImporter(
true,
$store = new RevisionStoreFactory(
$services->getDBLoadBalancerFactory(),
$services->getBlobStoreFactory(),
+ $services->getNameTableStoreFactory(),
$services->getMainWANObjectCache(),
$services->getCommentStore(),
$services->getActorMigration(),
return $factory;
},
- 'SlotRoleStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'slot_roles',
- 'role_id',
- 'role_name',
- 'strtolower'
- );
- },
-
'SpecialPageFactory' => function ( MediaWikiServices $services ) : SpecialPageFactory {
return new SpecialPageFactory(
$services->getMainConfig(),
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ * @file
+ */
+
+namespace MediaWiki\Storage;
+
+use Wikimedia\Rdbms\ILBFactory;
+use WANObjectCache;
+use Psr\Log\LoggerInterface;
+
+class NameTableStoreFactory {
+ private static $info;
+ private $stores = [];
+
+ /** @var ILBFactory */
+ private $lbFactory;
+
+ /** @var WANObjectCache */
+ private $cache;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ private static function getTableInfo() {
+ if ( self::$info ) {
+ return self::$info;
+ }
+ self::$info = [
+ 'change_tag_def' => [
+ 'idField' => 'ctd_id',
+ 'nameField' => 'ctd_name',
+ 'normalizationCallback' => null,
+ 'insertCallback' => function ( $insertFields ) {
+ $insertFields['ctd_user_defined'] = 0;
+ $insertFields['ctd_count'] = 0;
+ return $insertFields;
+ }
+ ],
+
+ 'content_models' => [
+ 'idField' => 'model_id',
+ 'nameField' => 'model_name',
+ /**
+ * No strtolower normalization is added to the service as there are examples of
+ * extensions that do not stick to this assumption.
+ * - extensions/examples/DataPages define( 'CONTENT_MODEL_XML_DATA','XML_DATA' );
+ * - extensions/Scribunto define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
+ */
+ ],
+
+ 'slot_roles' => [
+ 'idField' => 'role_id',
+ 'nameField' => 'role_name',
+ 'normalizationCallback' => 'strtolower',
+ ],
+ ];
+ return self::$info;
+ }
+
+ public function __construct(
+ ILBFactory $lbFactory,
+ WANObjectCache $cache,
+ LoggerInterface $logger
+ ) {
+ $this->lbFactory = $lbFactory;
+ $this->cache = $cache;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Get a NameTableStore for a specific table
+ *
+ * @param string $tableName The table name
+ * @param string|false $wiki The target wiki ID, or false for the current wiki
+ * @return NameTableStore
+ */
+ public function get( $tableName, $wiki = false ) : NameTableStore {
+ $infos = self::getTableInfo();
+ if ( !isset( $infos[$tableName] ) ) {
+ throw new \InvalidArgumentException( "Invalid table name \$tableName" );
+ }
+ if ( $wiki === wfWikiID() ) {
+ $wiki = false;
+ }
+ if ( isset( $this->stores[$tableName][$wiki] ) ) {
+ return $this->stores[$tableName][$wiki];
+ }
+
+ $info = $infos[$tableName];
+ $store = new NameTableStore(
+ $this->lbFactory->getMainLB( $wiki ),
+ $this->cache,
+ $this->logger,
+ $tableName,
+ $info['idField'],
+ $info['nameField'],
+ $info['normalizationCallback'] ?? null,
+ $wiki,
+ $info['insertCallback'] ?? null
+ );
+ $this->stores[$tableName][$wiki] = $store;
+ return $store;
+ }
+
+ /**
+ * Get a NameTableStore for the change_tag_def table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getChangeTagDef( $wiki = false ) : NameTableStore {
+ return $this->get( 'change_tag_def', $wiki );
+ }
+
+ /**
+ * Get a NameTableStore for the content_models table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getContentModels( $wiki = false ) : NameTableStore {
+ return $this->get( 'content_models', $wiki );
+ }
+
+ /**
+ * Get a NameTableStore for the slot_roles table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getSlotRoles( $wiki = false ) : NameTableStore {
+ return $this->get( 'slot_roles', $wiki );
+ }
+}
*/
private $contentHandlerUseDB;
+ /** @var NameTableStoreFactory */
+ private $nameTables;
+
/**
* @param ILBFactory $dbLoadBalancerFactory
* @param BlobStoreFactory $blobStoreFactory
+ * @param NameTableStoreFactory $nameTables
* @param WANObjectCache $cache
* @param CommentStore $commentStore
* @param ActorMigration $actorMigration
public function __construct(
ILBFactory $dbLoadBalancerFactory,
BlobStoreFactory $blobStoreFactory,
+ NameTableStoreFactory $nameTables,
WANObjectCache $cache,
CommentStore $commentStore,
ActorMigration $actorMigration,
Assert::parameterType( 'integer', $migrationStage, '$migrationStage' );
$this->dbLoadBalancerFactory = $dbLoadBalancerFactory;
$this->blobStoreFactory = $blobStoreFactory;
+ $this->nameTables = $nameTables;
$this->cache = $cache;
$this->commentStore = $commentStore;
$this->actorMigration = $actorMigration;
$this->loggerProvider = $loggerProvider;
$this->contentHandlerUseDB = $contentHandlerUseDB;
}
- /**
/**
* @since 1.32
$this->blobStoreFactory->newSqlBlobStore( $wikiId ),
$this->cache, // Pass local cache instance; Leave cache sharing to RevisionStore.
$this->commentStore,
- $this->getContentModelStore( $wikiId ),
- $this->getSlotRoleStore( $wikiId ),
+ $this->nameTables->getContentModels( $wikiId ),
+ $this->nameTables->getSlotRoles( $wikiId ),
$this->mcrMigrationStage,
$this->actorMigration,
$wikiId
return $store;
}
-
- /**
- * @param string $wikiId
- * @return NameTableStore
- */
- private function getContentModelStore( $wikiId ) {
- // XXX: a dedicated ContentModelStore subclass would avoid hard-coding
- // knowledge about the schema here.
- return new NameTableStore(
- $this->dbLoadBalancerFactory->getMainLB( $wikiId ),
- $this->cache, // Pass local cache instance; Leave cache sharing to NameTableStore.
- $this->loggerProvider->getLogger( 'NameTableSqlStore' ),
- 'content_models',
- 'model_id',
- 'model_name',
- null,
- $wikiId
- );
- }
-
- /**
- * @param string $wikiId
- * @return NameTableStore
- */
- private function getSlotRoleStore( $wikiId ) {
- // XXX: a dedicated ContentModelStore subclass would avoid hard-coding
- // knowledge about the schema here.
- return new NameTableStore(
- $this->dbLoadBalancerFactory->getMainLB( $wikiId ),
- $this->cache, // Pass local cache instance; Leave cache sharing to NameTableStore.
- $this->loggerProvider->getLogger( 'NameTableSqlStore' ),
- 'slot_roles',
- 'role_id',
- 'role_name',
- 'strtolower',
- $wikiId
- );
- }
-
}
/**
* @var int Compilation flags passed to LightnCandy
*/
- // Do not add more flags here without discussion.
- // If you do add more flags, be sure to update unit tests as well.
- protected $compileFlags = LightnCandy::FLAG_ERROR_EXCEPTION;
+ protected $compileFlags;
/**
* @param string|null $templateDir
public function __construct( $templateDir = null, $forceRecompile = false ) {
$this->templateDir = $templateDir ?: __DIR__ . '/templates';
$this->forceRecompile = $forceRecompile;
+
+ // Do not add more flags here without discussion.
+ // If you do add more flags, be sure to update unit tests as well.
+ $this->compileFlags = LightnCandy::FLAG_ERROR_EXCEPTION | LightnCandy::FLAG_MUSTACHELOOKUP;
}
/**
"apihelp-logout-summary": "登出並清除 session 資料。",
"apihelp-logout-example-logout": "登出當前使用者",
"apihelp-managetags-summary": "執行相關到更改標籤的管理任務。",
+ "apihelp-managetags-param-ignorewarnings": "是否在處理期間發生問題時忽略任何警告。",
"apihelp-managetags-param-tags": "在標籤管理日誌裡更改套用到項目的標籤。",
"apihelp-mergehistory-summary": "合併頁面歷史",
"apihelp-mergehistory-param-reason": "合併歷史的原因。",
"apihelp-query+alldeletedrevisions-param-user": "此列出由該使用者作出的修訂。",
"apihelp-query+alldeletedrevisions-param-excludeuser": "不要列出由該使用者作出的修訂。",
"apihelp-query+alldeletedrevisions-param-namespace": "僅列出此命名空間的頁面。",
+ "apihelp-query+alldeletedrevisions-example-user": "列出由使用者 <kbd>Example</kbd> 做出的最近 50 個貢獻。",
+ "apihelp-query+alldeletedrevisions-example-ns-main": "列出在主命名空間的前 50 個已刪除修訂。",
"apihelp-query+allfileusages-summary": "列出所有檔案用途,包含不存在的。",
"apihelp-query+allfileusages-param-from": "要起始列舉的檔案標題。",
"apihelp-query+allfileusages-param-to": "要終止列舉的檔案標題。",
"apihelp-query+allrevisions-param-user": "此列出由該使用者作出的修訂。",
"apihelp-query+allrevisions-param-excludeuser": "不要列出由該使用者作出的修訂。",
"apihelp-query+allrevisions-param-namespace": "僅列出此命名空間的頁面。",
+ "apihelp-query+allrevisions-example-user": "列出由使用者 <kbd>Example</kbd> 做出的最近 50 個貢獻。",
"apihelp-query+allrevisions-example-ns-main": "列出在主命名空間的前 50 個修訂。",
"apihelp-query+mystashedfiles-param-prop": "要索取的檔案屬性。",
"apihelp-query+mystashedfiles-paramvalue-prop-size": "索取檔案大小與圖片尺寸。",
"apihelp-query+filearchive-param-limit": "要回傳的圖片總數。",
"apihelp-query+filearchive-param-dir": "列出時所採用的方向。",
"apihelp-query+filearchive-param-sha1": "圖片的 SHA1 雜湊值。覆蓋 $1sha1base36。",
+ "apihelp-query+filearchive-param-sha1base36": "以 base 36 的圖片 SHA1 雜湊值(使用在 MediaWiki)。",
"apihelp-query+filearchive-param-prop": "要取得的圖片資訊:",
"apihelp-query+filearchive-paramvalue-prop-sha1": "替圖片添加 SHA-1 雜湊值。",
"apihelp-query+filearchive-paramvalue-prop-timestamp": "添加上傳版本的時間戳記。",
"apihelp-query+imageinfo-paramvalue-prop-timestamp": "添加上傳版本的時間戳記。",
"apihelp-query+imageinfo-paramvalue-prop-comment": "版本的註釋。",
"apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "解析版本上的註釋。",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "提供檔案與描述頁面的 URL。",
"apihelp-query+imageinfo-paramvalue-prop-sha1": "替檔案添加 SHA-1 雜湊值。",
"apihelp-query+imageinfo-paramvalue-prop-mime": "替檔案添加 MIME 類型。",
"apihelp-query+imageinfo-paramvalue-prop-mediatype": "添加檔案的媒體類型。",
+ "apihelp-query+imageinfo-paramvalue-prop-badfile": "無論檔案是否在 [[MediaWiki:Bad image list]] 都添加",
"apihelp-query+imageinfo-param-limit": "每個檔案要回傳的檔案修訂數量。",
"apihelp-query+imageinfo-param-start": "列出的起始時間戳記。",
"apihelp-query+imageinfo-param-end": "列出的終止時間戳記。",
"apihelp-query+imageinfo-param-urlheight": "與 $1urlwidth 相似。",
+ "apihelp-query+imageinfo-example-dated": "索取 [[:File:Test.jpg]] 自 2008 年以來的版本資訊。",
"apihelp-query+images-summary": "回傳指定頁面中包含的所有檔案。",
"apihelp-query+images-param-limit": "要回傳的檔案數量。",
"apihelp-query+images-param-dir": "列出時所採用的方向。",
"apihelp-query+images-example-simple": "取得使用在 [[Main Page]] 的檔案清單。",
+ "apihelp-query+images-example-generator": "取得在 [[Main Page]] 所有使用到檔案的相關資訊。",
"apihelp-query+imageusage-summary": "尋找使用到指定圖片標題的所有頁面。",
"apihelp-query+imageusage-param-title": "要搜尋的標題。不能與 $1pageid 一起使用。",
"apihelp-query+imageusage-param-pageid": "要搜尋的頁面 ID。不能與 $1title 一起使用。",
"apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "添加跨 wiki 標題。",
"apihelp-query+iwbacklinks-param-dir": "列出時所採用的方向。",
"apihelp-query+iwbacklinks-example-simple": "取得連結至 [[wikibooks:Test]] 的頁面。",
+ "apihelp-query+iwbacklinks-example-generator": "取得連結至 [[wikibooks:Test]] 的頁面相關資訊。",
"apihelp-query+iwlinks-summary": "回傳指定頁面的所有 interwiki 連結。",
"apihelp-query+iwlinks-param-url": "是否取得完整的 URL(不能與 $1prop 一同使用)。",
"apihelp-query+iwlinks-paramvalue-prop-url": "添加完整的 URL。",
"apihelp-query+logevents-paramvalue-prop-ids": "添加日誌事件的 ID。",
"apihelp-query+logevents-paramvalue-prop-title": "添加日誌事件的頁面標題。",
"apihelp-query+logevents-paramvalue-prop-type": "添加日誌事件的類型。",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "添加日誌事件的時間戳記。",
+ "apihelp-query+logevents-paramvalue-prop-comment": "添加日誌事件的註釋。",
+ "apihelp-query+logevents-paramvalue-prop-details": "列出日誌事件的額外詳細資訊。",
+ "apihelp-query+logevents-paramvalue-prop-tags": "列出日誌事件的標籤。",
"apihelp-query+logevents-param-type": "篩選僅為此類型的日誌項目。",
"apihelp-query+logevents-param-start": "起始列舉的時間戳記。",
"apihelp-query+logevents-param-end": "結束列舉的時間戳記。",
*/
use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\NameTableAccessException;
use Wikimedia\Rdbms\Database;
class ChangeTags {
throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' );
}
+ $tagTables[] = 'change_tag';
if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
- $tables[] = 'change_tag_def';
- $join_cond = [ $join_cond, 'ct_tag_id=ctd_id' ];
+ $tagTables[] = 'change_tag_def';
+ $join_cond_ts_tags = [ $join_cond, 'ct_tag_id=ctd_id' ];
$field = 'ctd_name';
} else {
$field = 'ct_tag';
+ $join_cond_ts_tags = $join_cond;
}
$fields['ts_tags'] = wfGetDB( DB_REPLICA )->buildGroupConcatField(
- ',', 'change_tag', $field, $join_cond
+ ',', $tagTables, $field, $join_cond_ts_tags
);
if ( $wgUseTagFilter && $filter_tag ) {
$tables[] = 'change_tag';
$join_conds['change_tag'] = [ 'INNER JOIN', $join_cond ];
if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
- $tables[] = 'change_tag_def';
- $join_conds['change_tag_def'] = [ 'INNER JOIN', 'ct_tag_id=ctd_id' ];
- $conds['ctd_name'] = $filter_tag;
+ $filterTagIds = [];
+ $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
+ foreach ( (array)$filter_tag as $filterTagName ) {
+ try {
+ $filterTagIds[] = $changeTagDefStore->getId( $filterTagName );
+ } catch ( NameTableAccessException $exception ) {
+ // Return nothing.
+ $conds[] = '0';
+ break;
+ };
+ }
+ $conds['ct_tag_id'] = $filterTagIds;
} else {
$conds['ct_tag'] = $filter_tag;
}
*
* Options:
* - columns
- * - Required list of columns in the matrix.
+ * - Required associative array mapping column labels (as HTML) to their tags.
* - rows
- * - Required list of rows in the matrix.
+ * - Required associative array mapping row labels (as HTML) to their tags.
* - force-options-on
- * - Accepts array of column-row tags to be displayed as enabled but unavailable to change
+ * - Array of column-row tags to be displayed as enabled but unavailable to change.
* - force-options-off
- * - Accepts array of column-row tags to be displayed as disabled but unavailable to change.
+ * - Array of column-row tags to be displayed as disabled but unavailable to change.
* - tooltips
- * - Optional array mapping row label to tooltip content
+ * - Optional associative array mapping row labels to tooltips (as text, will be escaped).
* - tooltip-class
* - Optional CSS class used on tooltip container span. Defaults to mw-icon-question.
+ * Not used by OOUI form fields.
*/
class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
static private $requiredParams = [
'id' => $this->mID,
'rows' => $this->mParams['rows'],
'columns' => $this->mParams['columns'],
- 'tooltips' => $this->mParams['tooltips'],
+ 'tooltips' => $this->mParams['tooltips'] ?? [],
'forcedOff' => $this->mParams['force-options-off'] ?? [],
'forcedOn' => $this->mParams['force-options-on'] ?? [],
- 'values' => $value
+ 'values' => $value,
] + OOUI\Element::configFromHtmlAttributes( $attribs )
);
}
/**
* Add an error to the 'errors' array and log it.
*
- * Should only be called from within respond().
- *
+ * @private For internal use by ResourceLoader and ResourceLoaderStartUpModule.
* @since 1.29
* @param Exception $e
* @param string $msg
* @param array $context
*/
- protected function outputErrorAndLog( Exception $e, $msg, array $context = [] ) {
+ public function outputErrorAndLog( Exception $e, $msg, array $context = [] ) {
MWExceptionHandler::logException( $e );
$this->logger->warning(
$msg,
try {
return $this->getModule( $module )->getVersionHash( $context );
} catch ( Exception $e ) {
- // If modules fail to compute a version, do still consider the versions
- // of other modules - don't set an empty string E-Tag for the whole request.
- // See also T152266 and StartupModule::getModuleRegistrations().
+ // If modules fail to compute a version, don't fail the request (T152266)
+ // and still compute versions of other modules.
$this->outputErrorAndLog( $e,
'Calculating version for "{module}" failed: {exception}',
[
* See also: OutputPage::disallowUserJs()
*/
class ResourceLoaderStartUpModule extends ResourceLoaderModule {
-
- // Cache for getConfigSettings() as it's called by multiple methods
- protected $configVars = [];
protected $targets = [ 'desktop', 'mobile' ];
/**
* @param ResourceLoaderContext $context
* @return array
*/
- protected function getConfigSettings( $context ) {
- $hash = $context->getHash();
- if ( isset( $this->configVars[$hash] ) ) {
- return $this->configVars[$hash];
- }
-
+ private function getConfigSettings( $context ) {
$conf = $this->getConfig();
// We can't use Title::newMainPage() if 'mainpage' is in
Hooks::run( 'ResourceLoaderGetConfigVars', [ &$vars ] );
- $this->configVars[$hash] = $vars;
- return $this->configVars[$hash];
+ return $vars;
}
/**
$out = '';
$states = [];
$registryData = [];
+ $moduleNames = $resourceLoader->getModuleNames();
+
+ // Preload with a batch so that the below calls to getVersionHash() for each module
+ // don't require on-demand loading of more information.
+ try {
+ $resourceLoader->preloadModuleInfo( $moduleNames, $context );
+ } catch ( Exception $e ) {
+ // Don't fail the request (T152266)
+ // Also print the error in the main output
+ $resourceLoader->outputErrorAndLog( $e,
+ 'Preloading module info from startup failed: {exception}',
+ [ 'exception' => $e ]
+ );
+ }
// Get registry data
- foreach ( $resourceLoader->getModuleNames() as $name ) {
+ foreach ( $moduleNames as $name ) {
$module = $resourceLoader->getModule( $name );
$moduleTargets = $module->getTargets();
if (
}
if ( $module->isRaw() ) {
- // Don't register "raw" modules (like 'jquery' and 'mediawiki') client-side because
- // depending on them is illegal anyway and would only lead to them being reloaded
- // causing any state to be lost (like jQuery plugins, mw.config etc.)
+ // Don't register "raw" modules (like 'startup') client-side because depending on them
+ // is illegal anyway and would only lead to them being loaded a second time,
+ // causing any state to be lost.
+
+ // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
+ // Think carefully before making changes to this code!
+ // The below code is going to call ResourceLoaderModule::getVersionHash() for every module.
+ // For StartUpModule (this module) the hash is computed based on the manifest content,
+ // which is the very thing we are computing right here. As such, this must skip iterating
+ // over 'startup' itself.
continue;
}
try {
$versionHash = $module->getVersionHash( $context );
} catch ( Exception $e ) {
- // See also T152266 and ResourceLoader::getCombinedVersion()
- MWExceptionHandler::logException( $e );
- $context->getLogger()->warning(
+ // Don't fail the request (T152266)
+ // Also print the error in the main output
+ $resourceLoader->outputErrorAndLog( $e,
'Calculating version for "{module}" failed: {exception}',
[
'module' => $name,
}
/**
- * Get the definition summary for this module.
- *
- * @param ResourceLoaderContext $context
- * @return array
- */
- public function getDefinitionSummary( ResourceLoaderContext $context ) {
- global $IP;
- $summary = parent::getDefinitionSummary( $context );
- $startup = [
- // getScript() exposes these variables to mw.config (T30899).
- 'vars' => $this->getConfigSettings( $context ),
- // getScript() uses this to decide how configure mw.Map for mw.config.
- 'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
- // Detect changes to the module registrations output by getScript().
- 'moduleHashes' => $this->getAllModuleHashes( $context ),
- // Detect changes to base modules listed by getScript().
- 'baseModules' => $this->getBaseModules(),
-
- 'fileHashes' => [
- $this->safeFileHash( "$IP/resources/src/startup/startup.js" ),
- $this->safeFileHash( "$IP/resources/src/startup/mediawiki.js" ),
- $this->safeFileHash( "$IP/resources/src/startup/mediawiki.requestIdleCallback.js" ),
- ],
- ];
- if ( $context->getDebug() ) {
- $startup['fileHashes'][] = $this->safeFileHash( "$IP/resources/src/startup/mediawiki.log.js" );
- }
- if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
- $startup['fileHashes'][] = $this->safeFileHash( "$IP/resources/src/startup/profiling.js" );
- }
- $summary[] = $startup;
- return $summary;
- }
-
- /**
- * Helper method for getDefinitionSummary().
- *
- * @param ResourceLoaderContext $context
- * @return string SHA-1
+ * @return bool
*/
- protected function getAllModuleHashes( ResourceLoaderContext $context ) {
- $rl = $context->getResourceLoader();
- // Preload for getCombinedVersion()
- $rl->preloadModuleInfo( $rl->getModuleNames(), $context );
-
- // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
- // Think carefully before making changes to this code!
- // Pre-populate versionHash with something because the loop over all modules below includes
- // the startup module (this module).
- // See ResourceLoaderModule::getVersionHash() for usage of this cache.
- $this->versionHash[$context->getHash()] = null;
-
- return $rl->getCombinedVersion( $context, $rl->getModuleNames() );
+ public function enableModuleContentVersion() {
+ // Enabling this means that ResourceLoader::getVersionHash will simply call getScript()
+ // and hash it to determine the version (as used by E-Tag HTTP response header).
+ return true;
}
/**
$code = $rl->makeModuleResponse( $startupContext, [
'startup' => $rl->getModule( 'startup' ),
] );
+ $code .= <<<JAVASCRIPT
+ // Disable module storage.
+ // The unit test for mw.loader.store will enable it
+ // explicitly with a mock timer.
+ mw.loader.store.enabled = false;
+JAVASCRIPT;
// The following has to be deferred via RLQ because the startup module is asynchronous.
$code .= ResourceLoader::makeLoaderConditionalScript(
// Embed page-specific mw.config variables.
*
* @param array $config Configuration array with the following options:
* - columns
- * - Required list of columns in the matrix.
+ * - Required associative array mapping column labels (as HTML) to their tags.
* - rows
- * - Required list of rows in the matrix.
+ * - Required associative array mapping row labels (as HTML) to their tags.
* - force-options-on
- * - Accepts array of column-row tags to be displayed as enabled but unavailable to change
+ * - Array of column-row tags to be displayed as enabled but unavailable to change.
* - force-options-off
- * - Accepts array of column-row tags to be displayed as disabled but unavailable to change.
+ * - Array of column-row tags to be displayed as disabled but unavailable to change.
* - tooltips
- * - Optional array mapping row label to tooltip content
- * - tooltip-class
- * - Optional CSS class used on tooltip container span. Defaults to mw-icon-question.
+ * - Optional associative array mapping row labels to tooltips (as text, will be escaped).
*/
public function __construct( array $config = [] ) {
// Configuration initialization
$tr->appendContent( $this->getCellTag( "\u{00A0}" ) );
foreach ( $this->columns as $columnLabel => $columnTag ) {
$tr->appendContent(
- $this->getCellTag( $columnLabel )
+ $this->getCellTag( new \OOUI\HtmlSnippet( $columnLabel ) )
);
}
$table->appendContent( $tr );
* Get a formatted table row for the option, with
* a checkbox widget.
*
- * @param string $label Row label
+ * @param string $label Row label (as HTML)
* @param string $tag Row tag name
* @return \OOUI\Tag The resulting table row
*/
$labelField = new \OOUI\FieldLayout(
new \OOUI\Widget(), // Empty widget, since we don't have the checkboxes here
[
- 'label' => $label,
+ 'label' => new \OOUI\HtmlSnippet( $label ),
'align' => 'inline',
] + $labelFieldConfig
);
/**
* Get an individual cell tag with requested content
*
- * @param string $content Content for the <td> cell
+ * @param mixed $content Content for the <td> cell
* @return \OOUI\Tag Resulting cell
*/
private function getCellTag( $content ) {
"jumptonavigation": "navigasie",
"jumptosearch": "soek",
"view-pool-error": "Jammer, die bedieners is tans oorbelas.\nTe veel gebruikers probeer om na hierdie bladsy te kyk.\nWag asseblief 'n rukkie voordat u weer probeer om die bladsy op te roep.\n\n$1",
- "generic-pool-error": "Jammer, die bedieners is tans oorbelas.\nTe veel gebruikers probeer om na hierdie bladsy te kyk.\nWag asseblief 'n rukkie voordat u weer toegang tot hierdie bron verkry.",
+ "generic-pool-error": "Jammer, die bedieners is tans oorlaai.\nTe veel gebruikers probeer om na hierdie hulpbron te kyk.\nWag asseblief 'n rukkie voordat u weer die hulpbron probeer besoek.",
"pool-timeout": "Die maksimum wagtyd vir 'n databasisversperring is oorskry.",
"pool-queuefull": "Die poel se wagtou is vol",
"pool-errorunknown": "Onbekende fout",
"ns-specialprotected": "Spesiale bladsye kan nie geredigeer word nie.",
"titleprotected": "Hierdie titel is beskerm teen skepping deur [[User:$1|$1]].\nDie rede gegee is <em>$2</em>.",
"filereadonlyerror": "Dit was nie moontlik om die lêer \"$1\" te wysig nie omdat die lêerstoor \"$2\" tans lees-alleen is.\n\nDie rede hiervoor is \"''$3''\".",
+ "invalidtitle": "Ongeldige titel",
"invalidtitle-knownnamespace": "Ongeldige titel met naamruimte \"$2\" en teks \"$3\"",
"invalidtitle-unknownnamespace": "Ongeldige titel met onbekende naamruimtenummer $1 en teks \"$2\"",
"exception-nologin": "Nie aangeteken nie",
- "exception-nologin-text": "[[Special:Userlogin|Meld aan]] om hierdie bladsy te wys of om die handeling uit te voer.",
+ "exception-nologin-text": "Meld aan om hierdie bladsy te sien of om die handeling uit te voer.",
"exception-nologin-text-manual": "U moet $1 om hierdie bladsy te wys of die handeling uit te voer.",
"virus-badscanner": "Slegte konfigurasie: onbekende virusskandeerder: ''$1''",
"virus-scanfailed": "skandering het misluk (kode $1)",
"virus-unknownscanner": "onbekende antivirus:",
"logouttext": "'''U is nou afgemeld'''\n\nSommige bladsye kan moontlik nog aandui dat u steeds aangemeld is, totdat u u webblaaier se kas skoonmaak.",
+ "cannotlogoutnow-title": "Kan nie tans afmeld nie",
+ "cannotlogoutnow-text": "Afmeld is nie moontlik terwyl $1 gebruik word nie.",
"welcomeuser": "Welkom, $1!",
"welcomecreation-msg": "U gebruiker is geskep.\nMoenie vergeet om u [[Special:Preferences|voorkeure vir {{SITENAME}}]] te stel nie.",
"yourname": "Gebruikersnaam:",
"createacct-yourpasswordagain-ph": "Sleutel weer u wagwoord in",
"userlogin-remembermypassword": "Hou my aangemeld",
"userlogin-signwithsecure": "Gebruik veilige verbinding",
+ "cannotlogin-title": "Kan nie aanmeld nie",
+ "cannotlogin-text": "Aanmelding is nie moontlik nie.",
+ "cannotloginnow-title": "Kan nie tans aanmeld nie",
+ "cannotloginnow-text": "Aanmelding is nie moontlik terwyl $1 gebruik word nie.",
+ "cannotcreateaccount-title": "Kan nie rekeninge skep nie",
+ "cannotcreateaccount-text": "Direkte skep van rekeninge is nie geaktiveer op hierdie wiki nie.",
"yourdomainname": "U domein:",
"password-change-forbidden": "U kan nie wagwoorde op hierdie wiki verander nie.",
"externaldberror": "'n Databasisfout het tydens aanmelding voorgekom of u het nie toestemming om u eksterne rekening op te dateer nie.",
"login": "Meld aan",
+ "login-security": "Verifieer u identiteit",
"nav-login-createaccount": "Meld aan / registreer",
"logout": "Teken uit",
"userlogout": "Teken uit",
"userlogin-resetpassword-link": "Wagwoord vergeet?",
"userlogin-helplink2": "Hulp met aanmelding",
"userlogin-loggedin": "U is reeds aangemeld as {{GENDER:$1|$1}}.\nGebruik die onderstaande vorm om as 'n ander gebruiker aan te meld.",
+ "userlogin-reauth": "U moet weer aanmeld om te verifieer dat u $1 is.",
"userlogin-createanother": "Skep nog 'n rekening",
"createacct-emailrequired": "E-posadres",
"createacct-emailoptional": "E-posadres (opsioneel)",
"createacct-email-ph": "Sleutel u e-posadres in",
"createacct-another-email-ph": "Verskaf e-posadres",
- "createaccountmail": "Gebruik 'n tydelike lukrake wagwoord en stuur dit na die e-posadres hier onder",
+ "createaccountmail": "Gebruik 'n tydelike lukrake wagwoord en stuur dit na die gespesifiseerde e-posadres",
+ "createaccountmail-help": "Kan gebruik word om 'n rekening vir 'n ander persoon te skep sonder om die wagwoord te weet.",
"createacct-realname": "Regte naam (opsioneel)",
"createacct-reason": "Rede",
"createacct-reason-ph": "Hoekom u nog 'n rekening skep",
"nosuchusershort": "Daar is geen gebruikersnaam \"$1\" nie. Maak seker dit is reg gespel.",
"nouserspecified": "U moet 'n gebruikersnaam spesifiseer.",
"login-userblocked": "Hierdie gebruiker is geblokkeer.\nIntekening word verbied.",
- "wrongpassword": "Ongeldige wagwoord, probeer weer.",
+ "wrongpassword": "Verkeerde gebruikernaam of wagwoord is getik. Probeer gerus weer.",
"wrongpasswordempty": "Die wagwoord was leeg. Probeer asseblief weer.",
"passwordtooshort": "Wagwoorde moet ten minste {{PLURAL:$1|1 karakter|$1 karakters}} lank wees.",
+ "passwordtoolong": "Wagwoorde kan nie langer as {{PLURAL:$1|1 karakter|$1 karakters}} wees nie.",
+ "passwordtoopopular": "Algemene wagwoorde kan nie gebruik word nie. Kies asb. 'n wagwoord wat moeiliker is om te raai.",
"password-name-match": "U wagwoord mag nie dieselfde as u gebruikersnaam wees nie.",
"password-login-forbidden": "Die gebruik van hierdie gebruikersnaam en wagwoord is geweier.",
"mailmypassword": "E-pos nuwe wagwoord",
"passwordremindertitle": "Wagwoordwenk van {{SITENAME}}",
- "passwordremindertext": "Iemand (waarskynlik u vanaf IP-adres $1) het 'n nuwe wagwoord vir {{SITENAME}} ($4) aangevra. 'n Tydelike wagwoord is vir gebruiker \"$2\" geskep. Die nuwe wagwoord is \"$3\". U kan met die tydelike wagwoord aanmeld en 'n nuwe wagwoord stel. Die tydelike wagwoord sal na {{PLURAL:$5|een dag|$5 dae}} verval.\n\nIndien iemand anders hierdie navraag gerig het, of u het die wagwoord intussen onthou en wil nie meer die wagwoord wysig nie, kan u die boodskap ignoreer en voortgaan om die ou wagwoord te gebruik.",
+ "passwordremindertext": "Iemand (vanaf IP-adres $1) het 'n nuwe wagwoord vir {{SITENAME}} ($4) aangevra. 'n Tydelike wagwoord is vir gebruiker \"$2\" geskep. Die nuwe wagwoord is \"$3\". As dit u bedoeling was, moet u nou aanmeld en 'n nuwe wagwoord kies. Die tydelike wagwoord sal na {{PLURAL:$5|een dag|$5 dae}} verval.\n\nIndien iemand anders hierdie navraag gerig het, of u die wagwoord intussen onthou het en nie meer die wagwoord wil wysig nie, kan u die boodskap ignoreer en voortgaan om die ou wagwoord te gebruik.",
"noemail": "Daar is geen e-posadres vir gebruiker \"$1\" nie.",
"noemailcreate": "U moet 'n geldige e-posadres verskaf",
"passwordsent": "'n Nuwe wagwoord is na die e-posadres vir \"$1\" gestuur.\nMeld asseblief aan sodra u dit ontvang het.",
- "blocked-mailpassword": "U IP-adres is tans teen wysigings geblokkeer. Om verdere misbruik te voorkom is dit dus nie moontlik om die wagwoordherwinningfunksie te gebruik nie.",
- "eauthentsent": "'n Bevestigingpos is gestuur na die gekose e-posadres.\nVoordat ander pos na die adres gestuur word,\nmoet die instruksies in bogenoemde pos gevolg word om te bevestig dat die adres werklik u adres is.",
+ "blocked-mailpassword": "U IP-adres is tans teen wysigings geblokkeer. Om verdere misbruik te voorkom is dit nie moontlik om wagwoorde te herwin vanaf hierdie IP-adres te nie.",
+ "eauthentsent": "'n Bevestigingpos is gestuur na die gegewe e-posadres.\nVoordat ander e-pos na die adres gestuur word, moet die instruksies in die e-pos gevolg word om te bevestig dat die adres werklik u adres is.",
"throttled-mailpassword": "Daar is reeds 'n wagwoordwenk in die laaste {{PLURAL:$1|uur|$1 ure}} gestuur.\nOm misbruik te voorkom, word slegs een E-pos per {{PLURAL:$1|uur|$1 ure}} gestuur.",
"mailerror": "Fout tydens e-pos versending: $1",
"acct_creation_throttle_hit": "Besoekers aan hierdie wiki wat u IP-adres gebruik het reeds {{PLURAL:$1|'n rekening|$1 rekeninge}} in die laaste dag geskep, wat die maksimum toelaatbaar is vir die periode. Dus kan besoekers wat hierdie IP-adres gebruik tans nie meer nuwe gebruikers registreer nie.",
"passwordreset-emailelement": "Gebruikersnaam: \n$1\n\nTydelike wagwoord: \n$2",
"passwordreset-emailsentemail": "'n E-pos is gestuur om u wagwoord te herstel.",
"passwordreset-invalidemail": "Ongeldige e-posadres",
- "changeemail": "Wysig E-posadres",
+ "passwordreset-nodata": "Daar is geen gebruikernaam of e-posadres gegee nie",
+ "changeemail": "Verander of verwyder e-posadres",
"changeemail-header": "Wysig rekening se e-posadres",
"changeemail-no-info": "U moet aangemeld wees om regstreeks toegang tot die bladsy te kry.",
"changeemail-oldemail": "Huidige e-posadres:",
"changeemail-none": "(geen)",
"changeemail-password": "U wagwoord vir {{SITENAME}}:",
"changeemail-submit": "Wysig E-posadres",
+ "changeemail-nochange": "Gee gerus 'n ander nuwe e-posadres",
"resettokens-token-label": "$1 (huidige waarde: $2)",
"bold_sample": "Vetdruk",
"bold_tip": "Vetdruk",
"savechanges": "Stoor wysigings",
"publishpage": "Publiseer bladsy",
"publishchanges": "Publiseer wysigings",
+ "savearticle-start": "Stoor bladsy…",
+ "savechanges-start": "Stoor wysigings…",
+ "publishpage-start": "Publiseer bladsy…",
+ "publishchanges-start": "Publiseer wysigings…",
"preview": "Voorskou",
"showpreview": "Wys voorskou",
"showdiff": "Wys veranderings",
+ "blankarticle": "<strong>Waarskuwing:</strong> Die bladsy wat u skep is leg.\nDeur weer \"$1\" te klik, sal die bladsy sonder enige inhoud geskep word.",
"anoneditwarning": "'''Waarskuwing:''' u is nie aangemeld nie. U IP-adres sal in die bladsy se wysigingsgeskiedenis gestoor word. As u <strong>[$1 aanmeld]</strong> of <strong>[$2 'n rekening skep]</strong> verskyn u wysigings onder u gebruikersnaam, naas andere voordele.",
"anonpreviewwarning": "''U is nie aangeteken nie.''\n''As u die bladsy stoor sal u IP-adres in die bladsy se geskeidenis aangeteken word.''",
"missingsummary": "'''Neem kennis''': Geen opsomming van die wysiging is verskaf nie. As \"Stoor\" weer gekliek word, word die wysiging sonder 'n opsomming gestoor.",
- "missingcommenttext": "Tik die opsomming onder.",
+ "selfredirect": "<strong>Waarskuwing:</strong> U stuur die bladsy na homself aan.\nDalk is die verkeerde teiken vir die aanstuur gegee, of dalk wysig u die verkeerde bladsy. Deur weer \"$1\" te klik, sal die aanstuur in elk geval gemaak word.",
+ "missingcommenttext": "Tik asb. die opmerking.",
"missingcommentheader": "'''Let op:''' U het geen onderwerp/opskrif vir die opmerking verskaf nie. As u weer op \"$1\" klik, sal u wysiging sonder die onderwerp/opskrif gestoor word.",
- "summary-preview": "Opsommingsvoorskou:",
- "subject-preview": "Onderwerp/opskrif voorskou:",
+ "summary-preview": "Voorskou van wysigingopsomming:",
+ "subject-preview": "Voorskou van onderwerp:",
"blockedtitle": "Gebruiker is geblokkeer",
- "blockedtext": "'''U gebruiker of IP-adres is geblokkeer.'''\n\nDie blokkade is deur $1 uitgevoer.\nDie rede verskaf is ''$2''.\n\n* Begin van blokkade: $8\n* Blokkade eindig: $6\n* Blokkade gemik teen: $7\n\nU mag $1 of een van die ander [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] kontak om dit te bespreek.\nU kan nie die 'e-pos hierdie gebruiker'-opsie gebruik nie, tensy 'n geldige e-posadres in u [[Special:Preferences|voorkeure]] gespesifiseer is en u nie geblokkeer is om dit te gebruik nie.\nU huidige IP-adres is $3 en die blokkadenommer is #$5.\nSluit asseblief een of albei hierdie verwysings by enige navrae in.",
+ "blockedtext": "<strong>U gebruikernaam of IP-adres is geblokkeer.</strong>\n\nDie blokkade is deur $1 uitgevoer.\nDie rede verskaf is <em>$2</em>.\n\n* Begin van blokkade: $8\n* Blokkade eindig: $6\n* Blokkade gemik teen: $7\n\nU mag $1 of een van die ander [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] kontak om dit te bespreek.\nU kan nie die \"{{int:emailuser}}\"-opsie gebruik nie, tensy 'n geldige e-posadres in u [[Special:Preferences|rekeningvoorkeure]] gespesifiseer is en u nie geblokkeer is om dit te gebruik nie.\nU huidige IP-adres is $3 en die blokkadenommer is #$5.\nSluit asseblief een of albei hierdie verwysings by enige navrae in.",
"autoblockedtext": "U IP-adres is outomaties geblok omdat dit deur 'n gebruiker gebruik was, wat deur $1 geblokkeer is.\nDie rede verskaf is:\n\n:''$2''\n\n* Aanvang van blok: $8\n* Einde van blok: $6\n* Bedoelde blokkeerder: $7\n\nU kan die blok met $1 of enige van die [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] bespreek.\n\nNeem kennis dat u slegs die 'e-pos die gebruiker' funksionaliteit kan gebruik as u 'n geldige e-posadres het in u [[Special:Preferences|voorkeure]] het, en die gebruik daarvan is nie ook geblokkeer is nie.\n\nU huidige IP-adres is $3 en die blokkadenommer is #$5.\nVermeld asseblief die bovermelde bloknommer as u die saak rapporteer,",
"blockednoreason": "geen rede verskaf nie",
"whitelistedittext": "U moet $1 om bladsye te wysig.",
"userpage-userdoesnotexist": "U is besig om 'n gebruikersblad wat nie bestaan nie te wysig (gebruiker \"<nowiki>$1</nowiki>\"). Maak asseblief seker of u die bladsy wil skep/ wysig.",
"userpage-userdoesnotexist-view": "Die gebruiker \"$1\" is nie geregistreer nie.",
"blocked-notice-logextract": "Hierdie gebruiker is tans geblokkeer.\nDie laaste inskrywing in die blokkeerlogboek word hieronder vertoon:",
- "clearyourcache": "'''Neem kennis''': Na die wysiging is dit dalk nodig om u blaaier se kasgeheue verfris voordat u die veranderinge sal sien:\n* '''Firefox / Safari:''' hou ''Shift'' en kliek ''Reload'', of druk ''Ctrl-F5'' of ''Ctrl-R'' (''⌘-R'' op 'n Mac)\n* '''Google Chrome:''' druk ''Ctrl-Shift-R'' (''⌘-Shift-R'' op 'n Mac)\n* '''Internet Explorer:''' hou ''Ctrl'' en kliek ''Refresh'', of druk ''Ctrl-F5''\n* '''Opera:''' maak die kas skoon by ''Tools → Preferences''",
+ "clearyourcache": "<strong>Let wel</strong>: Na die wysiging is dit dalk nodig om u blaaier se kasgeheue te verfris voordat u die veranderinge sal sien:\n* <strong>Firefox / Safari:</strong> hou <em>Shift</em> en kliek <em>Herlaai</em>, of druk <em>Ctrl-F5</em> of <em>Ctrl-R</em> (<em>⌘-R</em> op 'n Mac)\n* <strong>Google Chrome:</strong> Druk <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> op 'n Mac)\n* <strong>Internet Explorer:</strong> Hou <em>Ctrl</em> en kliek <em>Refresh</em>, of druk <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Gaan na <em>Kieslys → Settings</em (<em>Opera → Preferences</em> op 'n Mac) en dan na <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
"usercssyoucanpreview": "'''Wenk:''' Gebruik die \"{{int:showpreview}}\"-knoppie om u nuwe CSS te toets voor u dit stoor.",
"userjsyoucanpreview": "'''Wenk:''' Gebruik die \"{{int:showpreview}}\"-knoppie om u nuwe JS te toets voor u dit stoor.",
"usercsspreview": "'''Onthou hierdie is slegs 'n voorskou van u persoonlike CSS.'''\n'''Dit is nog nie gestoor nie!'''",
"postedit-confirmation-created": "Die bladsy is geskep.",
"postedit-confirmation-restored": "Die bladsy is teruggeplaas.",
"postedit-confirmation-saved": "U wysigings is gestoor.",
+ "postedit-confirmation-published": "Die wysiging is gepubliseer.",
"edit-already-exists": "Die bladsy is nie geskep nie.\nDit bestaan alreeds.",
"defaultmessagetext": "Verstekteks",
"content-failed-to-parse": "Dit was nie moontlik om die inhoud van die MIME-tipe $2 vir die model $1 te verwerk nie: $3.",
"prefs-rc": "Onlangse wysigings",
"prefs-watchlist": "Dophoulys",
"prefs-editwatchlist": "Wysig dophoulys",
+ "prefs-editwatchlist-label": "Wysig inskrywings op u dophoulys:",
+ "prefs-editwatchlist-edit": "Sien en verwyder titels op u dophoulys",
+ "prefs-editwatchlist-raw": "Wysig rou dophoulys",
+ "prefs-editwatchlist-clear": "Vee u dophoulys uit",
"prefs-watchlist-days": "Aantal dae om in dophoulys te wys:",
"prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|dag|dae}}",
"prefs-watchlist-edits": "Aantal wysigings om in uitgebreide dophoulys te wys:",
"recentchangeslinked-feed": "Verwante veranderings",
"recentchangeslinked-toolbox": "Verwante veranderings",
"recentchangeslinked-title": "Wysigings verwant aan \"$1\"",
- "recentchangeslinked-summary": "Hier volg 'n lys van wysigings wat onlangs gemaak is aan bladsye wat van die gespesifiseerde bladsy geskakel word (of van bladsye van die gespesifiseerde kategorie).\nBladsye op [[Special:Watchlist|u dophoulys]] word in '''vetdruk''' uitgewys.",
+ "recentchangeslinked-summary": "Tik 'n bladsynaam om veranderinge aan bladsye te sien wat daarvan of daarheen skakel. (Om inskrywings van 'n kategorie te sien, tik {{ns:category}}:Naam van kategorie). Veranderinge aan bladsye op [[Special:Watchlist|u dophoulys]] word in <strong>vetdruk</strong> aangedui.",
"recentchangeslinked-page": "Bladsynaam:",
"recentchangeslinked-to": "Besigtig wysigings aan bladsye met skakels na die bladsy",
"recentchanges-page-added-to-category": "[[:$1]] by kategorie gevoeg",
"filehist-filesize": "Lêergrootte",
"filehist-comment": "Opmerking",
"imagelinks": "Lêergebruik",
- "linkstoimage": "Die volgende {{PLURAL:$1|bladsy|$1 bladsye}} gebruik hierdie prent:",
- "linkstoimage-more": "Daar is meer as $1 {{PLURAL:$1|skakel|skakels}} na hierdie lêer.\nDie volgende lys vertoon slegs die eerste {{PLURAL:$1|skakel|$1 skakels}} wat na die lêer verwys.\n'n [[Special:WhatLinksHere/$2|Volledige lys]] is ook beskikbaar.",
- "nolinkstoimage": "Daar is geen bladsye wat skakel na hierdie lêer nie.",
+ "linkstoimage": "Die volgende {{PLURAL:$1|bladsy|$1 bladsye}} gebruik dié lêer:",
+ "linkstoimage-more": "Meer as $1 {{PLURAL:$1|bladsy|bladsye}} gebruik dié lêer.\nDie volgende lys vertoon die eerste {{PLURAL:$1|bladsy|$1 bladsye}} wat slegs dié lêer gebruik.\n'n [[Special:WhatLinksHere/$2|Volledige lys]] is beskikbaar.",
+ "nolinkstoimage": "Daar is geen bladsye wat dié lêer gebruik nie.",
"morelinkstoimage": "Wys [[Special:WhatLinksHere/$1|meer skakels]] na die lêer.",
"linkstoimage-redirect": "$1 (lêeraanstuur) $2",
"duplicatesoffile": "Die volgende {{PLURAL:$1|lêer is 'n duplikaat|$1 lêers is duplikate}} van die lêer ([[Special:FileDuplicateSearch/$2|meer details]]):",
"watchlist-details": "Daar is {{PLURAL:$1|$1 bladsy|$1 bladsye}} in u dophoulys (besprekingsblaaie ingesluit).",
"wlheader-enotif": "E-pos kennisgewings is aangeskakel.",
"wlheader-showupdated": "Bladsye wat verander is sedert u hulle laas besoek het word in '''vetdruk''' uitgewys.",
- "wlnote": "Hier volg die laaste {{PLURAL:$1|verandering<strong>$1</strong> veranderings}} binne die laaste {{PLURAL:$2|uur|<strong>$2</strong> ure}}, soos op $3 om $4.",
+ "wlnote": "Hier volg die laaste {{PLURAL:$1|verandering|<strong>$1</strong> veranderings}} binne die laaste {{PLURAL:$2|uur|<strong>$2</strong> ure}}, soos op $3 om $4.",
"wlshowlast": "Wys afgelope $1 ure, $2 dae",
"watchlist-hide": "Versteek",
"watchlist-submit": "Wys",
"version-libraries-license": "Lisensie",
"version-libraries-description": "Beskrywing",
"version-libraries-authors": "Outeurs",
- "redirect": "Aanstuur volgens lêer, gebruiker, bladsy of weergawenommer",
- "redirect-summary": "Hierdie spesiale bladsy stuur aan na 'n lêer (as 'n lêernaam verskaf word), 'n bladsy (as 'n weergawe-nommer verskaf word) of 'n gebruikersblad (as 'n gebruiker-ID verskaf word).",
+ "redirect": "Stuur aan volgens lêernaam, gebruiker-, bladsy-, weergawe-, of log-ID",
+ "redirect-summary": "Hierdie spesiale bladsy stuur aan na 'n lêer (as 'n lêernaam verskaf word), 'n bladsy (as 'n weergawe-ID of bladsy-ID verskaf word), 'n gebruikersblad (as 'n numeriese gebruiker-ID verskaf word) of 'n loginskrywing (as 'n log-ID verskaf word). Gebruik: [[{{#Special:Redirect}}/file/Voorbeeld.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] of [[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "OK",
"redirect-lookup": "Soek volgens:",
"redirect-value": "Waarde:",
"specialpage-securitylevel-not-allowed-title": "Nie toegestaan",
"cannotauth-not-allowed-title": "Geen toegang",
"cannotauth-not-allowed": "U word nie toegelaat om die bladsy te gebruik nie",
+ "changecredentials": "Wysig rekeninginligting",
+ "changecredentials-submit": "Wysig rekeninginligting",
+ "changecredentials-success": "U rekeninginligting is gewysig.",
+ "removecredentials": "Verwyder rekeninginligting",
+ "removecredentials-submit": "Verwyder rekeninginligting",
"credentialsform-account": "Gebruikersnaam:",
"edit-error-short": "Fout: $1",
- "edit-error-long": "Foute:\n\n$1"
+ "edit-error-long": "Foute:\n\n$1",
+ "pagedata-bad-title": "Ongeldige titel: $1.",
+ "passwordpolicies-policy-minimalpasswordlength": "Wagwoord moet ten minste $1 {{PLURAL:$1|karakter|karakters}} lank wees",
+ "passwordpolicies-policy-minimumpasswordlengthtologin": "Wagwoord moet ten minste $1 {{PLURAL:$1|karakter|karakters}} lank wees om te kan aanmeld",
+ "passwordpolicies-policy-passwordcannotmatchusername": "Wagwoord mag nie dieselfde wees as gebruikernaam nie"
}
"customjsprotected": "Вы ня маеце правоў на рэдагаваньне гэтай старонкі JavaScript, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
"sitecssprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай CSS-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў.",
"sitejsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў.",
- "sitejsprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JavaScript-старонкі, бо гэта можа паўплываць на ўсіх наведнікаў",
+ "sitejsprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JavaScript-старонкі, бо гэта можа паўплываць на ўсіх наведнікаў.",
"mycustomcssprotected": "Вы ня маеце дазволу рэдагаваць гэтую CSS-старонку.",
"mycustomjsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі.",
"mycustomjsprotected": "Вы ня маеце дазволу рэдагаваць гэтую JavaScript-старонку.",
"backend-fail-describe": "Не атрымалася зьмяніць мэтазьвесткі для файлу «$1».",
"backend-fail-alreadyexists": "Файл «$1» ужо існуе.",
"backend-fail-store": "Немагчыма захаваць файл «$1» у «$2».",
- "backend-fail-copy": "Немагчыма скапіяваць файл $1 у $2.",
+ "backend-fail-copy": "Немагчыма скапіяваць файл «$1» у «$2».",
"backend-fail-move": "Немагчыма перанесьці файл $1 у $2.",
"backend-fail-opentemp": "Немагчыма адкрыць часовы файл.",
"backend-fail-writetemp": "Немагчыма запісаць часовы файл.",
"autoblockedtext": "Vaša IP-adresa automatski je blokirana jer ju je koristio drugi korisnik, a blokirao ju je $1.\nNaveden je sljedeći razlog:\n\n:''$2''\n\n* Početak blokade: $8\n* Kraj blokade: $6\n* Blokirani korisnik: $7\n\nMožete kontaktirati sa $1 ili nekim drugim iz grupe [[{{MediaWiki:Grouppage-sysop}}|administratora]] i zahtijevati da Vas deblokira.\n\nZapamtite da ne možete koristiti opciju \"pošalji e-mail ovom korisniku\" sve dok ne unesete validnu e-mail adresu pri registraciji u Vašim [[Special:Preferences|korisničkim postavkama]] i dok niste spriječeni (blokadom) da je koristite.\n\nVaša trenutna IP-adresa je $3, a ID blokade je $5.\nMolimo da navedete sve gore navedene detalje u zahtjevu za deblokadu.",
"systemblockedtext": "MediaWiki je automatski blokirao Vaše korisničko ime ili IP-adresu.\nDat je sljedeći razlog:\n\n:<em>$2</em>\n\n* Početak blokade: $8\n* Istek blokade: $6\n* Blokada je namijenjena za: $7\n\nVaša trenutna IP-adresa je $3.\nAko imate pitanja u vezi s blokadom, priložite sve gorenavedene pojedinosti.",
"blockednoreason": "razlog nije naveden",
- "whitelistedittext": "Morate biti $1 da biste uređivali stranice.",
+ "whitelistedittext": "$1 da biste uređivali stranice.",
"confirmedittext": "Morate potvrditi svoju adresu e-pošte prije nego počnete mijenjati stranice.\nPostavite i potvrdite svoju adresu e-pošte u [[Special:Preferences|korisničkim postavkama]].",
"nosuchsectiontitle": "Ne mogu pronaći sekciju",
"nosuchsectiontext": "Pokušali ste uređivati sekciju koja ne postoji.\nMožda je premještena ili obrisana dok ste pregledavali stranicu.",
"loginreqtitle": "Potrebna je prijava",
- "loginreqlink": "prijavljeni",
- "loginreqpagetext": "Morate biti $1 da biste vidjeli druge stranice.",
+ "loginreqlink": "Prijavite se",
+ "loginreqpagetext": "$1 da biste vidjeli druge stranice.",
"accmailtitle": "Šifra poslana.",
"accmailtext": "Nasumično odabrana lozinka za [[User talk:$1|$1]] poslana je na $2. Lozinka se <em>[[Special:ChangePassword|može promijeniti]]</em> nakon prijave.",
"newarticle": "(Novi)",
"prefs-watchlist": "Spisak praćenja",
"prefs-editwatchlist": "Uređivanje spiska praćenja",
"prefs-editwatchlist-label": "Uređivanje spiska:",
- "prefs-editwatchlist-edit": "Uredi spisak",
- "prefs-editwatchlist-raw": "Napredno uredi spisak",
- "prefs-editwatchlist-clear": "Isprazni spisak",
+ "prefs-editwatchlist-edit": "vidi i ukloni naslove sa spiska praćenja",
+ "prefs-editwatchlist-raw": "uredi sirov spisak praćenja",
+ "prefs-editwatchlist-clear": "očisti spisak praćenja",
"prefs-watchlist-days": "Broj dana za prikaz u spisku praćenja:",
"prefs-watchlist-days-max": "Najviše $1 {{PLURAL:$1|dan|dana}}",
"prefs-watchlist-edits": "Najviše prikazanih izmjena na spisku praćenja:",
"reuploaddesc": "Vrati me na formular za postavljanje datoteka.",
"upload-tryagain": "Pošaljite izmijenjeni opis datoteke",
"uploadnologin": "Niste prijavljeni",
- "uploadnologintext": "Morate biti $1 kako biste postavljali datoteke.",
+ "uploadnologintext": "$1 da biste postavljali datoteke.",
"upload_directory_missing": "Folder za postavljanje ($1) nedostaje i webserver ga ne može napraviti.",
"upload_directory_read_only": "Folder za postavljanje ($1) na webserveru je postavljen samo za čitanje.",
"uploaderror": "Greška pri slanju",
"namespace_association": "Povezan imenski prostor",
"tooltip-namespace_association": "Označite ovu kutiju da također uključite razgovor ili imenski prostor teme koja je povezana sa odabranim imenskim prostorom",
"blanknamespace": "(glavni)",
- "contributions": "{{GENDER:$1|Korisnički}} doprinosi",
- "contributions-title": "Doprinosi korisnika $1",
+ "contributions": "Doprinosi {{GENDER:$1|korisnika|korisnice}}",
+ "contributions-title": "Doprinosi {{GENDER:$1|korisnika|korisnice}} $1",
"mycontris": "Doprinosi",
"anoncontribs": "Doprinosi",
"contribsub2": "Za {{GENDER:$3|$1}} ($2)",
"sp-contributions-newbies-sub": "Za nove korisnike",
"sp-contributions-newbies-title": "Doprinosi novih korisnika",
"sp-contributions-blocklog": "zapisnik blokiranja",
- "sp-contributions-suppresslog": "obrisani {{GENDER:$1|korisnički}} doprinosi",
- "sp-contributions-deleted": "obrisani {{GENDER:$1|korisnički}} doprinosi",
+ "sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
+ "sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"sp-contributions-uploads": "postavljanja",
"sp-contributions-logs": "zapisnici",
"sp-contributions-talk": "razgovor",
"tooltip-pt-userpage": "{{GENDER:|Vaša}} korisnička stranica",
"tooltip-pt-anonuserpage": "Korisnička stranica za ip koju Vi uređujete kao",
"tooltip-pt-mytalk": "{{GENDER:|Vaša}} stranica za razgovor",
- "tooltip-pt-anontalk": "Razgovor o doprinosu sa ove IP adrese",
+ "tooltip-pt-anontalk": "Rasprava o izmjenama s ove IP-adrese",
"tooltip-pt-preferences": "{{GENDER:|Vaše}} postavke",
"tooltip-pt-watchlist": "Spisak stranica koje pratite",
"tooltip-pt-mycontris": "Spisak {{GENDER:|Vaših}} doprinosa",
"tooltip-pt-anoncontribs": "Spisak izmjena napravljenih s ove IP-adrese",
- "tooltip-pt-login": "Predlažemo da se prijavite, ali nije obvezno.",
+ "tooltip-pt-login": "Predlažemo vam da se prijavite, iako to nije obavezno",
"tooltip-pt-login-private": "Morate se prijaviti da biste koristili ovaj wiki",
"tooltip-pt-logout": "Odjavi me",
- "tooltip-pt-createaccount": "Ohrabrujemo vas da otvorite nalog i prijavite se, međutim to nije obavezno",
+ "tooltip-pt-createaccount": "Predlažemo vam da napravite račun i prijavite se; međutim, to nije obavezno",
"tooltip-ca-talk": "Razgovor o sadržaju",
"tooltip-ca-edit": "Uredi ovu stranicu",
"tooltip-ca-addsection": "Započni novu sekciju.",
"tog-watchlisthideminor": "囥起監視單其過幼修改",
"tog-watchlisthideliu": "共已經登錄其用戶其編輯趁監視單𡅏囥起咯",
"tog-watchlistreloadautomatically": "Sìng-tō̤ dèu-giông gāi-biéng sèng-hâiu cê̤ṳ-dông gĕng-sĭng gáng-sê-dăng (JavaScript diŏh kŭi lā̤)",
+ "tog-watchlistunwatchlinks": "Ké̤ṳk ô gĕng-gāi gì găng-sê hiĕk-miêng tiĕng-gă dĭk-ciék (chṳ̄-siĕu) găng-sê biĕu-gé ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}, diŏh ô JavaScript câ â̤ sāi)",
"tog-watchlisthideanons": "共匿名其用戶其編輯趁監視單𡅏囥起咯",
"tog-watchlisthidepatrolled": "共巡查其編輯趁監視單𡅏囥起咯",
"tog-watchlisthidecategorization": "Káung kī hiĕk gì lôi-biék",
"editfont-monospace": "蜀様寬其字體",
"editfont-sansserif": "無襯線其字體",
"editfont-serif": "有襯線其字體",
- "sunday": "禮拜",
- "monday": "拜一",
+ "sunday": "Lā̤-bái",
+ "monday": "Bái-ék",
"tuesday": "Bái-nê",
"wednesday": "拜三",
"thursday": "拜四",
- "friday": "拜五",
- "saturday": "拜六",
- "sun": "Lā̤ buái",
+ "friday": "Bái-ngô",
+ "saturday": "Bái-lĕ̤k",
+ "sun": "Lā̤-buái",
"mon": "Buái ék",
- "tue": "Bái-nê",
+ "tue": "B2",
"wed": "Buái săng",
"thu": "Buái sé",
"fri": "Buái ngô",
"jan": "1 ng.",
"feb": "2 ng.",
"mar": "3 ng.",
- "apr": "四月",
- "may": "五月",
+ "apr": "4 ng.",
+ "may": "5 ng.",
"jun": "6 ng.",
- "jul": "七月",
+ "jul": "7 ng.",
"aug": "8 ng.",
"sep": "9 ng.",
"oct": "10 ng.",
"mytalk": "我其討論",
"anontalk": "攀講",
"navigation": "Dô̤-hòng",
- "and": " 共",
+ "and": " gê̤ṳng",
"faq": "真稠碰著其問題",
"actions": "動作",
"namespaces": "Miàng-kŭng-găng",
"navigation-heading": "Dô̤-hòng chái-dăng",
"errorpagetitle": "綻咯",
"returnto": "轉去$1。",
- "tagline": "Lài-nguòng: {{SITENAME}}",
+ "tagline": "Chók-cê̤ṳ {{SITENAME}}",
"help": "Bŏng-cô",
"search": "Sìng-tō̤",
- "searchbutton": "尋討",
+ "searchbutton": "Sìng-tō̤",
"go": "去",
"searcharticle": "Kó̤",
"history": "頁面歷史",
- "history_short": "歷史",
+ "history_short": "Lĭk-sṳ̄",
"history_small": "歷史",
"updatedmarker": "趁我最後蜀回訪問開始更新",
"printableversion": "Kō̤ páh-éng bēng-buōng",
"permalink": "Īng-giū lièng-giék",
"print": "拍印",
- "view": "覷蜀覷",
+ "view": "Ché̤ṳ siŏh ché̤ṳ",
"view-foreign": "敆$1𡅏看",
"edit": "Siŭ-gāi",
"edit-local": "編輯當地描述",
"talk": "Tō̤-lâung",
"views": "Ché̤ṳ siŏh ché̤ṳ",
"toolbox": "Gă-sĭ-huă",
+ "tool-link-userrights": "Gāi {{GENDER:$1|ê̤ṳng-hô}} hŭng-cū",
+ "tool-link-userrights-readonly": "Káng {{GENDER:$1|ê̤ṳng-hô}} hŭng-cū",
+ "tool-link-emailuser": "Siā-piĕ ké̤ṳk cī-ciáh {{GENDER:$1|ê̤ṳng-hô}}",
"imagepage": "覷蜀覷文件頁面",
"mediawikipage": "看消息頁",
"templatepage": "看模板頁",
"redirectedfrom": "(téng $1 tṳ̀ng-déng-hióng guó-lì)",
"redirectpagesub": "重定向頁",
"redirectto": "重定向遘",
- "lastmodifiedat": "茲蜀頁是著$1地方,$2辰候之後修改其。",
+ "lastmodifiedat": "Cī-hiĕk muōi-muōi siŏh-huôi biĕng-cĭk găk $1 $2.",
"viewcount": "茲蜀頁已經乞訪問$1回了。{{PLURAL:$1}}",
"protectedpage": "保護頁",
"jumpto": "Tiéu gáu:",
"pool-timeout": "等待鎖定其時間遘了",
"pool-queuefull": "隊列池已經滿了",
"pool-errorunknown": "𣍐曉什乇綻咯",
+ "pool-servererror": "Mò̤ bêng-huák sāi tiàng-sê̤ṳ gié-só hŭk-ô ($1).",
"poolcounter-usage-error": "Ê̤ṳng-huák chó̤-nguô: $1",
"aboutsite": "Guăng-ṳ̀ {{SITENAME}}",
"aboutpage": "Project:Guăng-ṳ̀",
"versionrequired": "需要版本$1其MediaWiki",
"versionrequiredtext": "需要MediaWiki其版本$1來使茲蜀頁。\n覷[[Special:Version|版本頁面]]。",
"ok": "好",
- "retrievedfrom": "Lài-nguòng: \"$1\"",
+ "retrievedfrom": "Lài-nguòng „$1“",
"youhavenewmessages": "{{PLURAL:$3|汝有}}$1($2)。",
"youhavenewmessagesfromusers": "汝有趁$3用戶($2)來其$1萆信息{{PLURAL:$3}}",
"youhavenewmessagesmanyusers": "汝有趁雅価用戶($2)其$1信息",
"viewsourceold": "看源代碼",
"editlink": "siŭ-gāi",
"viewsourcelink": "Káng nguòng-dâi-mā",
- "editsectionhint": "修改段落:$1",
+ "editsectionhint": "Siŭ-gāi dâung-lŏk: $1",
"toc": "Mŭk-liŏh",
"showtoc": "顯示",
"hidetoc": "囥起",
"readonly_lag": "從數據庫跟上主數據庫其辰候,數據庫已經自動鎖定",
"internalerror": "內部錯誤",
"internalerror_info": "內部錯誤:$1",
+ "internalerror-fatal-exception": "\"$1\" lôi gì ngièng-dê̤ṳng liê-nguôi",
"filecopyerror": "𣍐使趁「$1」𡅏複製文件遘「$2」。",
"filerenameerror": "𣍐使共「$1」其名字改去「$2」。",
"filedeleteerror": "𣍐使刪掉文件「$1」。",
"delete-hook-aborted": "刪除乞鉤子拍斷咯。\n無給出解釋。",
"no-null-revision": "𣍐使敆頁面$1𡅏新建空操作。",
"badtitle": "呆其標題",
+ "title-invalid-empty": "Sū chīng-giù gì hiĕk-miêng biĕu-dà̤ siŏh-cê dŭ mò̤, hĕ̤k-chiā nâ ô miàng-kŭng-găng.",
+ "title-invalid-utf8": "Sū chīng-giù gì hiĕk-miêng biĕu-dà̤ hàng ô ù-hâu gì UTF-8 hù-hô̤.",
+ "title-invalid-interwiki": "Sū chīng-giù gì hiĕk-miêng biĕu-dà̤ hàng ô mò̤ bêng-huák găk biĕu-dà̤ lā̤ sāi gì kuá Wiki liêng-ciék.",
+ "title-invalid-talk-namespace": "Chīng-giù gì hiĕk-miêng biĕu-dà̤ īng-ê̤ṳng gì tō̤-lâung-hiĕk kō̤-nèng mò̤ còng-câi.",
"perfcached": "下底其數據乞緩存固加可能伓是最新其。{{PLURAL:$1|$1條結果}}會敆緩存臺中討著。",
"perfcachedts": "下底其數據已經緩存過了,最後更新遘$1。{{PLURAL:$4|$4條結果}}會敆緩存臺中討著。",
"querypage-no-updates": "茲蜀頁其更新乞禁止了。\n數據嚽塊現刻時𣍐更新了。",
"nosuchusershort": "無總款其用戶名「$1」。\n檢查汝其拼寫。",
"nouserspecified": "汝著指定蜀萆用戶名。",
"login-userblocked": "茲隻用戶已經乞封鎖去了。登錄是𣍐允許其。",
- "wrongpassword": "密碼綻咯。\n起動再查蜀下。",
+ "wrongpassword": "Ê̤ṳng-hô-miàng hĕ̤k-chiā mĭk-mā dâng kó̤.\nKī-dâe̤ng gái că siŏh-hâ.",
"wrongpasswordempty": "未拍入密碼。\n起動汝再試蜀下。",
"passwordtooshort": "密碼著設最少{{PLURAL:$1|$1萆字符}}。",
"password-name-match": "汝其密碼無能耐共汝其用戶名蜀模蜀樣。",
"loginlanguagelabel": "語言:$1",
"pt-login": "Láuk-diē",
"pt-login-button": "躒入",
+ "pt-login-continue-button": "Gié-sṳ̆k láuk-diē",
"pt-createaccount": "Kŭi sĭng dióng-hô̤",
"pt-userlogout": "Láuk-chók",
"php-mail-error-unknown": "PHP其mail()函數,𣍐曉什乇綻去。",
"newpassword": "新密碼:",
"retypenew": "確認密碼:",
"resetpass_submit": "設置密碼再登錄",
+ "botpasswords": "Gĭ-ké-nè̤ng mĭk-mā",
+ "botpasswords-label-appid": "Gĭ-ké-nè̤ng miàng-cê:",
+ "botpasswords-label-create": "Cháung-gióng",
"botpasswords-label-update": "Gĕng-sĭng",
+ "botpasswords-label-cancel": "Chṳ̄-siĕu",
+ "botpasswords-label-delete": "Săng-dṳ̀",
+ "botpasswords-label-resetpassword": "Tṳ̀ng-gāi mĭk-mā",
"resetpass_forbidden": "密碼改𣍐來",
"resetpass-no-info": "汝著登錄乍會使直接看茲蜀頁。",
"resetpass-submit-loggedin": "修改密碼",
"passwordreset-email": "電批地址:",
"passwordreset-emailsentemail": "如果茲萆电子郵件地址共汝其賬號有關聯,噲密碼重設电子郵件會發過去。",
"changeemail": "修改或者刪除電子郵件地址",
- "changeemail-header": "修改賬戶電子郵件地址",
+ "changeemail-header": "Chiāng dèng lâ ciā dăng-dăng, siŭ-gāi nṳ̄ gì diêng-cṳ̄ iù-giông dê-cī, ṳ̀-guō nṳ̄ buóh siōng dṳ̀-lâi sū-iū ô liêng-ciék gáu nṳ̄ dióng-hô̤ gì diêng-cṳ̄ iù-giông dê-cī, cêu ng-sāi dèng sĭng diêng-cṳ̄ iù-giông dê-cī gì kĕ̤ng.",
"changeemail-oldemail": "現刻時其電批地址:",
"changeemail-newemail": "新其電批地址:",
"changeemail-none": "(無)",
"savearticle": "Bō̤-còng ciā hiĕk",
"publishpage": "Huák-buó ùng-ciŏng",
"publishchanges": "Huák-buó siŭ-gāi",
+ "savearticle-start": "Bō̤-còng ciā hiĕk…",
+ "savechanges-start": "Bō̤-còng siŭ-gāi…",
+ "publishpage-start": "Huák-buó hiĕk-miêng…",
+ "publishchanges-start": "Huák-buó siŭ-gāi…",
"preview": "預覽",
"showpreview": "顯示預覽",
"showdiff": "看改變其部分",
"anoneditwarning": "<strong>警告:</strong>汝固未登錄。\n儷是汝做出修改其話,汝其IP地址會敆編輯歷史裡勢公開。儷是汝<strong>[$1躒入]</strong>或者<strong>[$2註册新賬號]</strong>,汝其修改記錄會顯示汝其用戶名,固有其它其好處。",
"anonpreviewwarning": "<em>汝固未躒入。儷是汝卜想保存茲蜀頁其修改,汝其IP地址會乞記著茲蜀頁其編輯歷史臺中。</em>",
- "missingcommenttext": "起動敆下底拍蜀條評論。",
+ "missingcommenttext": "Kī-dâe̤ng páh siŏh-dèu bìng-lâung.",
"summary-preview": "修改總結預覽:",
"blockedtitle": "用戶乞封鎖了",
"blockednoreason": "無掏出原因",
"newarticletext": "汝已經跟鏈接跟遘無存在其頁面了。\n卜想創建頁面,敆下底其框框𡅏拍字(覷蜀覷[$1 幫助頁面]有無更更価其幫助)。\n如果汝是無注意來遘茲蜀萆頁面,篤囇汝其瀏覽器上其「返回」按鈕。",
"anontalkpagetext": "<em>茲是未登錄其用戶討論頁面。</em>\n故此儂家著使數字IP來確定伊。\n總款其IP地址會乞雅価用戶共享。\n如果蜀隻未登錄其用戶見覺無關係其評論指向汝,起動[[Special:CreateAccount|開賬戶]]或者[[Special:UserLogin|登錄]]來避免以後共其它未登錄其用戶混蜀堆。",
"noarticletext": "現在敆茲蜀頁𡅏無文字。汝會使敆其它其頁面𡅏[[Special:Search/{{PAGENAME}}|討蜀討茲蜀萆標題]],<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 討相關其記錄],或者[{{fullurl:{{FULLPAGENAME}}|action=edit}} 創建茲蜀頁]</span>。",
- "clearyourcache": "'''注意:'''保存以後,汝可能固著刷新汝其瀏覽器緩存來看遘變化。\n* '''火狐/Safari:'''擪下''Shift''篤蜀篤''重新載入'',或者擪蜀擪''Ctrl+F5''或者''Ctrl+R'' (''⌘-R''敆Mac懸頂)\n* '''Google Chrome:'''擪''Ctrl+Shift+R''(敆Mac𡅏使''⌘-Shift-R'')\n* '''Internet Explorer:'''擪''Ctrl''其時候篤蜀篤''刷新'',或者擪''Ctrl+F5''\n* '''Opera:'''敆''工具→首選項''𡅏清除緩存",
+ "userpage-userdoesnotexist-view": "Ê̤ṳng-hô „$1“ gó muôi kŭi dióng-hô̤.",
+ "clearyourcache": "<strong>注意:</strong>保存以後,汝可能固著刷新汝其瀏覽器緩存來看遘變化。\n* <strong>火狐/Safari:</strong>擪下<em>Shift</em>篤蜀篤<em>重新載入</em>,或者擪蜀擪<em>Ctrl+F5</em>或者<em>Ctrl+R</em>(<em>⌘-R</em>敆Mac懸頂)\n* <strong>Google Chrome:</strong>擪<em>Ctrl+Shift+R</em>(敆Mac𡅏使<em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong>擪<em>Ctrl</em>其時候篤蜀篤<em>刷新</em>,或者擪<em>Ctrl+F5</em>\n* <strong>Opera:</strong>去<em>菜單→設定</em>(Mac是<em>Opera→偏好設定</em>)再去<em>隱私&安全性→清除瀏覽資料→已緩存其圖片共檔案</em>。",
"note": "<strong>注意:</strong>",
"previewnote": "'''記定茲若是蜀萆預覽。'''\n汝其改變固𡅏未保存!",
"continue-editing": "繼續修改",
"yourdiff": "差別",
"readonlywarning": "<strong>警告:數據庫已經乞鎖定來保養去了,故此汝現刻時𣍐使保存汝其編輯。</strong>\n汝可能希望複製再粘貼汝其文字遘蜀萆文本文件𡅏,再共伊保存起咯。\n\n鎖定伊其系統管理員給出茲蜀萆解釋:$1",
"protectedpagewarning": "''警告:茲蜀頁已經乞保護起去了,故此囇有管理員權力其用戶乍會使修改伊。'''\n最新其日誌已經敆下底提供來做參考:",
- "semiprotectedpagewarning": "'''注意:''' 茲蜀頁已經乞保護起去了,故此囇有註冊其用戶乍會使修改伊。\n最新其日誌已經敆下底提供來做參考:",
+ "semiprotectedpagewarning": "<strong>Cé̤ṳ-é:</strong> cī-siŏh-hiĕk ī-gĭng ké̤ṳk bō̤-hô kī-kó̤ lāu, gó-chṳ̄ nâ ô cê̤ṳ-dông cê̤ṳ-nêng ê̤ṳng-hô câ â̤-sāi siŭ-gāi.\nCī-bŏng gì nĭk-cé dŭ găk â-dā̤, ké̤ṳk nṳ̄ chăng-kō̤:",
"templatesused": "{{PLURAL:$1}}茲頁裏勢使其模板:",
"templatesusedpreview": "茲萆預覽使其{{PLURAL:$1|模板}}:",
"templatesusedsection": "茲蜀段使其{{PLURAL:$1|模板}}:",
"histfirst": "最舊",
"histlast": "最遲",
"historysize": "({{PLURAL:$1|$1字節}})",
+ "historyempty": "(kĕ̤ng)",
"history-feed-title": "修改歷史",
"history-feed-description": "維基百科敆茲頁其修改歷史",
+ "history-feed-item-nocomment": "$1 găk $2",
"rev-delundel": "㪗/藏",
+ "rev-showdeleted": "hiēng-sê",
+ "revdelete-show-file-submit": "Ciáng-sê",
+ "revdelete-hide-comment": "Biĕng-cĭk cáik-iéu",
"revertmerge": "伓使合併",
"history-title": "「$1」其修改歷史",
"difference-title": "「$1」調整以後𣍐蜀樣其地方",
"lineno": "Dâ̤ $1 hòng:",
"compareselectedversions": "比並揀選版本",
"showhideselectedversions": "顯/藏揀選其調整",
- "editundo": "Chṳ̄-siĕu",
+ "editundo": "chṳ̄-siĕu",
+ "diff-empty": "(Mò̤ chă)",
"searchresults": "Sìng-tō̤ giék-guō",
- "searchresults-title": "Sìng-tō̤ \"$1\" gì giék-guō",
+ "searchresults-title": "Sìng-tō̤ „$1“ gì giék-guō",
"prevn": "sèng $1 bĭk",
"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",
+ "searchmenu-exists": "<strong>Cī-siŏh-bĭh wiki ī-gĭng ô dèu-mŭk hô̤ lā̤ „[[:$1]]“.</strong> {{PLURAL:$2|0=|Hĕ̤k-chiā gái káng-siŏh-káng tŏ̤-diŏh gì gì-tă nó̤h.}}",
"searchprofile-articles": "Nô̤i-ṳ̀ng hiĕk",
"searchprofile-images": "Dŏ̤-mùi-tā̤",
"searchprofile-everything": "Sū-iū-nó̤h",
"searchprofile-advanced": "Gŏ̤-ngék",
"searchprofile-articles-tooltip": "Găk $1 lā̤ sìng-tō̤",
"searchprofile-images-tooltip": "Sìng-tō̤ ùng-giông",
- "search-result-size": "$1 ({{PLURAL:$2|$2 bĭk dăng-sṳ̀}})",
- "search-redirect": "(趁$1重定向過來)",
+ "search-result-size": "$1 ({{PLURAL:$2|1 bĭh dăng-sṳ̀|$2 bĭh dăng-sṳ̀}})",
+ "search-result-category-size": "$1 giông nó̤h sṳ̆k-ṳ̀ cī-bĭh hŭng-lôi ($2 bĭh cṳ̄-hŭng-lôi, $3 bĭh ùng-giông)",
+ "search-redirect": "(téng $1 tṳ̀ng-déng-hióng guó-lì)",
+ "search-section": "(dâung-lŏk $1)",
+ "search-file-match": "(hù-hăk ùng-giông nô̤i-ṳ̀ng)",
"search-suggest": "汝其意思是伓是:$1",
"searchrelated": "相關其",
"searchall": "全部",
"saveprefs": "保存",
"prefs-editing": "編輯",
"searchresultshead": "尋討",
- "recentchangescount": "這般改變其條目:",
+ "recentchangescount": "Cī-bŏng gì gāi-biéng, hiĕk-miêng lĭk-sṳ̄, nĭk-cé diē-sié, ê̤ṳ-siék hièng-sê nióh-uâi biĕng-cĭk:",
"savedprefs": "汝其設定已經乞保存了。",
"timezonelegend": "時區:",
"localtime": "當地時間:",
"timezoneregion-europe": "歐洲",
"timezoneregion-indian": "印度洋",
"timezoneregion-pacific": "太平洋",
- "allowemail": "會肯別儂寄電批乞汝",
+ "allowemail": "Â̤ kīng biĕk-nè̤ng gié diêng-piĕ ké̤ṳk-nṳ̄",
"prefs-searchoptions": "尋討",
"prefs-namespaces": "命名空間",
"prefs-files": "文件",
"grouppage-suppress": "{{ns:project}}:監督員",
"newuserlogpage": "Kŭi dióng-hô nĭk-cé",
"action-edit": "修改茲蜀頁",
+ "enhancedrc-history": "lĭk-sṳ̄",
"recentchanges": "Cī-bŏng gì gāi-biéng",
+ "recentchanges-legend": "Cī-bŏng gāi-biéng gì sōng-hâung",
"recentchanges-summary": "敆維基茲頁跟蹤兹般其改變。",
"recentchanges-label-newpage": "Cī siŏh bĭk siŭ-gāi cháung-gióng lāu sĭng hiĕk",
"recentchanges-label-minor": "Cuòi sê siŏh bĭk guó-éu siŭ-gāi",
"recentchanges-label-bot": "Cuòi sê gĭ-ké-nè̤ng siŭ-gāi gì",
+ "recentchanges-label-unpatrolled": "Cī-bĭh biĕng-cĭk gó muôi sùng-că",
"recentchanges-label-plusminus": "Cī-bĭh hiĕk-miêng gāi-biéng gì ôi-nguòng-cū duâi-nâung",
+ "recentchanges-legend-heading": "<strong>Dù-liê:</strong>",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (chiāng chăng-kō̤ [[Special:NewPages|sĭng hiĕk-miêng chĭng-dăng]])",
"rcfilters-legend-heading": "<strong>Gāng-siā liĕk-biēu:</strong>",
"rcfilters-other-review-tools": "Gì-tă gì giēng-că gĕ̤ng-gê̤ṳ",
"rcfilters-activefilters": "Gēng-chók-lì gì biĕng-cĭk",
"rcfilters-liveupdates-button": "Sĭk-sì gĕng-sĭng",
"rclistfrom": "Hiēng-sê téng $3 $2 gáu dāng gì sĭng gāi-biéng",
"rcshowhideminor": "$1 guó-éu siŭ-gāi",
+ "rcshowhideminor-show": "Hiêng",
+ "rcshowhideminor-hide": "Iēng",
"rcshowhidebots": "$1 gĭ-ké-nè̤ng",
+ "rcshowhidebots-show": "Hiêng",
+ "rcshowhidebots-hide": "Iēng",
"rcshowhideliu": "$1 ī dĕng-gé gì ê̤ṳng-hô",
+ "rcshowhideliu-show": "Hiêng",
+ "rcshowhideliu-hide": "Iēng",
"rcshowhideanons": "$1 ù-mìng-sê",
+ "rcshowhideanons-show": "Hiêng",
+ "rcshowhideanons-hide": "Iēng",
"rcshowhidemine": "$1 nguāi gì siŭ-gāi",
+ "rcshowhidemine-show": "Hiêng",
+ "rcshowhidemine-hide": "Iēng",
"rclinks": "Hiēng-sê có̤i-gê̤ṳng $2 gĕ̤ng ī-nô̤i gì $1 huòi gāi-biéng",
"diff": "chă",
"hist": "sṳ̄",
- "hide": "掩",
- "show": "現",
+ "hide": "Iēng",
+ "show": "Hiêng",
"minoreditletter": "~",
"newpageletter": "!",
"boteditletter": "^",
"recentchangeslinked": "相關其改變",
"recentchangeslinked-feed": "相關其改變",
"recentchangeslinked-toolbox": "Sŏng-guăng gì gāi-biéng",
+ "recentchangeslinked-title": "Gê̤ṳng „$1“ ô guăng-hiê gì gāi-biéng",
"recentchangeslinked-page": "頁面名:",
"recentchangeslinked-to": "Hiēng-sê liêng-ciék gáu cī-dêng hiĕk-miêng gì gāi-biéng",
"upload": "Siông-diòng ùng-giông",
"listfiles_size": "尺寸",
"file-anchor-link": "Ùng-giông",
"filehist": "Ùng-giông lĭk-sṳ̄",
+ "filehist-revert": "Huàng-nguòng",
"filehist-current": "hiêng-káik-sì",
"filehist-datetime": "Nĭk-gĭ/Sì-găng",
+ "filehist-thumb": "Sáuk-liŏk-dù",
+ "filehist-thumbtext": "$1 bēng-buōng gì sáuk-liŏk-dù",
+ "filehist-nothumb": "Mò̤ sáuk-liŏk-dù",
"filehist-user": "Ê̤ṳng-hô",
"filehist-dimensions": "Chióh-cháung",
"filehist-comment": "Suók-mìng",
"imagelinks": "Ùng-giông sāi-ê̤ṳng cìng-huóng",
- "linkstoimage": "Â-dā̤ {{PLURAL:$1|$1 hiĕk}} lièng gáu ciā ùng-giông:",
- "nolinkstoimage": "無鏈接遘茲蜀萆文件其頁面。",
+ "linkstoimage": "Â-dā̤ {{PLURAL:$1|$1 hiĕk ô sāi}} ciā ùng-giông:",
+ "nolinkstoimage": "Mò̤ sāi cī-bĭh ùng-giông gì hiĕk-miêng.",
+ "sharedupload-desc-here": "Cī-siŏh-bĭh ùng-giông téng $1 lì, bĕng-chiā ô kō̤-nèng ké̤ṳk gì-tă cuŏng-áng sāi.\nÂ-dā̤ sê cī-bĭh ùng-giông găk [$2 ùng-giông mièu-sŭk hiĕk-miêng] gì mièu-sŭk nô̤i-ṳ̀ng.",
"uploadnewversion-linktext": "上傳蜀萆新版本其茲萆文件。",
"shared-repo-name-wikimediacommons": "Wikimedia Commons",
"upload-disallowed-here": "汝無年呆覆蓋茲萆文件。",
"withoutinterwiki": "Mò̤ ngṳ̄-nièng lièng-giék gì hiĕk",
"withoutinterwiki-summary": "下底其頁面無鏈接遘其它語言其版本。",
"fewestrevisions": "修改最少其頁面",
- "nbytes": "$1{{PLURAL:$1}} bĭk dăng-sṳ̀",
+ "nbytes": "$1 {{PLURAL:$1|ôi-nguòng-cū}}",
"nlinks": "$1 ciáh {{PLURAL:$1|lièng-giék}}",
"nmembers": "$1隻成員{{PLURAL:$1}}",
"wantedcategories": "卜挃其類別",
"ancientpages": "最舊其頁面",
"move": "移動",
"movethispage": "移動茲頁",
- "booksources": "書源",
+ "pager-newer-n": "Bĭ-gáu sĭng gì $1 huòi",
+ "booksources": "Dù-cṳ̆ cṳ̆-nguòng",
"booksources-search-legend": "尋討書源",
+ "booksources-search": "Sìng-tō̤",
"booksources-text": "下底是鏈接遘其它賣新書共舊書其站點其單單,固加可能有更多關於汝敆𡅏看其茲本書其信息:",
- "specialloguserlabel": "表演者:",
+ "specialloguserlabel": "Có̤ gì nè̤ng:",
"speciallogtitlelabel": "目標(頭銜或者{{ns:user}}:用戶其用戶名):",
"log": "日誌",
+ "all-logs-page": "Sū-iū gŭng-kŭi nĭk-cé",
"alllogstext": "所有會使趁{{SITENAME}}獲得其日誌其都合併顯示。\n汝會使使揀選日誌類型、用戶名(大小寫敏感),或者受影響其頁面(大小寫敏感)其方法來縮小視角。",
"logempty": "日誌裏勢討要𣍐着項目",
"allpages": "所有頁面",
"deletedcontributions-title": "乞刪唻其用戶貢獻",
"linksearch-ok": "尋討",
"linksearch-line": "$1是趁$2𡅏鏈接過其",
+ "listgrouprights-members": "(sìng-uòng chĭng-dăng)",
"emailuser": "寄電批乞茲隻用戶",
"defemailsubject": "{{SITENAME}}其用戶「$1」寄來其批",
"noemailtitle": "無電批地址",
"mywatchlist": "我其監視單",
"nowatchlist": "汝其監視單𡅏無項目。",
"watchnologin": "未躒入",
- "addedwatchtext": "頁面「[[:$1]]」已經加遘汝其[[Special:Watchlist|監視單]]。以後敆茲蜀頁其改變共伊關聯其討論頁都會列敆嚽塊。",
+ "addedwatchtext": "„[[:$1]]“ gê̤ṳng ĭ gì tō̤-lâung-hiĕk dŭ gă-diē nṳ̄ gì [[Special:Watchlist|găng-sê-dăng]] kó̤-lāu.",
"removewatch": "趁汝其監視單臺中移去",
- "removedwatchtext": "頁面「[[:$1]]」已經趁[[Special:Watchlist|汝其監視單]]移去了。",
+ "removedwatchtext": "„[[:$1]]“ gê̤ṳng ĭ gì tō̤-lâung-hiĕk dŭ téng nṳ̄ gì [[Special:Watchlist|găng-sê-dăng]] dṳ̀-kó̤ lāu.",
"watch": "監視",
"watchthispage": "監視茲頁",
"unwatch": "伓使監視",
"unwatchthispage": "停止監視",
- "watchlist-details": "{{PLURAL:$1|$1頁|$1頁}}敆汝其監視單𡅏,無單獨算討論頁。",
+ "watchlist-details": "Nṳ̄ gì găng-sê-dăng {{PLURAL:$1|ô $1 gó|dŭ liāng ô $1 gó}} hiĕk-miêng (bău-guák tō̤-lâung-hiĕk).",
"wlshowlast": "顯示最$1點鐘$2日",
"watchlist-options": "監視單選項",
"watching": "監視...",
"editcomment": "修改評論是:<em>$1</em>。",
"revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|Talk]])所做其修改轉去[[User:$1|$1]]其前蜀萆版本",
"protectlogpage": "保護日誌",
+ "protectedarticle": "ī bō̤-hô „[[$1]]“",
"protect-title": "改變「$1」其保護等級",
"prot_1movedto2": "[[$1]]移遘[[$2]]",
"protect-legend": "確認保護",
"protectcomment": "原因:",
+ "protect-default": "Ṳ̄ng-hṳ̄ sū-iū ê̤ṳng-hô",
"protect-level-autoconfirmed": "囇允許自動確認用戶",
"protect-level-sysop": "囇允許管理員",
"protect-expiry-options": "1點鐘:1 hour,1 日:1 day,1禮拜:1 week,2禮拜:2 weeks,1間月日:1 month,3間月日:3 months,6間月日:6 months,1年:1 year,永遠:infinite",
"undelete-search-submit": "尋討",
"namespace": "Miàng-kŭng-găng:",
"invert": "Huāng-sōng",
- "blanknamespace": "(ciō-iéu)",
+ "blanknamespace": "(Ciō-iéu)",
"contributions": "{{GENDER:$1|User}}用戶貢獻",
"contributions-title": "$1其用戶貢獻",
"mycontris": "我其貢獻",
+ "anoncontribs": "Góng-hióng",
+ "contribsub2": "{{GENDER:$3|$1}} gì góng-hióng ($2)",
"uctop": "(當前)",
"month": "趁月(共更早):",
"year": "趁年(共更早):",
"linkshere": "下底其頁面鏈接遘'''$2''':",
"nolinkshere": "無頁鏈接遘'''$2'''。",
"isredirect": "重定向頁面",
+ "istemplate": "káng-ĭk",
"isimage": "文件鏈接",
"whatlinkshere-prev": "{{PLURAL:$1|前|前$1}}",
"whatlinkshere-next": "{{PLURAL:$1|下|下$1}}",
"whatlinkshere-links": "← 鏈接",
"whatlinkshere-hideredirs": "$1重定向",
+ "whatlinkshere-hidetrans": "$1 īng-ê̤ṳng",
"whatlinkshere-hidelinks": "$1鏈接",
"whatlinkshere-hideimages": "$1 文件鏈接",
"whatlinkshere-filters": "過濾器",
"blockip": "封鎖{{GENDER:$1|用戶}}",
- "blockiptext": "使下底其表單來封鎖趁指定IP地址或者用戶名其寫入訪問。茲囇使廮𡅏防止破壞,固加著符合[[{{MediaWiki:Policy-url}}|政策]]。敆下底填入指定其原因(比如講:引用乞破壞其頁面)。",
+ "blockiptext": "Dèng lâ â-dā̤ gì dăng-dăng, kō̤-ī dṳ̀-kó̤ dĕk-dêng IP dê-cī hĕ̤k-chiā ê̤ṳng-hô-miàng biĕng-cĭk gì guòng-âing. \nCuòi nâ-sāi ĕng lā̤ huòng-cī pó-huâi, gó gă diŏh hù-hăk [[{{MediaWiki:Policy-url}}|huŏng-cĕng gê̤ṳng céng-cháik]]. \nChiāng găk â-dā̤ dèng-siā gê̤ṳ-tā̤ gì lī-iù, bī-ṳ̀ gōng, īng-sŭk siŏh-piĕng ké̤ṳk pó-huâi gì hiĕk-miêng.\nNṳ̄ kō̤-ī sāi [//cdo.wikipedia.org/wiki/ù lôi-biék mĭk-găng lô-iù CIDR] ngṳ̄-huák gáik-sék hŭng-sō̤ IP huâng-ùi, IPv4 dék duâi ṳ̄ng-hṳ̄ gì huâng-ùi sê /$1, IPv6 sê /$2.",
"ipaddressorusername": "IP地址或者用戶名:",
"ipbexpiry": "過期:",
"ipbreason": "原因:",
"databasenotlocked": "茲數據庫無鎖。",
"move-page-legend": "移動頁面",
"movepagetext": "使下底其表單重新乞茲蜀頁起蜀萆名字,移動伊共伊所有其歷史遘伊其新名字。\n舊其標題會變成新其標題其重定向頁。\n汝會使自動更新重定向許蜀點遘原底其標題。\n如果伊結果伓是總款其話,汝著檢查蜀下[[Special:DoubleRedirects|雙重重定向]]或者[[Special:BrokenRedirects|獃其重定向]]。\n汝有責任讓頁面鏈接遘正確其地方。\n\n注意儷是許塊已經有蜀隻頁面,噲就'''無能耐'''移動過了,除開噲儷是蜀萆重定向並且無舊底其修改歷史。\n嚽其意思就是講儷是汝名字起綻了,汝會使將茲蜀萆頁面重新起伊原底其名字,但是𣍐使覆蓋已經有其頁面。\n\n<strong>注意:</strong>\n嚽可能會對一般頁面造成盡大其並且無能耐想遘其改變;\n起動汝著敆做之前會意總款做其後果。",
- "movepagetalktext": "相關其討論頁會自動共伊移遘'''無挃''':\n* 汝其新其用戶名已經有蜀頁有內容其討論頁,或者\n* 汝取消下底其框框。\n\n若總款,汝會使自家移動或者是合併頁面。",
+ "movepagetalktext": "Nâ gău-sōng cī-bĭh huŏng-kuái, siŏng-guăng gì tō̤-lâung-hiĕk â̤ cê̤ṳ-dông gê̤ṳng cī-siŏh-hiĕk iè gáu sĭng gì sū-câi, dṳ̀-hĭ sĭng gì sū-câi ī-gĭng ô siŏh-bĭh tō̤-lâung-hiĕk còng-câi.\nNâ sê dŏng-cĭng ô hiĕk-miêng còng-câi, nṳ̄ diŏh cê-gă iè-dông ī-gĭng còng-câi gì hiĕk-miêng, hĕ̤k-chiā ciŏng ciā lâng-gì hăk siŏh-dŏi.",
"movenologintext": "著[[Special:UserLogin|躒入]]才有能耐移動頁面。",
"newtitle": "新題目:",
"move-watch": "監視茲頁",
"movelogpagetext": "下底是乞移動過其頁其單單。",
"movereason": "原因:",
"delete_and_move_confirm": "正式,刪掉茲蜀頁",
+ "export": "Dô̤-chók hiĕk-miêng",
"allmessages": "系統消息",
"allmessagesname": "名",
"allmessagesdefault": "默認其消息文字",
"tooltip-pt-preferences": "{{GENDER:|汝其}}設定",
"tooltip-pt-watchlist": "汝監視其頁面有改過其單單",
"tooltip-pt-mycontris": "{{GENDER:|汝其}}貢獻其單單",
- "tooltip-pt-login": "Gióng-ngiê nṳ̄ sĕng láuk-diē; bók-guó nàng-gă mò̤ ăng nṳ̄ cūng-kuāng có̤.",
+ "tooltip-pt-login": "Gióng-ngiê nṳ̄ sĕng láuk-diē; bók-guó nàng-gă mò̤ ăng nṳ̄ cūng-kuāng có̤",
"tooltip-pt-logout": "Láuk-chók",
- "tooltip-pt-createaccount": "Gióng-ngiê nṳ̄ sĕng kŭi dióng-hô gái láuk-diē; bók-guó nàng-gă mò̤ ăng nṳ̄ cūng-kuāng có̤.",
+ "tooltip-pt-createaccount": "Gióng-ngiê nṳ̄ sĕng kŭi dióng-hô gái láuk-diē; bók-guó nāng-gă mò̤ ăng nṳ̄ cūng-kuāng có̤",
"tooltip-ca-talk": "Nô̤i-ṳ̀ng gì tō̤-lâung",
"tooltip-ca-edit": "Siŭ-gāi cī hiĕk",
"tooltip-ca-addsection": "Gă sĭng dâung",
"tooltip-p-logo": "Ché̤ṳ-siŏh-ché̤ṳ tàu-hiĕk",
"tooltip-n-mainpage": "Ché̤ṳ-siŏh-ché̤ṳ tàu-hiĕk",
"tooltip-n-mainpage-description": "Ché̤ṳ-siŏh-ché̤ṳ tàu-hiĕk",
- "tooltip-n-portal": "Guăng-ṳ̀ ciā gĕ̤ng-tiàng, nṳ̄ â̤ có̤ gì, kó̤ diē-nē̤ tō̤ nó̤h",
+ "tooltip-n-portal": "Guăng-ṳ̀ ciā gŭng-tiàng, nṳ̄ â̤ có̤ gì, kó̤ diē-nē̤ tō̤ nó̤h",
"tooltip-n-recentchanges": "Cī-bŏng diŏh wiki ô gāi-biéng gì dăng-dăng",
"tooltip-n-randompage": "Sùi-biêng muōng ché̤ṳ",
"tooltip-n-help": "Sìng-tō̤ bŏng-cô gì sū-câi",
"tooltip-t-whatlinkshere": "Ciòng-buô lièng-gáu cŭ-uái gì wiki hiĕk-miêng dăng-dăng",
- "tooltip-t-recentchangeslinked": "鏈遘茲頁其頁面其最近修改\nCī hiĕk lièng gáu bĕk hiĕk gì cī-bŏng gì gāi-biéng",
+ "tooltip-t-recentchangeslinked": "Cī hiĕk lièng gáu bĕk hiĕk gì cī-bŏng gì gāi-biéng",
+ "tooltip-feed-atom": "Cī-siŏh-hiĕk gì Atom lài-nguòng",
"tooltip-t-contributions": "{{GENDER:$1|茲蜀隻用戶}}其貢獻單單",
"tooltip-t-emailuser": "向{{GENDER:$1|茲蜀隻用戶}}寄電批",
"tooltip-t-upload": "Siông-diòng ùng-giông",
"tooltip-t-specialpages": "Cuòng-buô dĕk-sṳ̀-hiĕk dăng-dăng",
- "tooltip-t-print": "Cī hiĕk gì â̤ páh-éng bēng-buōng",
- "tooltip-t-permalink": "茲頁茲版本其永久鏈接\nCī hiĕk cī bēng-buōng gì īng-giū lièng-giék",
+ "tooltip-t-print": "Cī-hiĕk â̤ páh-éng gì bēng-buōng",
+ "tooltip-t-permalink": "Cī hiĕk cī bēng-buōng gì īng-giū lièng-giék",
"tooltip-ca-nstab-main": "Káng iĕk gì nô̤i-ṳ̀ng",
"tooltip-ca-nstab-user": "覷蜀覷用戶頁",
- "tooltip-ca-nstab-special": "茲是蜀萆特殊頁,𣍐使修改。",
+ "tooltip-ca-nstab-special": "Cuòi sê dĕk-sṳ̀-hiĕk, mâ̤-sāi siŭ-gāi",
"tooltip-ca-nstab-project": "看工程頁",
"tooltip-ca-nstab-image": "Ché̤ṳ ùng-giông hiĕk",
+ "tooltip-ca-nstab-mediawiki": "Káng hiê-tūng séng-sék",
"tooltip-ca-nstab-template": "覷蜀覷模板",
+ "tooltip-ca-nstab-category": "Káng hŭng-lôi-hiĕk",
"tooltip-minoredit": "共茲標記成過幼修改",
"tooltip-save": "保存汝其改變 [alt-s]",
"tooltip-preview": "先覷蜀下汝其改變,起動汝敆保存之前先使蜀使嚽。",
"tooltip-watch": "共茲蜀頁加遘汝其監視單[alt-w]",
+ "tooltip-rollback": "Dók „huàng-nguòng“ cêu kō̤-ī huàng-nguòng gáu sèng-siŏh-ciáh nè̤ng gì bēng-buōng",
+ "tooltip-summary": "Siā nék-giāng cáik-iéu",
"anonymous": "{{SITENAME}}其無名{{PLURAL:$1|用戶}}",
"lastmodifiedatby": "茲頁最後是$3著$1$2改變其。",
+ "pageinfo-title": "„$1“ gì séng-sék",
+ "pageinfo-header-basic": "Gĭ-buōng séng-sék",
+ "pageinfo-header-restrictions": "Bō̤-hô hiĕk-miêng",
+ "pageinfo-display-title": "Hiēng-sê biĕu-dà̤",
+ "pageinfo-article-id": "Hiĕk-miêng ID",
+ "pageinfo-robot-policy": "Niông gĭ-ké-nè̤ng có̤ sáuk-īng",
+ "pageinfo-robot-noindex": "Mâ̤-sāi",
+ "pageinfo-watchers": "Găng-sê ciā hiĕk gì nè̤ng-só",
"pageinfo-toolboxlink": "Hiĕk-miêng séng-sék",
+ "pageinfo-contentpage-yes": "Ciáng-sê",
"deletedrevision": "刪掉舊其版本$1",
"previousdiff": "← 舊其修改",
"nextdiff": "新其修改 →",
+ "file-info-size-pages": "$1 × $2 chuông-só, ùng-giông duâi-nâung: $3, MIME lôi-hìng: $4, $5 {{PLURAL:$5|hiĕk}}",
"file-nohires": "無更高決斷",
- "show-big-image": "原底其文件",
- "show-big-image-preview": "茲萆預覽其尺寸:$1.",
- "show-big-image-other": "其他{{PLURAL:$2|分辨率}}:$1。",
+ "show-big-image": "Nguòng-dā̤ gì ùng-giông",
+ "show-big-image-preview": "Ê̤ṳ-lāng chék-cháung:$1.",
+ "show-big-image-other": "Gì-tă {{PLURAL:$2|hŭng-biêng-lŭk}}: $1.",
"show-big-image-size": "$1 × $2 chiông-só",
"ilsubmit": "尋討",
"bydate": "按日期",
"metadata": "Nguòng-só-gé̤ṳ",
"metadata-help": "茲萆文件臺中有多餘其信息,可能是數碼相機或者掃描儀敆創建或者數字化其過程臺中添加其。如果文件趁初始狀態開始就已經受遘修改,噲有其詳細說明可能無法反映修改以後其文件。",
"metadata-expand": "顯示詳細資料",
+ "exif-orientation": "Huōng-ôi",
+ "exif-make": "Kák-sióng-gĭ cié-cô̤-siŏng",
+ "exif-model": "Kák-sióng-gĭ hìng-hô̤",
+ "exif-software": "Sāi gì nuōng-giông",
+ "exif-exifversion": "Exif bēng-buōng",
+ "exif-colorspace": "Sáik-chāi kŭng-găng",
+ "exif-orientation-1": "Biĕu-cūng",
"exif-componentsconfiguration-0": "無存在",
"exif-meteringmode-0": "𣍐八",
"exif-lightsource-0": "𣍐八",
"imgmultipageprev": "← 前蜀頁",
"imgmultipagenext": "下蜀頁 →",
"imgmultigo": "去!",
+ "imgmultigoto": "Kó̤ {{PLURAL:$1|tàu-siŏh-hiĕk|dâ̤ $1 hiĕk}}",
"ascending_abbrev": "升",
"descending_abbrev": "降",
"table_pager_next": "下蜀頁",
"watchlisttools-view": "看相關改變",
"watchlisttools-edit": "看共修改監視單",
"watchlisttools-raw": "修改原始監視單",
+ "redirect-submit": "Kó̤",
+ "redirect-user": "Ê̤ṳng-hô ID",
+ "redirect-page": "Hiĕk-miêng ID",
+ "redirect-file": "Ùng-gióng miàng",
"specialpages": "Dĕk-sṳ̀-hiĕk",
- "tag-filter": "[[Special:Tags|標籤]]過濾器:",
- "tag-list-wrapper": "([[Special:Tags|$1萆標籤]]:$2)",
- "searchsuggest-search": "Tō̤ {{SITENAME}}"
+ "tag-filter": "Áng [[Special:Tags|biĕu-chiĕng]] tō̤:",
+ "tag-list-wrapper": "([[Special:Tags|$1 bĭh biĕu-chiĕng]]: $2)",
+ "tags-active-yes": "Ciáng-sê",
+ "tags-active-no": "Ng-sê",
+ "logentry-move-move": "$1 ī-gĭng ciŏng hiĕk-miêng $3 {{GENDER:$2|iè-dông}} gáu $4",
+ "logentry-newusers-create": "Ê̤ṳng-hô dióng-hô $1 {{GENDER:$2|kŭi-hō̤}} lāu",
+ "logentry-upload-upload": "$1 {{GENDER:$2|ī siông-diòng}} $3",
+ "searchsuggest-search": "Tō̤ {{SITENAME}}",
+ "duration-days": "$1 gĕ̤ng"
}
"longpageerror": "'''Σφάλμα: Το κείμενο που καταχωρήσατε έχει μήκος {{PLURAL:$1|ένα kilobyte|$1 kilobytes}}, το οποίο είναι μεγαλύτερο από το μέγιστο {{PLURAL:$2|του ενός kilobyte|των $2 kilobytes}}.'''\nΔεν μπορεί να αποθηκευτεί.",
"readonlywarning": "'''Προειδοποίηση: Η βάση δεδομένων έχει κλειδωθεί για συντήρηση, έτσι δεν θα μπορέσετε να αποθηκεύσετε τις επεξεργασίες σας αυτή τη στιγμή.'''\nΜπορείτε αν θέλετε να μεταφέρετε με αντιγραφή-επικόλληση το κείμενό σας σε αρχείο κειμένου και να το αποθηκεύσετε για αργότερα.\n\nΟ διαχειριστής που την κλείδωσε έδωσε την εξής εξήγηση: $1",
"protectedpagewarning": "'''Προειδοποίηση: Αυτή η σελίδα έχει κλειδωθεί ώστε μόνο χρήστες με δικαιώματα διαχειριστή μπορούν να την επεξεργαστούν.'''\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
- "semiprotectedpagewarning": "<strong>Σημείωση:<strong> Αυτή η σελίδα έχει προστατευθεί ώστε μόνο αυτοεπιβεβαιωμένοι χρήστες μπορούν να την επεξεργαστούν.\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
+ "semiprotectedpagewarning": "<strong>Σημείωση:</strong> Αυτή η σελίδα έχει προστατευτεί ώστε μόνο αυτοεπιβεβαιωμένοι χρήστες μπορούν να την επεξεργαστούν.\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
"cascadeprotectedwarning": "<strong>Προσοχή:</strong> Αυτή η σελίδα έχει κλειδωθεί ώστε μόνο χρήστες με [[Special:ListGroupRights|συγκεκριμένα δικαιώματα]] να μπορούν να την επεξεργαστούν, επειδή περιλαμβάνεται {{PLURAL:$1|στην ακόλουθη|στις ακόλουθες}} διαδοχικά (cascaded) {{PLURAL:$1|προστατευμένη σελίδα|προστατευμένες σελίδες}}:",
"titleprotectedwarning": "'''Προειδοποίηση: Αυτή η σελίδα έχει κλειδωθεί ώστε χρειάζονται [[Special:ListGroupRights|ειδικά δικαιώματα]] για να δημιουργηθεί.'''\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
"templatesused": "{{PLURAL:$1|Πρότυπο που χρησιμοποιείται|Πρότυπα που χρησιμοποιούνται}} σε αυτή τη σελίδα:",
"confirm-unwatch-top": "Quere eliminar esta páxina da lista de vixilancia?",
"confirm-rollback-button": "Aceptar",
"confirm-rollback-top": "Quere reverter as edicións desta páxina?",
+ "confirm-mcrundo-title": "Desfacer un cambio",
+ "mcrundofailed": "Erro ao desfacer",
+ "mcrundo-missingparam": "Faltan parámetros obrigatorios na solicitude.",
+ "mcrundo-changed": "A páxina foi mudada dende que veu o diff. Por favor, revise o novo cambio.",
"semicolon-separator": "; ",
"comma-separator": ", ",
"colon-separator": ": ",
"edit-error-long": "Erros:\n\n$1",
"revid": "revisión $1",
"pageid": "identificador de páxina $1",
- "interfaceadmin-info": "$1\n\nOs permisos para editar ficheiros globais de CSS/JS/JSON separáronse recentemente do dereito <code>editinterface</code>. Se non comprende porqué está vendo este erro, vexa [[mw:MediaWiki_1.32/interface-admin]].",
+ "interfaceadmin-info": "$1\n\nOs permisos para editar os ficheiros CSS/JS/JSON separáronse recentemente do dereito <code>editinterface</code>. Se non comprende porqué está vendo este erro, vexa [[mw:MediaWiki_1.32/interface-admin]].",
"rawhtml-notallowed": "As marcas <html> non poden usarse fóra das páxinas normais.",
"gotointerwiki": "Deixando {{SITENAME}}",
"gotointerwiki-invalid": "O título especificado non é válido.",
"yourdomainname": "Vaša domena",
"password-change-forbidden": "Ne možete promjeniti zaporku na ovom projektu.",
"externaldberror": "Došlo je do pogreške s vanjskom autorizacijom ili Vam nije dopušteno osvježavanje vanjskog suradničkog računa.",
- "login": "Prijavi se",
+ "login": "Prijava",
"login-security": "Potvrdite svoj identitet",
"nav-login-createaccount": "Prijavi se",
"logout": "Odjavi se",
"pt-login": "Prijavi se",
"pt-login-button": "Prijavi se",
"pt-login-continue-button": "Nastavi prijavu",
- "pt-createaccount": "Otvori novi suradnički račun",
+ "pt-createaccount": "Stvori račun",
"pt-userlogout": "Odjavi se",
"php-mail-error-unknown": "Nepoznata pogrješka u funkciji PHP-poruke()",
"user-mail-no-addy": "Pokušaj slanja e-maila bez e-mail adrese.",
"prefs-watchlist": "Praćene stranice",
"prefs-editwatchlist": "Uredi popis praćenja",
"prefs-editwatchlist-label": "Uredi stavke na popisu praćenja:",
- "prefs-editwatchlist-edit": "vidi i ukloni stavke s popisa praćenja",
- "prefs-editwatchlist-raw": "uredi popis praćenih stranica u okviru za uređivanje",
+ "prefs-editwatchlist-edit": "vidi i ukloni naslove s popisa praćenja",
+ "prefs-editwatchlist-raw": "uredi sirovi popis praćenja",
"prefs-editwatchlist-clear": "očisti popis praćenja",
"prefs-watchlist-days": "Broj dana koji će se prikazati na popisu praćenja:",
"prefs-watchlist-days-max": "Najviše $1 {{PLURAL:$1|dan|dana}}",
"tooltip-namespace_association": "Označite ovu kućicu da biste uključili i imenski prostor razgovora ili imenski prostor teme koja je povezana s odabranim imenskim prostorom",
"blanknamespace": "(Glavni)",
"contributions": "Doprinosi {{GENDER:$1|suradnika|suradnice}}",
- "contributions-title": "Suradnički doprinosi za $1",
+ "contributions-title": "Doprinosi {{GENDER:$1|suradnika|suradnice}} $1",
"mycontris": "Doprinosi",
"anoncontribs": "Doprinosi",
"contribsub2": "Za {{GENDER:$3|$1}} ($2)",
"sp-contributions-newbies-sub": "Za nove suradnike",
"sp-contributions-newbies-title": "Doprinosi novih suradnika",
"sp-contributions-blocklog": "evidencija blokiranja",
- "sp-contributions-suppresslog": "pobrisani {{GENDER:$1|suradnikovi|suradničini}} doprinosi",
- "sp-contributions-deleted": "pobrisani {{GENDER:$1|suradnikovi|suradničini}} doprinosi",
+ "sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|suradnika|suradnice}}",
+ "sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|suradnika|suradnice}}",
"sp-contributions-uploads": "postavljene datoteke",
"sp-contributions-logs": "evidencije",
"sp-contributions-talk": "razgovor",
"tooltip-pt-userpage": "Moja suradnička stranica",
"tooltip-pt-anonuserpage": "Suradnička stranica za IP adresu pod kojom uređujete",
"tooltip-pt-mytalk": "Vaša stranica za razgovor",
- "tooltip-pt-anontalk": "Razgovor o uređivanjima s ove IP adrese",
+ "tooltip-pt-anontalk": "Rasprava o uređivanjima s ove IP adrese",
"tooltip-pt-preferences": "Vaše postavke",
"tooltip-pt-watchlist": "Popis stranica koje pratite.",
"tooltip-pt-mycontris": "Popis Vaših doprinosa",
"tooltip-pt-anoncontribs": "Popis uređivanja učinjenih s ove IP adrese",
- "tooltip-pt-login": "Predlažemo Vam da se prijavite, međutim nije obvezno.",
+ "tooltip-pt-login": "Predlažemo Vam da se prijavite, iako to nije obavezno",
"tooltip-pt-logout": "Odjavi se",
- "tooltip-pt-createaccount": "Predlažemo Vam mogućnost stvaranja računa i prijave, iako to nije nužno.",
+ "tooltip-pt-createaccount": "Predlažemo Vam da stvorite račun i prijavite se, iako to nije obavezno",
"tooltip-ca-talk": "Razgovorna stranica",
"tooltip-ca-edit": "Uredi ovu stranicu",
"tooltip-ca-addsection": "Dodaj novi odlomak",
"Archd",
"Empu",
"Dodolzk",
- "Fitoschido"
+ "Fitoschido",
+ "Palladin911"
]
},
"tog-underline": "Garis bawahi pranala:",
"watchlisttools-view": "Tampilkan perubahan terkait",
"watchlisttools-edit": "Tampilkan dan sunting daftar pantauan",
"watchlisttools-raw": "Sunting daftar pantauan mentah",
- "hijri-calendar-m1": "Muharram",
+ "hijri-calendar-m1": "Muharam",
"hijri-calendar-m2": "Safar",
- "hijri-calendar-m3": "Rabiul awal",
- "hijri-calendar-m4": "Rabiul akhir",
- "hijri-calendar-m5": "Jumadil awal",
- "hijri-calendar-m6": "Jumadil akhir",
+ "hijri-calendar-m3": "Rabiulawal",
+ "hijri-calendar-m4": "Rabiulakhir",
+ "hijri-calendar-m5": "Jumadilawal",
+ "hijri-calendar-m6": "Jumadilakhir",
"hijri-calendar-m7": "Rajab",
- "hijri-calendar-m8": "Sya'ban",
- "hijri-calendar-m9": "Ramadhan",
+ "hijri-calendar-m8": "Syakban",
+ "hijri-calendar-m9": "Ramadan",
"hijri-calendar-m10": "Syawal",
- "hijri-calendar-m11": "Dzulkaidah",
- "hijri-calendar-m12": "Dzulhijjah",
+ "hijri-calendar-m11": "Zulkaidah",
+ "hijri-calendar-m12": "Zulhijah",
"hebrew-calendar-m1": "Tisyri",
"hebrew-calendar-m2": "Markhesywan",
"hebrew-calendar-m3": "Kislew",
"right-minoredit": "Означување на уредувањата како ситни",
"right-move": "Преместување страници",
"right-move-subpages": "Преместување на страници со нивните потстраници",
- "right-move-rootuserpages": "Ð\9fÑ\80емеÑ\81Ñ\82Ñ\83ваÑ\9aе на оÑ\81новна коÑ\80иÑ\81ниÑ\87ка Ñ\81Ñ\82Ñ\80аниÑ\86а",
+ "right-move-rootuserpages": "Ð\9fÑ\80емеÑ\81Ñ\82Ñ\83ваÑ\9aе на оÑ\81новни коÑ\80иÑ\81ниÑ\87ки Ñ\81Ñ\82Ñ\80аниÑ\86и",
"right-move-categorypages": "Преместување на категориски страници",
"right-movefile": "Преместување на податотеки",
"right-suppressredirect": "Не прави пренасочување од старото име при преместување на страница",
"ntransclusions": "$1{{PLURAL:$1|पानावर|पानांवर}} वापर",
"specialpage-empty": "या अहवालाकरिता(रिपोर्ट)कोणताही निकाल नाही.",
"lonelypages": "पोरकी पाने",
- "lonelypagestext": "खालील पानांना {{SITENAME}}च्या इतर पानांकडून दुवा जोड झालेली नाही.",
+ "lonelypagestext": "खालील पानांना या {{SITENAME}}च्या इतर कोणत्याही पानांवरुन दुवा जोडण्यात आला नाही किंवा ती आंतरविन्यासित झाली नाहीत.",
"uncategorizedpages": "अवर्गीकृत पाने",
"uncategorizedcategories": "अवर्गीकृत वर्ग",
"uncategorizedimages": "अवर्गीकृत संचिका",
"wantedpages-summary": "ही,ज्यांना अधिकांश दुवे आहेत अश्या अस्तित्वात नसलेल्या पानांची यादी आहे. यात ती पाने वगळली आहेत, ज्यांना फक्त पुनर्निर्देशनाचा दुवा आहे. अस्तित्वात नसलेली पण पुनर्निर्देशनाने जोडलेली जी पाने आहेत, अश्यांच्या यादीसाठी [[{{#special:BrokenRedirects}}|मोडकी पुनर्निर्देशने असलेल्या पानांची यादी]] बघा.",
"wantedpages-badtitle": "परिणामाच्या यादीत अवैध शीर्षक: $1",
"wantedfiles": "पाहिजे असलेल्या संचिका",
- "wantedfiletext-cat": "पà¥\81ढà¥\80ल फाà¤\87लà¥\8dस वापरलà¥\8dया à¤\85सतà¥\80ल पण à¤\86ता à¤\85सà¥\8dतितà¥\8dवात नाहà¥\80त. बाहà¥\87रà¥\80ल ठिà¤\95ाणाà¤\82à¤\9aà¥\8dया फाà¤\87लà¥\8dस यà¥\87थà¥\87 दिसतात पण à¤\85सतà¥\80लà¤\9a à¤\85सà¥\87 नाहà¥\80. à¤\85शा फाà¤\87लà¥\8dस à¤\86ढळलà¥\8dयास वà¤\97ळलà¥\8dया à¤\9cातà¥\80ल. à¤\85तिरिà¤\95à¥\8dतपणà¥\87,à¤\85शà¥\80 पानà¥\87, à¤\9cà¥\8dयात à¤\9fाà¤\95लà¥\87लà¥\8dया सà¤\82à¤\9aिà¤\95ा à¤\85सà¥\8dतितà¥\8dवात नाहà¥\80त,त्याची यादी [[:$1]] येथे दिसेल.",
+ "wantedfiletext-cat": "पà¥\81ढà¥\80ल सà¤\82à¤\9aिà¤\95ा (फाà¤\87लà¥\8dस) वापरलà¥\8dया à¤\85सतà¥\80ल पण तà¥\8dया à¤\86ता à¤\85सà¥\8dतितà¥\8dवात नाहà¥\80त. बाहà¥\87रà¥\80ल ठिà¤\95ाणाà¤\82à¤\9aà¥\8dया सà¤\82à¤\9aिà¤\95ा (फाà¤\87लà¥\8dस) यà¥\87थà¥\87 दिसतात पण तà¥\8dया à¤\85सतà¥\80लà¤\9a à¤\85सà¥\87 नाहà¥\80. à¤\85शा सà¤\82à¤\9aिà¤\95ा (फाà¤\87लà¥\8dस) à¤\86ढळलà¥\8dयास वà¤\97ळलà¥\8dया à¤\9cातà¥\80ल. à¤\85तिरिà¤\95à¥\8dतपणà¥\87,à¤\85शà¥\80 पानà¥\87, à¤\9cà¥\8dयात à¤\9fाà¤\95लà¥\87लà¥\8dया सà¤\82à¤\9aिà¤\95ा à¤\85सà¥\8dतितà¥\8dवात नाहà¥\80त, त्याची यादी [[:$1]] येथे दिसेल.",
"wantedfiletext-nocat": "पुढील फाइल्स वापरल्या असतील पण आता अस्तित्वात नाहीत. बाहेरील ठिकाणांच्या फाइल्स येथे दिसतात पण असतीलच असे नाही. अशा फाइल्स आढळल्यास वगळल्या जातील.",
"wantedtemplates": "पाहिजे असलेले साचे",
"mostlinked": "सर्वाधिक जोडलेली पाने",
"protectedpages": "सुरक्षित पाने",
"protectedpages-indef": "फक्त अनंत काळासाठी सुरक्षित केलेले",
"protectedpages-summary": "या पानात,अस्तित्वात असणाऱ्या संरक्षित अशा पानाची यादी आहे.नवनिर्माणापासून संरक्षित शीर्षकांच्या यादीसाठी [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]] बघा.",
- "protectedpages-cascade": "à¤\95à¥\87वळ à¤\8fà¤\95ामà¥\87à¤\95ाà¤\82वर à¤\85वलà¤\82बà¥\82न à¤\95ास्केडींग सुरक्षा (सुरक्षा शिडी)",
+ "protectedpages-cascade": "à¤\95à¥\87वळ à¤\8fà¤\95ामà¥\87à¤\95ाà¤\82वर à¤\85वलà¤\82बà¥\82न à¤\95à¥\85स्केडींग सुरक्षा (सुरक्षा शिडी)",
"protectedpages-noredirect": "पुनर्निर्देशने लपवा",
"protectedpagesempty": "सध्या या नियमावलीने कोणतीही पाने सुरक्षित केलेली नाहीत.",
"protectedpages-timestamp": "वेळशिक्का",
"cannotcreateaccount-text": "တိုက်ရိုက် အကောင့်ဖန်တီးခြင်းအား ဤဝီကီပေါ်၌ ဖွင့်မထားပါ။",
"yourdomainname": "သင့်ဒိုမိန်း -",
"password-change-forbidden": "ဤဝီကီတွင် စကားဝှက်များကို ပြောင်းလဲ၍ မရပါ။",
- "login": "Log in ဝင်ရန်",
+ "login": "အကောင့်ထဲဝင်ရန်",
"login-security": "သင်၏ အထောက်အထားကို အတည်ပြုပါ",
- "nav-login-createaccount": "Log in ဝင်ရန်/ အကောင့် ဖန်တီးရန်",
+ "nav-login-createaccount": "အကောင့်ထဲဝင်ရန် / အကောင့်ဖန်တီးရန်",
"logout": "ထွက်ရန်",
"userlogout": "ထွက်ရန်",
- "notloggedin": "log in ဝင်မထားပါ",
+ "notloggedin": "အကောင့် မဝင်ထားပါ",
"userlogin-noaccount": "အကောင့် မရှိဘူးလား။",
"userlogin-joinproject": "{{SITENAME}} ကို ချိတ်ဆက်ရန်",
"createaccount": "အကောင့် ဖန်တီးရန်",
"oldpassword": "စကားဝှက် အဟောင်း -",
"newpassword": "စကားဝှက် အသစ် -",
"retypenew": "စကားဝှက် အသစ်ကို ထပ်ရိုက်ပါ -",
- "resetpass_submit": "စကားဝှက်ကို သတ်မှတ်ပြီးနောက် Log in ဝင်ရန်",
+ "resetpass_submit": "စကားဝှက်ကို သတ်မှတ်ပြီးနောက် အကောင့်ထဲဝင်ရန်",
"changepassword-success": "သင့်စကားဝှက်ကို ပြောင်းလဲပြီးပါပြီ!",
"changepassword-throttled": "သင်သည် login ဝင်ရန် အကြိမ်ပေါင်းများစွာ အားထုတ်ခဲ့ပြီးဖြစ်သည်။ ကျေးဇူးပြု၍ ထပ်မဝင်ခင် $1 စောင့်ပေးပါ။",
"botpasswords": "ဘော့ စကားဝှက်များ",
"uploadbtn": "ဖိုင်တင်ရန်",
"reuploaddesc": "Upload တင်နေခြင်းကို ဖျက်သိမ်းပြီး upload တင်သည့် ပုံစံသို့ ပြန်သွားရန်",
"upload-tryagain": "ပြုပြင်ထားသောဖိုင်၏ ဖော်ပြချက်ကို ထည့်သွင်းရန်",
- "uploadnologin": "logged in ဝင်မထားပါ",
+ "uploadnologin": "အကောင့် မဝင်ထားပါ",
"uploadnologintext": "ဖိုင်များကို တင်ရန် ကျေးဇူးပြု၍ $1 ပါ။",
"uploaderror": "အပ်လုပ်တင်ခြင်း အမှား",
"upload-recreate-warning": "<strong>သတိပေးချက်။ ဤအမည်ဖြင့်ဖိုင်သည် ဖျက်ထားခြင်း သို့မဟုတ် ရွေ့ပြောင်းထားခြင်း ခံထားရသည်။</strong>\n\nဖျက်ထားခြင်းနှင့် ရွေ့ပြောင်းထားခြင်း မှတ်တမ်းကို သိရှိနိုင်ရန် ဖော်ပြထားပါသည်။",
"mywatchlist": "စောင့်ကြည့်စာရင်း",
"watchlistfor2": "$1 အတွက် $2",
"nowatchlist": "သင့်စောင့်ကြည့်စာရင်းမှာ ဘာမှ မရှိပါ။",
- "watchnologin": "logged in ဝင်မထားပါ",
+ "watchnologin": "အကောင့် မဝင်ထားပါ",
"addwatch": "စောင့်ကြည့်စာရင်းသို့ ပေါင်းထည့်ရန်",
"addedwatchtext": "\"[[:$1]]\" နှင့် ၎င်း၏ ဆွေးနွေးချက် စာမျက်နှာကို သင်၏ [[Special:Watchlist|စောင့်ကြည့်စာရင်း]]ထဲသို့ ပေါင်းထည့်ပြီးဖြစ်သည်။",
"addedwatchtext-talk": "\"[[:$1]]\" နှင့် ယင်း၏ဆက်နွယ် စာမျက်နှာကို သင်၏ [[Special:Watchlist|စောင့်ကြည့်စာရင်း]]ထဲသို့ ပေါင်းထည့်ပြီးဖြစ်သည်။",
"blockipsuccesstext": "[[Special:Contributions/$1|$1]] ကို ပိတ်ပင်ထားပါသည်။<br />\nပိတ်ပင်မှုများကို ပြန်လည်ဆန်းစစ်ရန် [[Special:BlockList|ပိတ်ပင်မှု စာရင်း]]ကို ကြည့်ပါ။",
"ipb-blockingself": "သင့်ကိုယ်သင် ပိတ်ပင်တားဆီးတော့မည် ဖြစ်သည်။ ဤသည်ကို လုပ်ဆောင်လိုသည်မှာ သေချာပါသလား။",
"ipb-confirmaction": "ဤသည်ကို လုပ်ဆောင်လိုသည်မှာ သေချာပါက အောက်ခြေရှိ \"{{int:ipb-confirm}}\" ကွင်းအား ကျေးဇူးပြု၌ စစ်ဆေးပါ။",
- "ipb-edit-dropdown": "ပိတ်ပင်ရသောအကြောင်းရင်းများ",
+ "ipb-edit-dropdown": "ပိတ်ပင်ရသောအကြောင်းရင်းများကို ပြင်ဆင်ရန်",
"ipb-unblock-addr": "$1 ကို ပိတ်ထားရာမှ ပြန်ဖွင့်ရန်",
"ipb-unblock": "အသုံးပြုသူအမည် သို့ IP address ကို ပိတ်ထားရာမှ ပြန်ဖွင့်ပေးရန်",
"ipb-blocklist": "ရှိနှင့်ပြီးသား ပိတ်ပင်မှုများကို ကြည့်ရန်",
"savechanges": "Publiser endringane",
"publishpage": "Publiser sida",
"publishchanges": "Publiser endringar",
+ "publishpage-start": "Publiser side …",
+ "publishchanges-start": "Publiser endringar …",
"preview": "Førehandsvising",
"showpreview": "Førehandsvis",
"showdiff": "Sjå skilnader",
"postedit-confirmation-created": "Sida vart oppretta.",
"postedit-confirmation-restored": "Sida vart attoppretta.",
"postedit-confirmation-saved": "Endringa di vart lagra.",
+ "postedit-confirmation-published": "Endringa di vart publisert.",
"edit-already-exists": "Kunne ikkje opprette ny side fordi ho alt eksisterer.",
"defaultmessagetext": "Standard meldingstekst",
"content-failed-to-parse": "Klarte ikkje å tolke innhaldet «$2» for innhaldsmodellen «$1»: $3",
"tooltip-ca-nstab-category": "Vis kategoriside",
"tooltip-minoredit": "Merk endringa som småplukk",
"tooltip-save": "Lagra endringane dine",
+ "tooltip-publish": "Publiser endringane dine",
"tooltip-preview": "Førehandsvis endringane dine. Helst brukar du denne funksjonen før du lagrar.",
"tooltip-diff": "Sjå kva endringar du gjorde i teksten",
"tooltip-compareselectedversions": "Sjå endringane mellom dei valde versjonane av denne sida.",
"customcssprotected": "Nie jesteś uprawniony do edytowania tej strony CSS, ponieważ zawiera ona ustawienia osobiste innego użytkownika.",
"customjsonprotected": "Nie jesteś uprawniony do edytowania tej strony JSON, ponieważ zawiera ona ustawienia osobiste innego użytkownika.",
"customjsprotected": "Nie jesteś uprawniony do edytowania tej strony JavaScript, ponieważ zawiera ona ustawienia osobiste innego użytkownika.",
- "sitecssprotected": "Nie masz uprawnień do edytowania tej strony CSS, ponieważ może to wpłynąć na wszystkich odwiedzających",
- "sitejsonprotected": "Nie masz uprawnień do edytowania tej strony JSON, ponieważ może to wpłynąć na wszystkich odwiedzających",
- "sitejsprotected": "Nie masz uprawnień do edytowania tej strony JavaScript, ponieważ może to wpłynąć na wszystkich odwiedzających",
+ "sitecssprotected": "Nie masz uprawnień do edytowania tej strony CSS, ponieważ może to wpłynąć na wszystkich odwiedzających.",
+ "sitejsonprotected": "Nie masz uprawnień do edytowania tej strony JSON, ponieważ może to wpłynąć na wszystkich odwiedzających.",
+ "sitejsprotected": "Nie masz uprawnień do edytowania tej strony JavaScript, ponieważ może to wpłynąć na wszystkich odwiedzających.",
"mycustomcssprotected": "Nie masz uprawnień do edytowania tej strony CSS.",
"mycustomjsonprotected": "Nie masz uprawnień do edytowania tej strony JSON.",
"mycustomjsprotected": "Nie masz uprawnień do edytowania tej strony JavaScript.",
"customcssprotected": "Nu aveți permisiunea de a modifica această pagină CSS, deoarece conține setările personale ale altui utilizator.",
"customjsonprotected": "Nu aveți permisiunea de a modifica această pagină JSON, deoarece conține setările personale ale altui utilizator.",
"customjsprotected": "Nu aveți permisiunea de a modifica această pagină JavaScript, deoarece conține setările personale ale altui utilizator.",
- "sitecssprotected": "Nu aveți dreptul să editați această pagină CSS deoarece poate afecta toți vizitatorii",
- "sitejsonprotected": "Nu aveți dreptul să editați această pagină JSON deoarece poate afecta toți vizitatorii",
- "sitejsprotected": "Nu aveți dreptul să editați această pagină JavaScript deoarece poate afecta toți vizitatorii",
+ "sitecssprotected": "Nu aveți dreptul să editați această pagină CSS deoarece poate afecta toți vizitatorii.",
+ "sitejsonprotected": "Nu aveți dreptul să editați această pagină JSON deoarece poate afecta toți vizitatorii.",
+ "sitejsprotected": "Nu aveți dreptul să editați această pagină JavaScript deoarece poate afecta toți vizitatorii.",
"mycustomcssprotected": "Nu aveți permisiunea să modificați această pagină CSS.",
"mycustomjsonprotected": "Nu aveți permisiunea să modificați această pagină JSON.",
"mycustomjsprotected": "Nu aveți permisiunea să modificați această pagină JavaScript.",
"http-timed-out": "Cererea HTTP a expirat.",
"http-curl-error": "Eroare la preluarea adresei URL: $1",
"http-bad-status": "A apărut o problemă în timpul solicitării HTTP: $1 $2",
+ "http-internal-error": "Eroare internă HTTP.",
"upload-curl-error6": "Nu pot găsi adresa URL",
"upload-curl-error6-text": "Adresa URL introdusă nu a putut fi atinsă.\nVă rugăm, verificați că adresa URL este corectă și că situl este funcțional.",
"upload-curl-error28": "Încărcarea a expirat",
"protectedtitles-submit": "Afișează titlurile",
"listusers": "Listă utilizatori",
"listusers-editsonly": "Arată doar utilizatorii cu modificări",
+ "listusers-temporarygroupsonly": "Arată doar utilizatorii din grupuri temporare",
"listusers-creationsort": "Sortează după data creării",
"listusers-desc": "Sortează descrescător",
"usereditcount": "$1 {{PLURAL:$1|editare|editări}}",
"interlanguage-link-title-nonlang": "$1 – $2",
"common.css": "/** CSS plasate aici vor fi aplicate tuturor aparițiilor */",
"print.css": "/* CSS plasate aici vor afecta modul în care paginile vor fi imprimate */",
+ "common.json": "/* Orice JSON din această pagină va fi încărcat pentru toți utilizatorii la fiecare pagină încărcată. */",
"anonymous": "{{PLURAL:$1|Utilizator anonim|Utilizatori anonimi}} ai {{SITENAME}}",
"siteuser": "Utilizator {{SITENAME}} $1",
"anonuser": "utlizator anonim $1 al {{SITENAME}}",
"confirm-unwatch-top": "Eliminați această pagină din lista de pagini urmărite?",
"confirm-rollback-button": "OK",
"confirm-rollback-top": "Anulați editările asupra acestei pagini?",
+ "confirm-mcrundo-title": "Anulează o modificare",
+ "mcrundofailed": "Anularea nu a reușit",
+ "mcrundo-missingparam": "Lipsește un parametru necesar în cerere.",
+ "mcrundo-changed": "Această pagină a fost schimbată de când ați văzut diferența. Vă rugăm să revizuiți noua schimbare.",
"quotation-marks": "„$1”",
"imgmultipageprev": "← pagina anterioară",
"imgmultipagenext": "pagina următoare →",
"tags-delete-not-found": "Eticheta „$1” nu există.",
"tags-delete-too-many-uses": "Eticheta „$1” este aplicată pentru mai mult de $2 {{PLURAL:$2|versiune|versiuni|de versiuni}}, ceea ce înseamnă că nu poate fi ștearsă.",
"tags-delete-warnings-after-delete": "Eticheta „$1” a fost ștearsă, deși {{PLURAL:$2|s-a întâlnit următorul avertisment|s-au întâlnit următoarele avertismente}}:",
+ "tags-delete-no-permission": "Nu aveți permisiunea de a șterge etichetele.",
"tags-activate-title": "Activare etichetă",
"tags-activate-question": "Sunteți pe cale să activați eticheta „$1”.",
"tags-activate-reason": "Motiv:",
"search-category": "(ذمرو $1)",
"search-file-match": "(فائيل جي مواد سان ملي ٿو)",
"search-suggest": "ڇا توهان جو مطلب ھيو: $1",
+ "search-rewritten": "نتيجا براءِ $1. يا $2 بابت نتيجا ڏسو.",
"search-interwiki-caption": "برادر رٿائن مان نتيجا",
"search-interwiki-default": "$1 مان نتيجا",
"search-interwiki-more": "(وڌيڪ)",
"morenotlisted": "Ovaj spisak nije kompletan.",
"mypage": "Moja stranica",
"mytalk": "Razgovor",
- "anontalk": "Razgovor za ovu IP adresu",
+ "anontalk": "Razgovor",
"navigation": "Navigacija - Навигација",
"and": " i",
"faq": "ČPP",
"yourdomainname": "Vaš domen:",
"password-change-forbidden": "Ne možete da promenite lozinku na ovom vikiju.",
"externaldberror": "Došlo je do greške pri vanjskoj autorizaciji baze podataka ili vam nije dopušteno osvježavanje Vašeg vanjskog korisničkog računa.",
- "login": "Prijavi me - Пријави ме",
+ "login": "Prijava / Пријава",
"nav-login-createaccount": "Prijavi se / Registruj se",
"logout": "Odjava",
"userlogout": "Odjavi se / Одјави се",
"loginlanguagelabel": "Jezik: $1",
"suspicious-userlogout": "Vaš zahtjev za odjavu je odbijen jer je poslan preko pokvarenog preglednika ili keširanog proksija.",
"createacct-another-realname-tip": "Pravo ime nije obavezno.\nAko izaberete da date ime, biće korišteno za pripisivanje za vaš rad.",
- "pt-login": "Prijava",
+ "pt-login": "Prijavi me / Пријави ме",
"pt-login-button": "Prijavi me / Пријави ме",
"pt-createaccount": "Izradi račun",
"pt-userlogout": "Odjava",
"prefs-watchlist": "Lista praćenja",
"prefs-editwatchlist": "Uredi popis praćenja",
"prefs-editwatchlist-label": "Uredi unose na popisu praćenja:",
- "prefs-editwatchlist-edit": "Vidite i uklonite naslove na vašem popisu praćenja",
- "prefs-editwatchlist-raw": "Uredi grubi popis praćenja",
- "prefs-editwatchlist-clear": "očisti popis praćenja",
+ "prefs-editwatchlist-edit": "vidi i ukloni naslove s liste praćenja",
+ "prefs-editwatchlist-raw": "uredi sirovu listu praćenja",
+ "prefs-editwatchlist-clear": "očisti listu praćenja",
"prefs-watchlist-days": "Broj dana za prikaz u spisku praćenja:",
"prefs-watchlist-days-max": "(najviše $1 {{PLURAL:$1|dan|dana}})",
"prefs-watchlist-edits": "Najveći broj izmjena za prikaz u proširenom spisku praćenja:",
"namespace_association": "Povezan imenski prostor",
"tooltip-namespace_association": "Označite ovu kutiju da također uključite razgovor ili imenski prostor teme koja je povezana sa odabranim imenskim prostorom",
"blanknamespace": "(Glavno)",
- "contributions": "Doprinosi {{GENDER:$1|korisnika|korisnice|korisnika}}",
- "contributions-title": "Korisnički doprinosi od $1",
+ "contributions": "Doprinosi {{GENDER:$1|korisnika|korisnice}}",
+ "contributions-title": "Doprinosi {{GENDER:$1|korisnika|korisnice}} $1",
"mycontris": "Doprinosi",
"anoncontribs": "Doprinosi",
"contribsub2": "Za {{GENDER:$3|$1}} ($2)",
"sp-contributions-newbies-sub": "Prikaži samo doprinose novih korisnika",
"sp-contributions-newbies-title": "Doprinosi novih korisnika",
"sp-contributions-blocklog": "registar blokiranja",
- "sp-contributions-suppresslog": "obrisani doprinosi korisnika",
- "sp-contributions-deleted": "obrisani doprinosi korisnika",
+ "sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
+ "sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"sp-contributions-uploads": "postavljanja",
"sp-contributions-logs": "registri",
"sp-contributions-talk": "razgovor",
"tooltip-pt-userpage": "{{GENDER:|Vaša korisnička}} stranica",
"tooltip-pt-anonuserpage": "Korisnička stranica za ip koju Vi uređujete kao",
"tooltip-pt-mytalk": "{{GENDER:|Vaša}} stranica za razgovor",
- "tooltip-pt-anontalk": "Razgovor o doprinosu sa ove IP adrese",
+ "tooltip-pt-anontalk": "Rasprava o izmjenama s ove IP adrese",
"tooltip-pt-preferences": "{{GENDER:|Vaše}} postavke",
"tooltip-pt-watchlist": "Lista stranica čije izmjene pratite",
"tooltip-pt-mycontris": "Lista {{GENDER:|vaših}} doprinosa",
- "tooltip-pt-anoncontribs": "Lista uređenja napravljenih s ove IP adrese",
+ "tooltip-pt-anoncontribs": "Lista izmjena napravljenih s ove IP adrese",
"tooltip-pt-login": "Predlažem da se prijavite; međutim, to nije obavezno",
"tooltip-pt-logout": "Odjava sa projekta {{SITENAME}}",
- "tooltip-pt-createaccount": "Ohrabrujemo vas da otvorite račun i prijavite se; to, međutim, nije obavezno",
+ "tooltip-pt-createaccount": "Predlažemo vam da izradite račun i prijavite se, iako to nije obavezno",
"tooltip-ca-talk": "Diskusija o stranici sadržaja",
"tooltip-ca-edit": "Uredi ovu stranicu",
"tooltip-ca-addsection": "Započnite novu sekciju.",
"yourdomainname": "Домен:",
"password-change-forbidden": "Не можете да промените лозинку на овом викију.",
"externaldberror": "Дошло је до грешке при потврди идентитета базе података или вам није дозвољено да ажурирате свој спољни налог.",
- "login": "Ð\9fÑ\80иÑ\98ави ме",
+ "login": "Ð\9fÑ\80иÑ\98ава",
"login-security": "Потврда вашег индентитета",
"nav-login-createaccount": "Пријава/регистрација",
"logout": "Одјава",
"blockedtext": "<strong>Ваше корисничко име или IP адреса је блокирана.</strong>\n\nБлокирање је {{GENDER:$4|извршио|извршила}} $1.\nРазлог је <em>$2</em>.\n\n* Почетак блокирања: $8\n* Истек блокирања: $6\n* Блокирани: $7\n\nМожете да контактирате {{GENDER:$4|корисника|корисницу}} $1 или другог [[{{MediaWiki:Grouppage-sysop}}|администратора]] да бисте разговарали о блокирању.\nНе можете да користите могућност „{{int:emailuser}}” осим ако сте навели валидну имејл адресу у својим [[Special:Preferences|подешавањима налога]] и нисте блокирани од коришћења исте.\nВаша актуелна IP адреса је $3, а ID блокаде #$5.\nНаведите све горње детаље при прављењу било каквих упита.",
"autoblockedtext": "Ваша IP адреса је аутоматски блокирана јер ју је користио други корисник, кога је {{GENDER:$4|блокирао|блокирала}} $1.\nРазлог:\n\n:<em>$2</em>\n\n* Почетак блокаде: $8\n* Крај блокаде: $6\n* Име корисника: $7\n\nМожете да контактирате {{GENDER:$4|корисника|корисницу}} $1 или другог [[{{MediaWiki:Grouppage-sysop}}|администратора]] да бисте расправљали о блокади.\n\nЗапамтите да не можете да користите могућност „{{int:emailuser}}“ осим ако сте навели ваљану имејл адресу у својим [[Special:Preferences|подешавањима]].\n\nВаша актуелна IP адреса је $3, а ID блокаде $5.\nУкључите све горње детаље при прављењу било каквих упита.",
"blockednoreason": "разлог није наведен",
- "whitelistedittext": "За уређивање странице је потребно да будете $1.",
+ "whitelistedittext": "$1 да бисте уређивали странице.",
"confirmedittext": "Морате да потврдите своју имејл адресу пре уређивања страница.\nПоставите и потврдите имејл адресу преко [[Special:Preferences|подешавања]].",
"nosuchsectiontitle": "Не могу да пронађем одељак.",
"nosuchsectiontext": "Покушали сте да уредите одељак који не постоји.\nМожда је премештен или избрисан док сте прегледали страницу.",
"loginreqtitle": "Потребна је пријава",
- "loginreqlink": "пÑ\80иÑ\98авÑ\99ени",
- "loginreqpagetext": "Морате бити $1 да бисте видели друге странице.",
+ "loginreqlink": "Ð\9fÑ\80иÑ\98авиÑ\82е Ñ\81е",
+ "loginreqpagetext": "$1 да бисте видели друге странице.",
"accmailtitle": "Лозинка је послата.",
"accmailtext": "Лозинка за {{GENDER:$1|корисника|корисницу}} [[User talk:$1|$1]] је послата на $2. Након пријаве, лозинка се може променити [[Special:ChangePassword|овде]].",
"newarticle": "(нови)",
"hiddencategories": "Ова страница је члан {{PLURAL:$1|једне скривене категорије|$1 скривене категорије|$1 скривених категорија}}:",
"edittools": "<!-- Овај текст ће бити приказан испод обрасца за уређивање и отпремање. -->",
"edittools-upload": "-",
- "nocreatetext": "Ð\9dа овом викиÑ\98Ñ\83 Ñ\98е огÑ\80аниÑ\87ено пÑ\80авÑ\99еÑ\9aе новиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а.\nÐ\9cожеÑ\82е Ñ\81е вÑ\80аÑ\82иÑ\82и и Ñ\83Ñ\80едиÑ\82и поÑ\81Ñ\82оÑ\98еÑ\9bÑ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, или се [[Special:UserLogin|пријавите или отворите налог]].",
+ "nocreatetext": "Ð\9dа пÑ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}} Ñ\98е огÑ\80аниÑ\87ена могÑ\83Ñ\9bноÑ\81Ñ\82 пÑ\80авÑ\99еÑ\9aа новиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а.\nÐ\9cожеÑ\82е Ñ\81е вÑ\80аÑ\82иÑ\82и и Ñ\83Ñ\80едиÑ\82и поÑ\81Ñ\82оÑ\98еÑ\9bÑ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 или се [[Special:UserLogin|пријавите или отворите налог]].",
"nocreate-loggedin": "Немате дозволу да правите нове странице.",
"sectioneditnotsupported-title": "Уређивање одељка није подржано",
"sectioneditnotsupported-text": "Уређивање одељка није подржано на овој страници.",
"prefs-watchlist": "Списак надгледања",
"prefs-editwatchlist": "Уређивање списка надгледања",
"prefs-editwatchlist-label": "Уреди уносе на списку надгледања:",
- "prefs-editwatchlist-edit": "погледајте и уклоните наслове са списка надгледања",
+ "prefs-editwatchlist-edit": "погледај и уклони наслове са списка надгледања",
"prefs-editwatchlist-raw": "уреди сиров списак надгледања",
"prefs-editwatchlist-clear": "очисти списак надгледања",
"prefs-watchlist-days": "Број дана у списку надгледања:",
"upload-tryagain": "Пошаљи измењени опис датотеке",
"upload-tryagain-nostash": "Пошаљите ре-отпремљену датотеку и измењен опис",
"uploadnologin": "Нисте пријављени",
- "uploadnologintext": "Морате бити $1 да бисте отпремали датотеке.",
+ "uploadnologintext": "$1 да бисте отпремали датотеке.",
"upload_directory_missing": "Фасцикла за слање ($1) недостаје и сервер је не може направити.",
"upload_directory_read_only": "Сервер не може да пише по фасцикли за слање ($1).",
"uploaderror": "Грешка при отпремању",
"tooltip-pt-userpage": "{{GENDER:|Ваша}} корисничка страница",
"tooltip-pt-anonuserpage": "Корисничка страница за IP адресу с које уређујете",
"tooltip-pt-mytalk": "{{GENDER:|Ваша}} страница за разговор",
- "tooltip-pt-anontalk": "РазговоÑ\80 о изменама са ове IP адресе",
+ "tooltip-pt-anontalk": "Ð\94иÑ\81кÑ\83Ñ\81иÑ\98а о Ñ\83Ñ\80еÑ\92иваÑ\9aима са ове IP адресе",
"tooltip-pt-preferences": "{{GENDER:|Ваша}} подешавања",
"tooltip-pt-watchlist": "Списак страница које надгледате",
"tooltip-pt-mycontris": "Списак {{GENDER:|Ваших}} доприноса",
"yourdomainname": "Domen:",
"password-change-forbidden": "Ne možete da promenite lozinku na ovom vikiju.",
"externaldberror": "Došlo je do greške pri potvrdi identiteta baze podataka ili vam nije dozvoljeno da ažurirate svoj spoljni nalog.",
- "login": "Prijavi me",
+ "login": "Prijava",
"login-security": "Potvrda vašeg indentiteta",
"nav-login-createaccount": "Prijava/registracija",
"logout": "Odjava",
"prefs-watchlist": "Spisak nadgledanja",
"prefs-editwatchlist": "Uređivanje spiska nadgledanja",
"prefs-editwatchlist-label": "Uredi unose na spisku nadgledanja:",
- "prefs-editwatchlist-edit": "pogledajte i uklonite naslove sa spiska nadgledanja",
+ "prefs-editwatchlist-edit": "pogledaj i ukloni naslove sa spiska nadgledanja",
"prefs-editwatchlist-raw": "uredi sirov spisak nadgledanja",
"prefs-editwatchlist-clear": "očisti spisak nadgledanja",
"prefs-watchlist-days": "Broj dana u spisku nadgledanja:",
"tooltip-pt-userpage": "{{GENDER:|Vaša}} korisnička stranica",
"tooltip-pt-anonuserpage": "Korisnička stranica za IP adresu s koje uređujete",
"tooltip-pt-mytalk": "{{GENDER:|Vaša}} stranica za razgovor",
- "tooltip-pt-anontalk": "Razgovor o izmenama sa ove IP adrese",
+ "tooltip-pt-anontalk": "Diskusija o uređivanjima sa ove IP adrese",
"tooltip-pt-preferences": "{{GENDER:|Vaša}} podešavanja",
"tooltip-pt-watchlist": "Spisak stranica koje nadgledate",
"tooltip-pt-mycontris": "Spisak {{GENDER:|Vaših}} doprinosa",
"watchlistanontext": "Xin hãy đăng nhập để xem hay sửa đổi các trang trong danh sách theo dõi của bạn.",
"watchnologin": "Chưa đăng nhập",
"addwatch": "Thêm vào danh sách theo dõi",
- "addedwatchtext": "“[[:$1]]” cùng trang thảo luận đã vào [[Special:Watchlist|danh sách theo dõi]] của bạn.",
+ "addedwatchtext": "Trang “[[:$1]]” cùng trang thảo luận đã được thêm vào [[Special:Watchlist|danh sách theo dõi]] của bạn.",
"addedwatchtext-talk": "“[[:$1]]” cùng trang đi kèm đã vào [[Special:Watchlist|danh sách theo dõi]] của bạn.",
"addedwatchtext-short": "Trang “$1” đã được thêm vào danh sách theo dõi của bạn.",
"removewatch": "Gỡ khỏi danh sách theo dõi",
"category-file-count": "{{PLURAL:$2|Dins cisse categoreye ci, gn a k' ene pådje.|{{PLURAL:$1|Gn a cisse pådje ci|Gn a les $1 pådjes ki shuvèt}} dins cisse categoreye ci, po $2 pådjes å totå.}}",
"category-file-count-limited": "{{PLURAL:$1|Gn a k' cisse pådje cial|Gn a les $1 pådjes ciddé padzo}} dins cisse categoreye ci.",
"listingcontinuesabbrev": "(shûte)",
+ "broken-file-category": "Pådjes avou des hårdêyes esketêyes",
"about": "Åd fwait",
"article": "Årtike",
"newwindow": "(drovant en on novea purnea)",
"namespaceprotected": "侬无没编辑'''$1'''名字空间里向页面个权限。",
"customcssprotected": "箇CSS页你呒处编,箇页有各许用户个私人设置。",
"customjsprotected": "箇JavaScript页你呒处编,箇页有各许用户个私人设置。",
+ "sitecssprotected": "编箇CSS代码页面尔呒数呒箇权力,张页面会搭一切望个人有影响。",
+ "sitejsonprotected": "编箇JSON代码页面尔呒数呒箇权力,张页面会搭一切望个人有影响。",
+ "sitejsprotected": "编箇Javascript代码页面尔呒数呒箇权力,张页面会搭一切望个人有影响。",
"mycustomcssprotected": "箇CSS页你呒处编。",
"mycustomjsprotected": "箇JavaScript页你呒处编。",
"myprivateinfoprotected": "你个私人信息你呒处编。",
"search-external": "外部搜索",
"searchdisabled": "{{SITENAME}}个搜索已禁用。侬可以暂时使用Google搜索,须注意渠拉索引个{{SITENAME}}内容作兴会过时。",
"search-error": "搜寻辰光发生错误:$1",
+ "search-warning": "寻$1箇朞,有一个“警示”趒出。",
"preferences": "偏好",
"mypreferences": "偏好设定",
"prefs-edits": "编辑数量:",
"filehist-filesize": "文件大細",
"filehist-comment": "备注",
"imagelinks": "文件用法",
- "linkstoimage": "ä¸\8b头$1个页é\9d¢é\93¾å\88°箇文件:",
- "linkstoimage-more": "超过$1只{{PLURAL:$1|页面链接}}到该只文件。下底个单子只显示链接到该只文件个{{PLURAL:$1|头一只页面|头$1只页面}}。侬好望[[Special:WhatLinksHere/$2|完整个单子]]。",
- "nolinkstoimage": "å\91\92ä¸\8d页é\9d¢é\93¾æ\8e¥å\88°è¯¥å\8fª文件。",
+ "linkstoimage": "ä¸\8bå\90\91许$1{{PLURAL:$1|å¼ ç\94¨ç\9d\80}}箇文件:",
+ "linkstoimage-more": "超过$1{{PLURAL:$1|张数页面用着}}箇文件。\n玱朞畀用着箇文件个{{PLURAL:$1|头一张|前$1张}}放下向。\n张[[Special:WhatLinksHere/$2|单]]囥㙮,尔好望。",
+ "nolinkstoimage": "å\91\92ä¸\80页ç\94¨ç\9d\80ç®\87文件。",
"linkstoimage-redirect": "$1(文件轉戳到)$2",
"sharedupload": "箇只文件来源于$1,渠作兴垃拉其他项目当中畀应用。",
"sharedupload-desc-here": "箇文件$1里个,作兴会畀别个项目使用。渠个[$2 描述页]里个说明显示如下。",
"customcssprotected": "您没有权限编辑此CSS页面,因为它包含另一位用户的个人设置。",
"customjsonprotected": "您没有权限编辑此JSON页面,因为它包含另一位用户的个人设置。",
"customjsprotected": "您没有权限编辑此JavaScript页面,因为它包含另一位用户的个人设置。",
- "sitecssprotected": "您无权编辑此CSS页面,因为它可能会影响所有访问者",
- "sitejsonprotected": "您无权编辑此JSON页面,因为它可能会影响所有访问者",
- "sitejsprotected": "您无权编辑此JavaScript页面,因为它可能会影响所有访问者",
+ "sitecssprotected": "您无权编辑此CSS页面,因为它可能会影响所有访问者。",
+ "sitejsonprotected": "您无权编辑此JSON页面,因为它可能会影响所有访问者。",
+ "sitejsprotected": "您无权编辑此JavaScript页面,因为它可能会影响所有访问者。",
"mycustomcssprotected": "您没有权限编辑这个 CSS 页面。",
"mycustomjsonprotected": "您没有权限编辑这个JSON页面。",
"mycustomjsprotected": "您没有权限编辑这个 JavaScript 页面。",
package/dist/README.md:
jquery:
type: file
- src: https://code.jquery.com/jquery-3.2.1.js
+ src: https://code.jquery.com/jquery-3.3.1.js
# Integrity from link modals https://code.jquery.com/jquery/
- integrity: sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=
+ integrity: sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=
dest: jquery.js
qunitjs:
type: multi-file
'oojs-ui-core',
'mediawiki.widgets.visibleLengthLimit',
'mediawiki.api',
+ 'mediawiki.util',
],
],
'mediawiki.action.edit.styles' => [
/*!
- * jQuery JavaScript Library v3.2.1
+ * jQuery JavaScript Library v3.3.1
* https://jquery.com/
*
* Includes Sizzle.js
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2017-03-20T18:59Z
+ * Date: 2018-01-20T17:24Z
*/
( function( global, factory ) {
var support = {};
+var isFunction = function isFunction( obj ) {
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML <object> elements
+ // (i.e., `typeof document.createElement( "object" ) === "function"`).
+ // We don't want to classify *any* DOM node as a function.
+ return typeof obj === "function" && typeof obj.nodeType !== "number";
+ };
- function DOMEval( code, doc ) {
+
+var isWindow = function isWindow( obj ) {
+ return obj != null && obj === obj.window;
+ };
+
+
+
+
+ var preservedScriptAttributes = {
+ type: true,
+ src: true,
+ noModule: true
+ };
+
+ function DOMEval( code, doc, node ) {
doc = doc || document;
- var script = doc.createElement( "script" );
+ var i,
+ script = doc.createElement( "script" );
script.text = code;
+ if ( node ) {
+ for ( i in preservedScriptAttributes ) {
+ if ( node[ i ] ) {
+ script[ i ] = node[ i ];
+ }
+ }
+ }
doc.head.appendChild( script ).parentNode.removeChild( script );
}
+
+
+function toType( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+
+ // Support: Android <=2.3 only (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+}
/* global Symbol */
// Defining this global in .eslintrc.json would create a danger of using the global
// unguarded in another place, it seems safer to define global only for this module
var
- version = "3.2.1",
+ version = "3.3.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // Matches dashed string for camelizing
- rmsPrefix = /^-ms-/,
- rdashAlpha = /-([a-z])/g,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return letter.toUpperCase();
- };
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
jQuery.fn = jQuery.prototype = {
}
// Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
+ if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
noop: function() {},
- isFunction: function( obj ) {
- return jQuery.type( obj ) === "function";
- },
-
- isWindow: function( obj ) {
- return obj != null && obj === obj.window;
- },
-
- isNumeric: function( obj ) {
-
- // As of jQuery 3.0, isNumeric is limited to
- // strings and numbers (primitives or objects)
- // that can be coerced to finite numbers (gh-2662)
- var type = jQuery.type( obj );
- return ( type === "number" || type === "string" ) &&
-
- // parseFloat NaNs numeric-cast false positives ("")
- // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
- // subtraction forces infinities to NaN
- !isNaN( obj - parseFloat( obj ) );
- },
-
isPlainObject: function( obj ) {
var proto, Ctor;
return true;
},
- type: function( obj ) {
- if ( obj == null ) {
- return obj + "";
- }
-
- // Support: Android <=2.3 only (functionish RegExp)
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ toString.call( obj ) ] || "object" :
- typeof obj;
- },
-
// Evaluates a script in a global context
globalEval: function( code ) {
DOMEval( code );
},
- // Convert dashed to camelCase; used by the css and data modules
- // Support: IE <=9 - 11, Edge 12 - 13
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
each: function( obj, callback ) {
var length, i = 0;
// A global GUID counter for objects
guid: 1,
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- var tmp, args, proxy;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- args = slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- },
-
- now: Date.now,
-
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support: support
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var length = !!obj && "length" in obj && obj.length,
- type = jQuery.type( obj );
+ type = toType( obj );
- if ( type === "function" || jQuery.isWindow( obj ) ) {
+ if ( isFunction( obj ) || isWindow( obj ) ) {
return false;
}
-var risSimple = /^.[^:#\[\.,]*$/;
-
// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
- if ( jQuery.isFunction( qualifier ) ) {
+ if ( isFunction( qualifier ) ) {
return jQuery.grep( elements, function( elem, i ) {
return !!qualifier.call( elem, i, elem ) !== not;
} );
} );
}
- // Simple selector that can be filtered directly, removing non-Elements
- if ( risSimple.test( qualifier ) ) {
- return jQuery.filter( qualifier, elements, not );
- }
-
- // Complex selector, compare the two sets, removing non-Elements
- qualifier = jQuery.filter( qualifier, elements );
- return jQuery.grep( elements, function( elem ) {
- return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;
- } );
+ // Filtered directly for both simple and complex selectors
+ return jQuery.filter( qualifier, elements, not );
}
jQuery.filter = function( expr, elems, not ) {
for ( match in context ) {
// Properties of context are called as methods if possible
- if ( jQuery.isFunction( this[ match ] ) ) {
+ if ( isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
// ...and otherwise set as attributes
// HANDLE: $(function)
// Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
+ } else if ( isFunction( selector ) ) {
return root.ready !== undefined ?
root.ready( selector ) :
( function add( args ) {
jQuery.each( args, function( _, arg ) {
- if ( jQuery.isFunction( arg ) ) {
+ if ( isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
- } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
+ } else if ( arg && arg.length && toType( arg ) !== "string" ) {
// Inspect recursively
add( arg );
try {
// Check for promise aspect first to privilege synchronous behavior
- if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
+ if ( value && isFunction( ( method = value.promise ) ) ) {
method.call( value ).done( resolve ).fail( reject );
// Other thenables
- } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
+ } else if ( value && isFunction( ( method = value.then ) ) ) {
method.call( value, resolve, reject );
// Other non-thenables
jQuery.each( tuples, function( i, tuple ) {
// Map tuples (progress, done, fail) to arguments (done, fail, progress)
- var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+ var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
// deferred.progress(function() { bind to newDefer or newDefer.notify })
// deferred.done(function() { bind to newDefer or newDefer.resolve })
// deferred.fail(function() { bind to newDefer or newDefer.reject })
deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
+ if ( returned && isFunction( returned.promise ) ) {
returned.promise()
.progress( newDefer.notify )
.done( newDefer.resolve )
returned.then;
// Handle a returned thenable
- if ( jQuery.isFunction( then ) ) {
+ if ( isFunction( then ) ) {
// Special processors (notify) just wait for resolution
if ( special ) {
resolve(
0,
newDefer,
- jQuery.isFunction( onProgress ) ?
+ isFunction( onProgress ) ?
onProgress :
Identity,
newDefer.notifyWith
resolve(
0,
newDefer,
- jQuery.isFunction( onFulfilled ) ?
+ isFunction( onFulfilled ) ?
onFulfilled :
Identity
)
resolve(
0,
newDefer,
- jQuery.isFunction( onRejected ) ?
+ isFunction( onRejected ) ?
onRejected :
Thrower
)
// fulfilled_callbacks.disable
tuples[ 3 - i ][ 2 ].disable,
+ // rejected_handlers.disable
+ // fulfilled_handlers.disable
+ tuples[ 3 - i ][ 3 ].disable,
+
// progress_callbacks.lock
- tuples[ 0 ][ 2 ].lock
+ tuples[ 0 ][ 2 ].lock,
+
+ // progress_handlers.lock
+ tuples[ 0 ][ 3 ].lock
);
}
// Use .then() to unwrap secondary thenables (cf. gh-3000)
if ( master.state() === "pending" ||
- jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+ isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
return master.then();
}
bulk = key == null;
// Sets many values
- if ( jQuery.type( key ) === "object" ) {
+ if ( toType( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[ i ], true, emptyGet, raw );
} else if ( value !== undefined ) {
chainable = true;
- if ( !jQuery.isFunction( value ) ) {
+ if ( !isFunction( value ) ) {
raw = true;
}
return len ? fn( elems[ 0 ], key ) : emptyGet;
};
+
+
+// Matches dashed string for camelizing
+var rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([a-z])/g;
+
+// Used by camelCase as callback to replace()
+function fcamelCase( all, letter ) {
+ return letter.toUpperCase();
+}
+
+// Convert dashed to camelCase; used by the css and data modules
+// Support: IE <=9 - 11, Edge 12 - 15
+// Microsoft forgot to hump their vendor prefix (#9572)
+function camelCase( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+}
var acceptData = function( owner ) {
// Accepts only:
// Handle: [ owner, key, value ] args
// Always use camelCase key (gh-2257)
if ( typeof data === "string" ) {
- cache[ jQuery.camelCase( data ) ] = value;
+ cache[ camelCase( data ) ] = value;
// Handle: [ owner, { properties } ] args
} else {
// Copy the properties one-by-one to the cache object
for ( prop in data ) {
- cache[ jQuery.camelCase( prop ) ] = data[ prop ];
+ cache[ camelCase( prop ) ] = data[ prop ];
}
}
return cache;
this.cache( owner ) :
// Always use camelCase key (gh-2257)
- owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
+ owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
},
access: function( owner, key, value ) {
// If key is an array of keys...
// We always set camelCase keys, so remove that.
- key = key.map( jQuery.camelCase );
+ key = key.map( camelCase );
} else {
- key = jQuery.camelCase( key );
+ key = camelCase( key );
// If a key with the spaces exists, use it.
// Otherwise, create an array by matching non-whitespace
if ( attrs[ i ] ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
- name = jQuery.camelCase( name.slice( 5 ) );
+ name = camelCase( name.slice( 5 ) );
dataAttr( elem, name, data[ name ] );
}
}
function adjustCSS( elem, prop, valueParts, tween ) {
- var adjusted,
- scale = 1,
+ var adjusted, scale,
maxIterations = 20,
currentValue = tween ?
function() {
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+ // Support: Firefox <=54
+ // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
+ initial = initial / 2;
+
// Trust units reported by jQuery.css
unit = unit || initialInUnit[ 3 ];
- // Make sure we update the tween properties later on
- valueParts = valueParts || [];
-
// Iteratively approximate from a nonzero starting point
initialInUnit = +initial || 1;
- do {
+ while ( maxIterations-- ) {
- // If previous iteration zeroed out, double until we get *something*.
- // Use string for doubling so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- initialInUnit = initialInUnit / scale;
+ // Evaluate and update our best guess (doubling guesses that zero out).
+ // Finish if the scale equals or crosses 1 (making the old*new product non-positive).
jQuery.style( elem, prop, initialInUnit + unit );
+ if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
+ maxIterations = 0;
+ }
+ initialInUnit = initialInUnit / scale;
- // Update scale, tolerating zero or NaN from tween.cur()
- // Break the loop if scale is unchanged or perfect, or if we've just had enough.
- } while (
- scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
- );
+ }
+
+ initialInUnit = initialInUnit * 2;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
}
if ( valueParts ) {
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
-var rscriptType = ( /^$|\/(?:java|ecma)script/i );
+var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
if ( elem || elem === 0 ) {
// Add nodes directly
- if ( jQuery.type( elem ) === "object" ) {
+ if ( toType( elem ) === "object" ) {
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
enumerable: true,
configurable: true,
- get: jQuery.isFunction( hook ) ?
+ get: isFunction( hook ) ?
function() {
if ( this.originalEvent ) {
return hook( this.originalEvent );
}
// Create a timestamp if incoming event doesn't have one
- this.timeStamp = src && src.timeStamp || jQuery.now();
+ this.timeStamp = src && src.timeStamp || Date.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
/* eslint-enable */
- // Support: IE <=10 - 11, Edge 12 - 13
+ // Support: IE <=10 - 11, Edge 12 - 13 only
// In IE/Edge using regex groups here causes severe slowdowns.
// See https://connect.microsoft.com/IE/feedback/details/1736512/
rnoInnerhtml = /<script|<style|<link/i,
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptTypeMasked = /^true\/(.*)/,
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
// Prefer a tbody over its parent table for containing new rows
if ( nodeName( elem, "table" ) &&
nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
- return jQuery( ">tbody", elem )[ 0 ] || elem;
+ return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
}
return elem;
return elem;
}
function restoreScript( elem ) {
- var match = rscriptTypeMasked.exec( elem.type );
-
- if ( match ) {
- elem.type = match[ 1 ];
+ if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
+ elem.type = elem.type.slice( 5 );
} else {
elem.removeAttribute( "type" );
}
l = collection.length,
iNoClone = l - 1,
value = args[ 0 ],
- isFunction = jQuery.isFunction( value );
+ valueIsFunction = isFunction( value );
// We can't cloneNode fragments that contain checked, in WebKit
- if ( isFunction ||
+ if ( valueIsFunction ||
( l > 1 && typeof value === "string" &&
!support.checkClone && rchecked.test( value ) ) ) {
return collection.each( function( index ) {
var self = collection.eq( index );
- if ( isFunction ) {
+ if ( valueIsFunction ) {
args[ 0 ] = value.call( this, index, self.html() );
}
domManip( self, args, callback, ignored );
!dataPriv.access( node, "globalEval" ) &&
jQuery.contains( doc, node ) ) {
- if ( node.src ) {
+ if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
// Optional AJAX dependency, but won't run scripts if not present
if ( jQuery._evalUrl ) {
jQuery._evalUrl( node.src );
}
} else {
- DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
+ DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );
}
}
}
return this.pushStack( ret );
};
} );
-var rmargin = ( /^margin/ );
-
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
var getStyles = function( elem ) {
return view.getComputedStyle( elem );
};
+var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
+
( function() {
return;
}
+ container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
+ "margin-top:1px;padding:0;border:0";
div.style.cssText =
- "box-sizing:border-box;" +
- "position:relative;display:block;" +
+ "position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
"margin:auto;border:1px;padding:1px;" +
- "top:1%;width:50%";
- div.innerHTML = "";
- documentElement.appendChild( container );
+ "width:60%;top:1%";
+ documentElement.appendChild( container ).appendChild( div );
var divStyle = window.getComputedStyle( div );
pixelPositionVal = divStyle.top !== "1%";
// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
- reliableMarginLeftVal = divStyle.marginLeft === "2px";
- boxSizingReliableVal = divStyle.width === "4px";
+ reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
- // Support: Android 4.0 - 4.3 only
+ // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
// Some styles come back with percentage values, even though they shouldn't
- div.style.marginRight = "50%";
- pixelMarginRightVal = divStyle.marginRight === "4px";
+ div.style.right = "60%";
+ pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
+
+ // Support: IE 9 - 11 only
+ // Detect misreporting of content dimensions for box-sizing:border-box elements
+ boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
+
+ // Support: IE 9 only
+ // Detect overflow:scroll screwiness (gh-3699)
+ div.style.position = "absolute";
+ scrollboxSizeVal = div.offsetWidth === 36 || "absolute";
documentElement.removeChild( container );
div = null;
}
- var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
+ function roundPixelMeasures( measure ) {
+ return Math.round( parseFloat( measure ) );
+ }
+
+ var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
+ reliableMarginLeftVal,
container = document.createElement( "div" ),
div = document.createElement( "div" );
div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
- container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
- "padding:0;margin-top:1px;position:absolute";
- container.appendChild( div );
-
jQuery.extend( support, {
- pixelPosition: function() {
- computeStyleTests();
- return pixelPositionVal;
- },
boxSizingReliable: function() {
computeStyleTests();
return boxSizingReliableVal;
},
- pixelMarginRight: function() {
+ pixelBoxStyles: function() {
+ computeStyleTests();
+ return pixelBoxStylesVal;
+ },
+ pixelPosition: function() {
computeStyleTests();
- return pixelMarginRightVal;
+ return pixelPositionVal;
},
reliableMarginLeft: function() {
computeStyleTests();
return reliableMarginLeftVal;
+ },
+ scrollboxSize: function() {
+ computeStyleTests();
+ return scrollboxSizeVal;
}
} );
} )();
// but width seems to be reliably pixels.
// This is against the CSSOM draft spec:
// https://drafts.csswg.org/cssom/#resolved-values
- if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+ if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
// Remember the original values
width = style.width;
value;
}
-function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
- var i,
- val = 0;
-
- // If we already have the right measurement, avoid augmentation
- if ( extra === ( isBorderBox ? "border" : "content" ) ) {
- i = 4;
+function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
+ var i = dimension === "width" ? 1 : 0,
+ extra = 0,
+ delta = 0;
- // Otherwise initialize for horizontal or vertical properties
- } else {
- i = name === "width" ? 1 : 0;
+ // Adjustment may not be necessary
+ if ( box === ( isBorderBox ? "border" : "content" ) ) {
+ return 0;
}
for ( ; i < 4; i += 2 ) {
- // Both box models exclude margin, so add it if we want it
- if ( extra === "margin" ) {
- val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ // Both box models exclude margin
+ if ( box === "margin" ) {
+ delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
}
- if ( isBorderBox ) {
+ // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
+ if ( !isBorderBox ) {
- // border-box includes padding, so remove it if we want content
- if ( extra === "content" ) {
- val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- }
+ // Add padding
+ delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- // At this point, extra isn't border nor margin, so remove border
- if ( extra !== "margin" ) {
- val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ // For "border" or "margin", add border
+ if ( box !== "padding" ) {
+ delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+
+ // But still keep track of it otherwise
+ } else {
+ extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
+
+ // If we get here with a border-box (content + padding + border), we're seeking "content" or
+ // "padding" or "margin"
} else {
- // At this point, extra isn't content, so add padding
- val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ // For "content", subtract padding
+ if ( box === "content" ) {
+ delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
- // At this point, extra isn't content nor padding, so add border
- if ( extra !== "padding" ) {
- val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ // For "content" or "padding", subtract border
+ if ( box !== "margin" ) {
+ delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
}
}
- return val;
+ // Account for positive content-box scroll gutter when requested by providing computedVal
+ if ( !isBorderBox && computedVal >= 0 ) {
+
+ // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
+ // Assuming integer scroll gutter, subtract the rest and round down
+ delta += Math.max( 0, Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ computedVal -
+ delta -
+ extra -
+ 0.5
+ ) );
+ }
+
+ return delta;
}
-function getWidthOrHeight( elem, name, extra ) {
+function getWidthOrHeight( elem, dimension, extra ) {
// Start with computed style
- var valueIsBorderBox,
- styles = getStyles( elem ),
- val = curCSS( elem, name, styles ),
- isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+ var styles = getStyles( elem ),
+ val = curCSS( elem, dimension, styles ),
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ valueIsBorderBox = isBorderBox;
- // Computed unit is not pixels. Stop here and return.
+ // Support: Firefox <=54
+ // Return a confounding non-pixel value or feign ignorance, as appropriate.
if ( rnumnonpx.test( val ) ) {
- return val;
+ if ( !extra ) {
+ return val;
+ }
+ val = "auto";
}
// Check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
- valueIsBorderBox = isBorderBox &&
- ( support.boxSizingReliable() || val === elem.style[ name ] );
+ valueIsBorderBox = valueIsBorderBox &&
+ ( support.boxSizingReliable() || val === elem.style[ dimension ] );
- // Fall back to offsetWidth/Height when value is "auto"
+ // Fall back to offsetWidth/offsetHeight when value is "auto"
// This happens for inline elements with no explicit setting (gh-3571)
- if ( val === "auto" ) {
- val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ];
+ // Support: Android <=4.1 - 4.3 only
+ // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
+ if ( val === "auto" ||
+ !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) {
+
+ val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ];
+
+ // offsetWidth/offsetHeight provide border-box values
+ valueIsBorderBox = true;
}
- // Normalize "", auto, and prepare for extra
+ // Normalize "" and auto
val = parseFloat( val ) || 0;
- // Use the active box-sizing model to add/subtract irrelevant styles
+ // Adjust for the element's box model
return ( val +
- augmentWidthOrHeight(
+ boxModelAdjustment(
elem,
- name,
+ dimension,
extra || ( isBorderBox ? "border" : "content" ),
valueIsBorderBox,
- styles
+ styles,
+
+ // Provide the current computed size to request scroll gutter calculation (gh-3589)
+ val
)
) + "px";
}
// Add in properties whose names you wish to fix before
// setting or getting the value
- cssProps: {
- "float": "cssFloat"
- },
+ cssProps: {},
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
// Make sure that we're working with the right name
var ret, type, hooks,
- origName = jQuery.camelCase( name ),
+ origName = camelCase( name ),
isCustomProp = rcustomProp.test( name ),
style = elem.style;
css: function( elem, name, extra, styles ) {
var val, num, hooks,
- origName = jQuery.camelCase( name ),
+ origName = camelCase( name ),
isCustomProp = rcustomProp.test( name );
// Make sure that we're working with the right name. We don't
}
} );
-jQuery.each( [ "height", "width" ], function( i, name ) {
- jQuery.cssHooks[ name ] = {
+jQuery.each( [ "height", "width" ], function( i, dimension ) {
+ jQuery.cssHooks[ dimension ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
// in IE throws an error.
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
swap( elem, cssShow, function() {
- return getWidthOrHeight( elem, name, extra );
+ return getWidthOrHeight( elem, dimension, extra );
} ) :
- getWidthOrHeight( elem, name, extra );
+ getWidthOrHeight( elem, dimension, extra );
}
},
set: function( elem, value, extra ) {
var matches,
- styles = extra && getStyles( elem ),
- subtract = extra && augmentWidthOrHeight(
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ subtract = extra && boxModelAdjustment(
elem,
- name,
+ dimension,
extra,
- jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ isBorderBox,
styles
);
+ // Account for unreliable border-box dimensions by comparing offset* to computed and
+ // faking a content-box to get border and padding (gh-3699)
+ if ( isBorderBox && support.scrollboxSize() === styles.position ) {
+ subtract -= Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ parseFloat( styles[ dimension ] ) -
+ boxModelAdjustment( elem, dimension, "border", false, styles ) -
+ 0.5
+ );
+ }
+
// Convert to pixels if value adjustment is needed
if ( subtract && ( matches = rcssNum.exec( value ) ) &&
( matches[ 3 ] || "px" ) !== "px" ) {
- elem.style[ name ] = value;
- value = jQuery.css( elem, name );
+ elem.style[ dimension ] = value;
+ value = jQuery.css( elem, dimension );
}
return setPositiveNumber( elem, value, subtract );
}
};
- if ( !rmargin.test( prefix ) ) {
+ if ( prefix !== "margin" ) {
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
}
} );
window.setTimeout( function() {
fxNow = undefined;
} );
- return ( fxNow = jQuery.now() );
+ return ( fxNow = Date.now() );
}
// Generate parameters to create a standard animation
// Restrict "overflow" and "display" styles during box animations
if ( isBox && elem.nodeType === 1 ) {
- // Support: IE <=9 - 11, Edge 12 - 13
+ // Support: IE <=9 - 11, Edge 12 - 15
// Record all 3 overflow attributes because IE does not infer the shorthand
- // from identically-valued overflowX and overflowY
+ // from identically-valued overflowX and overflowY and Edge just mirrors
+ // the overflowX value there.
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
// Identify a display type, preferring old show/hide data over the CSS cascade
// camelCase, specialEasing and expand cssHook pass
for ( index in props ) {
- name = jQuery.camelCase( index );
+ name = camelCase( index );
easing = specialEasing[ name ];
value = props[ index ];
if ( Array.isArray( value ) ) {
for ( ; index < length; index++ ) {
result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
if ( result ) {
- if ( jQuery.isFunction( result.stop ) ) {
+ if ( isFunction( result.stop ) ) {
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
- jQuery.proxy( result.stop, result );
+ result.stop.bind( result );
}
return result;
}
jQuery.map( props, createTween, animation );
- if ( jQuery.isFunction( animation.opts.start ) ) {
+ if ( isFunction( animation.opts.start ) ) {
animation.opts.start.call( elem, animation );
}
},
tweener: function( props, callback ) {
- if ( jQuery.isFunction( props ) ) {
+ if ( isFunction( props ) ) {
callback = props;
props = [ "*" ];
} else {
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
+ isFunction( speed ) && speed,
duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ easing: fn && easing || easing && !isFunction( easing ) && easing
};
// Go to the end state if fx are off
opt.old = opt.complete;
opt.complete = function() {
- if ( jQuery.isFunction( opt.old ) ) {
+ if ( isFunction( opt.old ) ) {
opt.old.call( this );
}
i = 0,
timers = jQuery.timers;
- fxNow = jQuery.now();
+ fxNow = Date.now();
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
// Strip and collapse whitespace according to HTML spec
- // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace
+ // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
function stripAndCollapse( value ) {
var tokens = value.match( rnothtmlwhite ) || [];
return tokens.join( " " );
return elem.getAttribute && elem.getAttribute( "class" ) || "";
}
+function classesToArray( value ) {
+ if ( Array.isArray( value ) ) {
+ return value;
+ }
+ if ( typeof value === "string" ) {
+ return value.match( rnothtmlwhite ) || [];
+ }
+ return [];
+}
+
jQuery.fn.extend( {
addClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
- if ( jQuery.isFunction( value ) ) {
+ if ( isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
} );
}
- if ( typeof value === "string" && value ) {
- classes = value.match( rnothtmlwhite ) || [];
+ classes = classesToArray( value );
+ if ( classes.length ) {
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
- if ( jQuery.isFunction( value ) ) {
+ if ( isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
} );
return this.attr( "class", "" );
}
- if ( typeof value === "string" && value ) {
- classes = value.match( rnothtmlwhite ) || [];
+ classes = classesToArray( value );
+ if ( classes.length ) {
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
},
toggleClass: function( value, stateVal ) {
- var type = typeof value;
+ var type = typeof value,
+ isValidValue = type === "string" || Array.isArray( value );
- if ( typeof stateVal === "boolean" && type === "string" ) {
+ if ( typeof stateVal === "boolean" && isValidValue ) {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
- if ( jQuery.isFunction( value ) ) {
+ if ( isFunction( value ) ) {
return this.each( function( i ) {
jQuery( this ).toggleClass(
value.call( this, i, getClass( this ), stateVal ),
return this.each( function() {
var className, i, self, classNames;
- if ( type === "string" ) {
+ if ( isValidValue ) {
// Toggle individual class names
i = 0;
self = jQuery( this );
- classNames = value.match( rnothtmlwhite ) || [];
+ classNames = classesToArray( value );
while ( ( className = classNames[ i++ ] ) ) {
jQuery.fn.extend( {
val: function( value ) {
- var hooks, ret, isFunction,
+ var hooks, ret, valueIsFunction,
elem = this[ 0 ];
if ( !arguments.length ) {
return;
}
- isFunction = jQuery.isFunction( value );
+ valueIsFunction = isFunction( value );
return this.each( function( i ) {
var val;
return;
}
- if ( isFunction ) {
+ if ( valueIsFunction ) {
val = value.call( this, i, jQuery( this ).val() );
} else {
val = value;
// Return jQuery for attributes-only inclusion
-var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
+support.focusin = "onfocusin" in window;
+
+
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ stopPropagationCallback = function( e ) {
+ e.stopPropagation();
+ };
jQuery.extend( jQuery.event, {
trigger: function( event, data, elem, onlyHandlers ) {
- var i, cur, tmp, bubbleType, ontype, handle, special,
+ var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
eventPath = [ elem || document ],
type = hasOwn.call( event, "type" ) ? event.type : event,
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
- cur = tmp = elem = elem || document;
+ cur = lastElement = tmp = elem = elem || document;
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+ if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
bubbleType = special.delegateType || type;
if ( !rfocusMorph.test( bubbleType + type ) ) {
// Fire handlers on the event path
i = 0;
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
-
+ lastElement = cur;
event.type = i > 1 ?
bubbleType :
special.bindType || type;
// Call a native DOM method on the target with the same name as the event.
// Don't do default actions on window, that's where global variables be (#6170)
- if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+ if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
// Don't re-trigger an onFOO event when we call its FOO() method
tmp = elem[ ontype ];
// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.addEventListener( type, stopPropagationCallback );
+ }
+
elem[ type ]();
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.removeEventListener( type, stopPropagationCallback );
+ }
+
jQuery.event.triggered = undefined;
if ( tmp ) {
} );
-jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup contextmenu" ).split( " " ),
- function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- return arguments.length > 0 ?
- this.on( name, null, data, fn ) :
- this.trigger( name );
- };
-} );
-
-jQuery.fn.extend( {
- hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- }
-} );
-
-
-
-
-support.focusin = "onfocusin" in window;
-
-
// Support: Firefox <=44
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
}
var location = window.location;
-var nonce = jQuery.now();
+var nonce = Date.now();
var rquery = ( /\?/ );
}
} );
- } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ } else if ( !traditional && toType( obj ) === "object" ) {
// Serialize object item.
for ( name in obj ) {
add = function( key, valueOrFunction ) {
// If value is a function, invoke it and use its return value
- var value = jQuery.isFunction( valueOrFunction ) ?
+ var value = isFunction( valueOrFunction ) ?
valueOrFunction() :
valueOrFunction;
i = 0,
dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
- if ( jQuery.isFunction( func ) ) {
+ if ( isFunction( func ) ) {
// For each dataType in the dataTypeExpression
while ( ( dataType = dataTypes[ i++ ] ) ) {
if ( s.crossDomain == null ) {
urlAnchor = document.createElement( "a" );
- // Support: IE <=8 - 11, Edge 12 - 13
+ // Support: IE <=8 - 11, Edge 12 - 15
// IE throws exception on accessing the href property if url is malformed,
// e.g. http://example.com:80x/
try {
// Remember the hash so we can put it back
uncached = s.url.slice( cacheURL.length );
- // If data is available, append data to url
- if ( s.data ) {
+ // If data is available and should be processed, append data to url
+ if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
// #9682: remove data so that it's not used in an eventual retry
jQuery[ method ] = function( url, data, callback, type ) {
// Shift arguments if data argument was omitted
- if ( jQuery.isFunction( data ) ) {
+ if ( isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
var wrap;
if ( this[ 0 ] ) {
- if ( jQuery.isFunction( html ) ) {
+ if ( isFunction( html ) ) {
html = html.call( this[ 0 ] );
}
},
wrapInner: function( html ) {
- if ( jQuery.isFunction( html ) ) {
+ if ( isFunction( html ) ) {
return this.each( function( i ) {
jQuery( this ).wrapInner( html.call( this, i ) );
} );
},
wrap: function( html ) {
- var isFunction = jQuery.isFunction( html );
+ var htmlIsFunction = isFunction( html );
return this.each( function( i ) {
- jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
+ jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
} );
},
return function() {
if ( callback ) {
callback = errorCallback = xhr.onload =
- xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
+ xhr.onerror = xhr.onabort = xhr.ontimeout =
+ xhr.onreadystatechange = null;
if ( type === "abort" ) {
xhr.abort();
// Listen to events
xhr.onload = callback();
- errorCallback = xhr.onerror = callback( "error" );
+ errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
// Support: IE 9 only
// Use onreadystatechange to replace onabort
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
// Get callback name, remembering preexisting value associated with it
- callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
s.jsonpCallback() :
s.jsonpCallback;
}
// Call if it was a function and we have a response
- if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ if ( responseContainer && isFunction( overwritten ) ) {
overwritten( responseContainer[ 0 ] );
}
}
// If it's a function
- if ( jQuery.isFunction( params ) ) {
+ if ( isFunction( params ) ) {
// We assume that it's the callback
callback = params;
curLeft = parseFloat( curCSSLeft ) || 0;
}
- if ( jQuery.isFunction( options ) ) {
+ if ( isFunction( options ) ) {
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
};
jQuery.fn.extend( {
+
+ // offset() relates an element's border box to the document origin
offset: function( options ) {
// Preserve chaining for setter
} );
}
- var doc, docElem, rect, win,
+ var rect, win,
elem = this[ 0 ];
if ( !elem ) {
return { top: 0, left: 0 };
}
+ // Get document-relative position by adding viewport scroll to viewport-relative gBCR
rect = elem.getBoundingClientRect();
-
- doc = elem.ownerDocument;
- docElem = doc.documentElement;
- win = doc.defaultView;
-
+ win = elem.ownerDocument.defaultView;
return {
- top: rect.top + win.pageYOffset - docElem.clientTop,
- left: rect.left + win.pageXOffset - docElem.clientLeft
+ top: rect.top + win.pageYOffset,
+ left: rect.left + win.pageXOffset
};
},
+ // position() relates an element's margin box to its offset parent's padding box
+ // This corresponds to the behavior of CSS absolute positioning
position: function() {
if ( !this[ 0 ] ) {
return;
}
- var offsetParent, offset,
+ var offsetParent, offset, doc,
elem = this[ 0 ],
parentOffset = { top: 0, left: 0 };
- // Fixed elements are offset from window (parentOffset = {top:0, left: 0},
- // because it is its only offset parent
+ // position:fixed elements are offset from the viewport, which itself always has zero offset
if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // Assume getBoundingClientRect is there when computed position is fixed
+ // Assume position:fixed implies availability of getBoundingClientRect
offset = elem.getBoundingClientRect();
} else {
+ offset = this.offset();
- // Get *real* offsetParent
- offsetParent = this.offsetParent();
+ // Account for the *real* offset parent, which can be the document or its root element
+ // when a statically positioned element is identified
+ doc = elem.ownerDocument;
+ offsetParent = elem.offsetParent || doc.documentElement;
+ while ( offsetParent &&
+ ( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
+ jQuery.css( offsetParent, "position" ) === "static" ) {
- // Get correct offsets
- offset = this.offset();
- if ( !nodeName( offsetParent[ 0 ], "html" ) ) {
- parentOffset = offsetParent.offset();
+ offsetParent = offsetParent.parentNode;
}
+ if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
- // Add offsetParent borders
- parentOffset = {
- top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ),
- left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true )
- };
+ // Incorporate borders into its offset, since they are outside its content origin
+ parentOffset = jQuery( offsetParent ).offset();
+ parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
+ }
}
// Subtract parent offsets and element margins
// Coalesce documents and windows
var win;
- if ( jQuery.isWindow( elem ) ) {
+ if ( isWindow( elem ) ) {
win = elem;
} else if ( elem.nodeType === 9 ) {
win = elem.defaultView;
return access( this, function( elem, type, value ) {
var doc;
- if ( jQuery.isWindow( elem ) ) {
+ if ( isWindow( elem ) ) {
// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
return funcName.indexOf( "outer" ) === 0 ?
} );
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+ function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+} );
+
+jQuery.fn.extend( {
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+} );
+
+
+
+
jQuery.fn.extend( {
bind: function( types, data, fn ) {
}
} );
+// Bind a function to a context, optionally partially applying any
+// arguments.
+// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
+// However, it is not slated for removal any time soon
+jQuery.proxy = function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+};
+
jQuery.holdReady = function( hold ) {
if ( hold ) {
jQuery.readyWait++;
jQuery.isArray = Array.isArray;
jQuery.parseJSON = JSON.parse;
jQuery.nodeName = nodeName;
+jQuery.isFunction = isFunction;
+jQuery.isWindow = isWindow;
+jQuery.camelCase = camelCase;
+jQuery.type = toType;
+
+jQuery.now = Date.now;
+
+jQuery.isNumeric = function( obj ) {
+
+ // As of jQuery 3.0, isNumeric is limited to
+ // strings and numbers (primitives or objects)
+ // that can be coerced to finite numbers (gh-2662)
+ var type = jQuery.type( obj );
+ return ( type === "number" || type === "string" ) &&
+
+ // parseFloat NaNs numeric-cast false positives ("")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ !isNaN( obj - parseFloat( obj ) );
+};
* "mediawiki" module, and will remain a default/implicit dependency for all
* regular modules, just like jquery and wikibits already are.
*/
-/* globals mw */
( function () {
'use strict';
* @class mw.errorLogger
* @singleton
*/
-( function ( mw ) {
+( function () {
'use strict';
mw.errorLogger = {
};
mw.errorLogger.installGlobalHandler( window );
-}( mediaWiki ) );
+}() );
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {Object} columns Required object representing the column labels and associated
- * tags in the matrix.
- * @cfg {Object} rows Required object representing the row labels and associated
- * tags in the matrix.
- * @cfg {string[]} [forcedOn] An array of column-row tags to be displayed as
- * enabled but unavailable to change
- * @cfg {string[]} [forcedOff] An array of column-row tags to be displayed as
- * disnabled but unavailable to change
- * @cfg {Object} Object mapping row label to tooltip content
+ * @cfg {Object} columns Required object mapping column labels (as HTML) to
+ * their tags.
+ * @cfg {Object} rows Required object mapping row labels (as HTML) to their
+ * tags.
+ * @cfg {string[]} [forcedOn] Array of column-row tags to be displayed as
+ * enabled but unavailable to change.
+ * @cfg {string[]} [forcedOff] Array of column-row tags to be displayed as
+ * disabled but unavailable to change.
+ * @cfg {Object} [tooltips] Optional object mapping row labels to tooltips
+ * (as text, will be escaped).
*/
mw.widgets.CheckMatrixWidget = function MWWCheckMatrixWidget( config ) {
var $headRow = $( '<tr>' ),
this.forcedOff = config.forcedOff || [];
// Build header
- $headRow.append( $( '<td>' ).html( ' ' ) );
+ $headRow.append( $( '<td>' ).text( '\u00A0' ) );
// Iterate over the columns object (ignore the value)
$.each( this.columns, function ( columnLabel ) {
- $headRow.append( $( '<td>' ).text( columnLabel ) );
+ $headRow.append( $( '<td>' ).html( columnLabel ) );
} );
$table.append( $headRow );
labelField = new OO.ui.FieldLayout(
new OO.ui.Widget(), // Empty widget, since we don't have the checkboxes here
{
- label: rowLabel,
+ label: new OO.ui.HtmlSnippet( rowLabel ),
help: widget.tooltips[ rowLabel ],
align: 'inline'
}
/**
* Base library for MediaWiki.
*
- * Exposed globally as `mediaWiki` with `mw` as shortcut.
+ * Exposed globally as `mw`, with `mediaWiki` as alias.
*
* @class mw
* @alternateClassName mediaWiki
log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
obj[ key ] = val;
} : function ( obj, key, val, msg, logName ) {
- var logged = new StringSet();
- logName = logName || key;
- msg = 'Use of "' + logName + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
- function uniqueTrace() {
- var trace = new Error().stack;
- if ( logged.has( trace ) ) {
- return false;
+ var stacks;
+ function maybeLog() {
+ var name,
+ trace = new Error().stack;
+ if ( !stacks ) {
+ stacks = new StringSet();
+ }
+ if ( !stacks.has( trace ) ) {
+ stacks.add( trace );
+ name = logName || key;
+ mw.track( 'mw.deprecate', name );
+ mw.log.warn(
+ 'Use of "' + name + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' )
+ );
}
- logged.add( trace );
- return true;
}
// Support: Safari 5.0
// Throws "not supported on DOM Objects" for Node or Element objects (incl. document)
configurable: true,
enumerable: true,
get: function () {
- if ( uniqueTrace() ) {
- mw.track( 'mw.deprecate', logName );
- mw.log.warn( msg );
- }
+ maybeLog();
return val;
},
set: function ( newVal ) {
- if ( uniqueTrace() ) {
- mw.track( 'mw.deprecate', logName );
- mw.log.warn( msg );
- }
+ maybeLog();
val = newVal;
}
} );
* - resolve: failed to sort dependencies for a module in mw.loader.load
* - store-eval: could not evaluate module code cached in localStorage
* - store-localstorage-init: localStorage or JSON parse error in mw.loader.store.init
- * - store-localstorage-json: JSON conversion error in mw.loader.store.set
- * - store-localstorage-update: localStorage or JSON conversion error in mw.loader.store.update
+ * - store-localstorage-json: JSON conversion error in mw.loader.store
+ * - store-localstorage-update: localStorage conversion error in mw.loader.store.
*/
/**
// The current module became 'ready'.
if ( registry[ module ].state === 'ready' ) {
- // Save it to the module store.
- mw.loader.store.set( module, registry[ module ] );
+ // Queue it for later syncing to the module store.
+ mw.loader.store.add( module );
// Recursively execute all dependent modules that were already loaded
// (waiting for execution) and no longer have unsatisfied dependencies.
for ( m in registry ) {
// Allow multiple registration
if ( typeof module === 'object' ) {
resolveIndexedDependencies( module );
+ // module is an array of arrays
for ( i = 0; i < module.length; i++ ) {
// module is an array of module names
- if ( typeof module[ i ] === 'string' ) {
- mw.loader.register( module[ i ] );
- // module is an array of arrays
- } else if ( typeof module[ i ] === 'object' ) {
- mw.loader.register.apply( mw.loader, module[ i ] );
- }
+ mw.loader.register.apply( mw.loader, module[ i ] );
}
return;
}
// to module implementations.
items: {},
+ // Names of modules to be stored during the next update.
+ // See add() and update().
+ queue: [],
+
// Cache hit stats
stats: { hits: 0, misses: 0, expired: 0, failed: 0 },
},
/**
- * Stringify a module and queue it for storage.
+ * Queue the name of a module that the next update should consider storing.
*
+ * @since 1.32
* @param {string} module Module name
- * @param {Object} descriptor The module's descriptor as set in the registry
*/
- set: function ( module, descriptor ) {
- var args, key, src;
-
+ add: function ( module ) {
if ( !this.enabled ) {
return;
}
+ this.queue.push( module );
+ this.requestUpdate();
+ },
+
+ /**
+ * Add the contents of the named module to the in-memory store.
+ *
+ * This method does not guarantee that the module will be stored.
+ * Inspection of the module's meta data and size will ultimately decide that.
+ *
+ * This method is considered internal to mw.loader.store and must only
+ * be called if the store is enabled.
+ *
+ * @private
+ * @param {string} module Module name
+ */
+ set: function ( module ) {
+ var key, args, src,
+ descriptor = mw.loader.moduleRegistry[ module ];
key = getModuleKey( module );
// Already stored a copy of this exact version
key in this.items ||
// Module failed to load
+ !descriptor ||
descriptor.state !== 'ready' ||
// Unversioned, private, or site-/user-specific
!descriptor.version ||
return;
}
this.items[ key ] = src;
- this.update();
},
/**
},
/**
- * Sync in-memory store back to localStorage.
+ * Request a sync of the in-memory store back to persisted localStorage.
+ *
+ * This function debounces updates. The debouncing logic should account
+ * for the following factors:
+ *
+ * - Writing to localStorage is an expensive operation that must not happen
+ * during the critical path of initialising and executing module code.
+ * Instead, it should happen at a later time after modules have been given
+ * time and priority to do their thing first.
+ *
+ * - This method is called from mw.loader.store.add(), which will be called
+ * hundreds of times on a typical page, including within the same call-stack
+ * and eventloop-tick. This is because responses from load.php happen in
+ * batches. As such, we want to allow all modules from the same load.php
+ * response to be written to disk with a single flush, not many.
*
- * This function debounces updates. When called with a flush already pending, the
- * scheduled flush is postponed. The call to localStorage.setItem will be keep
- * being deferred until the page is quiescent for 2 seconds.
+ * - Repeatedly deleting and creating timers is non-trivial.
*
- * Because localStorage is shared by all pages from the same origin, if multiple
- * pages are loaded with different module sets, the possibility exists that
- * modules saved by one page will be clobbered by another. The only impact of this
- * is minor (merely a less efficient cache use) and the problem would be corrected
- * by subsequent page views.
+ * - localStorage is shared by all pages from the same origin, if multiple
+ * pages are loaded with different module sets, the possibility exists that
+ * modules saved by one page will be clobbered by another. The impact of
+ * this is minor, it merely causes a less efficient cache use, and the
+ * problem would be corrected by subsequent page views.
*
+ * This method is considered internal to mw.loader.store and must only
+ * be called if the store is enabled.
+ *
+ * @private
* @method
*/
- update: ( function () {
- var timer, hasPendingWrites = false;
+ requestUpdate: ( function () {
+ var hasPendingWrites = false;
function flushWrites() {
var data, key;
- if ( !mw.loader.store.enabled ) {
- return;
- }
+ // Remove anything from the in-memory store that came from previous page
+ // loads that no longer corresponds with current module names and versions.
mw.loader.store.prune();
+ // Process queued module names, serialise their contents to the in-memory store.
+ while ( mw.loader.store.queue.length ) {
+ mw.loader.store.set( mw.loader.store.queue.shift() );
+ }
+
key = mw.loader.store.getStoreKey();
try {
// Replacing the content of the module store might fail if the new
} );
}
+ // Let the next call to requestUpdate() create a new timer.
hasPendingWrites = false;
}
- function request() {
- // If another mw.loader.store.set()/update() call happens in the narrow
- // time window between requestIdleCallback() and flushWrites firing, ignore it.
- // It'll be saved by the already-scheduled flush.
- if ( !hasPendingWrites ) {
- hasPendingWrites = true;
- mw.requestIdleCallback( flushWrites );
- }
+ function onTimeout() {
+ // Defer the actual write via requestIdleCallback
+ mw.requestIdleCallback( flushWrites );
}
return function () {
- // Cancel the previous timer (if it hasn't fired yet)
- clearTimeout( timer );
- timer = setTimeout( request, 2000 );
+ // On the first call to requestUpdate(), create a timer that
+ // waits at least two seconds, then calls onTimeout.
+ // The main purpose is to allow the current batch of load.php
+ // responses to complete before we do anything. This batch can
+ // trigger many hundreds of calls to requestUpdate().
+ if ( !hasPendingWrites ) {
+ hasPendingWrites = true;
+ setTimeout( onTimeout, 2000 );
+ }
};
}() )
}
* @author Michael Dale <mdale@wikimedia.org>
* @author Trevor Parscal <tparscal@wikimedia.org>
*/
-( function ( mw ) {
+( function () {
/* global console */
/* eslint-disable no-console */
var original = mw.log;
mw.log.error = original.error;
mw.log.deprecate = original.deprecate;
}
-}( mediaWiki ) );
+}() );
-( function ( mw ) {
+( function () {
var maxBusy = 50;
mw.requestIdleCallbackInternal = function ( callback ) {
// Note: Polyfill was previously disabled due to
// https://bugs.chromium.org/p/chromium/issues/detail?id=647870
// See also <http://codepen.io/Krinkle/full/XNGEvv>
-}( mediaWiki ) );
+}() );
* @author Timo Tijhof
* @since 1.32
*/
-/* global mw */
( function () {
'use strict';
* - Beware: This file MUST parse without errors on even the most ancient of browsers!
*/
/* eslint-disable vars-on-top, no-unmodified-loop-condition */
-/* global mw, isCompatible, $VARS, $CODE */
+/* global isCompatible, $VARS, $CODE */
/**
* See <https://www.mediawiki.org/wiki/Compatibility#Browsers>
*/
private function resetDB( $db, $tablesUsed ) {
if ( $db ) {
- // NOTE: Do not reset the slot_roles and content_models tables, but let them
- // leak across tests. Resetting them would require to reset all NamedTableStore
- // instances for these tables, of which there may be several beyond the ones
- // known to MediaWikiServices. See T202641.
$userTables = [ 'user', 'user_groups', 'user_properties', 'actor' ];
$pageTables = [
'page', 'revision', 'ip_changes', 'revision_comment_temp', 'comment', 'archive',
- 'revision_actor_temp', 'slots', 'content',
+ 'revision_actor_temp', 'slots', 'content', 'content_models', 'slot_roles',
];
$coreDBDataTables = array_merge( $userTables, $pageTables );
}
if ( array_intersect( $tablesUsed, $coreDBDataTables ) ) {
+ // Reset services that may contain information relating to the truncated tables
+ $this->overrideMwServices();
// Re-add core DB data that was deleted
$this->addCoreDBData();
}
$db->delete( $tableName, '*', __METHOD__ );
}
- if ( in_array( $db->getType(), [ 'postgres', 'sqlite' ], true ) ) {
+ if ( $db instanceof DatabasePostgres || $db instanceof DatabaseSqlite ) {
// Reset the table's sequence too.
$db->resetSequenceForTable( $tableName, __METHOD__ );
}
+
+ // re-initialize site_stats table
+ if ( $tableName === 'site_stats' ) {
+ SiteStatsInit::doPlaceholderInit();
+ }
}
private static function unprefixTable( &$tableName, $ind, $prefix ) {
--- /dev/null
+{{foo}}
+{{#bar}}
+ {{foo}} {{baz}}
+{{/bar}}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Storage;
+
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
+use MediaWikiTestCase;
+use Wikimedia\Rdbms\ILBFactory;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * @covers MediaWiki\Storage\NameTableStoreFactory
+ * @group Database
+ */
+class NameTableStoreFactoryTest extends MediaWikiTestCase {
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|ILoadBalancer
+ */
+ private function getMockLoadBalancer() {
+ return $this->getMockBuilder( ILoadBalancer::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|ILBFactory
+ */
+ private function getMockLoadBalancerFactory( $expectedWiki ) {
+ $mock = $this->getMockBuilder( ILBFactory::class )
+ ->disableOriginalConstructor()->getMock();
+
+ $mock->expects( $this->once() )
+ ->method( 'getMainLB' )
+ ->with( $this->equalTo( $expectedWiki ) )
+ ->willReturnCallback( function ( $domain ) use ( $expectedWiki ) {
+ return $this->getMockLoadBalancer();
+ } );
+
+ return $mock;
+ }
+
+ public static function provideTestGet() {
+ return [
+ [
+ 'change_tag_def',
+ false,
+ false,
+ ],
+ [
+ 'content_models',
+ false,
+ false,
+ ],
+ [
+ 'slot_roles',
+ false,
+ false,
+ ],
+ [
+ 'change_tag_def',
+ 'test7245',
+ 'test7245',
+ ],
+ ];
+ }
+
+ /** @dataProvider provideTestGet */
+ public function testGet( $tableName, $wiki, $expectedWiki ) {
+ $services = MediaWikiServices::getInstance();
+ $db = wfGetDB( DB_MASTER );
+ if ( $wiki === false ) {
+ $wiki2 = $db->getWikiID();
+ } else {
+ $wiki2 = $wiki;
+ }
+ $names = new NameTableStoreFactory(
+ $this->getMockLoadBalancerFactory( $expectedWiki ),
+ $services->getMainWANObjectCache(),
+ LoggerFactory::getInstance( 'NameTableStoreFactory' )
+ );
+
+ $table = $names->get( $tableName, $wiki );
+ $table2 = $names->get( $tableName, $wiki2 );
+ $this->assertSame( $table, $table2 );
+ $this->assertInstanceOf( NameTableStore::class, $table );
+ }
+
+ /*
+ * The next three integration tests verify that the schema information is correct by loading
+ * the relevant information from the database.
+ */
+
+ public function testIntegratedGetChangeTagDef() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getChangeTagDef();
+ $this->assertType( 'array', $store->getMap() );
+ }
+
+ public function testIntegratedGetContentModels() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getContentModels();
+ $this->assertType( 'array', $store->getMap() );
+ }
+
+ public function testIntegratedGetSlotRoles() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getSlotRoles();
+ $this->assertType( 'array', $store->getMap() );
+ }
+}
use MediaWiki\Storage\BlobStore;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionStore;
use MediaWiki\Storage\RevisionStoreFactory;
use MediaWiki\Storage\SqlBlobStore;
new RevisionStoreFactory(
$this->getMockLoadBalancerFactory(),
$this->getMockBlobStoreFactory(),
+ $this->getNameTableStoreFactory(),
$this->getHashWANObjectCache(),
$this->getMockCommentStore(),
ActorMigration::newMigration(),
) {
$lbFactory = $this->getMockLoadBalancerFactory();
$blobStoreFactory = $this->getMockBlobStoreFactory();
+ $nameTableStoreFactory = $this->getNameTableStoreFactory();
$cache = $this->getHashWANObjectCache();
$commentStore = $this->getMockCommentStore();
$actorMigration = ActorMigration::newMigration();
$factory = new RevisionStoreFactory(
$lbFactory,
$blobStoreFactory,
+ $nameTableStoreFactory,
$cache,
$commentStore,
$actorMigration,
return $mock;
}
+ /**
+ * @return NameTableStoreFactory
+ */
+ private function getNameTableStoreFactory() {
+ return new NameTableStoreFactory(
+ $this->getMockLoadBalancerFactory(),
+ $this->getHashWANObjectCache(),
+ new NullLogger() );
+ }
+
/**
* @return \PHPUnit_Framework_MockObject_MockObject|CommentStore
*/
$this->setExpectedException( MWException::class );
}
+ $nameTables = MediaWikiServices::getInstance()->getNameTableStoreFactory();
+
$store = new RevisionStore(
$this->getMockLoadBalancer(),
$this->getMockSqlBlobStore(),
$this->getHashWANObjectCache(),
$this->getMockCommentStore(),
- MediaWikiServices::getInstance()->getContentModelStore(),
- MediaWikiServices::getInstance()->getSlotRoleStore(),
+ $nameTables->getContentModels(),
+ $nameTables->getSlotRoles(),
$migrationMode,
MediaWikiServices::getInstance()->getActorMigration()
);
$blobStore = $this->getMockSqlBlobStore();
$cache = $this->getHashWANObjectCache();
$commentStore = $this->getMockCommentStore();
- $contentModelStore = MediaWikiServices::getInstance()->getContentModelStore();
- $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
+ $services = MediaWikiServices::getInstance();
+ $nameTables = $services->getNameTableStoreFactory();
+ $contentModelStore = $nameTables->getContentModels();
+ $slotRoleStore = $nameTables->getSlotRoles();
$store = new RevisionStore(
$loadBalancer,
$blobStore,
$cache,
$commentStore,
- MediaWikiServices::getInstance()->getContentModelStore(),
- MediaWikiServices::getInstance()->getSlotRoleStore(),
+ $nameTables->getContentModels(),
+ $nameTables->getSlotRoles(),
$migration,
- MediaWikiServices::getInstance()->getActorMigration()
+ $services->getActorMigration()
);
if ( !$expectException ) {
$store = TestingAccessWrapper::newFromObject( $store );
false,
'Exception',
],
+ [
+ 'parentvars',
+ [
+ 'foo' => 'f',
+ 'bar' => [
+ [ 'baz' => 'x' ],
+ [ 'baz' => 'y' ]
+ ]
+ ],
+ "f\n\n\tf x\n\n\tf y\n\n"
+ ]
];
}
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$version1 = $module->getVersionHash( $context );
$module = new ResourceLoaderStartupModule();
$version2 = $module->getVersionHash( $context );
+
$this->setMwGlobals( 'wgArticlePath', '/w3' );
$module = new ResourceLoaderStartupModule();
$version3 = $module->getVersionHash( $context );
}
/**
- * @covers ResourceLoaderStartupModule::getAllModuleHashes
- * @covers ResourceLoaderStartupModule::getDefinitionSummary
+ * @covers ResourceLoaderStartupModule
*/
public function testGetVersionHash_varyModule() {
$context1 = $this->getResourceLoaderContext();
$module = new ResourceLoaderStartupModule();
$version3 = $module->getVersionHash( $context3 );
- $this->assertEquals(
+ // Module name *is* significant (T201686)
+ $this->assertNotEquals(
$version1,
$version2,
- 'Module name is insignificant'
+ 'Module name is significant'
);
$this->assertNotEquals(
);
}
+ /**
+ * @covers ResourceLoaderStartupModule
+ */
+ public function testGetVersionHash_varyDeps() {
+ $context = $this->getResourceLoaderContext();
+ $rl = $context->getResourceLoader();
+ $rl->register( [
+ 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'y' ] ] ),
+ ] );
+ $module = new ResourceLoaderStartupModule();
+ $version1 = $module->getVersionHash( $context );
+
+ $context = $this->getResourceLoaderContext();
+ $rl = $context->getResourceLoader();
+ $rl->register( [
+ 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'z' ] ] ),
+ ] );
+ $module = new ResourceLoaderStartupModule();
+ $version2 = $module->getVersionHash( $context );
+
+ // Dependencies *are* significant (T201686)
+ $this->assertNotEquals(
+ $version1,
+ $version2,
+ 'Dependencies are significant'
+ );
+ }
+
}
( function ( mw, $ ) {
QUnit.module( 'mediawiki.loader', QUnit.newMwEnvironment( {
setup: function ( assert ) {
- mw.loader.store.enabled = false;
-
// Expose for load.mock.php
mw.loader.testFail = function ( reason ) {
assert.ok( false, reason );
};
},
teardown: function () {
- mw.loader.store.enabled = false;
// Teardown for StringSet shim test
if ( this.nativeSet ) {
window.Set = this.nativeSet;
QUnit.test( 'Stale response caching - T117587', function ( assert ) {
var count = 0;
- mw.loader.store.enabled = true;
+ // Enable store and stub timeout/idle scheduling
+ this.sandbox.stub( mw.loader.store, 'enabled', true );
+ this.sandbox.stub( window, 'setTimeout', function ( fn ) {
+ fn();
+ } );
+ this.sandbox.stub( mw, 'requestIdleCallback', function ( fn ) {
+ fn();
+ } );
+
mw.loader.register( 'test.stale', 'v2' );
assert.strictEqual( mw.loader.store.get( 'test.stale' ), false, 'Not in store' );
// After implementing, registry contains version as implemented by the response.
assert.strictEqual( mw.loader.getVersion( 'test.stale' ), 'v1', 'Override version' );
assert.strictEqual( mw.loader.getState( 'test.stale' ), 'ready' );
- assert.ok( mw.loader.store.get( 'test.stale' ), 'In store' );
+ assert.strictEqual( typeof mw.loader.store.get( 'test.stale' ), 'string', 'In store' );
} )
.then( function () {
// Reset run time, but keep mw.loader.store
QUnit.test( 'Stale response caching - backcompat', function ( assert ) {
var script = 0;
- mw.loader.store.enabled = true;
+ // Enable store and stub timeout/idle scheduling
+ this.sandbox.stub( mw.loader.store, 'enabled', true );
+ this.sandbox.stub( window, 'setTimeout', function ( fn ) {
+ fn();
+ } );
+ this.sandbox.stub( mw, 'requestIdleCallback', function ( fn ) {
+ fn();
+ } );
+
mw.loader.register( 'test.stalebc', 'v2' );
assert.strictEqual( mw.loader.store.get( 'test.stalebc' ), false, 'Not in store' );
.then( function () {
assert.strictEqual( script, 1, 'module script ran' );
assert.strictEqual( mw.loader.getState( 'test.stalebc' ), 'ready' );
- assert.ok( mw.loader.store.get( 'test.stalebc' ), 'In store' );
+ assert.strictEqual( typeof mw.loader.store.get( 'test.stalebc' ), 'string', 'In store' );
} )
.then( function () {
// Reset run time, but keep mw.loader.store