* Thomas Bleher
* Tim Starling
* Timo Tijhof
-* Tom Gries
+* Thomas Gries
* Trevor Parscal
* Victor Vasiliev
* Yesid Carrillo
=== Configuration changes in 1.22 ===
* $wgRedirectScript was removed. It was unused.
+* Removed $wgLocalMessageCacheSerialized, it is now always true.
=== New features in 1.22 ===
+* (bug 44525) mediawiki.jqueryMsg can now parse (whitelisted) HTML elements and attributes.
+* (bug 33454) Language::sprintfDate now has a timezone parameter, and supports
+ the "eIOPTZ" formatting characters.
+* EditWarning: A warning is shown when an editor leaves the edit form without
+ saving (enabled by default, users can opt-out via the 'useeditwarning'
+ preference). This feature was moved from the Vector extension, and is now part
+ of core for all skins. Take care when upgrading that you don't use an older
+ version of the Vector extension as this feature may conflict.
=== Bug fixes in 1.22 ===
=== API changes in 1.22 ===
+* (bug 46626) xmldoublequote parameter was removed. Because of a bug, the
+ parameter has had no effect since MediaWiki 1.16, and so its removal is
+ unlikely to impact existing clients.
=== Languages updated in 1.22===
use AuthPlugin for external authentication/authorization needs.
* The Quickbar feature of the legacy skin model and the last remnants of it
throughout the code base have been removed.
+* Externaledit/externaldiff preference was removed. Very few users used this
+ feature, and improper configuration can actually prevent a user from editing
== Compatibility ==
'EnhancedChangesList' => 'includes/ChangesList.php',
'ErrorPageError' => 'includes/Exception.php',
'ExplodeIterator' => 'includes/StringUtils.php',
- 'ExternalEdit' => 'includes/ExternalEdit.php',
'ExternalStore' => 'includes/externalstore/ExternalStore.php',
'ExternalStoreDB' => 'includes/externalstore/ExternalStoreDB.php',
'ExternalStoreHttp' => 'includes/externalstore/ExternalStoreHttp.php',
} elseif ( $blocksList['auto'] ) {
$chosenBlock = $blocksList['auto'];
} else {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Proxy block found, but couldn't be classified." );
}
'be-tarask' => array( "Ё" ),
'en' => array(),
'fi' => array( "Å", "Ä", "Ö" ),
- '-fi' => array( "Ǥ", "Ŋ", "Ŧ", "Ʒ" ), // sorted like G, N, T, Z - bug 46330
'hu' => array( "Cs", "Dz", "Dzs", "Gy", "Ly", "Ny", "Ö", "Sz", "Ty", "Ü", "Zs" ),
'it' => array(),
'pl' => array( "Ą", "Ć", "Ę", "Ł", "Ń", "Ó", "Ś", "Ź", "Ż" ),
'pt' => array(),
'ru' => array(),
'sv' => array( "Å", "Ä", "Ö" ),
- '-sv' => array( "Þ" ), // sorted as "th" in Swedish, causing unexpected output - bug 45446
'uk' => array( "Ґ", "Ь" ),
'vi' => array( "Ă", "Â", "Đ", "Ê", "Ô", "Ơ", "Ư" ),
// Not verified, but likely correct
}
}
ksort( $letterMap, SORT_STRING );
+ // Remove duplicate prefixes. Basically if something has a sortkey
+ // which is a prefix of some other sortkey, then it is an
+ // expansion and probably should not be considered a section
+ // header.
+ //
+ // For example 'þ' is sometimes sorted as if it is the letters
+ // 'th'. Other times it is its own primary element. Another
+ // example is '₨'. Sometimes its a currency symbol. Sometimes it
+ // is an 'R' followed by an 's'.
+ //
+ // Additionally an expanded element should always sort directly
+ // after its first element due to they way sortkeys work.
+ //
+ // UCA sortkey elements are of variable length but no collation
+ // element should be a prefix of some other element, so I think
+ // this is safe. See:
+ // * https://ssl.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm
+ // * http://site.icu-project.org/design/collation/uca-weight-allocation
+ //
+ // Additionally, there is something called primary compression to
+ // worry about. Basically, if you have two primary elements that
+ // are more than one byte and both start with the same byte then
+ // the first byte is dropped on the second primary. Additionally
+ // either \x03 or \xFF may be added to mean that the next primary
+ // does not start with the first byte of the first primary.
+ //
+ // This shouldn't matter much, as the first primary is not
+ // changed, and that is what we are comparing against.
+ //
+ // tl;dr: This makes some assumptions about how icu implements
+ // collations. It seems incredibly unlikely these assumptions
+ // will change, but nonetheless they are assumptions.
+
+ $prev = false;
+ $duplicatePrefixes = array();
+ foreach( $letterMap as $key => $value ) {
+ // Remove terminator byte. Otherwise the prefix
+ // comparison will get hung up on that.
+ $trimmedKey = rtrim( $key, "\0" );
+ if ( $prev === false || $prev === '' ) {
+ $prev = $trimmedKey;
+ // We don't yet have a collation element
+ // to compare against, so continue.
+ continue;
+ }
+
+ // Due to the fact the array is sorted, we only have
+ // to compare with the element directly previous
+ // to the current element (skipping expansions).
+ // An element "X" will always sort directly
+ // before "XZ" (Unless we have "XY", but we
+ // do not update $prev in that case).
+ if ( substr( $trimmedKey, 0, strlen( $prev ) ) === $prev ) {
+ $duplicatePrefixes[] = $key;
+ // If this is an expansion, we don't want to
+ // compare the next element to this element,
+ // but to what is currently $prev
+ continue;
+ }
+ $prev = $trimmedKey;
+ }
+ foreach( $duplicatePrefixes as $badKey ) {
+ wfDebug( "Removing '{$letterMap[$badKey]}' from first letters." );
+ unset( $letterMap[$badKey] );
+ // This code assumes that unsetting does not change sort order.
+ }
$data = array(
'chars' => array_values( $letterMap ),
'keys' => array_keys( $letterMap ),
*/
$wgUseLocalMessageCache = false;
-/**
- * Defines format of local cache.
- * - true: Serialized object
- * - false: PHP source file (Warning - security risk)
- */
-$wgLocalMessageCacheSerialized = true;
-
/**
* Instead of caching everything, only cache those messages which have
* been customised in the site content language. This means that
'enotifusertalkpages' => 1,
'enotifwatchlistpages' => 0,
'extendwatchlist' => 0,
- 'externaldiff' => 0,
- 'externaleditor' => 0,
'fancysig' => 0,
'forceeditsummary' => 0,
'gender' => 'unknown',
'watchlisthidepatrolled' => 0,
'watchmoves' => 0,
'wllimit' => 250,
+ 'useeditwarning' => 1,
);
/** An array of preferences to not show for the user */
NS_CATEGORY => true
);
-/**
- * Activate external editor interface for files and pages
- * See http://www.mediawiki.org/wiki/Manual:External_editors
- */
-$wgUseExternalEditor = true;
-
/** Go button goes straight to the edit screen if the article doesn't exist. */
$wgGoToEdit = false;
$this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
if ( $this->section !== null && $this->section !== '' && !$this->isSectionEditSupported() ) {
+ wfProfileOut( __METHOD__ );
throw new ErrorPageError( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
}
if ( $wgUser->getOption( 'uselivepreview', false ) ) {
$wgOut->addModules( 'mediawiki.action.edit.preview' );
}
+
+ if ( $wgUser->getOption( 'useeditwarning', false ) ) {
+ $wgOut->addModules( 'mediawiki.action.edit.editWarning' );
+ }
+
// Bug #19334: textarea jumps when editing articles in IE8
$wgOut->addStyle( 'common/IE80Fixes.css', 'screen', 'IE 8' );
}
// Inform caller about problem
+ wfProfileOut( __METHOD__ );
throw $e;
}
# For page dumps...
+++ /dev/null
-<?php
-/**
- * External editors support
- *
- * License: Public domain
- *
- * @file
- * @author Erik Moeller <moeller@scireview.de>
- */
-
-/**
- * Support for external editors to modify both text and files
- * in external applications. It works as follows: MediaWiki
- * sends a meta-file with the MIME type 'application/x-external-editor'
- * to the client. The user has to associate that MIME type with
- * a helper application (a reference implementation in Perl
- * can be found in extensions/ee), which will launch the editor,
- * and save the modified data back to the server.
- *
- */
-class ExternalEdit extends ContextSource {
-
- /**
- * Array of URLs to link to
- * @var Array
- */
- private $urls;
-
- /**
- * Constructor
- * @param $context IContextSource context to use
- * @param $urls array
- */
- public function __construct( IContextSource $context, array $urls = array() ) {
- $this->setContext( $context );
- $this->urls = $urls;
- }
-
- /**
- * Check whether external edit or diff should be used.
- *
- * @param $context IContextSource context to use
- * @param string $type can be either 'edit' or 'diff'
- * @return Bool
- */
- public static function useExternalEngine( IContextSource $context, $type ) {
- global $wgUseExternalEditor;
-
- if ( !$wgUseExternalEditor ) {
- return false;
- }
-
- $pref = $type == 'diff' ? 'externaldiff' : 'externaleditor';
- $request = $context->getRequest();
-
- return !$request->getVal( 'internaledit' ) &&
- ( $context->getUser()->getOption( $pref ) || $request->getVal( 'externaledit' ) );
- }
-
- /**
- * Output the information for the external editor
- */
- public function execute() {
- global $wgContLang, $wgScript, $wgScriptPath, $wgCanonicalServer;
-
- $this->getOutput()->disable();
-
- $response = $this->getRequest()->response();
- $response->header( 'Content-type: application/x-external-editor; charset=utf-8' );
- $response->header( 'Cache-control: no-cache' );
-
- $special = $wgContLang->getNsText( NS_SPECIAL );
-
- # $type can be "Edit text", "Edit file" or "Diff text" at the moment
- # See the protocol specifications at [[m:Help:External editors/Tech]] for
- # details.
- if ( count( $this->urls ) ) {
- $urls = $this->urls;
- $type = "Diff text";
- } elseif ( $this->getRequest()->getVal( 'mode' ) == 'file' ) {
- $type = "Edit file";
- $image = wfLocalFile( $this->getTitle() );
- if ( $image ) {
- $urls = array(
- 'File' => array(
- 'Extension' => $image->getExtension(),
- 'URL' => $image->getCanonicalURL()
- )
- );
- } else {
- $urls = array();
- }
- } else {
- $type = "Edit text";
- # *.wiki file extension is used by some editors for syntax
- # highlighting, so we follow that convention
- $urls = array( 'File' => array(
- 'Extension' => 'wiki',
- 'URL' => $this->getTitle()->getCanonicalURL(
- array( 'action' => 'edit', 'internaledit' => 'true' ) )
- ) );
- }
-
- $files = '';
- foreach( $urls as $key => $vars ) {
- $files .= "\n[$key]\n";
- foreach( $vars as $varname => $varval ) {
- $files .= "$varname=$varval\n";
- }
- }
-
- $url = $this->getTitle()->getFullURL(
- $this->getRequest()->appendQueryValue( 'internaledit', 1, true ) );
-
- $control = <<<CONTROL
-; You're seeing this file because you're using Mediawiki's External Editor feature.
-; This is probably because you selected use external editor in your preferences.
-; To edit normally, either disable that preference or go to the URL:
-; $url
-; See http://www.mediawiki.org/wiki/Manual:External_editors for details.
-[Process]
-Type=$type
-Engine=MediaWiki
-Script={$wgCanonicalServer}{$wgScript}
-Server={$wgCanonicalServer}
-Path={$wgScriptPath}
-Special namespace=$special
-$files
-CONTROL;
- echo $control;
- }
-}
*/
if ( is_array( $hook ) ) {
if ( count( $hook ) < 1 ) {
+ wfProfileOut( 'hook: ' . $event );
throw new MWException( 'Empty array in hooks for ' . $event . "\n" );
} elseif ( is_object( $hook[0] ) ) {
$object = $hook[0];
$have_data = true;
}
} else {
+ wfProfileOut( 'hook: ' . $event );
throw new MWException( 'Unknown datatype in hooks for ' . $event . "\n" );
}
} elseif ( is_string( $hook ) ) { # functions look like strings, too
$method = "on" . $event;
}
} else {
+ wfProfileOut( 'hook: ' . $event );
throw new MWException( 'Unknown datatype in hooks for ' . $event . "\n" );
}
$prettyFunc = strval( $callback );
}
if ( $badhookmsg ) {
+ wfProfileOut( 'hook: ' . $event );
throw new MWException(
'Detected bug in an extension! ' .
"Hook $prettyFunc has invalid call signature; " . $badhookmsg
);
} else {
+ wfProfileOut( 'hook: ' . $event );
throw new MWException(
'Detected bug in an extension! ' .
"Hook $prettyFunc failed to return a value; " .
* external editing (and instructions link) etc.
*/
protected function uploadLinksBox() {
- global $wgEnableUploads, $wgUseExternalEditor;
+ global $wgEnableUploads;
if ( !$wgEnableUploads ) {
return;
$out->addHTML( "<li id=\"mw-imagepage-upload-disallowed\">" . $this->getContext()->msg( 'upload-disallowed-here' )->escaped() . "</li>\n" );
}
- # External editing link
- if ( $wgUseExternalEditor ) {
- $elink = Linker::linkKnown(
- $this->getTitle(),
- wfMessage( 'edit-externally' )->escaped(),
- array(),
- array(
- 'action' => 'edit',
- 'externaledit' => 'true',
- 'mode' => 'file'
- )
- );
- $out->addHTML(
- '<li id="mw-imagepage-edit-external">' . $elink . ' <small>' .
- wfMessage( 'edit-externally-help' )->parse() .
- "</small></li>\n"
- );
- }
-
$out->addHTML( "</ul>\n" );
}
$wgContLang->getMagic( $this );
if ( !$this->mSynonyms ) {
$this->mSynonyms = array( 'dkjsagfjsgashfajsh' );
+ wfProfileOut( __METHOD__ );
throw new MWException( "Error: invalid magic word '$id'" );
#wfDebugLog( 'exception', "Error: invalid magic word '$id'\n" );
}
* @param $defaultPreferences Array
*/
static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
- global $wgUseExternalEditor, $wgAllowUserCssPrefs;
+ global $wgAllowUserCssPrefs;
## Editing #####################################
$defaultPreferences['cols'] = array(
);
}
- if ( $wgUseExternalEditor ) {
- $defaultPreferences['externaleditor'] = array(
- 'type' => 'toggle',
- 'section' => 'editing/advancedediting',
- 'label-message' => 'tog-externaleditor',
- );
- $defaultPreferences['externaldiff'] = array(
- 'type' => 'toggle',
- 'section' => 'editing/advancedediting',
- 'label-message' => 'tog-externaldiff',
- );
- }
-
$defaultPreferences['forceeditsummary'] = array(
'type' => 'toggle',
'section' => 'editing/advancedediting',
'section' => 'editing/advancedediting',
'label-message' => 'tog-uselivepreview',
);
+
+ $defaultPreferences['useeditwarning'] = array(
+ 'type' => 'toggle',
+ 'section' => 'editing/advancedediting',
+ 'label-message' => 'tog-useeditwarning',
+ );
+
}
/**
// Store and get the URL
$data = ExternalStore::insertToDefault( $data );
if( !$data ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Unable to store text to external storage" );
}
if( $flags ) {
$title = $this->getTitle();
if ( $title === null ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Insufficient information to determine the title of the revision's page!" );
}
$form = new HTMLForm( $this->fields, $this->getContext(), $this->getMessagePrefix() );
$form->setSubmitCallback( array( $this, 'onSubmit' ) );
- $form->setWrapperLegend( $this->msg( $this->getMessagePrefix() . '-legend' ) );
+ $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
$form->addHeaderText(
$this->msg( $this->getMessagePrefix() . '-text' )->parseAsBlock() );
'action',
'redirect', 'rdfrom',
# Options for preloaded edits
- 'preload', 'editintro', 'preloadtitle', 'summary',
+ 'preload', 'editintro', 'preloadtitle', 'summary', 'nosummary',
# Options for overriding user settings
- 'preview', 'internaledit', 'externaledit', 'mode',
+ 'preview', 'internaledit', 'externaledit', 'mode', 'minor', 'watchthis',
# Options for history/diffs
'section', 'oldid', 'diff', 'dir',
'limit', 'offset', 'feed',
protected function __construct() {}
+ /**
+ * @return StatCounter
+ */
public static function singleton() {
static $instance = null;
if ( !$instance ) {
* @return void
*/
public function incr( $key, $count = 1 ) {
+ $this->deltas[$key] = isset( $this->deltas[$key] ) ? $this->deltas[$key] : 0;
+ $this->deltas[$key] += $count;
if ( PHP_SAPI === 'cli' ) {
- $this->sendDelta( $key, $count );
- } else {
- if ( !isset( $this->deltas[$key] ) ) {
- $this->deltas[$key] = 0;
- }
- $this->deltas[$key] += $count;
+ $this->flush();
}
}
* @return void
*/
public function flush() {
- try {
- foreach ( $this->deltas as $key => $count ) {
- $this->sendDelta( $key, $count );
- }
- } catch ( MWException $e ) {
- trigger_error( "Caught exception: {$e->getMessage()}");
+ global $wgStatsMethod;
+
+ $deltas = array_filter( $this->deltas ); // remove 0 valued entries
+ if ( $wgStatsMethod === 'udp' ) {
+ $this->sendDeltasUDP( $deltas );
+ } elseif ( $wgStatsMethod === 'cache' ) {
+ $this->sendDeltasMemc( $deltas );
+ } else {
+ // disabled
}
$this->deltas = array();
}
- /**
- * @param string $key
- * @param string $count
- * @return void
- */
- protected function sendDelta( $key, $count ) {
- global $wgStatsMethod;
-
- $count = intval( $count );
- if ( $count == 0 ) {
- return;
- }
+ protected function sendDeltasUDP( array $deltas ) {
+ global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgAggregateStatsID;
- if ( $wgStatsMethod == 'udp' ) {
- global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgAggregateStatsID;
- static $socket;
+ $id = strlen( $wgAggregateStatsID ) ? $wgAggregateStatsID : wfWikiID();
- $id = $wgAggregateStatsID !== false ? $wgAggregateStatsID : wfWikiID();
+ $lines = array();
+ foreach ( $deltas as $key => $count ) {
+ $lines[] = "stats/{$id} - {$count} 1 1 1 1 {$key}\n";
+ }
+ if ( count( $lines ) ) {
+ static $socket = null;
if ( !$socket ) {
$socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
- $statline = "stats/{$id} - 1 1 1 1 1 -total\n";
+ array_unshift( $lines, "stats/{$id} - 1 1 1 1 1 -total\n" );
+ }
+ $packet = '';
+ $packets = array();
+ foreach ( $lines as $line ) {
+ if ( ( strlen( $packet ) + strlen( $line ) ) > 1450 ) {
+ $packets[] = $packet;
+ $packet = '';
+ }
+ $packet .= $line;
+ }
+ if ( $packet != '' ) {
+ $packets[] = $packet;
+ }
+ foreach ( $packets as $packet ) {
+ wfSuppressWarnings();
socket_sendto(
$socket,
- $statline,
- strlen( $statline ),
+ $packet,
+ strlen( $packet ),
0,
$wgUDPProfilerHost,
$wgUDPProfilerPort
);
+ wfRestoreWarnings();
}
- $statline = "stats/{$id} - {$count} 1 1 1 1 {$key}\n";
- wfSuppressWarnings();
- socket_sendto(
- $socket,
- $statline,
- strlen( $statline ),
- 0,
- $wgUDPProfilerHost,
- $wgUDPProfilerPort
- );
- wfRestoreWarnings();
- } elseif ( $wgStatsMethod == 'cache' ) {
- global $wgMemc;
- $key = wfMemcKey( 'stats', $key );
- if ( is_null( $wgMemc->incr( $key, $count ) ) ) {
- $wgMemc->add( $key, $count );
+ }
+ }
+
+ protected function sendDeltasMemc( array $deltas ) {
+ global $wgMemc;
+
+ foreach ( $deltas as $key => $count ) {
+ $ckey = wfMemcKey( 'stats', $key );
+ if ( $wgMemc->incr( $ckey, $count ) === null ) {
+ $wgMemc->add( $ckey, $count );
}
- } else {
- // Disabled
}
}
}
wfProfileIn( __METHOD__ );
if ( FileBackend::isStoragePath( $fname ) ) { // sanity
+ wfProfileOut( __METHOD__ );
throw new MWException( __FUNCTION__ . " given storage path '$fname'." );
}
wfProfileIn( $fname );
$caller = wfGetCaller( $level );
if ( ++$recursionLevel > 2 ) {
+ wfProfileOut( $fname );
throw new MWException( "Unstub loop detected on call of \${$this->mGlobal}->$name from $caller\n" );
}
wfDebug( "Unstubbing \${$this->mGlobal} on call of \${$this->mGlobal}::$name from $caller\n" );
*/
public function isLocal() {
if ( $this->mInterwiki != '' ) {
- return Interwiki::fetch( $this->mInterwiki )->isLocal();
- } else {
- return true;
+ $iw = Interwiki::fetch( $this->mInterwiki );
+ if ( $iw ) {
+ return $iw->isLocal();
+ }
}
+ return true;
}
/**
}
/**
- * Helper to fix up the get{Local,Full,Link,Canonical}URL args
- * get{Canonical,Full,Link,Local}URL methods accepted an optional
+ * Helper to fix up the get{Canonical,Full,Link,Local,Internal}URL args
+ * get{Canonical,Full,Link,Local,Internal}URL methods accepted an optional
* second argument named variant. This was deprecated in favor
* of passing an array of option with a "variant" key
* Once $query2 is removed for good, this helper can be dropped
*/
private static function fixUrlQueryArgs( $query, $query2 = false ) {
if( $query2 !== false ) {
- wfDeprecated( "Title::get{Canonical,Full,Link,Local} method called with a second parameter is deprecated. Add your parameter to an array passed as the first parameter.", "1.19" );
+ wfDeprecated( "Title::get{Canonical,Full,Link,Local,Internal}URL " .
+ "method called with a second parameter is deprecated. Add your " .
+ "parameter to an array passed as the first parameter.", "1.19" );
}
if ( is_array( $query ) ) {
$query = wfArrayToCgi( $query );
* Get a URL with no fragment or server name. If this page is generated
* with action=render, $wgServer is prepended.
*
-
* @param string|array $query an optional query string,
* not used for interwiki links. Can be specified as an associative array as well,
* e.g., array( 'action' => 'edit' ) (keys and values will be URL-escaped).
/**
* Check, if the given group has the given permission
*
+ * @since 1.21
* @param string $group Group to check
* @param string $role Role to check
* @return bool
wfRunHooks( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) );
if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( 'Not a valid page status!' );
}
$newContent = $sectionContent;
} else {
if ( !$this->supportsSections() ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "sections not supported for content model " . $this->getContentHandler()->getModelID() );
}
if ( $changed ) {
if ( !$content->isValid() ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "New content failed validity check!" );
}
public function show() {
$page = $this->page;
- $request = $this->getRequest();
$user = $this->getUser();
- $context = $this->getContext();
if ( wfRunHooks( 'CustomEditor', array( $page, $user ) ) ) {
- if ( ExternalEdit::useExternalEngine( $context, 'edit' )
- && $this->getName() == 'edit' && !$request->getVal( 'section' )
- && !$request->getVal( 'oldid' ) )
- {
- $extedit = new ExternalEdit( $context );
- $extedit->execute();
- } else {
- $editor = new EditPage( $page );
- $editor->edit();
- }
+ $editor = new EditPage( $page );
+ $editor->edit();
}
}
private $mRootElemName = 'api';
public static $namespace = 'http://www.mediawiki.org/xml/api/';
- private $mDoubleQuote = false;
private $mIncludeNamespace = false;
private $mXslt = null;
public function execute() {
$params = $this->extractRequestParams();
- $this->mDoubleQuote = $params['xmldoublequote'];
$this->mIncludeNamespace = $params['includexmlnamespace'];
$this->mXslt = $params['xslt'];
$this->printText(
self::recXmlPrint( $this->mRootElemName,
$data,
- $this->getIsHtml() ? - 2 : null,
- $this->mDoubleQuote
+ $this->getIsHtml() ? - 2 : null
)
);
}
* @param $elemName
* @param $elemValue
* @param $indent
- * @param $doublequote bool
*
* @return string
*/
- public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) {
+ public static function recXmlPrint( $elemName, $elemValue, $indent ) {
$retval = '';
if ( !is_null( $indent ) ) {
$indent += 2;
if ( is_array( $elemValue ) ) {
if ( isset( $elemValue['*'] ) ) {
$subElemContent = $elemValue['*'];
- if ( $doublequote ) {
- $subElemContent = Sanitizer::encodeAttribute( $subElemContent );
- }
unset( $elemValue['*'] );
// Add xml:space="preserve" to the
$indElements = array();
$subElements = array();
foreach ( $elemValue as $subElemId => & $subElemValue ) {
- if ( is_string( $subElemValue ) && $doublequote ) {
- $subElemValue = Sanitizer::encodeAttribute( $subElemValue );
- }
-
if ( is_int( $subElemId ) ) {
$indElements[] = $subElemValue;
unset( $elemValue[$subElemId] );
public function getAllowedParams() {
return array(
- 'xmldoublequote' => false,
'xslt' => null,
'includexmlnamespace' => false,
);
public function getParamDescription() {
return array(
- 'xmldoublequote' => 'If specified, double quotes all attributes and content',
'xslt' => 'If specified, adds <xslt> as stylesheet. This should be a wiki page '
. 'in the MediaWiki namespace whose page name ends with ".xsl"',
'includexmlnamespace' => 'If specified, adds an XML namespace'
}
break;
}
- $fit = $this->addPageSubItem( $pageId,
- self::getInfo( $oldie, $prop, $result,
- $finalThumbParams, $params['metadataversion'] ) );
+ $fit = self::getTransformCount() < self::TRANSFORM_LIMIT &&
+ $this->addPageSubItem( $pageId,
+ self::getInfo( $oldie, $prop, $result,
+ $finalThumbParams, $params['metadataversion']
+ )
+ );
if ( !$fit ) {
if ( count( $pageIds[NS_FILE] ) == 1 ) {
$this->setContinueEnumParameter( 'start',
* @param $code
* @param $key
* @param $subkey
- * @return
*/
protected function loadSubitem( $code, $key, $subkey ) {
if ( !in_array( $key, self::$splitKeys ) ) {
/**
* Returns true if the cache identified by $code is missing or expired.
+ *
+ * @param string $code
+ *
* @return bool
*/
public function isExpired( $code ) {
* @return array
*/
protected function readPHPFile( $_fileName, $_fileType ) {
+ wfProfileIn( __METHOD__ );
// Disable APC caching
$_apcEnabled = ini_set( 'apc.cache_by_default', '0' );
include( $_fileName );
} elseif ( $_fileType == 'aliases' ) {
$data = compact( 'aliases' );
} else {
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ": Invalid file type: $_fileType" );
}
+ wfProfileOut( __METHOD__ );
return $data;
}
*/
protected function readSourceFilesAndRegisterDeps( $code, &$deps ) {
global $IP;
+ wfProfileIn( __METHOD__ );
$fileName = Language::getMessagesFileName( $code );
if ( !file_exists( $fileName ) ) {
+ wfProfileOut( __METHOD__ );
return false;
}
$deps['plurals'] = new FileDependency( "$IP/languages/data/plurals.xml" );
$deps['plurals-mw'] = new FileDependency( "$IP/languages/data/plurals-mediawiki.xml" );
+ wfProfileOut( __METHOD__ );
return $data;
}
wfProfileIn( __METHOD__ );
if ( !$code ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Invalid language code requested" );
}
$this->recachedLangs[$code] = true;
# This is done after the core because we know the fallback sequence now.
# But it has a higher precedence for merging so that we can support things
# like site-specific message overrides.
+ wfProfileIn( __METHOD__ . '-extensions' );
$allData = $initialData;
foreach ( $wgExtensionMessagesFiles as $fileName ) {
$data = $this->readPHPFile( $fileName, 'extension' );
foreach ( $coreData as $key => $item ) {
$this->mergeItem( $key, $allData[$key], $item );
}
+ wfProfileOut( __METHOD__ . '-extensions' );
# Add cache dependencies for any referenced globals
$deps['wgExtensionMessagesFiles'] = new GlobalDependency( 'wgExtensionMessagesFiles' );
wfRunHooks( 'LocalisationCacheRecache', array( $this, $code, &$allData ) );
if ( is_null( $allData['namespaceNames'] ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' .
'Check that your languages/messages/MessagesEn.php file is intact.' );
}
}
# Save to the persistent cache
+ wfProfileIn( __METHOD__ . '-write' );
$this->store->startWrite( $code );
foreach ( $allData as $key => $value ) {
if ( in_array( $key, self::$splitKeys ) ) {
}
}
$this->store->finishWrite();
+ wfProfileOut( __METHOD__ . '-write' );
# Clear out the MessageBlobStore
# HACK: If using a null (i.e. disabled) storage backend, we
/**
* Start a write transaction.
- * @param $code Language code
+ * @param string $code Language code
*/
function startWrite( $code );
/**
* Set a key to a given value. startWrite() must be called before this
* is called, and finishWrite() must be called afterwards.
- * @param $key
- * @param $value
+ * @param string $key
+ * @param mixed $value
*/
function set( $key, $value );
}
*
*/
define( 'MSG_LOAD_TIMEOUT', 60 );
-define( 'MSG_LOCK_TIMEOUT', 10 );
-define( 'MSG_WAIT_TIMEOUT', 10 );
+define( 'MSG_LOCK_TIMEOUT', 30 );
+define( 'MSG_WAIT_TIMEOUT', 30 );
define( 'MSG_CACHE_VERSION', 1 );
/**
* Get the signleton instance of this class
*
* @since 1.18
- * @return MessageCache object
+ * @return MessageCache
*/
public static function singleton() {
if ( is_null( self::$instance ) ) {
global $wgUseDatabaseMessages, $wgMsgCacheExpiry;
- self::$instance = new self( wfGetMessageCacheStorage(), $wgUseDatabaseMessages, $wgMsgCacheExpiry );
+ self::$instance = new self(
+ wfGetMessageCacheStorage(),
+ $wgUseDatabaseMessages,
+ $wgMsgCacheExpiry
+ );
}
return self::$instance;
}
/**
* Try to load the cache from a local file.
- * Actual format of the file depends on the $wgLocalMessageCacheSerialized
- * setting.
*
* @param string $hash the hash of contents, to check validity.
- * @param $code Mixed: Optional language code, see documenation of load().
- * @return bool on failure.
+ * @param Mixed $code Optional language code, see documenation of load().
+ * @return array The cache array
*/
- function loadFromLocal( $hash, $code ) {
- global $wgCacheDirectory, $wgLocalMessageCacheSerialized;
+ function getLocalCache( $hash, $code ) {
+ global $wgCacheDirectory;
$filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
return false; // No cache file
}
- if ( $wgLocalMessageCacheSerialized ) {
- // Check to see if the file has the hash specified
- $localHash = fread( $file, 32 );
- if ( $hash === $localHash ) {
- // All good, get the rest of it
- $serialized = '';
- while ( !feof( $file ) ) {
- $serialized .= fread( $file, 100000 );
- }
- fclose( $file );
- return $this->setCache( unserialize( $serialized ), $code );
- } else {
- fclose( $file );
- return false; // Wrong hash
+ // Check to see if the file has the hash specified
+ $localHash = fread( $file, 32 );
+ if ( $hash === $localHash ) {
+ // All good, get the rest of it
+ $serialized = '';
+ while ( !feof( $file ) ) {
+ $serialized .= fread( $file, 100000 );
}
+ fclose( $file );
+ return unserialize( $serialized );
} else {
- $localHash = substr( fread( $file, 40 ), 8 );
fclose( $file );
- if ( $hash != $localHash ) {
- return false; // Wrong hash
- }
-
- # Require overwrites the member variable or just shadows it?
- require( $filename );
- return $this->setCache( $this->mCache, $code );
+ return false; // Wrong hash
}
}
wfRestoreWarnings();
}
- function saveToScript( $array, $hash, $code ) {
- global $wgCacheDirectory;
-
- $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
- $tempFilename = $filename . '.tmp';
- wfMkdirParents( $wgCacheDirectory, null, __METHOD__ ); // might fail
-
- wfSuppressWarnings();
- $file = fopen( $tempFilename, 'w' );
- wfRestoreWarnings();
-
- if ( !$file ) {
- wfDebug( "Unable to open local cache file for writing\n" );
- return;
- }
-
- fwrite( $file, "<?php\n//$hash\n\n \$this->mCache = array(" );
-
- foreach ( $array as $key => $message ) {
- $key = $this->escapeForScript( $key );
- $message = $this->escapeForScript( $message );
- fwrite( $file, "'$key' => '$message',\n" );
- }
-
- fwrite( $file, ");\n?>" );
- fclose( $file);
- rename( $tempFilename, $filename );
- }
-
- function escapeForScript( $string ) {
- $string = str_replace( '\\', '\\\\', $string );
- $string = str_replace( '\'', '\\\'', $string );
- return $string;
- }
-
- /**
- * Set the cache to $cache, if it is valid. Otherwise set the cache to false.
- *
- * @return bool
- */
- function setCache( $cache, $code ) {
- if ( isset( $cache['VERSION'] ) && $cache['VERSION'] == MSG_CACHE_VERSION ) {
- $this->mCache[$code] = $cache;
- return true;
- } else {
- return false;
- }
- }
-
/**
* Loads messages from caches or from database in this order:
* (1) local message cache (if $wgUseLocalMessageCache is enabled)
* or false if populating empty cache fails. Also returns true if MessageCache
* is disabled.
*
- * @param bool|String $code String: language to which load messages
+ * @param bool|String $code Language to which load messages
* @throws MWException
* @return bool
*/
function load( $code = false ) {
global $wgUseLocalMessageCache;
- $exception = null; // deferred error
-
if( !is_string( $code ) ) {
# This isn't really nice, so at least make a note about it and try to
# fall back
# Loading code starts
wfProfileIn( __METHOD__ );
$success = false; # Keep track of success
+ $staleCache = false; # a cache array with expired data, or false if none has been loaded
$where = array(); # Debug info, delayed to avoid spamming debug log too much
$cacheKey = wfMemcKey( 'messages', $code ); # Key in memc for messages
- # (1) local cache
+ # Local cache
# Hash of the contents is stored in memcache, to detect if local cache goes
- # out of date (due to update in other thread?)
+ # out of date (e.g. due to replace() on some other server)
if ( $wgUseLocalMessageCache ) {
wfProfileIn( __METHOD__ . '-fromlocal' );
$hash = $this->mMemc->get( wfMemcKey( 'messages', $code, 'hash' ) );
if ( $hash ) {
- $success = $this->loadFromLocal( $hash, $code );
- if ( $success ) $where[] = 'got from local cache';
+ $cache = $this->getLocalCache( $hash, $code );
+ if ( !$cache ) {
+ $where[] = 'local cache is empty or has the wrong hash';
+ } elseif ( $this->isCacheExpired( $cache ) ) {
+ $where[] = 'local cache is expired';
+ $staleCache = $cache;
+ } else {
+ $where[] = 'got from local cache';
+ $success = true;
+ $this->mCache[$code] = $cache;
+ }
}
wfProfileOut( __METHOD__ . '-fromlocal' );
}
- # (2) memcache
- # Fails if nothing in cache, or in the wrong version.
if ( !$success ) {
- wfProfileIn( __METHOD__ . '-fromcache' );
- $cache = $this->mMemc->get( $cacheKey );
- $success = $this->setCache( $cache, $code );
- if ( $success ) {
- $where[] = 'got from global cache';
- $this->saveToCaches( $cache, false, $code );
- }
- wfProfileOut( __METHOD__ . '-fromcache' );
- }
+ # Try the global cache. If it is empty, try to acquire a lock. If
+ # the lock can't be acquired, wait for the other thread to finish
+ # and then try the global cache a second time.
+ for ( $failedAttempts = 0; $failedAttempts < 2; $failedAttempts++ ) {
+ wfProfileIn( __METHOD__ . '-fromcache' );
+ $cache = $this->mMemc->get( $cacheKey );
+ if ( !$cache ) {
+ $where[] = 'global cache is empty';
+ } elseif ( $this->isCacheExpired( $cache ) ) {
+ $where[] = 'global cache is expired';
+ $staleCache = $cache;
+ } else {
+ $where[] = 'got from global cache';
+ $this->mCache[$code] = $cache;
+ $this->saveToCaches( $cache, 'local-only', $code );
+ $success = true;
+ }
- # (3)
- # Nothing in caches... so we need create one and store it in caches
- if ( !$success ) {
- $where[] = 'cache is empty';
- $where[] = 'loading from database';
-
- if ( $this->lock( $cacheKey ) ) {
- $that = $this;
- $osc = new ScopedCallback( function() use ( $that, $cacheKey ) {
- $that->unlock( $cacheKey );
- } );
- }
- # Limit the concurrency of loadFromDB to a single process
- # This prevents the site from going down when the cache expires
- $statusKey = wfMemcKey( 'messages', $code, 'status' );
- $success = $this->mMemc->add( $statusKey, 'loading', MSG_LOAD_TIMEOUT );
- if ( $success ) { // acquired lock
- $cache = $this->mMemc;
- $isc = new ScopedCallback( function() use ( $cache, $statusKey ) {
- $cache->delete( $statusKey );
- } );
- $cache = $this->loadFromDB( $code );
- $success = $this->setCache( $cache, $code );
- if ( $success ) { // messages loaded
- $success = $this->saveToCaches( $cache, true, $code );
- $isc = null; // unlock
- if ( !$success ) {
- $this->mMemc->set( $statusKey, 'error', 60 * 5 );
- wfDebug( __METHOD__ . ": set() error: restart memcached server!\n" );
- $exception = new MWException( "Could not save cache for '$code'." );
+ wfProfileOut( __METHOD__ . '-fromcache' );
+
+ if ( $success ) {
+ # Done, no need to retry
+ break;
+ }
+
+ # We need to call loadFromDB. Limit the concurrency to a single
+ # process. This prevents the site from going down when the cache
+ # expires.
+ $statusKey = wfMemcKey( 'messages', $code, 'status' );
+ $acquired = $this->mMemc->add( $statusKey, 'loading', MSG_LOAD_TIMEOUT );
+ if ( $acquired ) {
+ # Unlock the status key if there is an exception
+ $that = $this;
+ $statusUnlocker = new ScopedCallback( function () use ( $that, $statusKey ) {
+ $that->mMemc->delete( $statusKey );
+ } );
+
+ # Now let's regenerate
+ $where[] = 'loading from database';
+
+ # Lock the cache to prevent conflicting writes
+ # If this lock fails, it doesn't really matter, it just means the
+ # write is potentially non-atomic, e.g. the results of a replace()
+ # may be discarded.
+ if ( $this->lock( $cacheKey ) ) {
+ $mainUnlocker = new ScopedCallback( function () use ( $that, $cacheKey ) {
+ $that->unlock( $cacheKey );
+ } );
+ } else {
+ $mainUnlocker = null;
+ $where[] = 'could not acquire main lock';
}
+
+ $cache = $this->loadFromDB( $code );
+ $this->mCache[$code] = $cache;
+ $success = true;
+ $saveSuccess = $this->saveToCaches( $cache, 'all', $code );
+
+ # Unlock
+ ScopedCallback::consume( $mainUnlocker );
+ ScopedCallback::consume( $statusUnlocker );
+
+ if ( !$saveSuccess ) {
+ # Cache save has failed.
+ # There are two main scenarios where this could be a problem:
+ #
+ # - The cache is more than the maximum size (typically
+ # 1MB compressed).
+ #
+ # - Memcached has no space remaining in the relevant slab
+ # class. This is unlikely with recent versions of
+ # memcached.
+ #
+ # Either way, if there is a local cache, nothing bad will
+ # happen. If there is no local cache, disabling the message
+ # cache for all requests avoids incurring a loadFromDB()
+ # overhead on every request, and thus saves the wiki from
+ # complete downtime under moderate traffic conditions.
+ if ( !$wgUseLocalMessageCache ) {
+ $this->mMemc->set( $statusKey, 'error', 60 * 5 );
+ $where[] = 'could not save cache, disabled globally for 5 minutes';
+ } else {
+ $where[] = "could not save global cache";
+ }
+ }
+
+ # Load from DB complete, no need to retry
+ break;
+ } elseif ( $staleCache ) {
+ # Use the stale cache while some other thread constructs the new one
+ $where[] = 'using stale cache';
+ $this->mCache[$code] = $staleCache;
+ $success = true;
+ break;
+ } elseif ( $failedAttempts > 0 ) {
+ # Already retried once, still failed, so don't do another lock/unlock cycle
+ # This case will typically be hit if memcached is down, or if
+ # loadFromDB() takes longer than MSG_WAIT_TIMEOUT
+ $where[] = "could not acquire status key.";
+ break;
} else {
- $isc = null; // unlock
- $exception = new MWException( "Could not load cache from DB for '$code'." );
+ $status = $this->mMemc->get( $statusKey );
+ if ( $status === 'error' ) {
+ # Disable cache
+ break;
+ } else {
+ # Wait for the other thread to finish, then retry
+ $where[] = 'waited for other thread to complete';
+ $this->lock( $cacheKey );
+ $this->unlock( $cacheKey );
+ }
}
- } else {
- $exception = new MWException( "Could not acquire '$statusKey' lock." );
}
- $osc = null; // unlock
}
if ( !$success ) {
+ $where[] = 'loading FAILED - cache is disabled';
$this->mDisable = true;
$this->mCache = false;
- // This used to go on, but that led to lots of nasty side
- // effects like gadgets and sidebar getting cached with their
- // default content
- if ( $exception instanceof Exception ) {
- throw $exception;
- } else {
- throw new MWException( "MessageCache failed to load messages" );
- }
+ # This used to throw an exception, but that led to nasty side effects like
+ # the whole wiki being instantly down if the memcached server died
} else {
# All good, just record the success
- $info = implode( ', ', $where );
- wfDebug( __METHOD__ . ": Loading $code... $info\n" );
$this->mLoadedLanguages[$code] = true;
}
+ $info = implode( ', ', $where );
+ wfDebug( __METHOD__ . ": Loading $code... $info\n" );
wfProfileOut( __METHOD__ );
return $success;
}
* $wgMaxMsgCacheEntrySize are assigned a special value, and are loaded
* on-demand from the database later.
*
- * @param string $code language code.
- * @return Array: loaded messages for storing in caches.
+ * @param string $code Language code.
+ * @return array Loaded messages for storing in caches.
*/
function loadFromDB( $code ) {
wfProfileIn( __METHOD__ );
foreach ( $res as $row ) {
$text = Revision::getRevisionText( $row );
- if( $text === false ) {
+ if ( $text === false ) {
// Failed to fetch data; possible ES errors?
// Store a marker to fetch on-demand as a workaround...
$entry = '!TOO BIG';
- wfDebugLog( 'MessageCache', __METHOD__ . ": failed to load message page text for {$row->page_title} ($code)" );
+ wfDebugLog(
+ 'MessageCache',
+ __METHOD__
+ . ": failed to load message page text for {$row->page_title} ($code)"
+ );
} else {
$entry = ' ' . $text;
}
}
$cache['VERSION'] = MSG_CACHE_VERSION;
+ $cache['EXPIRY'] = wfTimestamp( TS_MW, time() + $this->mExpiry );
wfProfileOut( __METHOD__ );
return $cache;
}
/**
* Updates cache as necessary when message page is changed
*
- * @param string $title name of the page changed.
- * @param $text Mixed: new contents of the page.
+ * @param string $title Name of the page changed.
+ * @param mixed $text New contents of the page.
*/
public function replace( $title, $text ) {
global $wgMaxMsgCacheEntrySize;
}
# Update caches
- $this->saveToCaches( $this->mCache[$code], true, $code );
+ $this->saveToCaches( $this->mCache[$code], 'all', $code );
$this->unlock( $cacheKey );
// Also delete cached sidebar... just in case it is affected
wfProfileOut( __METHOD__ );
}
+ /**
+ * Is the given cache array expired due to time passing or a version change?
+ *
+ * @param $cache
+ * @return bool
+ */
+ protected function isCacheExpired( $cache ) {
+ if ( !isset( $cache['VERSION'] ) || !isset( $cache['EXPIRY'] ) ) {
+ return true;
+ }
+ if ( $cache['VERSION'] != MSG_CACHE_VERSION ) {
+ return true;
+ }
+ if ( wfTimestampNow() >= $cache['EXPIRY'] ) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Shortcut to update caches.
*
- * @param array $cache cached messages with a version.
- * @param bool $memc Wether to update or not memcache.
- * @param string $code Language code.
- * @return bool on somekind of error.
+ * @param array $cache Cached messages with a version.
+ * @param string $dest Either "local-only" to save to local caches only
+ * or "all" to save to all caches.
+ * @param string|bool $code Language code (default: false)
+ * @return bool
*/
- protected function saveToCaches( $cache, $memc = true, $code = false ) {
+ protected function saveToCaches( $cache, $dest, $code = false ) {
wfProfileIn( __METHOD__ );
- global $wgUseLocalMessageCache, $wgLocalMessageCacheSerialized;
+ global $wgUseLocalMessageCache;
$cacheKey = wfMemcKey( 'messages', $code );
- if ( $memc ) {
- $success = $this->mMemc->set( $cacheKey, $cache, $this->mExpiry );
+ if ( $dest === 'all' ) {
+ $success = $this->mMemc->set( $cacheKey, $cache );
} else {
$success = true;
}
if ( $wgUseLocalMessageCache ) {
$serialized = serialize( $cache );
$hash = md5( $serialized );
- $this->mMemc->set( wfMemcKey( 'messages', $code, 'hash' ), $hash, $this->mExpiry );
- if ( $wgLocalMessageCacheSerialized ) {
- $this->saveToLocal( $serialized, $hash, $code );
- } else {
- $this->saveToScript( $cache, $hash, $code );
- }
+ $this->mMemc->set( wfMemcKey( 'messages', $code, 'hash' ), $hash );
+ $this->saveToLocal( $serialized, $hash, $code );
}
wfProfileOut( __METHOD__ );
/**
* Represents a write lock on the messages key
*
- * @param $key string
- *
+ * @param string $key
* @return Boolean: success
*/
function lock( $key ) {
$lockKey = $key . ':lock';
- for ( $i = 0; $i < MSG_WAIT_TIMEOUT && !$this->mMemc->add( $lockKey, 1, MSG_LOCK_TIMEOUT ); $i++ ) {
+ $acquired = false;
+ $testDone = false;
+ for ( $i = 0; $i < MSG_WAIT_TIMEOUT && !$acquired; $i++ ) {
+ $acquired = $this->mMemc->add( $lockKey, 1, MSG_LOCK_TIMEOUT );
+ if ( $acquired ) {
+ break;
+ }
+
+ # Fail fast if memcached is totally down
+ if ( !$testDone ) {
+ $testDone = true;
+ if ( !$this->mMemc->set( wfMemcKey( 'test' ), 'test', 1 ) ) {
+ break;
+ }
+ }
sleep( 1 );
}
- return $i >= MSG_WAIT_TIMEOUT;
+ return $acquired;
}
function unlock( $key ) {
/**
* Get a message from either the content language or the user language.
*
- * @param $key String: the message cache key
- * @param $useDB Boolean: get the message from the DB, false to use only
+ * @param string $key The message cache key
+ * @param bool $useDB Get the message from the DB, false to use only
* the localisation
* @param bool|string $langcode Code of the language to get the message for, if
* it is a valid code create a language for that language,
* parameter functionality), or if it is a true boolean
* then use the wikis content language (also as a
* fallback).
- * @param $isFullKey Boolean: specifies whether $key is a two part key
- * "msg/lang".
+ * @param bool $isFullKey Specifies whether $key is a two part key "msg/lang".
*
* @throws MWException
* @return string|bool
global $wgLanguageCode, $wgContLang;
if ( is_int( $key ) ) {
- // "Non-string key given" exception sometimes happens for numerical strings that become ints somewhere on their way here
+ // "Non-string key given" exception sometimes happens for numerical
+ // strings that become ints somewhere on their way here
$key = strval( $key );
}
}
# Try the MediaWiki namespace
- if( !$this->mDisable && $useDB ) {
+ if ( !$this->mDisable && $useDB ) {
$title = $uckey;
- if( !$isFullKey && ( $langcode != $wgLanguageCode ) ) {
+ if ( !$isFullKey && ( $langcode != $wgLanguageCode ) ) {
$title .= '/' . $langcode;
}
$message = $this->getMsgFromNamespace( $title, $langcode );
}
# Try the array of another language
- if( $message === false ) {
+ if ( $message === false ) {
$parts = explode( '/', $lckey );
# We may get calls for things that are http-urls from sidebar
# Let's not load nonexistent languages for those
}
# Is this a custom message? Try the default language in the db...
- if( ( $message === false || $message === '-' ) &&
+ if ( ( $message === false || $message === '-' ) &&
!$this->mDisable && $useDB &&
- !$isFullKey && ( $langcode != $wgLanguageCode ) ) {
+ !$isFullKey && ( $langcode != $wgLanguageCode )
+ ) {
$message = $this->getMsgFromNamespace( $uckey, $wgLanguageCode );
}
# Final fallback
- if( $message === false ) {
+ if ( $message === false ) {
return false;
}
* and self::get() are some examples in core.
*
* @param string $title Message cache key with initial uppercase letter.
- * @param string $code code denoting the language to try.
- *
+ * @param string $code Code denoting the language to try.
* @return string|bool False on failure
*/
function getMsgFromNamespace( $title, $code ) {
return substr( $entry, 1 );
} elseif ( $entry === '!NONEXISTENT' ) {
return false;
- } elseif( $entry === '!TOO BIG' ) {
+ } elseif ( $entry === '!TOO BIG' ) {
// Fall through and try invididual message cache below
}
} else {
$content = $revision->getContent();
if ( !$content ) {
// A possibly temporary loading failure.
- wfDebugLog( 'MessageCache', __METHOD__ . ": failed to load message page text for {$title} ($code)" );
+ wfDebugLog(
+ 'MessageCache',
+ __METHOD__ . ": failed to load message page text for {$title} ($code)"
+ );
$message = null; // no negative caching
} else {
// XXX: Is this the right way to turn a Content object into a message?
- // NOTE: $content is typically either WikitextContent, JavaScriptContent or CssContent.
- // MessageContent is *not* used for storing messages, it's only used for wrapping them when needed.
+ // NOTE: $content is typically either WikitextContent, JavaScriptContent or
+ // CssContent. MessageContent is *not* used for storing messages, it's
+ // only used for wrapping them when needed.
$message = $content->getWikitextForTransclusion();
if ( $message === false || $message === null ) {
- wfDebugLog( 'MessageCache', __METHOD__ . ": message content doesn't provide wikitext "
- . "(content model: " . $content->getContentHandler() . ")" );
+ wfDebugLog(
+ 'MessageCache',
+ __METHOD__ . ": message content doesn't provide wikitext "
+ . "(content model: " . $content->getContentHandler() . ")"
+ );
$message = false; // negative caching
} else {
}
/**
- * @param $message string
- * @param $interface bool
- * @param $language
- * @param $title Title
+ * @param string $message
+ * @param bool $interface
+ * @param string $language Language code
+ * @param Title $title
* @return string
*/
function transform( $message, $interface = false, $language = null, $title = null ) {
// Avoid creating parser if nothing to transform
- if( strpos( $message, '{{' ) === false ) {
+ if ( strpos( $message, '{{' ) === false ) {
return $message;
}
}
/**
- * @param $text string
- * @param $title Title
- * @param $linestart bool
- * @param $interface bool
- * @param $language
+ * @param string $text
+ * @param Title $title
+ * @param bool $linestart Whether or not this is at the start of a line
+ * @param bool $interface Whether this is an interface message
+ * @param string $language Language code
* @return ParserOutput|string
*/
- public function parse( $text, $title = null, $linestart = true, $interface = false, $language = null ) {
+ public function parse( $text, $title = null, $linestart = true,
+ $interface = false, $language = null
+ ) {
if ( $this->mInParser ) {
return htmlspecialchars( $text );
}
public function figureMessage( $key ) {
global $wgLanguageCode;
$pieces = explode( '/', $key );
- if( count( $pieces ) < 2 ) {
+ if ( count( $pieces ) < 2 ) {
return array( $key, $wgLanguageCode );
}
$lang = array_pop( $pieces );
- if( !Language::fetchLanguageName( $lang, null, 'mw' ) ) {
+ if ( !Language::fetchLanguageName( $lang, null, 'mw' ) ) {
return array( $key, $wgLanguageCode );
}
* If $code is the content language code, this will return all message keys
* for which MediaWiki:msgkey exists. If $code is another language code, this
* will ONLY return message keys for which MediaWiki:msgkey/$code exists.
- * @param $code string
+ * @param string $code Language code
* @return array of message keys (strings)
*/
public function getAllMessageKeys( $code ) {
// Apparently load() failed
return null;
}
- $cache = $this->mCache[$code]; // Copy the cache
- unset( $cache['VERSION'] ); // Remove the VERSION key
- $cache = array_diff( $cache, array( '!NONEXISTENT' ) ); // Remove any !NONEXISTENT keys
+ // Remove administrative keys
+ $cache = $this->mCache[$code];
+ unset( $cache['VERSION'] );
+ unset( $cache['EXPIRY'] );
+ // Remove any !NONEXISTENT keys
+ $cache = array_diff( $cache, array( '!NONEXISTENT' ) );
// Keys may appear with a capital first letter. lcfirst them.
return array_map( array( $wgContLang, 'lcfirst' ), array_keys( $cache ) );
}
$urlArr = array_unique( $urlArr ); // Remove duplicates
foreach ( $urlArr as $url ) {
if( !is_string( $url ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( 'Bad purge URL' );
}
$url = SquidUpdate::expand( $url );
continue;
}
if ( !isset( $conf['host'] ) || !isset( $conf['port'] ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Invalid HTCP rule for URL $url\n" );
}
$sectionModelId = $with->getModel();
if ( $sectionModelId != $myModelId ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Incompatible content model for section: " .
"document uses $myModelId but " .
"section uses $sectionModelId." );
}
if ( istainted( $sql ) & TC_MYSQL ) {
+ if ( !Profiler::instance()->isStub() ) {
+ wfProfileOut( $queryProf );
+ wfProfileOut( $totalProf );
+ }
throw new MWException( 'Tainted query found' );
}
# Fail now
# Otherwise we get a suppressed fatal error, which is very hard to track down
if ( !function_exists( 'mysql_connect' ) ) {
+ wfProfileOut( __METHOD__ );
throw new DBConnectionError( $this, "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" );
}
interface IORMRow {
- /**
- * Constructor.
- *
- * @since 1.20
- *
- * @param IORMTable $table
- * @param array|null $fields
- * @param boolean $loadDefaults
- */
- public function __construct( IORMTable $table, $fields = null, $loadDefaults = false );
-
/**
* Load the specified fields from the database.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param array|null $fields
* @param boolean $override
* Gets the value of a field but first loads it if not done so already.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param string$name
*
* Load the default values, via getDefaults.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $override
*/
* @since 1.20
*
* @param string|null $functionName
+ * @deprecated since 1.21
*
* @return boolean Success indicator
*/
* Removes the object from the database.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @return boolean Success indicator
*/
/**
* Add an amount (can be negative) to the specified field (needs to be numeric).
- * TODO: most off this stuff makes more sense in the table class
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param string $field
* @param integer $amount
* Computes and updates the values of the summary fields.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param array|string|null $summaryFields
*/
* Sets the value for the @see $updateSummaries field.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $update
*/
* Sets the value for the @see $inSummaryMode field.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $summaryMode
*/
* Returns the table this IORMRow is a row in.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @return IORMTable
*/
}
if ( !$nonErrorLoads ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Empty server array given to LoadBalancer" );
}
wfProfileIn( __METHOD__ );
if ( $i == DB_LAST ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( 'Attempt to call ' . __METHOD__ . ' with deprecated server index DB_LAST' );
} elseif ( $i === null || $i === false ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( 'Attempt to call ' . __METHOD__ . ' with invalid server index' );
}
*/
protected $fields = array( 'id' => null );
- /**
- * @since 1.20
- * @var ORMTable
- */
- protected $table;
-
/**
* If the object should update summaries of linked items when changed.
* For example, update the course_count field in universities when a course in courses is deleted.
* Settings this to false can prevent needless updating work in situations
* such as deleting a university, which will then delete all it's courses.
*
+ * @deprecated since 1.21
* @since 1.20
* @var bool
*/
* This mode indicates that only summary fields got updated,
* which allows for optimizations.
*
+ * @deprecated since 1.21
* @since 1.20
* @var bool
*/
protected $inSummaryMode = false;
+ /**
+ * @deprecated since 1.21
+ * @since 1.20
+ * @var ORMTable|null
+ */
+ protected $table;
+
/**
* Constructor.
*
* @since 1.20
*
- * @param IORMTable $table
+ * @param IORMTable|null $table Deprecated since 1.21
* @param array|null $fields
- * @param boolean $loadDefaults
+ * @param boolean $loadDefaults Deprecated since 1.21
*/
- public function __construct( IORMTable $table, $fields = null, $loadDefaults = false ) {
+ public function __construct( IORMTable $table = null, $fields = null, $loadDefaults = false ) {
$this->table = $table;
if ( !is_array( $fields ) ) {
* Load the specified fields from the database.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param array|null $fields
* @param boolean $override
* Gets the value of a field but first loads it if not done so already.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param $name string
*
&& !is_null( $this->getField( 'id' ) );
}
- /**
- * Sets multiple fields.
- *
- * @since 1.20
- *
- * @param array $fields The fields to set
- * @param boolean $override Override already set fields with the provided values?
- */
- public function setFields( array $fields, $override = true ) {
- foreach ( $fields as $name => $value ) {
- if ( $override || !$this->hasField( $name ) ) {
- $this->setField( $name, $value );
- }
- }
- }
-
/**
* Gets the fields => values to write to the table.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @return array
*/
switch ( $type ) {
case 'array':
$value = (array)$value;
- // fall-through!
+ // fall-through!
case 'blob':
$value = serialize( $value );
- // fall-through!
+ // fall-through!
}
$values[$this->table->getPrefixedField( $name )] = $value;
return $values;
}
+ /**
+ * Sets multiple fields.
+ *
+ * @since 1.20
+ *
+ * @param array $fields The fields to set
+ * @param boolean $override Override already set fields with the provided values?
+ */
+ public function setFields( array $fields, $override = true ) {
+ foreach ( $fields as $name => $value ) {
+ if ( $override || !$this->hasField( $name ) ) {
+ $this->setField( $name, $value );
+ }
+ }
+ }
+
/**
* Serializes the object to an associative array which
* can then easily be converted into JSON or similar.
* Load the default values, via getDefaults.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $override
*/
* when it already exists, or inserting it when it doesn't.
*
* @since 1.20
+ * @deprecated since 1.21 Use IORMTable->updateRow or ->insertRow
*
* @param string|null $functionName
*
*/
public function save( $functionName = null ) {
if ( $this->hasIdField() ) {
- return $this->saveExisting( $functionName );
+ return $this->table->updateRow( $this, $functionName );
} else {
- return $this->insert( $functionName );
+ return $this->table->insertRow( $this, $functionName );
}
}
* Updates the object in the database.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param string|null $functionName
*
$success = $dbw->update(
$this->table->getName(),
$this->getWriteValues(),
- $this->table->getPrefixedValues( $this->getUpdateConditions() ),
+ $this->table->getPrefixedValues( $this->getWriteValues() ),
is_null( $functionName ) ? __METHOD__ : $functionName
);
* Inserts the object into the database.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param string|null $functionName
* @param array|null $options
* Removes the object from the database.
*
* @since 1.20
+ * @deprecated since 1.21, use IROMtable->removeRow
*
* @return boolean Success indicator
*/
public function remove() {
$this->beforeRemove();
- $success = $this->table->delete( array( 'id' => $this->getId() ), __METHOD__ );
-
- // DatabaseBase::delete does not always return true for success as documented...
- $success = $success !== false;
+ $success = $this->table->removeRow( $this, __METHOD__ );
if ( $success ) {
$this->onRemoved();
* Gets called before an object is removed from the database.
*
* @since 1.20
+ * @deprecated since 1.21
*/
protected function beforeRemove() {
$this->loadFields( $this->getBeforeRemoveFields(), false, true );
* Can be overridden to get rid of linked data.
*
* @since 1.20
+ * @deprecated since 1.21
*/
protected function onRemoved() {
$this->setField( 'id', null );
* @throws MWException
*/
public function setField( $name, $value ) {
- $fields = $this->table->getFields();
-
- if ( array_key_exists( $name, $fields ) ) {
- switch ( $fields[$name] ) {
- case 'int':
- $value = (int)$value;
- break;
- case 'float':
- $value = (float)$value;
- break;
- case 'bool':
- $value = (bool)$value;
- break;
- case 'array':
- if ( is_string( $value ) ) {
- $value = unserialize( $value );
- }
-
- if ( !is_array( $value ) ) {
- $value = array();
- }
- break;
- case 'blob':
- if ( is_string( $value ) ) {
- $value = unserialize( $value );
- }
- break;
- case 'id':
- if ( is_string( $value ) ) {
- $value = (int)$value;
- }
- break;
- }
-
- $this->fields[$name] = $value;
- } else {
- throw new MWException( 'Attempted to set unknown field ' . $name );
- }
+ $this->fields[$name] = $value;
}
/**
* Add an amount (can be negative) to the specified field (needs to be numeric).
- * TODO: most off this stuff makes more sense in the table class
*
* @since 1.20
+ * @deprecated since 1.21, use IORMTable->addToField
*
* @param string $field
* @param integer $amount
* @return boolean Success indicator
*/
public function addToField( $field, $amount ) {
- if ( $amount == 0 ) {
- return true;
- }
-
- if ( !$this->hasIdField() ) {
- return false;
- }
-
- $absoluteAmount = abs( $amount );
- $isNegative = $amount < 0;
-
- $dbw = $this->table->getWriteDbConnection();
-
- $fullField = $this->table->getPrefixedField( $field );
-
- $success = $dbw->update(
- $this->table->getName(),
- array( "$fullField=$fullField" . ( $isNegative ? '-' : '+' ) . $absoluteAmount ),
- array( $this->table->getPrefixedField( 'id' ) => $this->getId() ),
- __METHOD__
- );
-
- if ( $success && $this->hasField( $field ) ) {
- $this->setField( $field, $this->getField( $field ) + $amount );
- }
-
- $this->table->releaseConnection( $dbw );
-
- return $success;
+ return $this->table->addToField( $this->getUpdateConditions(), $field, $amount );
}
/**
* Return the names of the fields.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @return array
*/
* Computes and updates the values of the summary fields.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param array|string|null $summaryFields
*/
* Sets the value for the @see $updateSummaries field.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $update
*/
* Sets the value for the @see $inSummaryMode field.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @param boolean $summaryMode
*/
$this->inSummaryMode = $summaryMode;
}
- /**
- * Return if any fields got changed.
- *
- * @since 1.20
- *
- * @param IORMRow $object
- * @param boolean|array $excludeSummaryFields
- * When set to true, summary field changes are ignored.
- * Can also be an array of fields to ignore.
- *
- * @return boolean
- */
- protected function fieldsChanged( IORMRow $object, $excludeSummaryFields = false ) {
- $exclusionFields = array();
-
- if ( $excludeSummaryFields !== false ) {
- $exclusionFields = is_array( $excludeSummaryFields ) ? $excludeSummaryFields : $this->table->getSummaryFields();
- }
-
- foreach ( $this->fields as $name => $value ) {
- $excluded = $excludeSummaryFields && in_array( $name, $exclusionFields );
-
- if ( !$excluded && $object->getField( $name ) !== $value ) {
- return true;
- }
- }
-
- return false;
- }
-
/**
* Returns the table this IORMRow is a row in.
*
* @since 1.20
+ * @deprecated since 1.21
*
* @return IORMTable
*/
*/
public function getFieldsFromDBResult( stdClass $result ) {
$result = (array)$result;
- return array_combine(
+
+ $rawFields = array_combine(
$this->unprefixFieldNames( array_keys( $result ) ),
array_values( $result )
);
+
+ $fieldDefinitions = $this->getFields();
+ $fields = array();
+
+ foreach ( $rawFields as $name => $value ) {
+ if ( array_key_exists( $name, $fieldDefinitions ) ) {
+ switch ( $fieldDefinitions[$name] ) {
+ case 'int':
+ $value = (int)$value;
+ break;
+ case 'float':
+ $value = (float)$value;
+ break;
+ case 'bool':
+ if ( is_string( $value ) ) {
+ $value = $value !== '0';
+ } elseif ( is_int( $value ) ) {
+ $value = $value !== 0;
+ }
+ break;
+ case 'array':
+ if ( is_string( $value ) ) {
+ $value = unserialize( $value );
+ }
+
+ if ( !is_array( $value ) ) {
+ $value = array();
+ }
+ break;
+ case 'blob':
+ if ( is_string( $value ) ) {
+ $value = unserialize( $value );
+ }
+ break;
+ case 'id':
+ if ( is_string( $value ) ) {
+ $value = (int)$value;
+ }
+ break;
+ }
+
+ $fields[$name] = $value;
+ } else {
+ throw new MWException( 'Attempted to set unknown field ' . $name );
+ }
+ }
+
+ return $fields;
}
/**
*
* @since 1.20
*
- * @param array $data
+ * @param array $fields
* @param boolean $loadDefaults
*
* @return IORMRow
*/
- public function newRow( array $data, $loadDefaults = false ) {
+ public function newRow( array $fields, $loadDefaults = false ) {
$class = $this->getRowClass();
- return new $class( $this, $data, $loadDefaults );
+
+ return new $class( $this, $fields, $loadDefaults );
}
/**
return array_key_exists( $name, $this->getFields() );
}
+ /**
+ * Updated the provided row in the database.
+ *
+ * @since 1.21
+ *
+ * @param IORMRow $row The row to save
+ * @param string|null $functionName
+ *
+ * @return boolean Success indicator
+ */
+ public function updateRow( IORMRow $row, $functionName = null ) {
+ $dbw = $this->getWriteDbConnection();
+
+ $success = $dbw->update(
+ $this->getName(),
+ $this->getWriteValues( $row ),
+ $this->getPrefixedValues( array( 'id' => $row->getId() ) ),
+ is_null( $functionName ) ? __METHOD__ : $functionName
+ );
+
+ $this->releaseConnection( $dbw );
+
+ // DatabaseBase::update does not always return true for success as documented...
+ return $success !== false;
+ }
+
+ /**
+ * Inserts the provided row into the database.
+ *
+ * @since 1.21
+ *
+ * @param IORMRow $row
+ * @param string|null $functionName
+ * @param array|null $options
+ *
+ * @return boolean Success indicator
+ */
+ public function insertRow( IORMRow $row, $functionName = null, array $options = null ) {
+ $dbw = $this->getWriteDbConnection();
+
+ $success = $dbw->insert(
+ $this->getName(),
+ $this->getWriteValues( $row ),
+ is_null( $functionName ) ? __METHOD__ : $functionName,
+ $options
+ );
+
+ // DatabaseBase::insert does not always return true for success as documented...
+ $success = $success !== false;
+
+ if ( $success ) {
+ $row->setField( 'id', $dbw->insertId() );
+ }
+
+ $this->releaseConnection( $dbw );
+
+ return $success;
+ }
+
+ /**
+ * Gets the fields => values to write to the table.
+ *
+ * @since 1.20
+ *
+ * @param IORMRow $row
+ *
+ * @return array
+ */
+ protected function getWriteValues( IORMRow $row ) {
+ $values = array();
+
+ $rowFields = $row->getFields();
+
+ foreach ( $this->getFields() as $name => $type ) {
+ if ( array_key_exists( $name, $rowFields ) ) {
+ $value = $rowFields[$name];
+
+ switch ( $type ) {
+ case 'array':
+ $value = (array)$value;
+ // fall-through!
+ case 'blob':
+ $value = serialize( $value );
+ // fall-through!
+ }
+
+ $values[$this->getPrefixedField( $name )] = $value;
+ }
+ }
+
+ return $values;
+ }
+
+ /**
+ * Removes the provided row from the database.
+ *
+ * @since 1.21
+ *
+ * @param IORMRow $row
+ * @param string|null $functionName
+ *
+ * @return boolean Success indicator
+ */
+ public function removeRow( IORMRow $row, $functionName = null ) {
+ $success = $this->delete(
+ array( 'id' => $row->getId() ),
+ is_null( $functionName ) ? __METHOD__ : $functionName
+ );
+
+ // DatabaseBase::delete does not always return true for success as documented...
+ return $success !== false;
+ }
+
+ /**
+ * Add an amount (can be negative) to the specified field (needs to be numeric).
+ *
+ * @since 1.21
+ *
+ * @param array $conditions
+ * @param string $field
+ * @param integer $amount
+ *
+ * @return boolean Success indicator
+ * @throws MWException
+ */
+ public function addToField( array $conditions, $field, $amount ) {
+ if ( !array_key_exists( $field, $this->fields ) ) {
+ throw new MWException( 'Unknown field "' . $field . '" provided' );
+ }
+
+ if ( $amount == 0 ) {
+ return true;
+ }
+
+ $absoluteAmount = abs( $amount );
+ $isNegative = $amount < 0;
+
+ $fullField = $this->getPrefixedField( $field );
+
+ $dbw = $this->getWriteDbConnection();
+
+ $success = $dbw->update(
+ $this->getName(),
+ array( "$fullField=$fullField" . ( $isNegative ? '-' : '+' ) . $absoluteAmount ),
+ $this->getPrefixedValues( $conditions ),
+ __METHOD__
+ ) !== false; // DatabaseBase::update does not always return true for success as documented...
+
+ $this->releaseConnection( $dbw );
+
+ return $success;
+ }
+
}
throw new PermissionsError( 'read', $permErrors );
}
- # If external diffs are enabled both globally and for the user,
- # we'll use the application/x-external-editor interface to call
- # an external diff tool like kompare, kdiff3, etc.
- if ( ExternalEdit::useExternalEngine( $this->getContext(), 'diff' ) ) {
- //TODO: come up with a good solution for non-text content here.
- // at least, the content format needs to be passed to the client somehow.
- // Currently, action=raw will just fail for non-text content.
-
- $urls = array(
- 'File' => array( 'Extension' => 'wiki', 'URL' =>
- # This should be mOldPage, but it may not be set, see below.
- $this->mNewPage->getCanonicalURL( array(
- 'action' => 'raw', 'oldid' => $this->mOldid ) )
- ),
- 'File2' => array( 'Extension' => 'wiki', 'URL' =>
- $this->mNewPage->getCanonicalURL( array(
- 'action' => 'raw', 'oldid' => $this->mNewid ) )
- ),
- );
-
- $externalEditor = new ExternalEdit( $this->getContext(), $urls );
- $externalEditor->execute();
-
- wfProfileOut( __METHOD__ );
- return;
- }
-
$rollback = '';
$undoLink = '';
wfProfileIn( __METHOD__ . '-' . $this->name );
foreach ( $fileOpHandles as $fileOpHandle ) {
if ( !( $fileOpHandle instanceof FileBackendStoreOpHandle ) ) {
+ wfProfileOut( __METHOD__ . '-' . $this->name );
+ wfProfileOut( __METHOD__ );
throw new MWException( "Given a non-FileBackendStoreOpHandle object." );
} elseif ( $fileOpHandle->backend->getName() !== $this->getName() ) {
+ wfProfileOut( __METHOD__ . '-' . $this->name );
+ wfProfileOut( __METHOD__ );
throw new MWException( "Given a FileBackendStoreOpHandle for the wrong backend." );
}
}
$this->$name = $value;
}
} else {
+ wfProfileOut( $fname );
throw new MWException( "Could not find data for image '{$this->getName()}'." );
}
$this->$name = $value;
}
} else {
+ wfProfileOut( __METHOD__ );
throw new MWException( "Could not find data for image '{$this->archive_name}'." );
}
if ( $wgLocalisationCacheConf['manualRecache'] ) {
$this->rebuildLocalisationCache();
}
+ MessageBlobStore::clear();
$this->output( "done.\n" );
}
);
/** German (Deutsch)
+ * @author Geitost
* @author Kghbln
* @author LWChris
* @author Metalhead64
Das für sie vorgesehene Verzeichnis muss während des Installationsvorgangs beschreibbar sein.
-Es sollte '''nicht'' über das Web zugänglich sein, was der Grund ist, warum die Datei nicht dort abgelegt wird, wo sich die PHP-Dateien befinden.
+Es sollte '''nicht''' über das Web zugänglich sein, was der Grund ist, warum die Datei nicht dort abgelegt wird, wo sich die PHP-Dateien befinden.
Das Installationsprogramm wird mit der Datei zusammen eine zusätzliche <code>.htaccess</code>-Datei erstellen. Sofern dies scheitert, können Dritte auf die Datendatei zugreifen.
Dies umfasst die Nutzerdaten (E-Mail-Adressen, Passwörter, etc.) wie auch gelöschte Seitenversionen und andere vertrauliche Daten, die im Wiki gespeichert sind.
-Es ist daher zu erwägen die Datendatei an gänzlich anderer Stelle abzulegen, beispielsweise im Verzeichnis <code>./var/lib/mediawiki/yourwiki</code>.",
+Es ist daher zu erwägen, die Datendatei an gänzlich anderer Stelle abzulegen, beispielsweise im Verzeichnis <code>./var/lib/mediawiki/yourwiki</code>.",
'config-oracle-def-ts' => 'Standardtabellenraum:',
'config-oracle-temp-ts' => 'Temporärer Tabellenraum:',
'config-type-mysql' => 'MySQL',
'config-upload-deleted-help' => 'Bitte ein Verzeichnis auswählen, in dem gelöschte Dateien archiviert werden sollen.
Idealerweise sollte es nicht über das Internet zugänglich sein.',
'config-logo' => 'URL des Logos:',
- 'config-logo-help' => 'Die Standardoberfläche von MediaWiki verfügt links oberhalb der Seitenleiste über Platz für eine Logo mit den Maßen 135x160 Pixel.
+ 'config-logo-help' => 'Die Standardoberfläche von MediaWiki verfügt links oberhalb der Seitenleiste über Platz für ein Logo mit den Maßen 135x160 Pixel.
Bitte ein Logo in entsprechender Größe hochladen und die zugehörige URL an dieser Stelle angeben.
Du kannst $wgStylePath oder $wgScriptPath verwenden, falls dein Logo relativ zu diesen Pfaden ist.
'config-upload-deleted-help' => '삭제된 파일을 보관할 디렉토리를 선택하세요.
이상적으로 웹에서 접근할 수 없게 해야 합니다.',
'config-logo' => '로고 URL:',
- 'config-logo-help' => '미디어위키의 기본 스킨은 사이드바 메뉴 위에 135×160 픽셀의 로고를 포함하고 있습니다.
-적당한 크기로 이미지를 올리고 URL을 여기에 입력하세요.
+ 'config-logo-help' => '미디어위키의 기본 스킨은 사이드바 메뉴 위에 135×160 픽셀의 로고의 공간을 포함하고 있습니다.
+적당한 크기로 그림을 올리고 여기에 URL을 입력하세요.
+
+로고가 상대적인 경로에 있으면 $wgStylePath나 $wgScriptPath를 사용할 수 있습니다.
로고 사용을 원하지 않으면 이 상자를 비우세요.',
'config-instantcommons' => '인스턴트 공용 활성화',
'config-optional-continue' => 'Stellt mir méi Froen.',
'config-optional-skip' => "Ech hunn es genuch, installéier just d'Wiki.",
'config-profile' => 'Profil vun de Benotzerrechter:',
- 'config-profile-wiki' => 'Traditionell Wiki', # Fuzzy
+ 'config-profile-wiki' => 'Oppe Wiki',
'config-profile-no-anon' => 'Uleeë vun engem Benotzerkont verlaangt',
'config-profile-fishbowl' => 'Nëmmen autoriséiert Editeuren',
'config-profile-private' => 'Privat Wiki',
'config-header-sqlite' => 'SQLite-instellingen',
'config-header-oracle' => 'Oracle-instellingen',
'config-invalid-db-type' => 'Ongeldig databasetype',
- 'config-missing-db-name' => 'U moet een waarde ingeven voor "Databasenaam"',
+ 'config-missing-db-name' => 'U moet een waarde opgeven voor "Databasenaam"',
'config-missing-db-host' => 'U moet een waarde invoeren voor "Databaseserver"',
- 'config-missing-db-server-oracle' => 'U moet een waarde voor "Database-TNS" ingeven',
+ 'config-missing-db-server-oracle' => 'U moet een waarde opgeven voor "Database-TNS"',
'config-invalid-db-server-oracle' => 'Ongeldige database-TMS "$1".
Gebruik alleen letters (a-z, A-Z), cijfers (0-9) en liggende streepjes (_).',
'config-invalid-db-name' => 'Ongeldige databasenaam "$1".
'config-ns-other' => 'Andere (geef aan welke)',
'config-ns-other-default' => 'MijnWiki',
'config-project-namespace-help' => "In het kielzog van Wikipedia beheren veel wiki's hun beleidspagina's apart van hun inhoudelijke pagina's in een \"'''projectnaamruimte'''\".
-Alle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat u hier kunt aangeven.
+Alle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat u hier kunt opgeven.
Dit voorvoegsel wordt meestal afgeleid van de naam van de wiki, maar het kan geen bijzondere tekens bevatten als \"#\" of \":\".",
- 'config-ns-invalid' => 'De aangegeven naamruimte "<nowiki>$1</nowiki>" is ongeldig.
+ 'config-ns-invalid' => 'De opgegeven naamruimte "<nowiki>$1</nowiki>" is ongeldig.
Geef een andere naamruimte op.',
- 'config-ns-conflict' => 'De aangegeven naamruimte "<nowiki>$1</nowiki>" conflicteert met een standaard naamruimte in MediaWiki.
+ 'config-ns-conflict' => 'De opgegeven naamruimte "<nowiki>$1</nowiki>" conflicteert met een standaard naamruimte in MediaWiki.
Geef een andere naam op voor de projectnaamruimte.',
'config-admin-box' => 'Beheerdersgebruiker',
'config-admin-name' => 'Uw naam:',
'config-cc-error' => 'De licentiekiezer van Creative Commons heeft geen resultaat opgeleverd.
Voer de licentie handmatig in.',
'config-cc-again' => 'Opnieuw kiezen...',
- 'config-cc-not-chosen' => 'Kies alstublieft de Creative Commonslicentie die u wilt gebruiken en klik op "doorgaan".',
+ 'config-cc-not-chosen' => 'Kies de Creative Commonslicentie die u wilt gebruiken en klik op "doorgaan".',
'config-advanced-settings' => 'Gevorderde instellingen',
'config-cache-options' => 'Instellingen voor het cachen van objecten:',
'config-cache-help' => 'Het cachen van objecten wordt gebruikt om de snelheid van MediaWiki te verbeteren door vaak gebruikte gegevens te bewaren.
Mogelijk moet u aanvullende instellingen maken, maar u kunt deze uitbreidingen nu inschakelen.',
'config-install-alreadydone' => "'''Waarschuwing:''' het lijkt alsof u MediaWiki al hebt geïnstalleerd en probeert het programma opnieuw te installeren.
-Ga alstublieft door naar de volgende pagina.",
+Ga door naar de volgende pagina.",
'config-install-begin' => 'Als u nu op "{{int:config-continue}}" klikt, begint de installatie van MediaWiki.
Als u nog wijzigingen wilt maken, klik dan op "{{int:config-back}}".',
'config-install-step-done' => 'afgerond',
$1
Als je het databasesysteem dat je wilt gebruiken niet in de lijst terugvindt, volg dan de handleiding waarnaar hierboven wordt verwezen om ondersteuning toe te voegen.',
- 'config-missing-db-name' => 'Je moet een waarde ingeven voor "Databasenaam"',
+ 'config-missing-db-name' => 'Je moet een waarde opgeven voor "Databasenaam"',
'config-missing-db-host' => 'Je moet een waarde invoeren voor "Databaseserver"',
- 'config-missing-db-server-oracle' => 'Je moet een waarde voor "Database-TNS" ingeven',
+ 'config-missing-db-server-oracle' => 'Je moet een waarde opgeven voor "Database-TNS"',
'config-postgres-old' => 'PostgreSQL $1 of hoger is vereist.
Jij gebruikt $2.',
'config-sqlite-name-help' => 'Kies een naam die je wiki identificeert.
In '''UTF-8-modus''' kent MySQL de tekenset van je gegevens en kan de databaseserver ze juist weergeven en converteren.
Het is dat niet mogelijk tekens op te slaan die de \"[//nl.wikipedia.org/wiki/Lijst_van_Unicode-subbereiken#Basic_Multilingual_Plane Basic Multilingual Plane]\" te boven gaan.",
- 'config-ibm_db2-low-db-pagesize' => "Je DB2-database heeft een standaard tablespace met een onvoldoende grote pagesize. De pagesize moet tenminste '''32K''' zijn.",
'config-project-namespace-help' => "In het kielzog van Wikipedia beheren veel wiki's hun beleidspagina's apart van hun inhoudelijke pagina's in een \"'''projectnaamruimte'''\".
-Alle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat je hier kunt aangeven.
+Alle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat je hier kunt opgeven.
Dit voorvoegsel wordt meestal afgeleid van de naam van de wiki, maar het kan geen bijzondere tekens bevatten als \"#\" of \":\".",
'config-admin-name' => 'Je naam:',
'config-admin-password-mismatch' => 'De twee door jou ingevoerde wachtwoorden komen niet overeen.',
'config-logo-help' => 'Het standaarduiterlijk van MediaWiki bevat ruimte voor een logo van 135x160 pixels boven het menu.
Upload een afbeelding met de juiste afmetingen en voer de URL hier in.
-Als je geen logo wilt gebruiken, kan je dit veld leeg laten.',
- 'config-cc-not-chosen' => 'Kies alsjeblieft de Creative Commonslicentie die je wilt gebruiken en klik op "doorgaan".',
+Als je geen logo wilt gebruiken, kan je dit veld leeg laten.', # Fuzzy
+ 'config-cc-not-chosen' => 'Kies de Creative Commonslicentie die je wilt gebruiken en klik op "doorgaan".',
'config-memcache-needservers' => 'Je hebt Memcached geselecteerd als je cache, maar je hebt geen servers opgegeven.',
'config-memcache-badip' => 'Je hebt een ongeldig IP-adres ingevoerd voor Memcached: $1.',
'config-memcache-noport' => 'Je hebt geen poort opgegeven voor de Memcachedserver: $1.
Mogelijk moet je aanvullende instellingen maken, maar je kunt deze uitbreidingen nu inschakelen.',
'config-install-alreadydone' => "'''Waarschuwing:''' het lijkt alsof je MediaWiki al hebt geïnstalleerd en probeert het programma opnieuw te installeren.
-Ga alsjeblieft door naar de volgende pagina.",
+Ga door naar de volgende pagina.",
'config-install-begin' => 'Als je nu op "{{int:config-continue}}" klikt, begint de installatie van MediaWiki.
Als je nog wijzigingen wilt maken, klik dan op "Terug".', # Fuzzy
'config-pg-no-plpgsql' => 'Je moet de taal PL/pgSQL installeren in de database $1',
/** Polish (polski)
* @author Beau
* @author BeginaFelicysym
+ * @author Chrumps
* @author Holek
* @author Saper
* @author Sp5uhe
'config-optional-continue' => 'Zadaj mi więcej pytań.',
'config-optional-skip' => 'Jestem już znudzony, po prostu zainstaluj wiki.',
'config-profile' => 'Profil uprawnień użytkowników',
- 'config-profile-wiki' => 'Tradycyjne wiki', # Fuzzy
+ 'config-profile-wiki' => 'Otwarte wiki',
'config-profile-no-anon' => 'Wymagane utworzenie konta',
'config-profile-fishbowl' => 'Wyłącznie zatwierdzeni edytorzy',
'config-profile-private' => 'Prywatna wiki',
'config-logo-help' => 'Domyślny motyw MediaWiki zawiera miejsce na logo wielkości 135 x 160 pikseli powyżej menu na pasku bocznym.
Prześlij obrazek o odpowiednim rozmiarze, a następnie wpisz jego URL tutaj.
-Jeśli nie chcesz logo, pozostaw to pole puste.',
+Jeśli nie chcesz logo, pozostaw to pole puste.', # Fuzzy
'config-instantcommons' => 'Włącz Instant Commons',
'config-instantcommons-help' => '[//www.mediawiki.org/wiki/InstantCommons Instant Commons] jest funkcją, która pozwala wiki używać obrazów, dźwięków i innych mediów znalezionych na witrynie [//commons.wikimedia.org/ Wikimedia Commons].
Aby to zrobić, MediaWiki wymaga dostępu do internetu.
if( defined( 'PRETTY_UTF8' ) ) {
function pretty( $string ) {
- return preg_replace( '/([\x00-\xff])/e',
- 'sprintf("%02X", ord("$1"))',
- $string );
+ return strtoupper( bin2hex( $string ) );
}
} else {
/**
* @return string
*/
function pretty( $string ) {
- return trim( preg_replace( '/(.)/use',
- 'sprintf("%04X ", utf8ToCodepoint("$1"))',
- $string ) );
+ return strtoupper( utf8ToHexSequence( $string ) );
}
}
* @private
*/
function utf8ToHexSequence( $str ) {
- return rtrim( preg_replace( '/(.)/uSe',
- 'sprintf("%04x ", utf8ToCodepoint("$1"))',
- $str ) );
+ $buf = '';
+ foreach ( preg_split( '//u', $str, -1, PREG_SPLIT_NO_EMPTY ) as $cp ) {
+ $buf .= sprintf( '%04x ', utf8ToCodepoint( $cp ) );
+ }
+ return rtrim( $buf );
}
/**
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
if ( $bits === false ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "PCRE needs to be compiled with --enable-unicode-properties in order for MediaWiki to function" );
}
$s = array_shift( $bits );
}
break;
default:
+ wfProfileOut( __METHOD__ );
throw new MWException( "State machine error in " . __METHOD__ );
}
}
$result = $this->callParserFunction( $frame, $func, $funcArgs );
} catch ( Exception $ex ) {
wfProfileOut( __METHOD__ . '-pfunc' );
+ wfProfileOut( __METHOD__ );
throw $ex;
}
$this->parser->mGeneratedPPNodeCount += substr_count( $xml, '<' );
$max = $this->parser->mOptions->getMaxGeneratedPPNodeCount();
if ( $this->parser->mGeneratedPPNodeCount > $max ) {
+ if ( $cacheable ) {
+ wfProfileOut( __METHOD__ . '-cacheable' );
+ }
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ': generated node count limit exceeded' );
}
// 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2 don't barf when the XML is >256 levels deep
$result = $dom->loadXML( $xml, 1 << 19 );
if ( !$result ) {
+ wfProfileOut( __METHOD__ . '-loadXML' );
+ if ( $cacheable ) {
+ wfProfileOut( __METHOD__ . '-cacheable' );
+ }
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ' generated invalid XML' );
}
}
$lastNode = $node;
}
if ( !$node ) {
+ if ( $cacheable ) {
+ wfProfileOut( __METHOD__ . '-cache-miss' );
+ wfProfileOut( __METHOD__ . '-cacheable' );
+ }
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ': eqpos not found' );
}
if ( $node->name !== 'equals' ) {
+ if ( $cacheable ) {
+ wfProfileOut( __METHOD__ . '-cache-miss' );
+ wfProfileOut( __METHOD__ . '-cacheable' );
+ }
+ wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . ': eqpos is not equals' );
}
$equalsNode = $node;
foreach ( $registrations as $name => $info ) {
// Disallow duplicate registrations
if ( isset( $this->moduleInfos[$name] ) ) {
+ wfProfileOut( __METHOD__ );
// A module has already been registered by this name
throw new MWException(
'ResourceLoader duplicate registration error. ' .
// Check $name for validity
if ( !self::isValidModuleName( $name ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( "ResourceLoader module name '$name' is invalid, see ResourceLoader::isValidModuleName()" );
}
// Old calling convention
// Validate the input
if ( !( $info instanceof ResourceLoaderModule ) ) {
+ wfProfileOut( __METHOD__ );
throw new MWException( 'ResourceLoader invalid module error. ' .
'Instances of ResourceLoaderModule expected.' );
}
// no matter how often we call ob_get_clean(), so instead of doing
// the more intuitive while ( ob_get_level() > 0 ) ob_get_clean();
// we have to be safe here and avoid an infinite loop.
- for ( $i = 0, $len = ob_get_level(); $i < $len; $i++ ) {
+ // Caching the level is not an option, need to allow it to
+ // shorten the loop on-the-fly (bug 46836)
+ for ( $i = 0; $i < ob_get_level(); $i++ ) {
ob_end_clean();
}
),
), $this->getContext() );
$form->setMethod( 'get' );
- $form->setAction( $this->getTitle()->getFullURL() );
$form->setSubmitCallback( array( $this, 'onSubmit' ) );
- $form->setWrapperLegend( $this->msg( 'pageswithprop-legend' ) );
+ $form->setWrapperLegendMsg( 'pageswithprop-legend' );
$form->addHeaderText( $this->msg( 'pageswithprop-text' )->parseAsBlock() );
$form->setSubmitTextMsg( 'pageswithprop-submit' );
$ret = Linker::link( $title, null, array(), array(), array( 'known' ) );
if ( $result->pp_value !== '' ) {
$value = $this->msg( 'parentheses' )
- ->rawParams( Xml::span( $result->pp_value, 'prop-value' ) )
+ ->rawParams( Html::element( 'span', array( 'class' => 'prop-value' ), $result->pp_value ) )
->escaped();
$ret .= " $value";
}
$textMatches = $search->searchText( $rewritten );
}
+ $textStatus = null;
+ if( $textMatches instanceof Status ) {
+ $textStatus = $textMatches;
+ $textMatches = null;
+ }
+
// did you mean... suggestions
- if( $textMatches && $textMatches->hasSuggestion() ) {
+ if( $textMatches && !$textStatus && $textMatches->hasSuggestion() ) {
$st = SpecialPage::getTitleFor( 'Search' );
# mirror Go/Search behavior of original request ..
}
$titleMatches->free();
}
- if( $textMatches ) {
+ if( $textMatches && !$textStatus ) {
// output appropriate heading
if( $numTextMatches > 0 && $numTitleMatches > 0 ) {
// if no title matches the heading is redundant
$textMatches->free();
}
if( $num === 0 ) {
- $out->wrapWikiMsg( "<p class=\"mw-search-nonefound\">\n$1</p>", array( 'search-nonefound', wfEscapeWikiText( $term ) ) );
- $this->showCreateLink( $t );
+ if ( $textStatus ) {
+ $out->addHTML( '<div class="error">' .
+ htmlspecialchars( $textStatus->getWikiText( 'search-error' ) ) . '</div>' );
+ } else {
+ $out->wrapWikiMsg( "<p class=\"mw-search-nonefound\">\n$1</p>",
+ array( 'search-nonefound', wfEscapeWikiText( $term ) ) );
+ $this->showCreateLink( $t );
+ }
}
$out->addHtml( "</div>" );
$out->addHTML( $this->IPInfo() );
if ( $this->getRequest()->getVal( 'easteregg' ) ) {
- if ( $this->showEasterEgg() ) {
- // TODO: put something interesting here
- }
+ // TODO: put something interesting here
}
} else {
// Credits sub page
return 'wiki';
}
- function showEasterEgg() {
- $rx = $rp = $xe = '';
- $alpha = array( "", "kbQW", "\$\n()" );
- $beta = implode( "', '", $alpha);
- $juliet = 'echo $delta + strrev( $foxtrot ) - $alfa + $wgVersion . base64_decode( $bravo ) * $charlie';
- for ( $i = 1; $i <= 4; $i++ ) {
- $rx .= '([^j]*)J';
- $rp .= "+(\\$i)";
- }
-
- $rx = "/$rx/Sei";
- $O = substr( "$alpha')", 1 );
- for ( $i = 1; $i <= strlen( $rx ) / 3; $i++ ) {
- $rx[$i-1] = strtolower( $rx[$i-1] );
- }
- $ry = ".*?(.((.)(.))).{1,3}(.)(.{1,$i})(\\4.\\3)(.).*";
- $ry = "/$ry/Sei";
- $O = substr( "$beta')", 1 );
- preg_match_all( '/(?<=\$)[[:alnum:]]*/', substr( $juliet, 0, $i<<1 ), $charlie );
- foreach( $charlie[0] as $bravo ) {
- $$bravo =& $xe;
- }
- $xe = 'xe=<<<mo/./hfromowoxv=<<<m
-쵍潅旅왎캎𐺆ߨ趥䲀쫥Ꝍ螃䤎꤯溃櫅褡䞠⽬✡栠迤⾏쾃줏袏浣।궇䬃꼁꿤𘐧
-윥桯䦎䵎Ꞅ涁쭀讀撠蝠讄伣枮ⵇ𐡃𐭏沢𞴏⠤쳯蒣䮎컡豣ۅ⦇𐫁漅蛁꼤从楆
-⥀䡦沢⠬輁䲯좡梇䟇伄육较촅䥃要迯쟠꺃ⶥ栆궀撠満ꐣ좧𐠅𐠧讇輤亀➏欣첡쮧⽬
-氀쮧跧𐫥䪀⬬⾅ⵏ괬ত櫤䭀楦괥챣楀귧읠죯쒡ۅ䳄䤄괬躏譇䮄搥䯄津䶮⾅𐫅
-𐴂௧쮯궣輥ߡ亀氀诤⿅諃⫤䮣⦬죄椎貧ඇ쿇亏跤⦌术থۏ仆䛇枡䪄곁謠ⶏⶃ䞣
-궥螏蝁ꤣ⟬极涇𞴧伢ଅ즡⡌浣䯇쿃ⳇ궏ས⢃曦⦥蛧갠컡楧𘬧袏⦏⢠䳠챤⽧⬣⼀潧⭅椤
-軁종쵃䬆꤇溎楯곡⢡꾥첥쫧Ⱨ균檏辀䭮⡄𐞯쿁䱤𐠠柅迠웏⾅豠𐡀𐡅䱀轡⾯쥃⥁溆
-䢣䞮柄ꠌⶡ𐳣蛤椏✠귬ຄ䶃毥𞡯桥ꐥ❣쳀⡧𖥢꽧죄തޥ歠ແ위䯎撯쬁䮣浅
-쾇泮𐢁켄䦯꾯迡曎䢦쿣杦궯⡀䤦䷢𐭢쟁쯯⧤蟯䡏氇𞢣蝤궧ߢ𐭆䛃찃쭣沠
-䴃𐣣䣎𐺃ꥅ轃⣄蟧⦡蟃毣洇䞎Ҡ潄仆𐲃철䢤俎譯泠쮄␥栏쾯ⳏ짡⥡߂ކ澥䲀ⵀ
-ⵡ✬輄䱀굡榏❡첄⦄ꡥⶣ𞡤⺁ݣ𐢅⤡꿄蝡ⴄ贁氃ޅ짣߁𐫄ۥ𐱅欤
-梢蝡柧䥏仏撣𐳣𞠅좇蒣䰤྅࿂ಇ濤䞦쮅沮潁좤澅杣棦ꤤ洯𐳃콅궧쭠
-桎䝆겡쭄겯䥂ⶀ⽬䠇쳄❬Ⰼ䐦⿌웃𒿠첏𐛡浣涆⢤অ䭎갣䴮⡃꤯죠䰀쬯༄䫏
-𐱂ꢅ䬦賧유辇➥佃仮귣젏⭅ꢡ각컄⒤⻠讁涅䠃跥袏佄𐳇泄껧棇满གྷ輤괅❥겠
-𒐧䣂ꤏ襃伎襡웅걯䳣켁쭄洠컥❅⿏亂쯅⢁𐠦诤꣏辀𖥢椯겇毣濢➠
-䮮浥겁沣졣䜦泇歏𐾄搯曯柆ۇۇ䞀泆武況꽌𐧢ꝅ軀⬠쾣𞡀榧𞣏Ⱡ䠦Ⲥ쿇䬄貃柅涢
-갏⼁𐿧ݏౠ𐿣褀涡༅䮄➇ꝣݥ䡏䯎梢輇ꤠ䫣䵀ण漂⢡軀௦襁쫇⾡濧沤
-䜇伢ۇ汧첏䤎잤䛯Ⰱ俇ꢧ殂궏榮ޣ涂氏滦즤蜀⠥𐺏쐣⾏껬콇漯Ꝡ柦櫇읁梠仇장滦⟠꿯
-쮁搥櫢𐫣ꠏ椥𐛤誅栮朥迣⺄ඇ⿏䬂쾏⫠⒧✏궇襤⡁濃Ⱐ歯䛠쮠𞟤컃𞢯⬣濡䦣
-衏貣柂森챏ಇ고蟄䤏젯⫯楀䞄䳣쮅궤轧껯𐪃潇ބ浣𐬀蝤⽧쐣쾇➣𐡦䮠䤣𐠄
-Ꝡ𐾁蠤䬦覯搦⥯쥏梂걯ⵁ೦챁躄轡䢦𐝂財䲧𐦁䬎첁棏␣౦잧棆젥襁젃䤏⢏榀ⵁ
-螅赡𒿯ⶣ赧꾤濁涆𐴂ॡ䳦ߢ赁䯇䢃ꠌ泄柠泡찇𐛢䪂𐝢櫇漥⟤淣ഡ䳮த谀ཡ
-➁血꽧蟧辧게⻣쳏ഡ䠄杮죃汦諤య毠蝅𐦄謄殯䳀ⳏ쟇ආ잏𐿡䳃ۂ䝇䦇⥌켏쥯춏
-𖽢𐳃𐿧𐝢䥦棇潡⥄歡찁朆⻠䤆𖤧漢ꡅ⽄쾠衏䤣অ䤣𐡡𐢏䞦ߣ裏
-ཅۄ춁䲃欆귬𐺀诀滁䝃챃첥꺏쫅䱮અ견Ф𐫁佣澢쿏⽅侮榅𐾄य쥏蜏䣣
-𐫏쵥➤跡殃䰣䯤읤ⴏ굄⥇줡걬০켃𜼧첣䜂찃궀谀Ɽ伎䢮ꤥ⾣𐭁沅䬇䧠𐱇
-沀濡ठ쟠𐺅ꐣ𐴂躄佇⦇毄计賀䢎澡䲄캀䟣褀蠤൯棏蜃澄❧⾥撦⽬ⶥ𐪄யބ躄
-䬎챯⽯䬎Ꞅ굥𐢂⠥䝧朄࿏웥꽬གྷ浅⦁❬𐺆侢栦⧠궠ඦ趤谥此𐲂𐬃軠𐞦
-蛄俧袥补榏읠⤁⠀豇俢쮯꤇➏𐴁ⶤ涮찣읁榠跣⦅ໃಆ䵣谠ꢯ⡧淯柤궡✠䮎괯❅朎
-⥅웣䯮첀꒤𐣠쭏洀蛡楆ൡ䮮ү氠𐜏濆䜢䷯潣歃䷯웁쭄椥䟂➅ૡༀ䭧ܣ죅ए軯䧣
-Ⱔ䐢⬥檂䠮⫤䛠꜡䛆讠✠꿏欣蠡켏豣譄𞣇춣䠃䰠撦朅䮄榦溃貀䶇⾁澡䲮榀
-𐪄䢆侄朦꜇ཏ췧꺁枠櫧桠괬枇ꜯ곇𐰂𘜧𐦄컡濦汥줠𞲡輀𐠣쥇⣃𞴏䳂⟤漇쯣껃𐾀衃
-쯇𐝄浥洄楠৯춥蒧⾯𐫆༂ꤌ毮䤆⺄༠०袀䢂죃ⴣ𐿯梇溄毦螄櫤쳃栅満걌毠ⱌ꒧䢆
-ꥁ泎仧궀辯諯웅津趃অ꿏伏캁⠃𐦂ꝣ䛂贤济杧𐝁撠䱤殥歡躇楄꒧꽧䡣쵧𐱆ꜯ위
-ཀ谠諃𐬃軅␥贠撣߅꽤⠥ಡ𐝀궥윁Ⰴܯ즡歎ⵅഏ蝁구ꝧ܅䱦껡䛦߅蒯俧콣梧䛠ꡇ
-ݧ웥Т⬠䬦榀𐢂貤謣䱦⒡췧濇⧣⤀좯殧줤⣀楏楎굏ݤ滁ۇ𘐧䒯Ⰰҡ䰦椯❏
-趯𐣯豀쵅춀⳥䷠읡ۯ⺄ۅ䶏춤枂櫅ۅ𞥅䱃䭣汮澃𞢃谥ⵤ구콡曤𞣏ই߂읅蠠䞦ꞇⲏ諧
-趯첏䬎𐡏李겠⥇曢汥浆欠躅𐦁𞲯谡袧襃棧𞡡蟀侠찇챠쪇洠܀쯤䝇螏蜏俄⼀ལ
-谥촯䲦⥁ඤ𐐧⤃궅༡褡䭏毆濆⧡蛣Ф蠏ݤ賯꜁溅⡡ߡ䮄榆䵄求謥𐐧Ꞁ쯏⧡貇䛇䐢撦袥
-쮇䫀দ굯⻤襇줅⬅ہఠ⻀쒠䫆𐡅梄梯輤䥣읏⤄ⶡ诃䮢譡ߤ枤櫥伦袠ꢃ쳀裣䰄
-槥淠䯃ඏ⒯𞠣椦泮汣赃潥ദ䰏쮡蝏毁䶂䦧档䪂쟀𐿯졇웄䳎汀𐫣
-漠ꐡଥ认꽡𐭏⦄梎આ枀䠦楇쒤ꞃꤡⴅꞅඅҡ氣즤裀櫁༦𐳃쳣𐡯桧权굁죁
-짤𖤧蟃澀𞲯ߏ⣣⬁Ⱔ졥潆ꐡ⽤웁浥𐫄棆갤濧⼣겅쬄൧젣此潆⻯䜃꤯궠쮥𘬧曀⿅譅槣䞂
-䝎ꡏ䰀梥⾬ܡ𞠥𞺃䢮આ䧮쮃誅櫆죯诠䵀䯀跥⻥䤆Ⰰ꜄棧枃⻇థ誃࿇贄𞡣欎⽡
-𞲄⬏杇𐠅𐱃𞢤➁𐢄꒥즏亀쭁漆첁殎쮁滠𐠥榯⡀䮆䣠준讥䶇⪅껃泃楀갠複撮
-✡𐭢ແ쫃⽤規䥇沁轁𐡅ಢ䧮椁⬇𐤁𞡯杅武楥歎䟄溇䯢迃䪎䳤满ଅⱇ쭀ಥ𞥄䥆⧥좃
-유栤༡𐰃俇Ⰵ殇蠄⽏⾠܇澄⡤䪎榮Я견濂賣쮠仠䝮䶢𐫆ݏ襅褥찯𞤤ݥ象侯쵇궥𞠃윀웧
-殀蛡⫥亃觯潥蠀补ⴄ觧𐡇𐾆ꐯ䡣췡潏⻯⾁諏య꿧䱠찥ꞅ⪃콄즯쳣覧Ⲅ쐯⬃ඤ겤
-ⵃ蟥谣轇䛂𐮄佀߁氣榡桇䷯觠椄챥ꠌ蒯꜌䭤➡侦䣤䲀쥁⒤𐦄Ꝭ䢮ꡌ歡䝯䢣괯⥀
-줣०殣⟄趥좠洦ꢬ装䠆曧➁𒿧椃䠀𞡅𖼧䳇ງ줄ধⰬ覠ꝃ殣涡䳠귥⫤覯𞲡༦
-䢦쥥줤ꡤড젃ಧꢥ諤ඥ枅줄躀ఏ䦎졯譄➇仄䰏蛏촡䞣춅涧⡄滀ଢ䮇每𘠧侇澀ꐡ杣
-槧߅䶠윥귡귧⤯ཆ裁毧⬤蝧첀⭁潤䝎池殤Ҡ䝯ཁ쟧氢귡𒿯ꥄ⭌䜇ۥ
-ꝡ棄⣏ꤥ০쮁桧𐐧ⴤꠡ軅衄䠦ߤ܅ⲃଢ蛄溎椀𞠀䛃𞡣𞟣澅䧤⡇贤⫌쪄ށ朣
-⻏켅⼡𐲀잠௧𞥀౧䦤ས誇漎譠迄䦂䳇正계楧ޅ✬棅쭯诠枢䥮䭆楆컧ଆ
-➬అ䤦誃𐠅𐿤䟀洀⡤滤𞥇즀𐠁⼃䰎溄꽅웇✡䲀⡏ܣ讣⼤覄䡇అ蝀⥌侧껄Ꝭ流贀
-漁쒤첧죏곡⣃趃賄撠।읠ⶌ⾥춧쒡쿀䵯毁涠⣡ꡄ䢀満棃䡯𐛣୯䳯ⵡୡ䥃❇⠅䣆杧𐳃
-귧覀漎𞴁𞤡ཇ䰦𞲣❃歆콣꿇朏𞢄Ꝍ𞡅賡曏꼃꼬ಇ𞴯资榎쮯輤ॡ䜎⦌𐠏⡃쳁࿀
-쯣껧쪃椃쐡⟤߇웅䱧䛣𐳤쮀䠏꽣⠣쟣𞢅ദ洅촥컇쵡ꞅ䠆⒥涯䐢ⴅ쮤꺅
-𞥇컠ⳁ漃𐲃윇诤겣𞥄伣䜠⻇𞡀修꜡䳎❄켇꽡쭄洂꜠Ⰳ쵅𐬂梀櫯䜯꜡䛣༏杇⪀캄⼌
-条𐳄没ⳅ➏첡❬侯캅检𞡧棡䥧𐳃𐝁ཧ謏𐫇讄枥첡쾀欎육웠𐭤୯濧譁챤䶢껤
-쒤𐾂辧褡⼣䳃␠豁ߡ櫦极ⶠઇꝠ𐭤沣棁柄𐳂䠯楅곅⼣⥃ༀ螡ߥ柤褣曠沧꒬
-𐴃䵂䲇蠀𐿧䲇ඦ⺁커謁컁漢䠀调ⲃ䢢ބ辅毡갯䤣椦𞲯१輯𘜧𐳅⽄䴆ଦ
-䱠䒮諃ఏ𐠡桦谁𐡁쥡浣譀⫌쮥ꢅ컁曅ꥅଏ찀汅ೡ谠䬀𞴡䢠쳀⡏ߠߠඅ겧淤
-쥣每譄꼠쫁쭥讥ॡ쿇ஆ伃⫠汇䜢衯楥济俏极撮쬅蜏⧤蛥쮁⥃것ஃ줠䣇迅泆⤯𐧣
-萠泎ଡ蠄涣త⾏⻌䝧ༀ榮ү𐳃歂浅ꡥ첤⬇유讏欤俤잧⡌ⱁ춥氤𐠧修流쫤䵆𞠃܀웣
-곧萡ꠀ걁𞟠认쮀谥잡佮𞺏軡⾁쮯ߡ⧯쟡䰆⽀굇촤认䵄輥𞲇䡮侢朆쬣搢⽃濃⣧柁༢
-⼅ॠ軀浯ܡ컡谤ඤ曢⧠짠컠꿡𐺀곌濂ণ웧⾡栅䞠괬ܤ䦄伏曀了ཡ榧䭦⛃衧濠읥
-쵁𐛣⪅蜤𞤁装고쳅⻁ݣ䳆ৠ䐦ऄ⫏쿧䜎𐿣젡귧棥櫁쿣泯俣佦⾥朦潏ꢤꙧ𐺆ڦՈ췥
-췧䙭䶍澥쨯쵥Ⱕ쵥䗌쵍潅旅暬Ոⵤ旆줭젠ৡ쮠┢潧贮跣쓄䔭⽇𞴥ꔥ䓭
-₎챍澥엇곭贇Ԇ쬡쩯䘠䯃湁Ո꽤엇ꔭ₎谥䗌쳭䙭䟍◎쳭䙍侭쾇쵤蓄䕍췥췧䓭◎쳭
-䒭ߏ䓭亭è청䙭侭䷤擏䕍췤⽇䐍䕍ⵤ摆位ཧ暬è춍찤ⲥ䙭䔭è谥䗌첍䙭䟍◎䕍
-엎ߏ◎첍⒬䓭亭è效𐱅궤◄虬䶭侄䗌꾄쓅䕍췥췧╂旄◌첍旌藂꾄쓅䕍ⵤ檦첍旌暬è效
-꽤엇虬䕍𐱅궤⚤è챍澥엇춍찤ⲥ₎찭䙭侭쾇൧蓇䕍꽤엇暬೨藅䗌ⳇ查䗌찭䓭䙭䔭
-枅ද➥赏ⵯඏ춥쟅ⵅ쟥螥ⴅ춯䟏췯淯䴏ꗍ旌₆效ꡁ桁⪣꼭ⱅ졣쓀暬è
-줭젠ৡ쮠┢꽠跮쵅䭀𞡀䗌è斈쳮𞴤侭ට潅暅汤津࿄𞴥ⶎ澥쑏肌惨澈漥쵤
-趤굄䶍澥쨯Ⱕ쵥䗌찭䓭䓭䐍è惨Э薎è擨₎
-mowoxf=<<<moDzk=hgs8GbPbqrcbvagDdJkbe zk=zk>0kssss?zk-0k10000:zk kbe zk=DDzk<<3&0kssssJ|Dzk>>13JJ^3658 kbe zk=pueDzk&0kssJ.pueDzk>>8JJ?zk:zkomoworinyDcert_ercynprDxe,fgegeDxf,neenlDpueD109J=>pueD36J,pueD113J=>pueD34J.pueD92J. 0 .pueD34JJJ,fgegeDxv,neenlDpueD13J=>snyfr,pueD10J=>snyfrJJJJwo';
-
- $haystack = preg_replace( $ry, "$1$2$5$1_$7$89$i$5$6$8$O", $juliet );
- return preg_replace( $rx, $rp, $haystack );
- }
}
* internationalisation, a reduced set of format characters, and a better
* escaping format.
*
- * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrU. See the
- * PHP manual for definitions. There are a number of extensions, which
+ * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrUeIOPTZ. See
+ * the PHP manual for definitions. There are a number of extensions, which
* start with "x":
*
* xn Do not translate digits of the next numeric format character
* Backslash escaping is also supported.
*
* Input timestamp is assumed to be pre-normalized to the desired local
- * time zone, if any.
+ * time zone, if any. Note that the format characters crUeIOPTZ will assume
+ * $ts is UTC if $zone is not given.
*
* @param $format String
* @param $ts String: 14-character timestamp
* YYYYMMDDHHMMSS
* 01234567890123
+ * @param $zone DateTimeZone: Timezone of $ts
* @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai?
*
* @return string
*/
- function sprintfDate( $format, $ts ) {
+ function sprintfDate( $format, $ts, DateTimeZone $zone = null ) {
$s = '';
$raw = false;
$roman = false;
$hebrewNum = false;
- $unix = false;
+ $dateTimeObj = false;
$rawToggle = false;
$iranian = false;
$hebrew = false;
$num = substr( $ts, 6, 2 );
break;
case 'D':
- if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
- $s .= $this->getWeekdayAbbreviation( gmdate( 'w', $unix ) + 1 );
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
+ }
+ $s .= $this->getWeekdayAbbreviation( $dateTimeObj->format( 'w' ) + 1 );
break;
case 'j':
$num = intval( substr( $ts, 6, 2 ) );
$num = $hebrew[2];
break;
case 'l':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $s .= $this->getWeekdayName( gmdate( 'w', $unix ) + 1 );
- break;
- case 'N':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $w = gmdate( 'w', $unix );
- $num = $w ? $w : 7;
- break;
- case 'w':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'w', $unix );
- break;
- case 'z':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'z', $unix );
- break;
- case 'W':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $num = gmdate( 'W', $unix );
+ $s .= $this->getWeekdayName( $dateTimeObj->format( 'w' ) + 1 );
break;
case 'F':
$s .= $this->getMonthName( substr( $ts, 4, 2 ) );
}
$num = $hebrew[1];
break;
- case 't':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 't', $unix );
- break;
case 'xjt':
if ( !$hebrew ) {
$hebrew = self::tsToHebrew( $ts );
}
$num = $hebrew[3];
break;
- case 'L':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'L', $unix );
- break;
- case 'o':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'o', $unix );
- break;
case 'Y':
$num = substr( $ts, 0, 4 );
break;
$num = substr( $ts, 12, 2 );
break;
case 'c':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $s .= gmdate( 'c', $unix );
- break;
case 'r':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ case 'e':
+ case 'O':
+ case 'P':
+ case 'T':
+ // Pass through string from $dateTimeObj->format()
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $s .= gmdate( 'r', $unix );
+ $s .= $dateTimeObj->format( $code );
break;
+ case 'w':
+ case 'N':
+ case 'z':
+ case 'W':
+ case 't':
+ case 'L':
+ case 'o':
case 'U':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ case 'I':
+ case 'Z':
+ // Pass through number from $dateTimeObj->format()
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $num = $unix;
+ $num = $dateTimeObj->format( $code );
break;
case '\\':
# Backslash escaping
$wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
- /**
- * this should give much better diff info
- *
- * @param $text string
- * @return string
- */
- function segmentForDiff( $text ) {
- return preg_replace(
- "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
- "' ' .\"$1\"", $text );
- }
-
- /**
- * @param $text string
- * @return string
- */
- function unsegmentForDiff( $text ) {
- return preg_replace(
- "/ ([\\xc0-\\xff][\\x80-\\xbf]*)/e",
- "\"$1\"", $text );
- }
-
/**
* word segmentation
*
return parent::normalizeForSearch( $string, $autoVariant );
}
- /**
- * @param $termsArray array
- * @return array
- */
- function convertForSearchResult( $termsArray ) {
- $terms = implode( '|', $termsArray );
- $terms = self::convertDoubleWidth( $terms );
- $terms = implode( '|', $this->mConverter->autoConvertToAllVariants( $terms ) );
- $ret = array_unique( explode( '|', $terms ) );
- return $ret;
- }
}
* @return string
*/
function segmentForDiff( $text ) {
- return preg_replace(
- "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
- "' ' .\"$1\"", $text );
+ return preg_replace( '/[\xc0-\xff][\x80-\xbf]*/', ' $0', $text );
}
/**
* @return string
*/
function unsegmentForDiff( $text ) {
- return preg_replace(
- "/ ([\\xc0-\\xff][\\x80-\\xbf]*)/e",
- "\"$1\"", $text );
+ return preg_replace( '/ ([\xc0-\xff][\x80-\xbf]*)/', '$1', $text );
}
/**
'tog-diffonly' => "Moenie 'n bladsy se inhoud onder die wysigingsverskil wys nie",
'tog-showhiddencats' => 'Wys versteekte kategorië',
'tog-norollbackdiff' => 'Laat verskille weg na terugrol',
+'tog-useeditwarning' => "Waarsku my as ek 'n gewysigde bladsy verlaat alvorens dit gestoor is",
'underline-always' => 'Altyd',
'underline-never' => 'Nooit',
'content-failed-to-parse' => 'Dit was nie moontlik om die inhoud van die MIME-tipe $2 vir die model $1 te verwerk nie: $3.',
'invalid-content-data' => 'Ongeldige inhoud',
'content-not-allowed-here' => '"$1" word nie op bladsy [[$2]] toegelaat nie.',
+'editwarning-warning' => 'As u hierdie bladsy verlaat, verloor u moontlik die wysigings wat u aangebring het.
+Indien u aangemeld is, kan u hierdie waarskuwing in die {{int:prefs-editing}}"-afdeling van u voorkeure afskakel.',
# Content models
'content-model-wikitext' => 'Wikiteks',
# Search results
'searchresults' => 'Soekresultate',
'searchresults-title' => 'Soekresultate vir "$1"',
-'searchresulttext' => 'Vir meer inligting oor {{SITENAME}} soekresultate, lees [[{{MediaWiki:Helppage}}|{{int:help}}]].',
+'searchresulttext' => 'Vir meer inligting oor {{SITENAME}}-soekresultate, sien [[{{MediaWiki:Helppage}}|{{int:help}}]].',
'searchsubtitle' => 'U soek vir \'\'\'[[:$1]]\'\'\' ([[Special:Prefixindex/$1|alle bladsye wat met "$1" begin]]{{int:pipe-separator}}[[Special:WhatLinksHere/$1|alle bladsye wat aan "$1" skakel]])',
'searchsubtitleinvalid' => 'Vir navraag "$1"',
'toomanymatches' => "Te veel resultate. Probeer asseblief 'n ander soektog.",
# Statistics
'statistics' => 'Statistieke',
-'statistics-header-pages' => 'Bladsy statistieke',
-'statistics-header-edits' => 'Wysig statistieke',
+'statistics-header-pages' => 'Bladsystatistiek',
+'statistics-header-edits' => 'Wysigingstatistiek',
'statistics-header-views' => 'Wys statistieke',
'statistics-header-users' => 'Gebruikerstatistiek',
'statistics-header-hooks' => 'Ander statistieke',
# Undelete
'undelete' => 'Besigtig geskrapte bladsye',
-'undeletepage' => 'Kyk na en herstel geskrapte bladsye',
+'undeletepage' => 'Wys en herstel geskrapte bladsye',
'undeletepagetitle' => "'''Hier onder is die verwyderde weergawes van [[:$1]]'''.",
'viewdeletedpage' => 'Bekyk geskrapte bladsye',
'undeletepagetext' => 'Die volgende {{PLURAL:$1|bladsy|$1 bladsye}} is geskrap, maar is nog in die argief en kan teruggeplaas word. Die argief van geskrapte blaaie kan periodiek skoongemaak word.',
'undeletehistorynoadmin' => 'Die bladsy is geskrap.
Die rede hiervoor word onder in die opsomming aangedui, saam met besonderhede van die gebruikers wat die bladsy gewysig het voordat dit verwyder is.
Die verwyderde inhoud is slegs vir administrateurs sigbaar.',
-'undelete-revision' => 'Verwyder weergawe van $1 (per $4 om $5) deur $3:',
+'undelete-revision' => 'Verwyderde weergawe van $1 (soos op $4 om $5) deur $3:',
'undeleterevision-missing' => "Ongeldige of vermiste weergawe.
U mag moontlik 'n foutiewe skakel hê, of die weergawe is reeds herstel of uit die argief verwyder.",
'undelete-nodiff' => 'Geen vorige wysigings gevind.',
# Delete conflict
'deletedwhileediting' => "'''Let op''': die bladsy is verwyder terwyl u besig was om dit te wysig!",
-'confirmrecreate' => "Gebruiker [[User:$1|$1]] ([[User talk:$1|bespreek]]) het hierdie blad uitgevee ná u begin redigeer het met rede: : ''$2''
-Bevestig asseblief dat u regtig hierdie blad oor wil skep.",
+'confirmrecreate' => "Gebruiker [[User:$1|$1]] ([[User talk:$1|kontak]]) het hierdie bladsy uitgevee nádat u begin redigeer het met rede:
+:''$2''
+Bevestig asseblief dat u hierdie blad weer wil skep.",
'confirmrecreate-noreason' => 'Gebruiker [[User:$1|$1]] ([[User talk:$1|bespreking]]) het die bladsy geskrap nadat u dit begin wysig het.
Bevestig dat u die bladsy wil herskep.',
'recreate' => 'Herskep',
'watchlisttools-raw' => 'Wysig bronkode',
# Signatures
-'signature' => '[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|bespreek]])',
+'signature' => '[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|kontak]])',
# Core parser functions
'unknown_extension_tag' => 'Onbekende etiket "$1"',
'tog-diffonly' => 'موقاییسهلر آلیتندا صحیفهلرین ایچیندهکیلرینی گؤسترمه',
'tog-showhiddencats' => 'گیزلی بؤلمهلری گؤستر',
'tog-norollbackdiff' => 'قایتاراندان سونرا موقاییسه گؤسترمه',
+'tog-useeditwarning' => 'دَییشدیرمه صحیفهسینده چیخیش زامانی، آچیق و قئید اولمایان دَییشدیرمه صحیفه وارسا منه هشدار وئریلسین',
'underline-always' => 'همیشه',
'underline-never' => 'هئچ واخت',
'article' => 'सामग्री पन्ना',
'newwindow' => '(नया विंडो में खोलीं)',
'cancel' => 'निरस्त',
-'mytalk' => 'हमार बात',
+'mytalk' => 'राà¤\89र बात',
'navigation' => 'परिभ्रमण',
# Cologne Blue skin
'disclaimerpage' => 'Project:सामान्य अस्विकरण',
'edithelp' => 'मदद सम्पादन',
'edithelppage' => 'Help:सम्पादन',
-'helppage' => 'मदद:सामग्री',
+'helppage' => 'Help:सामग्री',
'mainpage' => 'मुख्य पन्ना',
'mainpage-description' => 'पहिलका पन्ना',
'portal' => 'सामुदायिक पन्ना',
'powersearch-togglenone' => 'कउनो ना',
'search-external' => 'बाहरी खोज',
-# Quickbar
-'qbsettings-none' => 'कउनो ना',
-
# Preferences page
'preferences' => 'वरीयता',
-'mypreferences' => 'हमार पसन्द',
+'mypreferences' => 'राà¤\89र पसन्द',
'prefs-edits' => 'सम्पादन संख्या',
'prefsnologin' => 'खाता में प्रवेश नईखीं कईले',
'changepassword' => 'गुप्त शब्द बदलीं',
'filehist-filesize' => 'फाईल के आकार',
'filehist-comment' => 'टिप्पणी',
'filehist-missing' => 'गायब फाईल',
-'imagelinks' => 'फाà¤\88ल लिà¤\82à¤\95',
+'imagelinks' => 'फाà¤\88ल à¤\95à¥\87 à¤\89पयà¥\8bà¤\97',
'nolinkstoimage' => 'इ फाईल जोड़े कौनो फाइल लिंक नईखे।',
'morelinkstoimage' => 'इ फाइल संगे जुड़ल [[Special:WhatLinksHere/$1|सब लिंक]] देखीं।',
'sharedupload' => 'इ फाईल $1 से बा आ दुसर परियोजना में प्रयोग करल जा सकत बा।',
# Watchlist
'watchlist' => 'हमार ध्यानसूची',
-'mywatchlist' => 'हमार धà¥\8dयानसूची',
+'mywatchlist' => 'राà¤\89र धà¥\8dयान दियल पनà¥\8dना à¤\95à¥\87 सूची',
'watch' => 'ध्यानसूची में डालीं',
'watchthispage' => 'ई पन्ना ध्यानसूची में डालीं',
'unwatch' => 'ध्यानसूची से हटाईं',
# Contributions
'contributions' => 'प्रयोगकर्ता योगदान',
'contributions-title' => ' $1 खातिर प्रयोगकर्ता योगदान',
-'mycontris' => 'हमार यà¥\8bà¤\97दान',
+'mycontris' => 'राà¤\89र यà¥\8bà¤\97दान à¤\95à¥\87 सà¥\82à¤\9aà¥\80',
'nocontribs' => 'ई मानदंड से मिलत जुलत कौनो बदलाव ना मिलल।',
'uctop' => '(शीर्ष)',
'month' => 'महिना से (आ उ से पहिले):',
# Block/unblock
'blockip' => 'प्रतिबंधित प्रयोगकर्ता',
+'ipboptions' => '२ घंटे:2 hours,१ दिन:1 day,३ दिन:3 days,१ हफ्ता:1 week,२ हफ्ते:2 weeks,१ महिना:1 month,३ महिने:3 months,६ महिने:6 months,१ साल:1 year,हमेशा खातिर:infinite',
'blocklink' => 'निष्क्रिय',
'unblocklink' => 'ताला खोलीं',
'change-blocklink' => 'ब्लॉक बदलीं',
'tog-diffonly' => 'Kada usah manampaiakan isi tungkaran di bawah balain',
'tog-showhiddencats' => 'Tampaiakan tutumbung tasungkup',
'tog-norollbackdiff' => 'Kada usah manampaiakan lainan imbah mambulikakan',
+'tog-useeditwarning' => 'Ingatakan ulun pabila maninggalakan tungkaran pambabakan sabalum manyimpan parubahan',
'underline-always' => 'Tarus',
'underline-never' => 'Kada suah',
'viewhelppage' => 'Tiringi tungkaran patulung',
'categorypage' => 'Tiringi tungkaran tumbung',
'viewtalkpage' => 'Tiringi tungkaran pamandiran',
-'otherlanguages' => 'Dalam bahasa lain',
+'otherlanguages' => 'Dalam basa lain',
'redirectedfrom' => '(Diugahakan matan $1)',
'redirectpagesub' => 'Tungkaran paugahan',
-'lastmodifiedat' => 'Tungkaran ngini tauncit diubah pada $1, $2.',
+'lastmodifiedat' => 'Tungkaran ngini pauncitnya diubah pada $1, $2.',
'viewcount' => 'Tungkaran ini sudah diungkai {{PLURAL:$1|kali|$1 kali}}.',
'protectedpage' => 'Tungkaran nang dilindungi',
'jumpto' => 'Malacung ka',
'aboutpage' => 'Project:Pasal',
'copyright' => 'Isi tasadia sasuai lawan $1.',
'copyrightpage' => '{{ns:project}}:Hak cipta',
-'currentevents' => 'Paristiwa damini',
-'currentevents-url' => 'Project:Paristiwa damini',
+'currentevents' => 'Kajadian wayahini',
+'currentevents-url' => 'Project:Kajadian wayahini',
'disclaimers' => 'Panyangkalan',
'disclaimerpage' => 'Project:Panyangkalan umum',
'edithelp' => 'Patulung mambabak',
'delete-hook-aborted' => 'Pahapusan diwalangakan ulih kait parser.
Kadada katarangan.',
'badtitle' => 'Judul buruk',
-'badtitletext' => 'Judul tungkaran nang diminta kada sah, kada baisi, atawa kada pasnya tautan judul antar-bahasa atawa antar-wiki.
-Nangini bisa baisi satu atawa labih hurup nang saharusnya kadada di judul.',
+'badtitletext' => 'Judul tungkaran nang diminta kada sah, kada baisi, atawa kada pasnya tautan judul antar-basa atawa antar-wiki.
+Nangini kawa baisi satu atawa labih hurup nang saharusnya kadada di judul.',
'perfcached' => 'Data barikut adalah timbuluk wan pina kada mutakhir. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.',
'perfcachedts' => 'Data nang dudi ni adalah timbuluk, wan tauncit dihahanyari pada $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.',
'querypage-no-updates' => 'Pamugaan matan tungkaran ngini rahat dipajahkan. Data nang ada di sia wayahini kada akan dimuat ulang.',
'blocked-mailpassword' => 'Alamat IP Pian diblukir hagan mambabak, wan kada dibulihakan mamakai pungsi pamulihan kata sunduk hagan mancagah salah puruk.',
'eauthentsent' => 'Sabuting suril payakinan hudah dikirim ka alamat suril.
Sabalum ada suril lain nang takirim ka akun, Pian akan parlu maumpati anjuran dalam suril nangitu, hagan mayakinakan bahwasanya akun nangitu bujur-bujur ampun Pian.',
-'throttled-mailpassword' => 'Sabuting pangingat kata sunduk hudah takirim, dalam {{PLURAL:$1|jam|$1 jam}} tauncit. Hagan mancagah salah puruk, asa pangingat kata sunduk haja nang dikirim saban {{PLURAL:$1|jam|$1 jam}}.',
+'throttled-mailpassword' => 'Sabuting pangingat kata sunduk hudah takirim, dalam {{PLURAL:$1|jam|$1 jam}} pauncitnya. Hagan mancagah salah puruk, asa pangingat kata sunduk haja nang dikirim saban {{PLURAL:$1|jam|$1 jam}}.',
'mailerror' => 'Kasalahan pangiriman suril: $1',
'acct_creation_throttle_hit' => "Pa'ilang wiki nangini mamuruk alamat IP Pian hudah maulah {{PLURAL:$1|1 akun|$1 akun}} dalam asa harian ini, dimana nangitu jumlah paling banyak nang diijinakan. Sawagai hasilnya, pa'ilang awan alamat IP nangini kada kawa maulah akun pulang gasan pahadangan.",
'emailauthenticated' => 'Alamat suril Pian rasuk pada $2, $3',
'login-throttled' => 'Pian sudah kabanyakan mancuba babuat log.
Muhun hadangi dahulu sapandang hanyar cubai pulang.',
'login-abort-generic' => 'Pian kada ruhui babuat log - Diwalangi',
-'loginlanguagelabel' => 'Bahasa: $1',
-'suspicious-userlogout' => 'Parmintaan Pian hagan kaluar log kada ditarima karana nangkaya dikirim matan panjalajah web rakai atawa tatangkap proxy.',
+'loginlanguagelabel' => 'Basa: $1',
+'suspicious-userlogout' => 'Pamintaan Pian hagan kaluar log kada ditarima marga nangkaya dikirim matan panjalajah web rakai atawa tatangkap proxy.',
# Email sending
'php-mail-error-unknown' => 'Kasalahan kada dipinandui dalam pungsi surat () PHP',
'passwordreset-capture-help' => 'Amun Pian cintang kutak ngini, suril (awan katasunduk pahadangan) akan ditampaiakan ka Pian bahwasa lagi dikirim ka pamakai.',
'passwordreset-email' => 'Alamat suril:',
'passwordreset-emailtitle' => 'Rarincian akun pada {{SITENAME}}',
-'passwordreset-emailtext-ip' => 'Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting pangingat hagan rarincian akun Pian gasan {{SITENAME}} ($4). pPamakai barikut {{PLURAL:$3|akun|akun}}
+'passwordreset-emailtext-ip' => 'Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting pangingat hagan rarincian akun Pian gasan {{SITENAME}} ($4). Pamakai barikut {{PLURAL:$3|akun|akun}}
tarait awan suril:
$2
'post-expand-template-argument-category' => 'Tungkaran-tungkaran nang mangandung kalimat-kalimat citakan diabaiakan',
'parser-template-loop-warning' => 'Citakan baulang takantup: [[$1]]',
'parser-template-recursion-depth-warning' => 'Citakan batas kadalaman recursi limpuar ($1)',
-'language-converter-depth-warning' => 'Batas kadalaman pakonversi bahasa limpuar ($1)',
+'language-converter-depth-warning' => 'Batas kadalaman pangonversi basa limpuar ($1)',
'node-count-exceeded-category' => 'Tungkaran di mana node-count tarlalui',
'node-count-exceeded-warning' => 'Tungkaran malabihi node-count',
'expansion-depth-exceeded-category' => 'Tungkaran dimana kadalaman ikspansi talalui',
* @ingroup Language
* @file
*
+ * @author Aftab1995
* @author Ali Haidar Khan
* @author Bellayet
* @author Ehsanulhb
'tog-diffonly' => 'পার্থক্যের নিচে পাতার বিষয়বস্তু না দেখানো হোক',
'tog-showhiddencats' => 'লুকায়িত বিষয়শ্রেণীসমূহ দেখাও',
'tog-norollbackdiff' => 'রোলব্যাকের পরে পার্থক্য দেখিও না',
+'tog-useeditwarning' => 'অসংরক্ষিত পরিবর্তন সহ কোনো পাতা ত্যাগের সময় সাবধান করো',
'underline-always' => 'সব সময়',
'underline-never' => 'কখনো নয়',
'vector-view-edit' => 'সম্পাদনা',
'vector-view-history' => 'ইতিহাস',
'vector-view-view' => 'পড়ুন',
-'vector-view-viewsource' => 'সà§\8bরà§\8dস দেখুন',
+'vector-view-viewsource' => 'à¦\89à§\8eস দেখুন',
'actions' => 'কার্যক্রম',
'namespaces' => 'নামস্থান',
'variants' => 'বিকল্পসমূহ',
'ok' => 'ঠিক আছে',
'retrievedfrom' => "'$1' থেকে আনীত",
-'youhavenewmessages' => 'আপনার $1 ($2) এসেছে৷',
+'youhavenewmessages' => 'আপনার $1 এসেছে ($2)৷',
'newmessageslink' => 'নতুন বার্তা',
'newmessagesdifflink' => 'সর্বশেষ পরিবর্তন',
-'youhavenewmessagesfromusers' => 'আপনি {{PLURAL:$3|অন্য ব্যবহারকারী|$3 ব্যবহারকারী}} ($2) থেকে $1পেয়েছেন।',
-'youhavenewmessagesmanyusers' => 'আপনি অনেক ব্যবহারকারী ($2) থেকে $1 পেয়েছেন।',
+'youhavenewmessagesfromusers' => 'আপনি {{PLURAL:$3|অন্য ব্যবহারকারীর|$3 ব্যবহারকারীর}} কাছ থেকে $1 পেয়েছেন ($2)।',
+'youhavenewmessagesmanyusers' => 'আপনি অনেক ব্যবহারকারীর কাছ থেকে $1 পেয়েছেন ($2)।',
'newmessageslinkplural' => '{{PLURAL:$1|একটি নতুন বার্তা|নতুন বার্তা}}',
-'newmessagesdifflinkplural' => '$1 {{PLURAL:$1|পরিবর্তন|পরিবর্তনসমূহ}}',
+'newmessagesdifflinkplural' => 'সর্বশেষ {{PLURAL:$1|পরিবর্তন|পরিবর্তনসমূহ}}',
'youhavenewmessagesmulti' => 'আপনার $1টি নতুন বার্তা এসেছে',
'editsection' => 'সম্পাদনা',
'editold' => 'সম্পাদনা',
'filereadonlyerror' => '"$1" ফাইলটিকে পরিবর্তন করা সম্ভব হচ্ছে না কারন "$2" ফাইল রিপোসিটোরি রিড-অনলি-মোডে আছে।
একজন প্রশাসক যিনি এটাকে লকড করেছেন তার যৌক্তিকতা দেওয়া হল: "$3"',
-'invalidtitle-knownnamespace' => 'অবৈধ শিরনাম, যেখানে নামস্থান "$2" এবং লেখা হয়েছে "$3"',
-'invalidtitle-unknownnamespace' => 'অবৈধ শিরনাম, যেখানে ব্যবহৃত হয়েছে অপরিচিত নামস্থান সংখ্যা $1 এবং লেখা হয়েছে "$2"',
+'invalidtitle-knownnamespace' => 'à¦\85বà§\88ধ শিরà§\8bনাম, যà§\87à¦\96ানà§\87 নামসà§\8dথান "$2" à¦\8fবà¦\82 লà§\87à¦\96া হয়à§\87à¦\9bà§\87 "$3"',
+'invalidtitle-unknownnamespace' => 'à¦\85বà§\88ধ শিরà§\8bনাম, যà§\87à¦\96ানà§\87 বà§\8dযবহà§\83ত হয়à§\87à¦\9bà§\87 à¦\85পরিà¦\9aিত নামসà§\8dথান সà¦\82à¦\96à§\8dযা $1 à¦\8fবà¦\82 লà§\87à¦\96া হয়à§\87à¦\9bà§\87 "$2"',
'exception-nologin' => 'লগইন করা হয়নি',
'exception-nologin-text' => 'এই কাজটি করার জন্য উইকিতে লগইন করা প্রয়োজন।',
'anoneditwarning' => 'আপনি লগ ইন করেননি। এই পাতার সম্পাদনার ইতিহাসে আপনার আইপি সংখ্যা সংরক্ষিত হবে।',
'anonpreviewwarning' => 'আপনি লগ ইন করেননি। এই পাতার সম্পাদনার ইতিহাসে আপনার আইপি সংখ্যা সংরক্ষিত হবে।',
'missingsummary' => "'''খেয়াল করুন''': আপনি কিন্তু সম্পাদনার সারাংশ দেননি। আবার যদি \"সংরক্ষণ\" বোতামে ক্লিক করেন, তাহলে ঐ সারাংশ বাক্যটি ছাড়াই আপনার সম্পাদনা সংরক্ষিত হবে।",
-'missingcommenttext' => 'দয়াকরে নিচে মন্তব্য যোগ করুন।',
+'missingcommenttext' => 'দয়া করে নিচে মন্তব্য যোগ করুন।',
'missingcommentheader' => "'''খেয়াল করুন:''' আপনি এই মন্তব্যের জন্য কোন বিষয়/শিরোনাম দেননি। সংরক্ষণ বোতামে ক্লিক করলে, আপনার এই সম্পাদনা কোন বিষয়/শিরোনাম ছাড়াই সংরক্ষিত হবে।",
'summary-preview' => 'সারাংশ প্রাকদর্শন:',
'subject-preview' => 'বিষয়/শিরোনাম প্রাকদর্শন:',
আপনার বর্তমান IP ঠিকানা হচ্ছে $3, এবং যা বাধা দানের আইডি হল $5।
যেকোন প্রশ্ন করার সময় উপরের সকল তথ্য উল্লেখ করুন।',
'blockednoreason' => 'কোন কারণ দেওয়া হয়নি',
-'whitelistedittext' => 'পাতায় সমà§\8dপাদনা à¦\95রতà§\87 à¦\86পশ্যই $1 করতে হবে।',
+'whitelistedittext' => 'পাতায় সমà§\8dপাদনা à¦\95রতà§\87 à¦\86বশ্যই $1 করতে হবে।',
'confirmedittext' => 'কোন সম্পাদনা করার আগে আপনার ই-মেইল ঠিকানাটি অবশ্যই নিশ্চিত করতে হবে। দয়া করে আপনার ই-মেইল ঠিকানাটি [[Special:Preferences|ব্যবহারকারীর পছন্দতালিকায়]] ঠিকমত দিন।',
'nosuchsectiontitle' => 'অনুচ্ছেদ পাওয়া যায়নি',
'nosuchsectiontext' => 'আপনি এমন একটি অনুচ্ছেদ সম্পাদনার চেষ্টা করেছেন, যার কোন অস্তিত্ব নেই।
'content-failed-to-parse' => '$1 মডেলের জন্য $2 কন্টেন্ট পার্স করা যাচ্ছে না: $3',
'invalid-content-data' => 'ভুল কন্টেন্ট ডাটা',
'content-not-allowed-here' => '"$1" কন্টেন্টটি [[$2]] পাতায় অনুমোদিত নয়',
+'editwarning-warning' => 'এই পাতাটি ত্যাগ করলে আপনার আপনার করা পরিবর্তনগুলো হারিয়ে যেতে পারে।
+আপনি যদি লগইন করা থাকেন, আপনি এই সতর্কীকরণ বার্তাটি আপনার পছন্দের "{{int:prefs-editing}}" অনুচ্ছেদ থেকে নিস্ক্রিয় করতে পারেন।',
# Content models
'content-model-wikitext' => 'উইকিটেক্সট',
'post-expand-template-argument-warning' => "' ' ' সাবধান: ' ' ' এই পাতাটিতে অন্তত একটি ফর্মা যুক্তি আছে যা একটি খুব বড় বিস্তার আকার ধারণ করেছে।
তাই এই আর্গুমেন্টটি বাদ দেওয়া হয়েছে।",
'post-expand-template-argument-category' => 'বাদ ফর্মা আর্গুমেন্ট ধারণকারী পাতা',
-'parser-template-loop-warning' => 'à¦\9fà§\87মà§\8dপলেট লুপ সনাক্ত হয়েছে: [[$1]]',
-'parser-template-recursion-depth-warning' => 'টেমপ্লেট পুনরাবৃত্তি (রিকার্শন) ডেপথ্ সীমা অতক্রম করেছে ($1)',
-'language-converter-depth-warning' => 'ভাষা পরিবর্তন ডেপথ্ সীমা অতক্রম করেছে ($1)',
+'parser-template-loop-warning' => 'à¦\9fà§\87মপà§\8dলেট লুপ সনাক্ত হয়েছে: [[$1]]',
+'parser-template-recursion-depth-warning' => 'টেমপ্লেট পুনরাবৃত্তি (রিকার্শন) ডেপথ্ সীমা অতক্রম করেছে ($1)',
+'language-converter-depth-warning' => 'ভাষা পরিবর্তন ডেপথ্ সীমা অতক্রম করেছে ($1)',
'node-count-exceeded-category' => 'যে সকল পাতার নোড কাউন্ট সীমানা পার হয়েছে',
'node-count-exceeded-warning' => 'পাতাটি নোড কাউন্ট সীমানা পার করেছে',
'expansion-depth-exceeded-category' => 'যে সকল পাতার এক্সেপশন সীমানা অতিক্রম করেছে',
'search-external' => 'বহিঃস্থ অনুসন্ধান',
'searchdisabled' => '{{SITENAME}} অনুসন্ধান এখন নিষ্ক্রিয় আছে। আপনি গুগলের মাধ্যমে অনুসন্ধান চালাতে পারেন। লক্ষ্য করুন যে {{SITENAME}}-এর বিষয়বস্তুর উপর গুগলের ইন্ডেক্সগুলি হালনাগাদ না-ও করা থাকতে পারে।',
-# Quickbar
-'qbsettings' => 'কুইকবার',
-'qbsettings-none' => 'কিছুই না',
-'qbsettings-fixedleft' => 'স্থায়ী বাম',
-'qbsettings-fixedright' => 'স্থায়ী ডান',
-'qbsettings-floatingleft' => 'ভাসমান বাম',
-'qbsettings-floatingright' => 'ভাসমান ডান',
-'qbsettings-directionality' => 'ফিক্সড, আপনার ভাষার লেখা শুরুর দিকের উপর ভিত্তি করে',
-
# Preferences page
'preferences' => 'আমার পছন্দ',
'mypreferences' => 'পছন্দসমূহ',
'http-read-error' => 'HTTP পঠন ত্রুটি।',
'http-timed-out' => 'HTTP অনুরোধের সময় পার হয়েছে।',
'http-curl-error' => 'ইউআরএল নিয়ে আসার ক্ষেত্রে ত্রুটি: $1',
-'http-host-unreachable' => 'URL-এ পৌঁছানো যায়নি',
'http-bad-status' => 'HTTP অনুরোধের সময় কোন সমস্যা হয়েছে: $1 $2',
# Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
এর পরিবর্তে এগুলি থেকে একটি উপযুক্ত বিষয়ে সংযোগ থাকা আবশ্যক।<br />
যদি কোন পাতায় এমন কোন টেমপ্লেট থাকে যেটিতে [[MediaWiki:Disambiguationspage]] থেকে সংযোগ আছে, তবে সেই পাতাটিকে একটি দ্ব্যর্থতা নিরসন পাতা হিসেবে গণ্য করা হয়।",
+'pageswithprop' => 'পাতার উপাদান সম্বলিত পৃষ্ঠাসমূহ',
+'pageswithprop-legend' => 'পাতার উপাদান সম্বলিত পৃষ্ঠাসমূহ',
+'pageswithprop-text' => 'একটি নির্দিষ্ট পাতার বৈশিষ্ট রয়েছে এমন পাতাসমূহের তালিকা।',
+'pageswithprop-prop' => 'বৈশিষ্টের নাম:',
'pageswithprop-submit' => 'চলো',
'doubleredirects' => 'দুইবার করা পুনর্নির্দেশনাগুলি',
'prot_1movedto2' => '[[$1]]-কে [[$2]]-এ সরিয়ে নেওয়া হয়েছে',
'protect-badnamespace-title' => 'নামস্থানটি সুরক্ষিত করা সম্ভব নয়',
'protect-badnamespace-text' => 'এই নামস্থানের পাতাগুলো সুরক্ষিত করা সম্ভব নয়।',
+'protect-norestrictiontypes-text' => 'এই পাতাটি সুরক্ষিত করা যাচ্ছে না কারণ এখানে সুরক্ষার কোনো বেশিষ্ট নেই।',
'protect-norestrictiontypes-title' => 'সুরক্ষা প্রযোজ্য নয় এমন পাতা',
'protect-legend' => 'সুরক্ষা নিশ্চিত করুন',
'protectcomment' => 'কারণ:',
'pageinfo-category-files' => 'ফাইলের সংখ্যা',
# Skin names
-'skinname-standard' => 'ক্লাসিক',
'skinname-vector' => 'ভেক্টর',
# Patrolling
'api-error-ok-but-empty' => 'অভ্যন্তরীণ ত্রুটি: সার্ভার হতে কোন সাড়া পাওয়া যাচ্ছে না।',
'api-error-overwrite' => 'ইতিমধ্যেই রয়েছে এমন কোনো ফাইলের প্রতিস্থাপন গ্রহণযোগ্য নয়।',
'api-error-stashfailed' => 'অভ্যন্তরীণ ত্রুটি: সার্ভার অস্থায়ী ফাইলটি সংরক্ষণ করতে ব্যর্থ হয়েছে।',
+'api-error-publishfailed' => 'অভ্যন্তরীন ত্রুটি: সার্ভার টেম্পরারি ফাইলটি প্রকাশ করতে পারছে না।',
'api-error-timeout' => 'কাঙ্খিত সময়ের মধ্যে সার্ভারের কোন সাড়া পাওয়া যায়নি।',
'api-error-unclassified' => 'একটি অজানা ত্রুটি দেখা দিয়েছে',
'api-error-unknown-code' => 'অজানা ত্রুটি: "$1"',
'duration-centuries' => '$1 {{PLURAL:$1|শতাব্দী|শতাব্দী}}',
'duration-millennia' => '$1 {{PLURAL:$1|সহস্রাব্দ|সহস্রাব্দ}}',
+# Image rotation
+'rotate-comment' => 'ছবিটি ঘড়ির কাটার দিকে $1 {{PLURAL:$1|ডিগ্রি}} ঘুরানো হয়েছে',
+
);
'tog-showhiddencats' => 'Diskouez ar rummadoù kuzhet',
'tog-noconvertlink' => 'Diweredekaat amdroadur an titloù',
'tog-norollbackdiff' => 'Na ziskouez an diff goude un distaoladenn',
+'tog-useeditwarning' => 'Kas keloù din pa guitaan ur bajenn degaset kemmoù enni hep enrollañ',
'underline-always' => 'Atav',
'underline-never' => 'Morse',
'content-failed-to-parse' => "C'hwitet eo dielfennadur endalc'had $2 evit ar patrom $1: $3",
'invalid-content-data' => "n'eo ket mat roadennoù an endalc'had",
'content-not-allowed-here' => 'N\'eo ket aotreet an endalc\'had "$1" er bajenn [[$2]]',
+'editwarning-warning' => "Mar kuitait ar bajenn-mañ e c'hallit koll ar c'hemmoù degaset ganeoc'h.
+Ma'z oc'h kevreet e c'hallit diweredekaat ar c'hemenn-diwall-mañ e rann \"{{int:prefs-editing}}\" ho penndibaboù.",
# Content models
'content-model-wikitext' => 'wikitestenn',
'tog-showhiddencats' => 'Prikaži skrivene kategorije',
'tog-noconvertlink' => 'Onemogući konverziju naslova linkova',
'tog-norollbackdiff' => 'Nakon vraćanja zanemari prikaz razlika',
+'tog-useeditwarning' => 'Upozori me kada napustim stranicu za izmjene bez spašenih promjena',
'underline-always' => 'Uvijek',
'underline-never' => 'Nikad',
# Vector skin
'vector-action-addsection' => 'Dodaj temu',
-'vector-action-delete' => 'Brisanje',
+'vector-action-delete' => 'Izbriši',
'vector-action-move' => 'Pomjeri',
'vector-action-protect' => 'Zaštiti',
'vector-action-undelete' => 'Vrati obrisano',
'vector-action-unprotect' => 'Promijeni zaštitu',
'vector-simplesearch-preference' => 'Omogući pojednostavljenu traku pretrage (samo vektorski izgled)',
'vector-view-create' => 'Napravi',
-'vector-view-edit' => 'Uređivanje',
+'vector-view-edit' => 'Uredi',
'vector-view-history' => 'Pregled historije',
'vector-view-view' => 'Čitanje',
'vector-view-viewsource' => 'Pogledaj izvor',
'mainpage-description' => 'Početna strana',
'policy-url' => 'Project:Pravila',
'portal' => 'Portal zajednice',
-'portal-url' => 'Project:Portal_zajednice',
+'portal-url' => 'Project:Portal zajednice',
'privacy' => 'Politika privatnosti',
'privacypage' => 'Project:Pravila o anonimnosti',
'versionrequired' => 'Potrebna je verzija $1 MediaWikija',
'versionrequiredtext' => 'Potrebna je verzija $1 MediaWikija da bi se koristila ova strana. Pogledaj [[Special:Version|verziju]].',
-'ok' => 'da',
+'ok' => 'U redu',
'retrievedfrom' => 'Dobavljeno iz "$1"',
'youhavenewmessages' => 'Imate $1 ($2).',
'newmessageslink' => 'novih poruka',
'youhavenewmessagesfromusers' => 'Imate $1 od {{PLURAL:$3|drugog korisnika|$3 korisnika}} ($2).',
'youhavenewmessagesmanyusers' => 'Imate $1 od mnogo korisnika ($2).',
'newmessageslinkplural' => '{{PLURAL:$1|novu poruku|nove poruke}}',
-'newmessagesdifflinkplural' => '{{PLURAL:$1|zadnja izmjena|zadnje izmjene}}',
+'newmessagesdifflinkplural' => '{{PLURAL:$1|posljednja izmjena|posljednje izmjene}}',
'youhavenewmessagesmulti' => 'Imate nove poruke na $1',
'editsection' => 'uredi',
'editsection-brackets' => '[$1]',
'toc' => 'Sadržaj',
'showtoc' => 'pokaži',
'hidetoc' => 'sakrij',
-'collapsible-collapse' => 'Sakrij',
+'collapsible-collapse' => 'sklopi',
'collapsible-expand' => 'Proširi',
'thisisdeleted' => 'Pogledaj ili vrati $1?',
'viewdeleted' => 'Pogledaj $1?',
'edit-already-exists' => 'Stranica nije mogla biti kreirana.
Izgleda da već postoji.',
'defaultmessagetext' => 'Uobičajeni tekst poruke',
+'editwarning-warning' => 'Napuštanje ove stranice može dovesti do gubitka svih promjena koje ste načinili.
+Ako ste prijavljeni, možete isključiti ovo upozorenje u "{{int:prefs-editing}}" dijelu vaših opcija.',
# Content models
'content-model-wikitext' => 'wikitekst',
'search-external' => 'Vanjska pretraga',
'searchdisabled' => '<p>Izvinjavamo se! Puno pretraga teksta je privremeno onemogućena. U međuvremenu, možete koristiti Google za pretragu. Indeks može biti stariji.',
-# Quickbar
-'qbsettings' => 'Podešavanja brze palete',
-'qbsettings-none' => 'Nikakva',
-'qbsettings-fixedleft' => 'Pričvršćena lijevo',
-'qbsettings-fixedright' => 'Pričvršćena desno',
-'qbsettings-floatingleft' => 'Plutajuća lijevo',
-'qbsettings-floatingright' => 'Plutajući desno',
-'qbsettings-directionality' => 'Čvrsto, u zavisnosti od usmjerenosti pisma Vašeg jezika',
-
# Preferences page
'preferences' => 'Podešavanja',
'mypreferences' => 'Postavke',
'http-read-error' => 'Greška pri čitanju HTTP.',
'http-timed-out' => 'Istekao HTTP zahtjev.',
'http-curl-error' => 'Greška pri otvaranju URLa: $1',
-'http-host-unreachable' => 'Ovaj URL nije bilo moguće otvoriti',
'http-bad-status' => 'Nastao je problem tokom HTTP zahtjeva: $1 $2',
# Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
'listusers-noresult' => 'Nije pronađen korisnik.',
'listusers-blocked' => '(blokiran)',
-# Special:ActiveUsers
-'activeusers' => 'Spisak aktivnih korisnika',
-'activeusers-intro' => 'Ovo je spisak korisnika koji su napravili neku aktivnost u {{PLURAL:$1|zadnji $1 dan|zadnja $1 dana|zadnjih $1 dana}}.',
-'activeusers-count' => '{{PLURAL:$1|nedavna $1 izmjena|nedavne $1 izmjene|nedavnih $1 izmjena}} u {{PLURAL:$3|posljednji $3 dan|posljednja $3 dana|posljednjih $3 dana}}',
-'activeusers-from' => 'Prikaži korisnike koji počinju sa:',
-'activeusers-hidebots' => 'Sakrij botove',
-'activeusers-hidesysops' => 'Sakrij administratore',
-'activeusers-noresult' => 'Nije pronađen korisnik.',
-
# Special:ListGroupRights
'listgrouprights' => 'Prava korisničkih grupa',
'listgrouprights-summary' => 'Slijedi spisak korisničkih grupa na ovoj wiki, s njihovim pravima pristupa.
# Stylesheets
'common.css' => '/* CSS umetnut ovdje primijenit će se na sve skinove */',
-'standard.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Standard skin */',
-'nostalgia.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Nostalgia skin */',
'cologneblue.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Cologne Blue skin */',
'monobook.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Monobook skin */',
-'myskin.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste MySkin skin */',
-'chick.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Chick skin */',
-'simple.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Simple skin */',
'modern.css' => '/* CSS umetnut ovdje uticat će na korisnike koji koriste Modern skin */',
'print.css' => '/* CSS umetnut ovdje uticat će na izgled isprintane stranice */',
'handheld.css' => '/* CSS umetnut ovdje uticat će na ručne sprave koji rade na skinu konfigurisanom u $wgHandheldStyle */',
# Scripts
'common.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike pri svakom učitavanju stranice. */',
-'standard.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Standard skin */',
-'nostalgia.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Nostalgia skin */',
'cologneblue.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Cologne Blue skin */',
'monobook.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste MonoBook skin */',
-'myskin.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste MySkin skin */',
-'chick.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Chick skin */',
-'simple.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Simple skin */',
'modern.js' => '/* Bilo koja JavaScript će biti učitana za sve korisnike koji koriste Modern skin */',
# Metadata
'pageinfo-category-pages' => 'Broj stranica',
# Skin names
-'skinname-standard' => 'Klasično',
-'skinname-nostalgia' => 'Nostalgija',
'skinname-cologneblue' => 'Kelnsko plavo',
'skinname-monobook' => 'MonoKnjiga',
-'skinname-myskin' => 'MojaKoža',
-'skinname-chick' => 'Pile (chick)',
-'skinname-simple' => 'Jednostavna',
'skinname-modern' => 'Moderna',
# Patrolling
'sqlite-no-fts' => '$1 bez podrške pretrage cijelog teksta',
# New logging system
-'logentry-delete-delete' => '$1 je obrisao stranicu $3',
-'logentry-delete-restore' => '$1 je vratio stranicu $3',
+'logentry-delete-delete' => '$1 je {{GENDER:$2|obrisao|obrisala}} stranicu $3',
+'logentry-delete-restore' => '$1 je {{GENDER:$2|vratio|vratila}} stranicu $3',
'logentry-delete-event' => '$1 je {{GENDER:|promijenio|promijenila}} vidljivost {{PLURAL:$5|događaja|$5 događaja}} u evidenciji na $3: $4',
'logentry-delete-revision' => '$1 je {{GENDER:|promijenio|promijenila}} vidljivost {{PLURAL:$5|izmjene|$5 izmjene|$5 izmjena}} na stranici $3: $4',
'logentry-delete-event-legacy' => '$1 je {{GENDER:|promijenio|promijenila}} vidljivost događaja u evidenciji na $3',
'tog-showhiddencats' => 'Mostra les categories ocultes',
'tog-noconvertlink' => 'Inhabilita la conversió dels títols dels enllaços',
'tog-norollbackdiff' => 'Omet la pàgina de diferències després de realitzar una reversió',
+'tog-useeditwarning' => "Avisa'm quan surti d'una pàgina d'edició amb canvis sense desar",
'underline-always' => 'Sempre',
'underline-never' => 'Mai',
'about' => 'Quant a',
'article' => 'Pàgina de contingut',
'newwindow' => '(obre en una nova finestra)',
-'cancel' => 'Anuŀla',
+'cancel' => 'Cancel·lar',
'moredotdotdot' => 'Més...',
'morenotlisted' => 'Més no en la llista...',
'mypage' => 'Pàgina',
'content-failed-to-parse' => "Ha fallat l'anàlisi del contingut de $2 per al model $1: $3",
'invalid-content-data' => 'Dades de contingut no vàlides',
'content-not-allowed-here' => 'No és permés el contingut "$1" a la pàgina [[$2]]',
+'editwarning-warning' => "Si sortiu d'aquesta pàgina perdreu tots els canvis que hàgiu fet.
+Si teniu un compte d'usuari, podeu eliminar aquest avís a la secció «{{int:prefs-editing}}» de les vostres preferències.",
# Content models
'content-model-wikitext' => 'wikitext',
'tog-showhiddencats' => 'ھاوپۆلە شاراوەکان نیشان بدە',
'tog-noconvertlink' => 'لەکارخستنی ئاڵوگۆڕی سەرناوی بەستەر',
'tog-norollbackdiff' => 'لە دوای گەڕاندنەوە جیاوازی نیشان مەدە',
+'tog-useeditwarning' => 'ھۆشیارم بکەوە کاتێک لە پەڕەیەکی دەستکاری بە گۆڕانکاریی پاشەکەوتنەکراو دەردەچم',
'underline-always' => 'ھەمیشە',
'underline-never' => 'قەت',
ئەوە لەپێشدا هەبوو.',
'defaultmessagetext' => 'دەقی پەیامی هەمیشەیی',
'invalid-content-data' => 'دراوەی ناوەرۆکی نادروست',
+'editwarning-warning' => 'بەجێهێشتنی ئەم لاپەڕەیە دەبێتە هۆی لەدەست چوونی هەموو ئەو گۆڕانکاریانەی کردووتە.',
# Content models
'content-model-wikitext' => 'ویکیدەق',
'search-external' => 'Tış qıdıruv',
'searchdisabled' => '{{SITENAME}} saytında qıdıruv yapma vaqtınca toqtatıldı. Bu arada Google qullanıp {{SITENAME}} içinde qıdıruv yapıp olasıñız. Qıdıruv saytlarında indekslemeleriniñ biraz eski qalğan ola bilecegini köz ögüne alıñız.',
-# Quickbar
-'qbsettings' => 'Vızlı irişim sutun sazlamaları',
-
# Preferences page
'preferences' => 'Sazlamalar',
'mypreferences' => 'Sazlamalar',
'spam_blanking' => 'Bar olğan versiyalarda $1 saytına bağlantılar bar, temizlev',
# Skin names
-'skinname-standard' => 'Standart',
-'skinname-nostalgia' => 'Nostalgiya',
'skinname-cologneblue' => 'Köln asretligi',
'skinname-monobook' => 'MonoBook',
-'skinname-myskin' => 'Öz resimleme',
-'skinname-chick' => 'Çipçe',
-'skinname-simple' => 'Adiy',
# Patrol log
'patrol-log-page' => 'Teşkerüv jurnalı',
'blankpage' => 'Bоş saife',
'intentionallyblankpage' => 'Bu saife aselet boş qaldırılğan',
+# Special:ComparePages
+'comparepages' => 'Saifelerni teñeştirüv',
+'compare-selector' => 'Saifelerniñ versiyalarını teñeştirüv',
+'compare-submit' => 'Teñeştir',
+
# HTML forms
'htmlform-reset' => 'Deñişikliklerni keri al',
'tog-showhiddencats' => 'Zobrazit skryté kategorie',
'tog-noconvertlink' => 'Vypnout konverzi názvů',
'tog-norollbackdiff' => 'Po vrácení změny nezobrazovat porovnání rozdílů',
+'tog-useeditwarning' => 'Upozornit, když budu opouštět editaci bez uložení změn',
'underline-always' => 'Vždy',
'underline-never' => 'Nikdy',
'content-failed-to-parse' => 'Nepodařilo se zpracovat data $2 do modelu $1: $3',
'invalid-content-data' => 'Obsažená data jsou chybná',
'content-not-allowed-here' => 'Obsah typu $1 není na stránce [[$2]] dovolen.',
+'editwarning-warning' => 'Opuštěním této stránky se mohou veškeré provedené změny ztratit.
+Pokud jste {{GENDER:|přihlášen|přihlášena|přihlášeni}}, můžete si toto varování vypnout na záložce „{{int:prefs-editing}}“ v uživatelském nastavení.',
# Content models
'content-model-wikitext' => 'wikitext',
'tog-diffonly' => "Peidio â dangos cynnwys y dudalen islaw'r gymhariaeth ar dudalennau cymharu",
'tog-showhiddencats' => 'Dangos categorïau cuddiedig',
'tog-norollbackdiff' => 'Hepgor dangos cymhariaeth ar ôl gwrthdroi golygiad',
+'tog-useeditwarning' => "Tynnwch fy sylw pan wyf ar fin gadael tudalen olygu heb roi'r newidiadau ar gadw",
'underline-always' => 'Bob amser',
'underline-never' => 'Byth',
'content-failed-to-parse' => "Ni lwyddwyd i ddosrannu'r cynnwys sydd ar ffurf $2 yn ôl y model $1: $3",
'invalid-content-data' => "Data annilys i'r cynnwys",
'content-not-allowed-here' => 'Nid yw cynnwys ar ffurf "$1" yn cael ei ganiatau ar y dudalen [[$2]]',
+'editwarning-warning' => 'Os y gadewch y dudalen hon mae\'n bosib y collwch eich newidiadau iddi.
+Gallwch ddiddymu\'r rhybudd hwn yn yr adran "{{int:prefs-editing}}" yn eich dewisiadau.',
# Content models
'content-model-wikitext' => 'cystrawen wici',
'tog-showhiddencats' => 'Anzeige versteckter Kategorien',
'tog-noconvertlink' => 'Konvertierung des Titels deaktivieren',
'tog-norollbackdiff' => 'Unterschied nach dem Zurücksetzen unterdrücken',
+'tog-useeditwarning' => 'Warnen, sofern eine zur Bearbeitung geöffnete Seite verlassen wird, die nicht gespeicherte Änderungen enthält',
'underline-always' => 'immer',
'underline-never' => 'nie',
'showpreview' => 'Vorschau zeigen',
'showlivepreview' => 'Sofortige Vorschau',
'showdiff' => 'Änderungen zeigen',
-'anoneditwarning' => "Du bearbeitest diese Seite unangemeldet. Wenn du sie speicherst, wird deine aktuelle IP-Adresse in der Versionsgeschichte aufgezeichnet und ist damit unwiderruflich '''öffentlich''' einsehbar.",
+'anoneditwarning' => "Du bearbeitest diese Seite unangemeldet. Wenn du sie abspeicherst, wird deine aktuelle IP-Adresse in der Versionsgeschichte aufgezeichnet und ist damit unwiderruflich '''öffentlich''' einsehbar.",
'anonpreviewwarning' => "''Du bist nicht angemeldet. Beim Speichern wird deine IP-Adresse in der Versionsgeschichte aufgezeichnet.''",
'missingsummary' => "'''Hinweis:''' Du hast keine Zusammenfassung angegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Änderung ohne Zusammenfassung übernommen.",
'missingcommenttext' => 'Dein Abschnitt enthält keinen Text.',
'content-failed-to-parse' => 'Parsen des Inhalts $2 für Modell $1 fehlgeschlagen: $3',
'invalid-content-data' => 'Ungültige Inhaltsdaten',
'content-not-allowed-here' => 'Der Inhalt „$1“ ist auf der Seite [[$2]] nicht erlaubt',
+'editwarning-warning' => 'Das Verlassen dieser Seite kann dazu führen, dass deine Änderungen verloren gehen.
+Wenn du angemeldet bist, kannst du das Anzeigen dieser Warnung im „{{int:prefs-editing}}“-Bereich deiner Einstellungen abschalten.',
# Content models
'content-model-wikitext' => 'Wikitext',
'powersearch-togglenone' => 'Keine',
'search-external' => 'Externe Suche',
'searchdisabled' => 'Die {{SITENAME}}-Suche ist deaktiviert. Du kannst unterdessen mit Google suchen. Bitte bedenke, dass der Suchindex von {{SITENAME}} veraltet sein kann.',
+'search-error' => 'Bei der Suche ist ein Fehler aufgetreten: $1',
# Preferences page
'preferences' => 'Einstellungen',
'ipbenableautoblock' => 'Sperre die aktuell von diesem Benutzer genutzte IP-Adresse sowie automatisch alle folgenden, von denen aus er Bearbeitungen oder das Anlegen von Benutzerkonten versucht',
'ipbsubmit' => 'IP-Adresse/Benutzer sperren',
'ipbother' => 'Andere Dauer (englisch):',
-'ipboptions' => '2 Stunden:2 hours,1 Tag:1 day,3 Tage:3 days,1 Woche:1 week,2 Wochen:2 weeks,1 Monat:1 month,3 Monate:3 months,6 Monate:6 months,1 Jahr:1 year,Unbeschränkt:infinite',
+'ipboptions' => '2 Stunden:2 hours,1 Tag:1 day,3 Tage:3 days,1 Woche:1 week,2 Wochen:2 weeks,1 Monat:1 month,3 Monate:3 months,6 Monate:6 months,1 Jahr:1 year,unbeschränkt:infinite',
'ipbotheroption' => 'Andere Dauer',
'ipbotherreason' => 'Anderer/ergänzender Grund:',
'ipbhidename' => 'Benutzername in Bearbeitungen und Listen verstecken',
Stelle sicher, dass du im Anschluss alle [[Special:DoubleRedirects|doppelten]] oder [[Special:BrokenRedirects|defekten Weiterleitungen]] überprüfst.
Du bist dafür verantwortlich, dass Links weiterhin auf das korrekte Ziel verweisen.
-Die Seite wird '''nicht''' verschoben, sofern es bereits eine Seite mit dem vorgesehenen Titel gibt, es sei denn, diese eine Weiterleitung ohne Versionsgeschichte.
+Die Seite wird '''nicht''' verschoben, sofern es bereits eine Seite mit dem vorgesehenen Titel gibt, es sei denn, letztere ist eine Weiterleitung ohne Versionsgeschichte.
Dies bedeutet, dass du die Umbenennung rückgängig machen kannst, sofern du einen Fehler gemacht hast. Du kannst hingegen keine existierende Seite überschreiben.
'''Warnung!'''
'htmlform-submit' => 'Speichern',
'htmlform-reset' => 'Änderungen rückgängig machen',
'htmlform-selectorother-other' => 'Andere',
+'htmlform-no' => 'Nein',
+'htmlform-yes' => 'Ja',
# SQLite database support
'sqlite-has-fts' => 'Version $1 mit Unterstützung für die Volltextsuche',
'tog-showhiddencats' => 'Kategoriyanê dızdine bımocne',
'tog-noconvertlink' => 'Greyê sernami çerx kerdışi bıqefılne',
'tog-norollbackdiff' => 'Peyserardışi ra dıme ferqi caverde',
+'tog-useeditwarning' => 'wexta ke ez pelo nêqeydbiyaye ra veciyaya mı hişyar bıker',
'underline-always' => 'Tım',
'underline-never' => 'Qet',
'content-failed-to-parse' => 'Qandê madela $3 zereyê $1, $2 sero nêagozyayo',
'invalid-content-data' => 'Zerrey malumati nêravêrdeyo',
'content-not-allowed-here' => '"$1" sero per da [[$2]] rê mısade nêdeyêno',
+'editwarning-warning' => 'ihtimal o ke wexta şıma peli ra bıveci, vurnayiş o ke şıma kerdo, hewna şiyêro .
+eke şıma kewtê hesabê xo, no hişyari tercihanê xo ra şıma eşkeni "{{int:prefs-editing}}" bıvındarnî .',
# Content models
'content-model-wikitext' => 'wikimetin',
'tog-shownumberswatching' => 'Show the number of watching users',
'tog-oldsig' => 'Existing signature:',
'tog-fancysig' => 'Treat signature as wikitext (without an automatic link)',
-'tog-externaleditor' => 'Use external editor by default (for experts only, needs special settings on your computer. [//www.mediawiki.org/wiki/Manual:External_editors More information.])',
-'tog-externaldiff' => 'Use external diff by default (for experts only, needs special settings on your computer. [//www.mediawiki.org/wiki/Manual:External_editors More information.])',
'tog-showjumplinks' => 'Enable "jump to" accessibility links',
'tog-uselivepreview' => 'Use live preview (requires JavaScript) (experimental)',
'tog-forceeditsummary' => 'Prompt me when entering a blank edit summary',
'tog-showhiddencats' => 'Show hidden categories',
'tog-noconvertlink' => 'Disable link title conversion', # only translate this message to other languages if you have to change it
'tog-norollbackdiff' => 'Omit diff after performing a rollback',
+'tog-useeditwarning' => 'Warn me when I leave an edit page with unsaved changes',
'underline-always' => 'Always',
'underline-never' => 'Never',
'content-failed-to-parse' => 'Failed to parse $2 content for $1 model: $3',
'invalid-content-data' => 'Invalid content data',
'content-not-allowed-here' => '"$1" content is not allowed on page [[$2]]',
+'editwarning-warning' => 'Leaving this page may cause you to lose any changes you have made.
+If you are logged in, you can disable this warning in the "Editing" section of your preferences.',
# Content models
'content-model-wikitext' => 'wikitext',
# OpenSearch description
'opensearch-desc' => '{{SITENAME}} ({{CONTENTLANGUAGE}})', # do not translate or duplicate this message to other languages
+'search-error' => 'An error has occurred while searching: $1',
# Preferences page
'preferences' => 'Preferences',
'htmlform-submit' => 'Submit',
'htmlform-reset' => 'Undo changes',
'htmlform-selectorother-other' => 'Other',
+'htmlform-no' => 'No',
+'htmlform-yes' => 'Yes',
# SQLite database support
'sqlite-has-fts' => '$1 with full-text search support',
'tog-diffonly' => "''Diff''-ak agertzen direnean, orrialdearen edukiera ezkutatu",
'tog-showhiddencats' => 'Ikusi kategoria ezkutuak',
'tog-norollbackdiff' => 'Rollback bat egin ondoren ezberdintasunak ez hartu aintzat',
+'tog-useeditwarning' => 'Abisa nazazu gorde gabeko aldaketak eginez orrialde bat uzten dudanean',
'underline-always' => 'Beti',
'underline-never' => 'Inoiz ez',
'edit-no-change' => 'Zure edizioa baztertu da testua aldatu ez duzulako.',
'edit-already-exists' => 'Ezin izan da orri berria sortu.
Jada existitzen da.',
+'editwarning-warning' => 'Orrialde honetatik irteten bazara, egindako aldaketak galdu egingo dira.
+Saioa hasi baduzu, mezu hau kendu dezakezu zure hobespenen orrialdeko "{{int:prefs-editing}}" atalean.',
# Content models
'content-model-wikitext' => 'wikitestua',
'tog-showhiddencats' => 'ردههای پنهان نمایش داده شود',
'tog-noconvertlink' => 'تبدیل عنوان پیوند غیرفعال شود',
'tog-norollbackdiff' => 'بعد از واگردانی تفاوت نشان داده نشود',
+'tog-useeditwarning' => 'زمان خروج از صفحهٔ ویرایش در صورت داشتن ویرایشهای ذخیرهنشده به من هشدار داده شود',
'underline-always' => 'همیشه',
'underline-never' => 'هرگز',
'content-failed-to-parse' => 'عدم موفقیت در تجزیه محتوای $2 برای مدل $1: $3',
'invalid-content-data' => 'داده محتوای نامعتبر',
'content-not-allowed-here' => 'محتوای «$1» در صفحهٔ [[$2]] مجاز نیست',
+'editwarning-warning' => 'خروج از این صفحه ممکن است باعث از دست رفتن هرچه نوشتهاید شود.
+اگر شما با نام کاربری وارد شدهاید میتوانید این هشدار را در بخش «در حال ویرایش» ترجیحاتتان بیابید.',
# Content models
'content-model-wikitext' => 'ویکیمتن',
'tog-showhiddencats' => 'Afficher les catégories cachées',
'tog-noconvertlink' => 'Désactiver la conversion des titres',
'tog-norollbackdiff' => "Ne pas afficher le diff lors d'une révocation",
+'tog-useeditwarning' => 'M’avertir quand je quitte une page de modification sans publier les changements',
'underline-always' => 'Toujours',
'underline-never' => 'Jamais',
'content-failed-to-parse' => "Échec de l'analyse du contenu de $2 pour le modèle $1: $3",
'invalid-content-data' => 'Données du contenu non valides',
'content-not-allowed-here' => 'Le contenu "$1" n\'est pas autorisé sur la page [[$2]]',
+'editwarning-warning' => 'Quitter cette page vous fera perdre toutes les modifications que vous avez faites.
+Si vous êtes connecté avec votre compte, vous pouvez retirer cet avertissement dans la section « {{int:prefs-editing}} » de vos préférences.',
# Content models
'content-model-wikitext' => 'wikitexte',
'powersearch-togglenone' => 'Aucune',
'search-external' => 'Recherche externe',
'searchdisabled' => 'La recherche sur {{SITENAME}} est désactivée. En attendant la réactivation, vous pouvez effectuer une recherche via Google. Attention, leur indexation du contenu de {{SITENAME}} peut ne pas être à jour.',
+'search-error' => 'Une erreur s’est produite en recherchant : $1',
# Preferences page
'preferences' => 'Préférences',
'htmlform-submit' => 'Soumettre',
'htmlform-reset' => 'Défaire les modifications',
'htmlform-selectorother-other' => 'Autre',
+'htmlform-no' => 'Non',
+'htmlform-yes' => 'Oui',
# SQLite database support
'sqlite-has-fts' => '$1 avec recherche en texte intégral supportée',
'tog-diffonly' => 'Wis bai di fersjoonsferglik bloot da unerschiise, ai jü hiilj sid',
'tog-showhiddencats' => 'Wis ferstäägene kategoriie',
'tog-norollbackdiff' => 'Unerschiis eefter dåt tübäägseeten unerdrüke',
+'tog-useeditwarning' => 'Waarskaue mi, wan en sidj slööden woort, huar noch ünseekert feranrangen maaget wurden san',
'underline-always' => 'Åltens',
'underline-never' => 'uler',
'content-failed-to-parse' => "Parsing faan $2 för't model $1 ging skiaf: $3",
'invalid-content-data' => 'Diar stäänt wat uun, wat diar ei hen hiart',
'content-not-allowed-here' => '„$1“ mut ei skrewen wurd üüb sidj [[$2]]',
+'editwarning-warning' => 'Wan dü detheer sidj slotst, kön feranrangen ferleesen gung.
+Üs uunmeldet brüker könst dü detheer wäärnang bi din iinstelangen oner „Bewerke“ wechknipse.',
# Content models
'content-model-wikitext' => 'wikitekst',
'tog-showhiddencats' => 'Mostrar as categorías ocultas',
'tog-noconvertlink' => 'Desactivar a conversión dos títulos de ligazón',
'tog-norollbackdiff' => 'Omitir as diferenzas despois de levar a cabo unha reversión de edicións',
+'tog-useeditwarning' => 'Avisádeme cando deixe unha páxina de edición cos cambios sen gardar',
'underline-always' => 'Sempre',
'underline-never' => 'Nunca',
'content-failed-to-parse' => 'Erro ao analizar o contido de "$2" para o modelo de $1: $3',
'invalid-content-data' => 'Datos de contido inválidos',
'content-not-allowed-here' => 'O contido "$1" non está permitido na páxina "[[$2]]"',
+'editwarning-warning' => 'Deixar esta páxina pode causar a perda de calquera cambio feito.
+Se accedeu ao sistema, pode desactivar esta mensaxe de advertencia na sección "{{int:prefs-editing}}" das súas preferencias.',
# Content models
'content-model-wikitext' => 'texto wiki',
'searchdisabled' => 'As procuras en {{SITENAME}} están deshabilitadas por cuestións de rendemento.
Mentres tanto pode procurar usando o Google.
Note que os seus índices do contido de {{SITENAME}} poden estar desactualizados.',
+'search-error' => 'Produciuse un erro durante a procura: $1',
# Preferences page
'preferences' => 'Preferencias',
* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|texto alternativo]]</nowiki></code>''' para usar unha resolución de 200 píxeles de ancho nunha caixa na marxe esquerda cunha descrición (\"texto alternativo\")
* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' para ligar directamente co ficheiro sen que este saia na páxina",
'upload-permitted' => 'Tipos de ficheiro permitidos: $1.',
-'upload-preferred' => 'Tipos de arquivos preferidos: $1.',
-'upload-prohibited' => 'Tipos de arquivos prohibidos: $1.',
+'upload-preferred' => 'Tipos de ficheiro preferidos: $1.',
+'upload-prohibited' => 'Tipos de ficheiro prohibidos: $1.',
'uploadlog' => 'rexistro de cargas',
'uploadlogpage' => 'Rexistro de cargas',
'uploadlogpagetext' => 'A continuación está a lista cos últimos ficheiros cargados no servidor.
'filereuploadsummary' => 'Cambios no ficheiro:',
'filestatus' => 'Estado dos dereitos de autor:',
'filesource' => 'Fonte:',
-'uploadedfiles' => 'Ficheiros cargados en {{SITENAME}}',
+'uploadedfiles' => 'Ficheiros cargados',
'ignorewarning' => 'Ignorar a advertencia e gardar o ficheiro de calquera xeito',
-'ignorewarnings' => 'Ignorar os avisos',
+'ignorewarnings' => 'Ignorar as advertencias',
'minlength1' => 'Os nomes dos ficheiros deben ter cando menos unha letra.',
'illegalfilename' => 'O nome de ficheiro "$1" contén caracteres que non están permitidos nos títulos das páxinas.
Por favor, cambie o nome do ficheiro e intente cargalo de novo.',
'uploadfromurl-queued' => 'A súa carga púxese á cola.',
'uploaddisabledtext' => 'A carga de ficheiros está desactivada.',
'php-uploaddisabledtext' => 'As cargas de ficheiros PHP están desactivadas. Por favor, comprobe a característica file_uploads.',
-'uploadscripted' => 'Este ficheiro contén HTML ou código (script code) que pode producir erros ao ser interpretado polo navegador.',
+'uploadscripted' => 'Este ficheiro contén código HTML ou script que pode producir erros ao ser interpretado polo navegador.',
'uploadvirus' => 'O ficheiro contén un virus! Detalles: $1',
'uploadjava' => 'O ficheiro é un ZIP que contén un ficheiro .class de Java.
Non están permitidas as cargas de ficheiros Java, dado que poden causar restricións de seguridade.',
'upload-warning-subj' => 'Advertencia ao cargar',
'upload-warning-msg' => 'Houbo un problema durante a carga desde [$2]. Pode volver ao [[Special:Upload/stash/$1|formulario de subidas]] para corrixilo.',
-'upload-proto-error' => 'Protocolo erróneo',
-'upload-proto-error-text' => 'A carga remota require URLs que comecen por <code>http://</code> ou <code>ftp://</code>.',
+'upload-proto-error' => 'Protocolo incorrecto',
+'upload-proto-error-text' => 'A carga remota require enderezos URL que comecen por <code>http://</code> ou <code>ftp://</code>.',
'upload-file-error' => 'Erro interno',
'upload-file-error-text' => 'Produciuse un erro interno ao intentar crear un ficheiro temporal no servidor.
Por favor, contacte cun [[Special:ListUsers/sysop|administrador]] do sistema.',
'http-bad-status' => 'Houbo un problema durante a solicitude HTTP: $1 $2',
# Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
-'upload-curl-error6' => 'Non se logrou acceder a ese URL',
-'upload-curl-error6-text' => 'Non se logrou acceder ao URL que indicou. Comprobe que ese URL é correcto e que o sitio está activo.',
+'upload-curl-error6' => 'Non se puido acceder ao enderezo URL',
+'upload-curl-error6-text' => 'Non se puido acceder ao enderezo URL especificado.
+Comprobe que ese enderezo URL é correcto e que o sitio está activo.',
'upload-curl-error28' => 'Rematou o tempo de espera',
'upload-curl-error28-text' => 'O sitio tardou demasiado en responder.
Por favor, comprobe que está activo, agarde un anaco e inténteo de novo.
'htmlform-submit' => 'Enviar',
'htmlform-reset' => 'Desfacer os cambios',
'htmlform-selectorother-other' => 'Outro',
+'htmlform-no' => 'Non',
+'htmlform-yes' => 'Si',
# SQLite database support
'sqlite-has-fts' => '$1 con soporte para procuras de texto completo',
'tog-showhiddencats' => 'છુપી શ્રેણીઓ દર્શાવો',
'tog-noconvertlink' => 'Disable link title conversion',
'tog-norollbackdiff' => 'રોલબેક કર્યા પછીના તફાવતો છુપાવો',
+'tog-useeditwarning' => 'સાચવ્યા વગર જો હું પૃષ્ઠ છોડું તો મને ચેતવણી આપો',
'underline-always' => 'હંમેશાં',
'underline-never' => 'કદી નહિ',
'newwindow' => '(નવા પાનામાં ખુલશે)',
'cancel' => 'રદ કરો',
'moredotdotdot' => 'વધારે...',
+'morenotlisted' => 'વધુ યાદી કરેલી નથી...',
'mypage' => 'પાનું',
'mytalk' => 'ચર્ચા',
'anontalk' => 'આ IP માટેનું ચર્ચા પાનું',
'cannotdelete' => 'ફાઇલ કે પાનું "$1" હટાવી શકાયું નથી.
શક્ય છે કે અન્ય કોઈએ પહેલેથી હટાવી દીધું હોય.',
'cannotdelete-title' => '"$1" પાનું કાઢી શકતા નથી',
+'delete-hook-aborted' => 'દૂર કરવાનું હૂક વડે રોકી રાખવામાં આવ્યું.
+તે કોઇ કારણ આપતું નથી.',
'badtitle' => 'ખરાબ નામ',
'badtitletext' => 'આપનું ઈચ્છિત શીર્ષક અમાન્ય છે, ખાલી છે, અથવાતો અયોગ્ય રીતે આંતર-ભાષિય કે આંતર-વિકિ સાથે જોડાયેલું શીર્ષક છે.
શક્ય છે કે તેમાં એક કે વધુ એવા અક્ષર કે ચિહ્નો છે કે જે પાનાનાં શીર્ષક માટે અવૈધ છે.',
'gotaccount' => "પહેલેથી ખાતું ખોલેલું છે? '''$1'''.",
'gotaccountlink' => 'પ્રવેશ કરો',
'userlogin-resetlink' => 'પોતાની પ્રવેશ માહિતી ભૂલી ગયા છો?',
-'createaccountmail' => 'àª\87-મà«\87àª\87લ દà«\8dવારા',
+'createaccountmail' => 'àª\95ામàª\9aલાàª\89 àª\97મà«\87-તà«\87મ પાસવરà«\8dડ વાપરà«\8b àª\85નà«\87 તà«\87નà«\87 નà«\80àª\9aà«\87 àª\86પà«\87લ àª\87મà«\87લ સરનામા પર મà«\8bàª\95લà«\8b',
'createaccountreason' => 'કારણ:',
'badretype' => 'તમે દાખલ કરેલ ગુપ્તસંજ્ઞા મળતી આવતી નથી.',
'userexists' => 'દાખલ કરેલું સભ્ય નુ નામ વપરાશમાં છે.</br>
# Special:PasswordReset
'passwordreset' => 'પાસવર્ડ રીસેટ કરો',
-'passwordreset-text' => 'àª\86પના àª\88 મà«\87લ àª\96ાતા નà«\80 માહિતà«\80 મà«\87ળવવા માàª\9fà«\87 àª\86 ફà«\8bરà«\8dમ માàª\82 વિàª\97તà«\8b àªરો.',
+'passwordreset-text' => 'તમારà«\8b પાસવરà«\8dડ બદલવા માàª\9fà«\87 àª\86 ફà«\8bરà«\8dમ પà«\82રà«\81 àª\95રો.',
'passwordreset-legend' => 'પાસવર્ડ રીસેટ કરો',
'passwordreset-disabled' => 'આ વિકી પર પાસવર્ડ રીસેટ કરવા પર પ્રતિબંધ છે.',
'passwordreset-pretext' => '{{PLURAL: $1| | એક નીચે માહિતીના ટુકડાઓ દાખલ}}',
{{PLURAL:$3|આ કામચલાઉ પાસવર્ડ|આ બધા કામચલાઉ પાસવર્ડ}} {{PLURAL:$5|એક દિવસ|$5 દિવસ}} માં નષ્ટ થઇ જશે. તમારે અત્યારે જ ખાતું ખોલીને નવો પાસવર્ડ સેટ કરી લેવો જોઈએ .જો કોઈ બીજા એ આ રજૂઆત કરી હોય, અથવા જો તમને પોતાનો અસલ પાસવર્ડ યાદ હોય, અને તેને બદલવા નથી માગતા, તો આ સંદેશાને જતો કરીને પોતાના અસલ પાસવર્ડ ને વાપરી શકો છો..',
'passwordreset-emailelement' => 'વપરાશકર્તા નામ: $1
કામચલાઉ પાસવર્ડ: $2',
-'passwordreset-emailsent' => 'àª\8fàª\95 સà«\8dમà«\83તિપતà«\8dર àª\88 મેલ મોકલવામાં આવ્યો છે.',
-'passwordreset-emailsent-capture' => 'àª\8fàª\95 સà«\8dમà«\83તિપતà«\8dર àª\88 મà«\87લ મà«\8bàª\95લવામાàª\82 àª\86વà«\8dયà«\8b àª\9bà«\87, àª\9cà«\87 àª\86 પ્રમાણે છે.',
+'passwordreset-emailsent' => 'પાસવરà«\8dડ બદલવાનà«\8b àª\87મેલ મોકલવામાં આવ્યો છે.',
+'passwordreset-emailsent-capture' => 'પાસવરà«\8dડ બદલવાનà«\8b àª\87મà«\87લ મà«\8bàª\95લવામાàª\82 àª\86વà«\8dયà«\8b àª\9bà«\87, àª\9cà«\87 નà«\80àª\9aà«\87 પ્રમાણે છે.',
'passwordreset-emailerror-capture' => 'એક સ્મૃતિપત્ર ઈ મેલ બનાવવા માં આવ્યો છે, જે આ પ્રમાણે છે, પરંતુ તે યુઝર ને મોકલવા માં નિષ્ફળ થયો છે: $1',
# Special:ChangeEmail
તે પહેલેથી હાજર છે.',
'defaultmessagetext' => 'મૂળભૂત સંદેશ લખાણ',
'invalid-content-data' => 'અયોગ્ય વિગત માહિતી',
+'editwarning-warning' => 'આ પાનું છોડી દેશો તો તમારા ફેરફારો સચવાશે નહીં.
+જો તમે પ્રવેશ કરેલો હોય તો તમે આ ચેતવણીને તમારી પસંદના "ફેરફાર" વિભાગના વિકલ્પો બદલીને બંધ કરી શકો છો.',
# Content models
'content-model-wikitext' => 'વિકિલખાણ',
'search-interwiki-default' => '$1 પરીણામો:',
'search-interwiki-more' => '(વધુ)',
'search-relatedarticle' => 'શોધ સંબંધિત',
-'mwsuggest-disable' => 'AJAX સુઝાવો નિષ્ક્રીય કરો',
+'mwsuggest-disable' => 'શોધ સુઝાવો નિષ્ક્રીય કરો',
'searcheverything-enable' => 'નામસ્થળોમાં શોધો:',
'searchrelated' => 'શોધ સંબંધિત',
'searchall' => 'બધા',
'searchdisabled' => "{{SITENAME}} ઉપર શોધ બંધ કરી દેવામાં આવી છે.
ત્યાં સુધી તમે ગુગલ દ્વારા શોધ કરી શકો.
'''નોંધઃ'''{{SITENAME}}નાં તેમના (ગુગલના) ઈન્ડેક્સ જુના હોઇ શકે.",
-
-# Quickbar
-'qbsettings' => 'શીઘ્રપટ્ટ',
-'qbsettings-none' => 'કોઇપણ નહીં',
-'qbsettings-fixedleft' => 'અચળ ડાબે',
-'qbsettings-fixedright' => 'અચળ જમણે',
-'qbsettings-floatingleft' => 'ચલિત ડાબે',
-'qbsettings-floatingright' => 'ચલિત જમણે',
-'qbsettings-directionality' => 'નિશ્ચિત, તમારી ભાષા સ્ક્રિપ્ટ directionality પર આધાર રાખીને',
+'search-error' => 'શોધ કરતી વખતે ક્ષતિ આવી: $1',
# Preferences page
'preferences' => 'પસંદ',
'http-read-error' => 'HTTP વાચન ત્રુટિ.',
'http-timed-out' => ' HTTP અરજી કાલાતિત થઇ ગઇ.',
'http-curl-error' => 'URL: $1 ખેંચી લાવવામાં ત્રુટિ',
-'http-host-unreachable' => 'URL સુધી ન પહોંચી શકાયું.',
'http-bad-status' => 'HTTP અરજી વખતે કોઈ અડચણ આવી : $1 $2',
# Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
'uploadnewversion-linktext' => 'આ ફાઇલની નવી આવૃત્તિ ચઢાવો',
'shared-repo-from' => '$1 થી',
'shared-repo' => 'સાંઝો ભંડાર',
+'upload-disallowed-here' => 'તમે આ ફાઇલ ઉપર લખી શકતા નથી.',
# File reversion
'filerevert' => '$1 હતું તેવું કરો',
તેઓ વધુ યોગ્ય પાનાં સાથે જોડાયેલા હોવા જોઇએ.<br />
પાનાને સંદિગ્ધ વાક્યો વાળું પાનું ત્યારે કહી શકાય જ્યારે તે [[MediaWiki:Disambiguationspage]] નામના માળખા સાથે જોડાયેલું હોય.",
+'pageswithprop' => 'પાનાં ગુણધર્મ સાથેનાં પાનાંઓ',
+'pageswithprop-legend' => 'પાનાં ગુણધર્મ સાથેનાં પાનાંઓ',
+'pageswithprop-prop' => 'ગુણધર્મ નામ:',
+'pageswithprop-submit' => 'જાઓ',
+
'doubleredirects' => 'બમણું દિશાનિર્દેશન',
'doubleredirectstext' => 'આ પાનું દિશા નિર્દેશિત પાના પર થયેલા દિશા નિર્દેશિત પાનાની યાદિ બતાવે છે.
દરેક લિટીમાં પાના પ્રથમ અને દ્વીતીય દિશા નિર્દેશન ક્ડી બતાવે છે, તે સિવાય દ્વીતીય દિશા નિર્દેશનનું લક્ષ્ય પણ બતાવે છે કે મોટે ભાગે મૂળ પાનું હોઇ શકે છેૢ જેના પર પ્રથમ દિશા નિર્દેશન લક્ષિત છે. <del>Crossed out</del> લિટીઓ નો ઉત્તર મેળવાયો છે.',
'listusers-noresult' => 'કોઇ સભ્ય ન મળ્યો',
'listusers-blocked' => '(પ્રતિબંધિત)',
-# Special:ActiveUsers
-'activeusers' => 'સક્રિય સભ્યોની યાદી',
-'activeusers-intro' => 'છેલ્લા $1 {{PLURAL:$1|દિવસ|દિવસો}}માં જે સભ્યોએ કંઈક યોગદાન કર્યું હોય તેમની યાદી.',
-'activeusers-count' => '$1 {{PLURAL:$1|ફેરફાર|ફેરફારો}} છેલ્લા {{PLURAL:$3|દિવસ |$3 દિવસો }}માં',
-'activeusers-from' => 'આનાથી શરૂ થતા સભ્યો દર્શાવો:',
-'activeusers-hidebots' => 'બોટને છુપાવો',
-'activeusers-hidesysops' => 'પ્રબંધકો છુપાવો',
-'activeusers-noresult' => 'કોઇ સક્રીય સભ્ય ન મળ્યો',
-
# Special:ListGroupRights
'listgrouprights' => 'સભ્ય જૂથ ના હક્કો',
'listgrouprights-summary' => 'નીચે આ વિકિ પર વ્યાખ્યાયિત સભ્ય જૂથોની યાદી, તેમની સાથે સંકળાયેલા હક્કો સાથે આપી છે.
'usermessage-editor' => 'તંત્ર સંદેશાઓ',
# Watchlist
-'watchlist' => 'મારà«\80 ધà«\8dયાનસà«\82àª\9aà«\80',
+'watchlist' => 'ધ્યાનસૂચી',
'mywatchlist' => 'ધ્યાનસૂચિ',
'watchlistfor2' => 'ધ્યાન સૂચિ $1 $2',
'nowatchlist' => 'તમારી ધ્યાન સૂચિ ખાલી છે',
'prot_1movedto2' => '[[$1]]નું નામ બદલીને [[$2]] કરવામાં આવ્યું છે.',
'protect-badnamespace-title' => 'સંરક્ષિત ન કરી શકાતું નામસ્થળ',
'protect-badnamespace-text' => 'આ નામસ્થળમાં પાના સુરક્ષિત કરી શકાતા નથી.',
+'protect-norestrictiontypes-title' => 'અસુરક્ષિત પાનું',
'protect-legend' => 'સંરક્ષણ બહાલી આપો',
'protectcomment' => 'કારણ:',
'protectexpiry' => 'સમાપ્તિ:',
તમે આ પાનાઓનું સંરક્ષણ સ્તર બદલી શકો છો, પરંતુ તેની અસર ધોધાકાર સંરક્ષણ પર પડવી જોઇએ નહીં.',
'protect-default' => 'બધા સભ્યોને પરવાનગી',
-'protect-fallback' => '"$1" પરવાનગી જરૂરી',
-'protect-level-autoconfirmed' => 'નવા àª\85નà«\87 નહà«\80 નà«\8bàª\82ધાયà«\87લા સàªà«\8dયà«\8b પર પà«\8dરતિબàª\82ધ',
-'protect-level-sysop' => 'માત્ર પ્રબંધકો',
+'protect-fallback' => 'માત્ર "$1" પરવાનગી સાથેના સભ્યોને માન્ય રાખો',
+'protect-level-autoconfirmed' => 'માતà«\8dર àª\86પમà«\87ળà«\87 àª\96ાતરà«\80 થયà«\87લા સàªà«\8dયà«\8bનà«\87 માનà«\8dય રાàª\96à«\8b',
+'protect-level-sysop' => 'માત્ર પ્રબંધકોને માન્ય રાખો',
'protect-summary-cascade' => 'ધોધાકાર',
'protect-expiring' => '$1 (UTC) એ સમાપ્ત થાય છે',
'protect-expiring-local' => '$1ના નિવૃત્ત થશે',
'pageinfo-title' => ' $1 પાના ની માહિતી નૂ મથાડૂ',
'pageinfo-header-basic' => 'સામાન્ય માહિતી',
'pageinfo-header-edits' => 'ઇતિહાસ સંપાદન',
+'pageinfo-header-restrictions' => 'પાનાંની સુરક્ષા',
'pageinfo-header-properties' => 'પાનાંના ગુણધર્મો',
'pageinfo-display-title' => 'દેખાવ શિર્ષક',
+'pageinfo-default-sort' => 'મૂળભૂત ગોઠવણી કળ',
'pageinfo-length' => 'પૃષ્ઠની લંબાઇ (બાઇટમાં)',
+'pageinfo-article-id' => 'પાનાં ઓળખ',
+'pageinfo-language' => 'પાનાંની વિગતની ભાષા',
'pageinfo-robot-policy' => 'શોધ એન્જિન સ્થિતિ',
+'pageinfo-robot-index' => 'અનુક્રમિય',
+'pageinfo-robot-noindex' => 'અનુક્રમિય નહી',
'pageinfo-views' => 'જોનારાની સંખ્યા',
'pageinfo-watchers' => 'પાના નીરીક્ષકોની સંખ્યા',
+'pageinfo-subpages-name' => 'આ પાનાંનું ઉપપાનું',
'pageinfo-firstuser' => 'પૃષ્ઠ સર્જક',
'pageinfo-firsttime' => 'પૃષ્ઠ સર્જનની તારીખ',
'pageinfo-lastuser' => 'છેલ્લો ફેરફાર કરનાર',
'pageinfo-redirectsto-info' => 'માહિતી',
'pageinfo-contentpage-yes' => 'હા',
'pageinfo-protect-cascading-yes' => 'હા',
+'pageinfo-category-info' => 'શ્રેણી માહિતી',
+'pageinfo-category-pages' => 'પાનાંઓની સંખ્યા',
+'pageinfo-category-subcats' => 'ઉપશ્રેણીઓની સંખ્યા',
+'pageinfo-category-files' => 'ફાઇલ્સની સંખ્યા',
# Patrolling
'markaspatrolleddiff' => 'નિરીક્ષીત અંકિત કરો',
'specialpages-group-highuse' => 'વધુ વપરાશ ધરાવતા પાના',
'specialpages-group-pages' => 'પાનાની યાદીઓ',
'specialpages-group-pagetools' => 'પાના સાધનો',
-'specialpages-group-wiki' => 'વિàª\95િ માહિતà«\80સàª\82àª\9a અને સાધનો',
+'specialpages-group-wiki' => 'માહિતà«\80 અને સાધનો',
'specialpages-group-redirects' => 'ખાસ પાના પરના સમૂહ દિશાનિર્દેશન',
'specialpages-group-spam' => 'સ્પેમ સાધનો',
'logentry-move-move_redir-noredirect' => '$1એ દિશાનિર્દેશન કરીને પાના $3ને $4 પર વાળ્યું પણ પાછળ દિશાનિર્દેશન છોડ્યું નહી',
'logentry-patrol-patrol' => '$1 આવૃત્તિ ચિહ્નિત થયેલ પાનાં $4 $3 ચોકી કરવા ફરવા નીકળવું',
'logentry-patrol-patrol-auto' => '$1 આપોઆપ ચિહ્નિત ચોકી પહેરો કરવા લાગ્યા આવૃત્તિ પાનું $4 $3',
-'logentry-newusers-newusers' => 'સભ્ય ખાતું $1 બનાવવામાં આવ્યું',
-'logentry-newusers-create' => 'સભ્ય ખાતું $1 બનાવવામાં આવ્યું',
-'logentry-newusers-create2' => 'સભ્ય ખાતું $3 $1 વડે બનાવવામાં આવ્યું',
-'logentry-newusers-autocreate' => 'àª\8fàª\95ાàª\89નà«\8dàª\9f $1 બનાવનાર àª\86પà«\8bàª\86પ',
+'logentry-newusers-newusers' => 'સભ્ય ખાતું $1 {{GENDER:$2|બનાવવામાં આવ્યું}}',
+'logentry-newusers-create' => 'સભ્ય ખાતું $1 {{GENDER:$2|બનાવવામાં આવ્યું}}',
+'logentry-newusers-create2' => 'સભ્ય ખાતું $3 $1 વડે {{GENDER:$2|બનાવવામાં આવ્યું હતું}}',
+'logentry-newusers-autocreate' => 'વપરાશàª\95રà«\8dતા àª\96ાતà«\81àª\82 $1 àª\86પમà«\87ળà«\87 {{GENDER:$2|બનાવવામાàª\82 àª\86વà«\8dયà«\81àª\82 હતà«\81àª\82}}',
'rightsnone' => '(કંઈ નહી)',
# Feedback
'tog-showhiddencats' => 'הצגת קטגוריות מוסתרות',
'tog-noconvertlink' => 'ביטול המרת קישורים לכותרות',
'tog-norollbackdiff' => 'השמטת ההבדלים בין הגרסאות לאחר ביצוע שחזור',
+'tog-useeditwarning' => 'הצגת אזהרה בעת עזיבת דף עריכה עם שינויים שטרם נשמרו',
'underline-always' => 'תמיד',
'underline-never' => 'לעולם לא',
'content-failed-to-parse' => 'פענוח $2 כתוכן מסוג $1 נכשל: $3',
'invalid-content-data' => 'מידע שגוי על התוכן',
'content-not-allowed-here' => 'תוכן מסוג "$1" אינו מותר בדף [[$2]]',
+'editwarning-warning' => 'עזיבת דף זה עשויה לגרום לאובדן כל השינויים שביצעתם.
+אם אתם מחוברים לחשבון, תוכלו לבטל אזהרה זו בחלק "{{int:prefs-editing}}" שבהעדפות שלכם.',
# Content models
'content-model-wikitext' => 'טקסט ויקי',
'searchdisabled' => 'חיפוש ב{{grammar:תחילית|{{SITENAME}}}} אינו מופעל כעת.
בינתיים אפשר לחפש באמצעות גוגל.
שימו לב שייתכן שהמידע של {{SITENAME}} שם אינו מעודכן.',
+'search-error' => 'אירעה שגיאה במהלך החיפוש: $1',
# Preferences page
'preferences' => 'העדפות',
'htmlform-submit' => 'שליחה',
'htmlform-reset' => 'ביטול השינויים',
'htmlform-selectorother-other' => 'אחר',
+'htmlform-no' => 'לא',
+'htmlform-yes' => 'כן',
# SQLite database support
'sqlite-has-fts' => '$1 עם תמיכה בחיפוש בטקסט מלא',
'tog-showhiddencats' => 'Tampilkan kategori tersembunyi',
'tog-noconvertlink' => 'Matikan konversi judul pranala',
'tog-norollbackdiff' => 'Jangan tampilkan perbedaan setelah melakukan pengembalian',
+'tog-useeditwarning' => 'Ingatkan saya bila meninggalkan halaman penyuntingan sebelum menyimpan perubahan',
'underline-always' => 'Selalu',
'underline-never' => 'Tidak pernah',
'content-failed-to-parse' => 'Gagal menjabarkan konten $2 untuk model $1: $3',
'invalid-content-data' => 'Data konten tidak sah',
'content-not-allowed-here' => 'Konten "$1" tidak diizinkan di halaman [[$2]]',
+'editwarning-warning' => 'Meninggalkan halaman ini dapat menyebabkan semua perubahan yang belum tersimpan hilang.
+Jika Anda telah masuk log, Anda dapat mematikan peringatan ini lewat "{{int:prefs-editing}}" pada halaman preferensi Anda.',
# Content models
'content-model-wikitext' => 'teks wiki',
'searchdisabled' => 'Pencarian {{SITENAME}} sementara dimatikan.
Anda dapat mencari melalui Google untuk sementara waktu.
Perlu diingat bahwa indeks Google untuk konten {{SITENAME}} mungkin belum mencakup perubahan-perubahan terakhir.',
+'search-error' => 'Kesalahan terjadi saat mencari: $1',
# Preferences page
'preferences' => 'Preferensi',
'sorbs' => 'DNSBL',
'sorbsreason' => 'Alamat IP anda terdaftar sebagai proxy terbuka di DNSBL.',
'sorbs_create_account_reason' => 'Alamat IP anda terdaftar sebagai proxy terbuka di DNSBL. Anda tidak dapat membuat akun.',
+'xffblockreason' => 'Sebuah alamat IP di kepala X-Forwarded-For, entah milik Anda atau server proxy yang Anda pakai, telah diblokir. Alasan pemblokirannya adalah: $1',
'cant-block-while-blocked' => 'Anda tidak dapat memblokir pengguna lain ketika Anda sendiri sedang diblokir.',
'cant-see-hidden-user' => 'Pengguna yang anda coba blokir telah di blokir dan di sembunyikan. Selama anda tidak memiliki hak sembunyikan pengguna, anda tidak dapat melihat atau menyunting pemblokiran pengguna ini.',
'ipbblocked' => 'Anda tidak dapat memblokir atau membuka blokir pengguna lain, karena anda sendiri diblokir',
'tog-showhiddencats' => 'Mostra categorie nascoste',
'tog-noconvertlink' => 'Disattiva la conversione dei titoli dei link',
'tog-norollbackdiff' => 'Non mostrare il confronto tra versioni dopo aver effettuato un rollback',
+'tog-useeditwarning' => 'Avvisa quando si lascia una pagina di modifica con modifiche non salvate',
'underline-always' => 'Sempre',
'underline-never' => 'Mai',
'content-failed-to-parse' => 'Impossibile analizzare $2 per il modello $1: $3',
'invalid-content-data' => 'Dati contenuti non validi',
'content-not-allowed-here' => 'Contenuto in "$1" non consentito nella pagine [[$2]]',
+'editwarning-warning' => 'Lasciare questa pagina potrebbe costarti la perdita di tutti i cambiamenti effettuati.
+Se sei loggato, puoi disattivare questo avviso nella sezione "{{int:prefs-editing}}" delle tue preferenze.',
# Content models
'content-model-wikitext' => 'wikitesto',
'powersearch-togglenone' => 'Nessuno',
'search-external' => 'Ricerca esterna',
'searchdisabled' => 'La ricerca interna di {{SITENAME}} non è attiva; nel frattempo si può provare ad usare un motore di ricerca esterno come Google. (Si noti però che i contenuti di {{SITENAME}} presenti in tali motori potrebbero non essere aggiornati.)',
+'search-error' => 'Si è verificato un errore durante la ricerca: $1',
# Preferences page
'preferences' => 'Preferenze',
'proxyblocksuccess' => 'Fatto.',
'sorbsreason' => 'Questo indirizzo IP è elencato come proxy aperto nella blacklist DNSBL utilizzata da {{SITENAME}}.',
'sorbs_create_account_reason' => 'Non è possibile creare nuovi accessi da questo indirizzo IP perché è elencato come proxy aperto nella blacklist DNSBL utilizzata da {{SITENAME}}.',
+'xffblockreason' => "Un indirizzo IP presente nell'intestazione X-Forwarded-For, tuo o del server proxy che stai utilizzando, è stato bloccato. La motivazione originale del blocco è: $1",
'cant-block-while-blocked' => 'Non è possibile bloccare altri utenti mentre si è bloccati.',
'cant-see-hidden-user' => 'L\'utente che si sta tentando di bloccare è stato già bloccato e nascosto. Poiché non hai il permesso "hideuser", non è possibile visualizzare o modificare il blocco dell\'utente.',
'ipbblocked' => 'Non puoi bloccare o sbloccare altri utenti, perché tu stesso sei bloccato',
'tog-showhiddencats' => '隠しカテゴリを表示',
'tog-noconvertlink' => 'リンクタイトル変換を無効にする',
'tog-norollbackdiff' => '巻き戻し後の差分を表示しない',
+'tog-useeditwarning' => '変更を保存せずに編集画面から離れようとしたら警告',
'underline-always' => '常に付ける',
'underline-never' => '常に付けない',
'content-failed-to-parse' => '$2のコンテンツを$1モデルとして構文解析できませんでした: $3',
'invalid-content-data' => '本文データが無効です',
'content-not-allowed-here' => 'ページ [[$2]] では、「$1」コンテンツは許可されていません',
+'editwarning-warning' => 'このページを離れると、あなたが行った変更はすべて失われてしまうかもしれません。ログインしている場合、個人設定の「{{int:prefs-editing}}」タブでこの警告を表示しないようにすることができます。',
# Content models
'content-model-wikitext' => 'ウィキテキスト',
'searchdisabled' => '{{SITENAME}}の検索機能は無効化されています。
さしあたってはGoogleなどで検索できます。
ただし外部の検索エンジンの索引にある{{SITENAME}}のコンテンツは古い場合があります。',
+'search-error' => '検索する際にエラーが発生しました: $1',
# Preferences page
'preferences' => '個人設定',
'htmlform-submit' => '送信',
'htmlform-reset' => '変更を取り消す',
'htmlform-selectorother-other' => 'その他',
+'htmlform-no' => 'いいえ',
+'htmlform-yes' => 'はい',
# SQLite database support
'sqlite-has-fts' => '$1 (全文検索あり)',
'tog-diffonly' => 'Aja dituduhaké isi kaca ing ngisor bédané suntingan',
'tog-showhiddencats' => 'Tuduhna kategori sing didelikaké',
'tog-norollbackdiff' => 'Lirwaaké prabédan sawusé nglakokaké sawijining pambalikan.',
+'tog-useeditwarning' => 'Èlingaké kula yèn kula ninggalaké suntingan sing durung kasimpen',
'underline-always' => 'Tansah',
'underline-never' => 'Ora',
'tog-showhiddencats' => '숨은 분류 보기',
'tog-noconvertlink' => '링크 제목 변환을 비활성화',
'tog-norollbackdiff' => '되돌리기 후 차이를 보이지 않기',
+'tog-useeditwarning' => '수정한 내용을 저장하지 않고 편집 양식을 닫거나 다른 페이지로 이동할 때 알림',
'underline-always' => '항상',
'underline-never' => '치지 않음',
'content-failed-to-parse' => '$1 모델에 대한 $2 내용을 구문 분석하는 데 실패했습니다: $3',
'invalid-content-data' => '잘못된 내용 데이터입니다',
'content-not-allowed-here' => '"$1" 내용은 [[$2]] 문서예 허용하지 않습니다',
+'editwarning-warning' => '이 창에서 벗어나면 저장하지 않은 편집이 모두 사라집니다.
+로그인한 경우, 환경 설정 ‘{{int:prefs-editing}}’란에서 이 경고창을 띄우지 않도록 설정할 수 있습니다.',
# Content models
'content-model-wikitext' => '위키텍스트',
'searchdisabled' => '{{SITENAME}} 찾기 기능이 비활성화되어 있습니다.
기능이 작동하지 않는 동안에는 구글(Google)을 이용해 찾을 수 있습니다.
검색 엔진의 내용은 최신이 아닐 수 있다는 점을 주의해주세요.',
+'search-error' => '찾는 동안 오류가 발생했습니다: $1',
# Preferences page
'preferences' => '사용자 환경 설정',
'htmlform-submit' => '저장',
'htmlform-reset' => '바꾼 것을 되돌리기',
'htmlform-selectorother-other' => '기타',
+'htmlform-no' => '아니오',
+'htmlform-yes' => '예',
# SQLite database support
'sqlite-has-fts' => '$1 (본문 전체 찾기)',
'tog-showhiddencats' => 'Donn de verstoche Saachjroppe aanzeije',
'tog-noconvertlink' => 'Don de Tittele nit ümwandelle',
'tog-norollbackdiff' => 'Donn noh „{{int:Rollback}}“ de Ungerscheide nit aanzeije',
+'tog-useeditwarning' => 'Donn mesch warne, wann esch vun en Sigg fott jonn, ih dat esch all ming Änderunge avjeschpeischert hann.',
'underline-always' => 'jo, ongershtriishe',
'underline-never' => 'nä',
'content-failed-to-parse' => 'Et wohr nit müjjelesch, dä Enhalld met däm <i lang="en">MIME-Typ</i> $2 för en Dattei met $1 dren ze verwooschte: $3.',
'invalid-content-data' => 'Di Daate en dä Sigg sen onjöltesch.',
'content-not-allowed-here' => 'Ene Enhalld vun dä Zoot „$1“ es op dä Sigg „[[$2]]“ nit zohjelohße.',
+'editwarning-warning' => 'Wann de vun hee dä Sigg fott jeihß, doh künnte all Ding Änderunge aan dä Sigg verschött jonn.
+Do kanns heh di Warnung affschallde, wann de aanjemelldt un enjelogg bes, dann kriß de se nieh mieh wider. Jangk doför en dä Affschnett „{{int:prefs-editing}}“ en Dinge Enshtellunge.',
# Content models
'content-model-wikitext' => 'Wikitäx',
Et es nit jesaht,
dat dänne ihr Daate topaktuell sin,
ävver et es besser wie jaa_nix.',
+'search-error' => 'An error has occurred while searching: $1',
# Preferences page
'preferences' => 'ming Enstellunge',
'listgrouprights-key' => 'Lejend:
* Dat es e <span class="listgrouprights-granted">jejovve Rääsch</span>
* Dat es e <span class="listgrouprights-revoked">fottjenumme Rääsch</span>',
-'listgrouprights-group' => 'Jrupp',
+'listgrouprights-group' => 'Jropp',
'listgrouprights-rights' => 'Räächte',
'listgrouprights-helppage' => 'Help:Jrupperäächte',
'listgrouprights-members' => '(opliste)',
'tog-diffonly' => 'Nerādīt lapu saturu zem izmaiņām',
'tog-showhiddencats' => 'Rādīt slēptās kategorijas',
'tog-norollbackdiff' => 'Neņemt vērā atšķirības, veicot atriti',
+'tog-useeditwarning' => 'Brīdināt mani, kad es atstāju lapas rediģēšanu nesaglabājot izmaiņas',
'underline-always' => 'vienmēr',
'underline-never' => 'nekad',
'emailconfirmlink' => 'Apstiprināt tavu e-pasta adresi',
'invalidemailaddress' => 'E-pasta adrese nevar tikt apstiprināta, jo izskatās nederīga. Lūdzu ievadi korekti noformētu e-pasta adresi, vai arī atstāj to lauku tukšu.',
'cannotchangeemail' => 'Konta e-pasta adresi nevar nomainīt šajā wiki.',
+'emaildisabled' => 'Šī vietne nevar nosūtīt e-pastus.',
'accountcreated' => 'Konts izveidots',
'accountcreatedtext' => 'Lietotāja konts priekš $1 tika izveidots.',
'createaccount-title' => 'Lietotāja konta izveidošana {{grammar:lokatīvs|{{SITENAME}}}}',
Tā jau eksistē.',
'defaultmessagetext' => 'Noklusētais ziņojuma teksts',
'invalid-content-data' => 'Nederīgi satura dati',
+'editwarning-warning' => 'Atstājot šo lapu tu zaudēsi izdarītās izmaiņas.
+Ja esi pieteicies, jūs vari atspējot šo brīdinājumu savās izvēlēs sadaļā "rediģēšana"',
# Content models
'content-model-javascript' => 'JavaScript kods',
'tog-showhiddencats' => 'Прикажи скриени категории',
'tog-noconvertlink' => 'Оневозможи претворање на наслов на врска',
'tog-norollbackdiff' => 'Изостави ја разликата по извршено отповикување',
+'tog-useeditwarning' => 'Предупреди ме кога сакам да напуштам страница за уредување без да ги имам зачувано промените',
'underline-always' => 'Секогаш',
'underline-never' => 'Никогаш',
'content-failed-to-parse' => 'Не успеав да ја предадам содржината од типот $2 за моделот $1: $3',
'invalid-content-data' => 'Неважечки податоци од содржината',
'content-not-allowed-here' => 'Содржините од моделот „$1“ не се допуштени на страницата [[$2]]',
+'editwarning-warning' => 'Ако ја напуштите страницата ќе ги изгубите сите промени кои сте ги направиле.
+Ако сте најавени, можете да го исклучите ова предупредување во одделот „{{int:prefs-editing}}“ во вашите нагодувања.',
# Content models
'content-model-wikitext' => 'викитекст',
'searchdisabled' => '{{SITENAME}} пребарувањето е оневозможено.
Во меѓувреме, можете да пребарувате преку Google.
Да напоменеме дека нивното индексирање на {{SITENAME}} содржините може да биде застарено.',
+'search-error' => 'Се појави грешка при пребарувањето: $1',
# Preferences page
'preferences' => 'Нагодувања',
'tog-showhiddencats' => 'Tunjukkan kategori tersembunyi',
'tog-noconvertlink' => 'Lumpuhkan penukaran tajuk pautan',
'tog-norollbackdiff' => 'Abaikan perbezaan selepas melakukan pengunduran suntingan.',
+'tog-useeditwarning' => 'Beri saya amaran apabila saya meninggalkan sesebuah laman penyuntingan tanpa menyimpan perubahan.',
'underline-always' => 'Sentiasa',
'underline-never' => 'Jangan',
'content-failed-to-parse' => 'Kandungan $2 tidak dapat dihuraikan untuk model $1: $3',
'invalid-content-data' => 'Data kandungan tidak sah',
'content-not-allowed-here' => 'Kandungan "$1" tidak dibenarkan di halaman [[$2]]',
+'editwarning-warning' => 'Meninggalkan laman ini mungkin akan menyebabkan anda kehilangan sebarang perubahan yang telah anda lakukan.
+Anda boleh melumpuhkan amaran in di bahagian "{{int:prefs-editing}}" dalam keutamaan anda.',
# Content models
'content-model-wikitext' => 'wikiteks',
'powersearch-togglenone' => 'Tiada',
'search-external' => 'Carian luar',
'searchdisabled' => 'Ciri pencarian dalam {{SITENAME}} dimatikan. Anda boleh mencari melalui Google. Sila ambil perhatian bahawa indeks dalam Google mungkin bukan yang terkini.',
+'search-error' => 'Berlakunya ralat ketika mencari: $1',
# Preferences page
'preferences' => 'Keutamaan',
'tog-diffonly' => 'Ikke vis sideinnhold under differ',
'tog-showhiddencats' => 'Vis skjulte kategorier',
'tog-norollbackdiff' => 'Ikke vis diff etter tilbakestilling',
+'tog-useeditwarning' => 'Si ifra dersom jeg forlater en side jeg har gjort redigeringer på men ikke har lagret siden.',
'underline-always' => 'Alltid',
'underline-never' => 'Aldri',
'content-failed-to-parse' => 'Klarte ikke å tolke innholdet $2 for innholdsmodellen $1: $3',
'invalid-content-data' => 'Ugyldig innhold',
'content-not-allowed-here' => 'Innholdsmodellen «$1» er ikke tillatt på siden [[$2]]',
+'editwarning-warning' => 'Ved å forlate siden vil du miste alle endringer du har utført.
+Denne advarselen kan slås av under {{int:prefs-editing}} i instillingene dine.',
# Content models
'content-model-wikitext' => 'WikiTekst',
'tog-showhiddencats' => 'Verborgen categorieën weergeven',
'tog-noconvertlink' => 'Paginanaamconversie uitschakelen',
'tog-norollbackdiff' => 'Wijzigingen weglaten na terugdraaien',
+'tog-useeditwarning' => 'Waarschuw mij als ik een bewerkte pagina die nog niet is opgeslagen wil verlaten',
'underline-always' => 'Altijd',
'underline-never' => 'Nooit',
'jumptosearch' => 'zoeken',
'view-pool-error' => 'De servers zijn op het moment helaas overbelast.
Te veel gebruikers proberen deze pagina te bekijken.
-Wacht alstublieft even voordat u opnieuw toegang probeert te krijgen tot deze pagina.
+Wacht even voordat u opnieuw toegang probeert te krijgen tot deze pagina.
$1',
'pool-timeout' => 'De maximaal te wachten tijd voor het wachten op een lock is verstreken',
'delete-hook-aborted' => 'Het verwijderen is afgebroken door een hook.
Er is geen toelichting beschikbaar.',
'badtitle' => 'Ongeldige paginanaam',
-'badtitletext' => 'De naam van de opgevraagde pagina was ongeldig, leeg of bevatte een verkeerde intertaal- of interwikikoppeling.
+'badtitletext' => 'De naam van de opgegeven pagina was ongeldig, leeg of bevatte een verkeerde intertaal- of interwikikoppeling.
Wellicht bevat de paginanaam niet toegestane tekens.',
'perfcached' => 'Deze gegevens komen uit een cache en zijn mogelijk niet actueel. Er {{PLURAL:$1|is maximaal één resultaat|zijn maximaal $1 resultaten}} beschikbaar in de cache.',
'perfcachedts' => 'Deze gegevens komen uit een cache die voor het laatst is bijgewerkt op $2 om $3. Er {{PLURAL:$4|is maximaal één resultaat|zijn maximaal $4 resultaten}} beschikbaar in de cache.',
'nouserspecified' => 'Geef een gebruikersnaam op.',
'login-userblocked' => 'Deze gebruiker is geblokkeerd.
Aanmelden is niet mogelijk.',
-'wrongpassword' => 'Het ingegeven wachtwoord is onjuist.
+'wrongpassword' => 'Het opgegeven wachtwoord is onjuist.
Probeer het opnieuw.',
'wrongpasswordempty' => 'Het opgegeven wachtwoord was leeg.
Probeer het opnieuw.',
'content-failed-to-parse' => 'Het was niet mogelijk de inhoud van het MIME-type $2 voor het model $1 te verwerken: $3.',
'invalid-content-data' => 'Ongeldige inhoudsgegevens',
'content-not-allowed-here' => 'De inhoud "$1" is niet toegestaan op pagina [[$2]].',
+'editwarning-warning' => 'Als u deze pagina verlaat verliest u mogelijk wijzigingen die u hebt gemaakt.
+Als u bent aangemeld, kunt u deze waarschuwing uitschakelen in het tabblad "{{int:prefs-editing}}" in uw voorkeuren.',
# Content models
'content-model-wikitext' => 'wikitekst',
'rev-showdeleted' => 'weergeven',
'revisiondelete' => 'Versies verwijderen of terugplaatsen',
'revdelete-nooldid-title' => 'Ongeldige doelversie',
-'revdelete-nooldid-text' => 'U hebt geen doelversie(s) voor deze handeling opgegeven. De aangegeven versie bestaat niet of u probeert de laatste versie te verbergen.',
+'revdelete-nooldid-text' => 'U hebt geen doelversie(s) voor deze handeling opgegeven. De opgegeven versie bestaat niet of u probeert de laatste versie te verbergen.',
'revdelete-nologtype-title' => 'Er is geen logboektype opgegeven',
'revdelete-nologtype-text' => 'U hebt geen logboektype opgegeven om deze handeling op uit te voeren.',
'revdelete-nologid-title' => 'Ongeldige logboekregel',
-'revdelete-nologid-text' => 'U hebt ofwel geen doellogboekregel opgegeven of de aangegeven logboekregel bestaat niet.',
-'revdelete-no-file' => 'Het aangegeven bestand bestaat niet.',
+'revdelete-nologid-text' => 'U hebt ofwel geen doellogboekregel opgegeven of de opgegeven logboekregel bestaat niet.',
+'revdelete-no-file' => 'Het opgegeven bestand bestaat niet.',
'revdelete-show-file-confirm' => 'Weet u zeker dat u de verwijderde versie van het bestand "<nowiki>$1</nowiki>" van $2 om $3 wilt bekijken?',
'revdelete-show-file-submit' => 'Ja',
'revdelete-selected' => "'''Geselecteerde {{PLURAL:$2|bewerking|bewerkingen}} van [[:$1]]:'''",
'revdelete-modify-no-access' => 'Er is een fout opgetreden tijdens het wijzigen van het object van $1 om $2: dit object is gemarkeerd als "beschermd".
U hebt geen toegang tot dit object.',
'revdelete-modify-missing' => 'Er is een fout opgetreden bij het wijzigen van versienummer $1: het komt niet voor in de database!',
-'revdelete-no-change' => "'''Waarschuwing:''' het object van $1 om $2 uur had al de aangegeven zichtbaarheidsinstellingen.",
+'revdelete-no-change' => "'''Waarschuwing:''' het object van $1 om $2 uur had al de opgegeven zichtbaarheidsinstellingen.",
'revdelete-concurrent-change' => 'Er is een fout opgetreden bij het wijzigen van het object van $1 om $2: de status is inmiddels gewijzigd door iemand anders.
Controleer de logboeken.',
'revdelete-only-restricted' => 'Er is een fout opgetreden tijdens het verbergen van het item van $1, $2: u kunt geen items onderdrukken uit het zicht van beheerders zonder ook een van de andere zichtbaarheidsopties te selecteren.',
'mergehistory-from' => 'Bronpagina:',
'mergehistory-into' => 'Bestemmingspagina:',
'mergehistory-list' => 'Samenvoegbare bewerkingsgeschiedenis',
-'mergehistory-merge' => 'De volgende versies van [[:$1]] kunnen samengevoegd worden naar [[:$2]].
-Gebruik de kolom met keuzerondjes om alleen de versies gemaakt op en voor de aangegeven tijd samen te voegen.
+'mergehistory-merge' => 'De volgende versies van [[:$1]] kunnen worden samengevoegd naar [[:$2]].
+Gebruik de kolom met keuzerondjes om alleen de versies gemaakt op en voor de opgegeven tijd samen te voegen.
Let op dat het gebruiken van de navigatiekoppelingen deze kolom opnieuw instelt.',
'mergehistory-go' => 'Samenvoegbare bewerkingen bekijken',
'mergehistory-submit' => 'Versies samenvoegen',
'searchprofile-project-tooltip' => 'Zoeken in $1',
'searchprofile-images-tooltip' => 'Zoeken naar bestanden',
'searchprofile-everything-tooltip' => "Alle inhoud doorzoeken (inclusief overlegpagina's)",
-'searchprofile-advanced-tooltip' => 'Zoeken in aangegeven naamruimten',
+'searchprofile-advanced-tooltip' => 'Zoeken in opgegeven naamruimten',
'search-result-size' => '$1 ({{PLURAL:$2|1 woord|$2 woorden}})',
'search-result-category-size' => '{{PLURAL:$1|1 categorielid|$1 categorieleden}} ({{PLURAL:$2|1 ondercategorie|$2 ondercategorieën}}, {{PLURAL:$3|1 bestand|$3 bestanden}})',
'search-result-score' => 'Relevantie: $1%',
'timezonelegend' => 'Tijdzone:',
'localtime' => 'Plaatselijke tijd:',
'timezoneuseserverdefault' => 'Wikistandaard gebruiken ($1)',
-'timezoneuseoffset' => 'Anders (tijdverschil aangeven)',
+'timezoneuseoffset' => 'Anders (tijdverschil opgeven)',
'timezoneoffset' => 'Tijdsverschil¹:',
'servertime' => 'Servertijd:',
'guesstimezone' => 'Vanuit de browser toevoegen',
'badsiglength' => 'Uw ondertekening is te lang.
Deze moet minder dan $1 {{PLURAL:$1|teken|tekens}} bevatten.',
'yourgender' => 'Geslacht:',
-'gender-unknown' => 'Niet aangegeven',
+'gender-unknown' => 'Niet opgegeven',
'gender-male' => 'Man',
'gender-female' => 'Vrouw',
'prefs-help-gender' => 'Optioneel: dit wordt gebruikt om gebruikers correct aan te spreken in de software.
'recentchangeslinked-toolbox' => 'Verwante wijzigingen',
'recentchangeslinked-title' => 'Wijzigingen verwant aan "$1"',
'recentchangeslinked-noresult' => "Er zijn in de opgegeven periode geen bewerkingen geweest op de pagina's waarheen vanaf hier verwezen wordt.",
-'recentchangeslinked-summary' => "Deze speciale pagina geeft de laatste bewerkingen weer op pagina's waarheen verwezen wordt vanaf een aangegeven pagina of op pagina's in een aangegeven categorie.
+'recentchangeslinked-summary' => "Deze speciale pagina geeft de laatste bewerkingen weer op pagina's waarheen verwezen wordt vanaf een opgegeven pagina of op pagina's in een opgegeven categorie.
Pagina's die op [[Special:Watchlist|uw volglijst]] staan worden '''vet''' weergegeven.",
'recentchangeslinked-page' => 'Paginanaam:',
'recentchangeslinked-to' => "Wijzigingen aan pagina's met koppelingen naar deze pagina bekijken",
Uw server is niet ingesteld om deze gegevens door te geven.
Misschien gebruikt deze CGI, en dan wordt img_auth niet ondersteund.
Zie https://www.mediawiki.org/wiki/Manual:Image_Authorization voor meer informatie.',
-'img-auth-notindir' => 'Het opgevraagde pad is niet de ingestelde uploadmap.',
+'img-auth-notindir' => 'Het opgegeven pad is niet de ingestelde uploadmap.',
'img-auth-badtitle' => 'Het was niet mogelijk een geldige paginanaam te maken van "$1".',
'img-auth-nologinnWL' => 'U bent niet aangemeld en "$1" staat niet op de witte lijst.',
'img-auth-nofile' => 'Bestand "$1" bestaat niet.',
'filedelete-success' => "'''$1''' is verwijderd.",
'filedelete-success-old' => "De versie van '''[[Media:$1|$1]]''' van $3, $2 is verwijderd.",
'filedelete-nofile' => "'''$1''' bestaat niet.",
-'filedelete-nofile-old' => "Er is geen versie van '''$1''' in het archief met de aangegeven eigenschappen.",
+'filedelete-nofile-old' => "Er is geen versie van '''$1''' in het archief met de opgegeven eigenschappen.",
'filedelete-otherreason' => 'Andere reden:',
'filedelete-reason-otherlist' => 'Andere reden',
'filedelete-reason-dropdown' => '*Veel voorkomende redenen voor verwijderen
'booksources-search-legend' => 'Bronnen en gegevens over een boek zoeken',
'booksources-go' => 'OK',
'booksources-text' => 'Hieronder staat een lijst met koppelingen naar andere websites die nieuwe of gebruikte boeken verkopen, en die wellicht meer informatie over het boek dat u zoekt hebben:',
-'booksources-invalid-isbn' => 'Het ingegeven ISBN lijkt niet geldig te zijn.
+'booksources-invalid-isbn' => 'Het opgegeven ISBN lijkt niet geldig te zijn.
Controleer of u wellicht een fout hebt gemaakt bij de invoer.',
# Special:Log
'protect-legend' => 'Beveiliging bevestigen',
'protectcomment' => 'Reden:',
'protectexpiry' => 'Duur:',
-'protect_expiry_invalid' => 'De aangegeven duur is ongeldig.',
+'protect_expiry_invalid' => 'De opgegeven duur is ongeldig.',
'protect_expiry_old' => 'Vervaldatum is in het verleden.',
'protect-unchain-permissions' => 'Overige beveiligingsinstellingen beschikbaar maken',
'protect-text' => "Hier kunt u het beveiligingsniveau voor de pagina '''$1''' bekijken en wijzigen.",
'xml-error-string' => '$1 op regel $2, kolom $3 (byte $4): $5',
'import-upload' => 'XML-gegevens uploaden',
'import-token-mismatch' => 'De sessiegegevens zijn verloren gegaan. Probeer het opnieuw.',
-'import-invalid-interwiki' => 'Het is niet mogelijk van de aangegeven wiki te importeren.',
+'import-invalid-interwiki' => 'Het is niet mogelijk van de opgegeven wiki te importeren.',
'import-error-edit' => 'De pagina "$1" is niet geïmporteerd omdat u niet de rechten hebt om die te bewerken.',
'import-error-create' => 'De pagina "$1" is niet geïmporteerd omdat u niet de rechten hebt om die aan te maken.',
'import-error-interwiki' => 'De pagina "$1" is niet geïmporteerd omdat deze naam is gereserveerd voor externe koppelingen (interwiki).',
$1',
'filedelete-missing' => 'Het bestand "$1" kan niet verwijderd worden, omdat het niet bestaat.',
-'filedelete-old-unregistered' => 'De aangegeven bestandsversie "$1" staat niet in de database`.',
-'filedelete-current-unregistered' => 'Het aangegeven bestand "$1" staat niet in de database.',
+'filedelete-old-unregistered' => 'De opgegeven bestandsversie "$1" staat niet in de database`.',
+'filedelete-current-unregistered' => 'Het opgegeven bestand "$1" staat niet in de database.',
'filedelete-archive-read-only' => 'De webserver kan niet in de archiefmap "$1" schrijven.',
# Browsing diffs
# Email address confirmation
'confirmemail' => 'E-mailadres bevestigen',
-'confirmemail_noemail' => 'U hebt geen geldig e-mailadres ingegeven in uw [[Special:Preferences|gebruikersvoorkeuren]].',
+'confirmemail_noemail' => 'U hebt geen geldig e-mailadres opgegeven in uw [[Special:Preferences|gebruikersvoorkeuren]].',
'confirmemail_text' => '{{SITENAME}} eist bevestiging van uw e-mailadres voordat u de e-mailmogelijkheden kunt gebruiken.
Klik op de onderstaande knop om een bevestigingsbericht te ontvangen.
Dit bericht bevat een koppeling met een code.
'dberr-cachederror' => 'Deze pagina is een kopie uit de cache en is wellicht niet de meest recente versie.',
# HTML forms
-'htmlform-invalid-input' => 'Er zijn problemen met enkele ingegeven waarden',
-'htmlform-select-badoption' => 'De ingegeven waarde is ongeldig.',
-'htmlform-int-invalid' => 'De ingegeven waarde is geen geheel getal.',
+'htmlform-invalid-input' => 'Er zijn problemen met enkele opgegeven waarden',
+'htmlform-select-badoption' => 'De opgegeven waarde is ongeldig.',
+'htmlform-int-invalid' => 'De opgegeven waarde is geen geheel getal.',
'htmlform-float-invalid' => 'De waarde die u hebt opgegeven is geen getal.',
-'htmlform-int-toolow' => 'De ingegeven waarde ligt onder de minimumwaarde van $1',
-'htmlform-int-toohigh' => 'De ingegeven waarde ligt boven de maximumwaarde van $1',
+'htmlform-int-toolow' => 'De opgegeven waarde ligt onder de minimumwaarde van $1',
+'htmlform-int-toohigh' => 'De opgegeven waarde ligt boven de maximumwaarde van $1',
'htmlform-required' => 'Deze waarde is verplicht',
'htmlform-submit' => 'Opslaan',
'htmlform-reset' => 'Wijzigingen ongedaan maken',
'tog-showhiddencats' => 'Pokazuj ukryte kategorie',
'tog-noconvertlink' => 'Wyłącz konwersję tytułów w linkach',
'tog-norollbackdiff' => 'Pomiń pokazywanie zmian po użyciu funkcji „cofnij”',
+'tog-useeditwarning' => 'Ostrzegaj mnie, gdy opuszczam stronę edycji bez zapisania zmian',
'underline-always' => 'zawsze',
'underline-never' => 'nigdy',
'content-failed-to-parse' => 'Format zawartości typu $2 (dla modelu: $1) nieprawidłowy: $3',
'invalid-content-data' => 'Zawartość strony zawiera nieprawidłowe dane',
'content-not-allowed-here' => 'Zawartość tego typu ($1) nie jest dozwolona na stronie [[$2]]',
+'editwarning-warning' => 'Opuszczenie tej strony może spowodować utratę wprowadzonych przez Ciebie zmian.
+Jeśli jesteś zalogowany możesz wyłączyć wyświetlanie tego ostrzeżenia w zakładce {{int:prefs-editing}} w swoich preferencjach.',
# Content models
'content-model-wikitext' => 'wikitekst',
'right-autoconfirmed' => 'Edycja stron częściowo zabezpieczonych',
'right-bot' => 'Oznaczanie edycji jako wykonanych automatycznie',
'right-nominornewtalk' => 'Drobne zmiany na stronach dyskusji użytkowników nie włączają powiadomienia o nowej wiadomości',
-'right-apihighlimits' => 'Zwiększony limit w zapytaniach, wykonywanych poprzez interfejs API',
+'right-apihighlimits' => 'Zwiększony limit w zapytaniach wykonywanych poprzez interfejs API',
'right-writeapi' => 'Zapis poprzez interfejs API',
'right-delete' => 'Usuwanie stron',
'right-bigdelete' => 'Usuwanie stron z długą historią edycji',
'protectlogtext' => 'Poniżej znajduje się lista zmian w zabezpieczeniu pojedynczych stron.
Wszystkie aktywne zabezpieczenia odnajdziesz na liście [[Special:ProtectedPages|zabezpieczonych stron]].',
'protectedarticle' => 'zabezpieczono "[[$1]]"',
-'modifiedarticleprotection' => 'zmieniono poziom zabezpieczenia "[[$1]]"',
+'modifiedarticleprotection' => 'zmieniono stopień zabezpieczenia "[[$1]]"',
'unprotectedarticle' => 'odbezpieczył [[$1]]',
'movedarticleprotection' => 'przeniósł ustawienia zabezpieczeń z [[$2]] do [[$1]]',
'protect-title' => 'Zmiana poziomu zabezpieczenia „$1”',
'protect_expiry_invalid' => 'Podany czas automatycznego odbezpieczenia jest nieprawidłowy.',
'protect_expiry_old' => 'Podany czas automatycznego odblokowania znajduje się w przeszłości.',
'protect-unchain-permissions' => 'Odblokuj dodatkowe opcje zabezpieczania',
-'protect-text' => "Możesz tu sprawdzić i zmienić poziom zabezpieczenia strony '''$1'''.",
+'protect-text' => "Możesz tu sprawdzić i zmienić stopień zabezpieczenia strony '''$1'''.",
'protect-locked-blocked' => "Nie możesz zmienić poziomów zabezpieczenia, ponieważ jesteś zablokowany.
Obecne ustawienia dla strony '''$1''' to:",
'protect-locked-dblock' => "Nie można zmienić poziomu zabezpieczenia z powodu działającej blokady bazy danych. Obecne ustawienia dla strony '''$1''' to:",
'protect-locked-access' => "Nie masz uprawnień do zmiany poziomu zabezpieczenia strony. Obecne ustawienia dla strony '''$1''' to:",
-'protect-cascadeon' => 'Ta strona jest zabezpieczona przed edycją, ponieważ jest używana przez {{PLURAL:$1|następującą stronę, która została zabezpieczona|następujące strony, które zostały zabezpieczone}} z włączoną opcją dziedziczenia. Możesz zmienić poziom zabezpieczenia strony, ale nie wpłynie to na dziedziczenie zabezpieczenia.',
+'protect-cascadeon' => 'Ta strona jest zabezpieczona przed edycją, ponieważ jest używana przez {{PLURAL:$1|następującą stronę, która została zabezpieczona|następujące strony, które zostały zabezpieczone}} z włączoną opcją dziedziczenia. Możesz zmienić stopień zabezpieczenia strony, ale nie wpłynie to na dziedziczenie zabezpieczenia.',
'protect-default' => 'Dostęp mają wszyscy użytkownicy',
'protect-fallback' => 'Wymaga uprawnień „$1”',
-'protect-level-autoconfirmed' => 'Blokuj nowych i niezarejestrowanych użytkowników',
+'protect-level-autoconfirmed' => 'Dozwolone dla wszystkich poza nowymi i niezalogowanymi użytkownikami',
'protect-level-sysop' => 'Dozwolone tylko dla administratorów',
'protect-summary-cascade' => 'dziedziczenie',
'protect-expiring' => 'wygasa $1 (UTC)',
'protect-edit-reasonlist' => 'Edytuj listę przyczyn zabezpieczenia',
'protect-expiry-options' => '1 godzina:1 hour,1 dzień:1 day,1 tydzień:1 week,2 tygodnie:2 weeks,1 miesiąc:1 month,3 miesiące:3 months,6 miesięcy:6 months,1 rok:1 year,na zawsze:infinite',
'restriction-type' => 'Ograniczenia',
-'restriction-level' => 'Poziom',
+'restriction-level' => 'Stopień',
'minimum-size' => 'Minimalny rozmiar',
'maximum-size' => 'Maksymalny rozmiar',
'pagesize' => '(bajtów)',
# Restriction levels
'restriction-level-sysop' => 'całkowite zabezpieczenie',
'restriction-level-autoconfirmed' => 'częściowe zabezpieczenie',
-'restriction-level-all' => 'dowolny poziom',
+'restriction-level-all' => 'dowolny stopień',
# Undelete
'undelete' => 'Odtwórz usuniętą stronę',
'tooltip-pt-login' => 'Zachęcamy do zalogowania się, choć nie jest to obowiązkowe.',
'tooltip-pt-anonlogin' => 'Zachęcamy do zalogowania się, choć nie jest to obowiązkowe',
'tooltip-pt-logout' => 'Wyloguj',
-'tooltip-ca-talk' => 'Dyskusja o zawartości tej strony.',
+'tooltip-ca-talk' => 'Dyskusja o zawartości tej strony',
'tooltip-ca-edit' => 'Możesz edytować tę stronę. Przed zapisaniem zmian użyj przycisku podgląd.',
'tooltip-ca-addsection' => 'Dodaj nowy wątek.',
'tooltip-ca-viewsource' => 'Ta strona jest zabezpieczona. Możesz zobaczyć tekst źródłowy.',
'tog-watchdefault' => "Gionté le pàgine e j'archivi che i modìfico mi a la lista dle ròbe ch'i ten-o sot-euj",
'tog-watchmoves' => "Gionté le pàgine e j'archivi che i tramudo a lòn che im ten-o sot-euj",
'tog-watchdeletion' => "Gionté le pàgine e j'archivi che i scancelo via a la lista ëd lòn che im ten-o sot-euj",
-'tog-minordefault' => 'Marché tute le modìfice coma cite coma predefinission',
+'tog-minordefault' => 'Marché tute le modìfiche coma cite coma predefinission',
'tog-previewontop' => 'Smon-e la preuva dzora al quàder ëd modìfica dël test e nen sota',
-'tog-previewonfirst' => 'Smon na preuva la prima vira che as fa na modìfica',
+'tog-previewonfirst' => 'Smon-e na preuva la prima vira che as fa na modìfica',
'tog-nocache' => 'Disabilité la memòria local ëd le pàgine dël navigador',
-'tog-enotifwatchlistpages' => "Mandeme un mëssagi an pòsta eletrònica quand a-i son dle modìfiche a le pàgine ch'im ten-o sot euj",
-'tog-enotifusertalkpages' => 'Mand-me un messagi ëd pòsta eletrònica quand a-i son dle modìfiche a mia pàgina dle ciaciarade',
+'tog-enotifwatchlistpages' => "Mandeme un mëssagi an pòsta eletrònica quand a-i son dle modìfiche a le pàgine ch'im ten-o sot-euj",
+'tog-enotifusertalkpages' => 'Mandeme un mëssagi ëd pòsta eletrònica quand a-i son dle modìfiche a mia pàgina dle ciaciarade',
'tog-enotifminoredits' => "Mandeme un mëssagi an pòsta eletrònica bele che për le modìfiche cite dle pàgine o dj'archivi",
-'tog-enotifrevealaddr' => 'Lassa che a së s-ciàira mia adrëssa ëd pòsta eletrònica ant ij messagi ëd notìfica',
-'tog-shownumberswatching' => "Smon ël nùmer d'utent che as ten-o la pàgina sot euj",
+'tog-enotifrevealaddr' => 'Lassé che a së s-ciàira mia adrëssa ëd pòsta eletrònica ant ij mëssagi ëd notìfica',
+'tog-shownumberswatching' => "Smon-e ël nùmer d'utent che as ten-o la pàgina sot-euj",
'tog-oldsig' => 'Firma esistenta:',
-'tog-fancysig' => "Trata la firma com test wiki (sensa n'anliura automàtica)",
+'tog-fancysig' => "Traté la firma com dël test wiki (sensa n'anliura automàtica)",
'tog-externaleditor' => "Dovré coma stàndard n'editor estern (mach për espert, a-i é dabzògn d'ampostassion speciaj dzora a sò ordinator. [//www.mediawiki.org/wiki/Manual:External_editors Për savèjne ëd pi.])",
'tog-externaldiff' => "Dovré për stàndard un programa comparator estern (mach për espert, a-i é dabzògn d'ampostassion speciaj ansima a sò ordinator [//www.mediawiki.org/wiki/Manual:External_editors Për savèjne ëd pi.])",
'tog-showjumplinks' => 'Dovré j\'anliure d\'acessibilità dla sòrt "Va a"',
'tog-showhiddencats' => 'Smon le categorìe stërmà',
'tog-noconvertlink' => "Disativé la conversion dij tìtoj ant j'anliure",
'tog-norollbackdiff' => "Fa nen vëdde le diferense apress d'avèj ripristinà",
+'tog-useeditwarning' => 'Avisme quand che i lasso na pàgina ëd modìfiche con modìfiche nen salvà',
'underline-always' => 'Sempe',
'underline-never' => 'Mai',
'content-failed-to-parse' => "Faliment ëd l'anàlisi dël contnù ëd $2 për ël model $1: $3",
'invalid-content-data' => 'Dat dël contnù pa bon',
'content-not-allowed-here' => "Ël contnù «$1» a l'é nen autorisà an sla pàgina [[$2]]",
+'editwarning-warning' => "Lassé sta pàgina-sì a peul fé an manera che it perde tute le modìfiche ch'it l'has fàit.
+S'it ses logà, it peule disabilité st'avis-sì ant la session \"{{int:prefs-editing}}\" dij tò gust.",
# Content models
'content-model-wikitext' => 'test wiki',
'tog-showhiddencats' => 'Exibir categorias ocultas',
'tog-noconvertlink' => 'Desabilitar conversão de títulos de links',
'tog-norollbackdiff' => 'Omitir diferenças depois de desfazer edições em bloco',
+'tog-useeditwarning' => 'Avisar-me quando eu deixar uma janela de edição sem ter salvo as alterações',
'underline-always' => 'Sempre',
'underline-never' => 'Nunca',
'content-failed-to-parse' => 'Falha ao analisar o conteúdo $2 para o modelo $1: $3',
'invalid-content-data' => 'Dados de conteúdo inválidos',
'content-not-allowed-here' => 'Conteúdo do tipo "$1" não é permitido na página [[$2]]',
+'editwarning-warning' => 'Abandonar esta página pode fazer com que você perca todas as alterações que fez.
+Se você estiver autenticado, você pode desabilitar este aviso na seção "{{int:prefs-editing}}" de suas preferências.',
# Content models
'content-model-wikitext' => 'wikitexto',
'content-not-allowed-here' => 'Error message indicating that the desired content model is not supported in given localtion.
* $1 - the human readable name of the content model: {{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}}
* $2 - the title of the page in question',
+'editwarning-warning' => "{{doc-important|Do ''not'' use <nowiki>{{int:prefs-editing}}</nowiki> for \"Editing\". It is forbidden in this message, see [[mwr:68405]].}}
+
+but you can see the text of that button here: {{msg-mw|Prefs-editing}}",
# Content models
'content-model-wikitext' => 'Name for the wikitext content model, used when decribing what type of content a page contains.
In this sentence, "their indexes" refers to "Google\'s indexes".
Shown on [[Special:Search]] when the internal search is disabled.',
+'search-error' => 'Shown when an error has occurred when performing a search
+* $1 is the localized error that was returned',
# Preferences page
'preferences' => 'Title of the [[Special:Preferences]] page.
{{Identical|Search}}',
'resultsperpage' => "Option on the 'Search options' tab of [[Special:Preferences]]",
'stub-threshold' => 'Used in [[Special:Preferences]], tab "Misc".',
-'stub-threshold-disabled' => 'Used in [[Special:Preferences]].',
+'stub-threshold-disabled' => 'Used in [[Special:Preferences]].
+{{Identical|Disabled}}',
'recentchangesdays' => 'Used in [[Special:Preferences]], tab "Recent changes".',
'recentchangesdays-max' => 'Shown as hint in [[Special:Preferences]], tab "Recent changes"',
'recentchangescount' => 'Used in [[Special:Preferences]], tab "Recent changes".',
'nocontribs' => 'Optional parameter: $1 is the user name',
'uctop' => 'This message is used in [[Special:Contributions]]. It is used to show that a particular edit was the last made to a page. Example: 09:57, 11 February 2008 (hist) (diff) Pagename (edit summary) (top)',
'month' => 'Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for a dropdown box to select a specific month to view the edits made in that month, and the earlier months. See also {{msg-mw|year}}.',
-'year' => 'Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for a inputbox to select a specific year to view the edits made in that year, and the earlier years. See also {{msg-mw|month}}.',
+'year' => 'Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for an input box to select a specific year to view the edits made in that year, and the earlier years.
+
+See also:
+* {{msg-mw|month}}',
'sp-contributions-newbies' => 'Text of radio button on special page [[Special:Contributions]].',
'sp-contributions-newbies-sub' => "Note at the top of the page of results for a search on [[Special:Contributions]] where 'Show contributions for new accounts only' has been selected.",
* stub threshold (appearance tab)
{{Identical|Other}}',
+'htmlform-no' => 'Used in form, such as with radio buttons, for generic yes / no questions.
+{{Identical|No}}',
+'htmlform-yes' => 'Used in form, such as with radio buttons, for generic yes / no questions.
+{{Identical|Yes}}',
# SQLite database support
'sqlite-has-fts' => 'Shown on [[Special:Version]].
'tog-showhiddencats' => 'Arată categoriile ascunse',
'tog-noconvertlink' => 'Dezactivează conversia titlurilor',
'tog-norollbackdiff' => 'Nu arăta diferența după efectuarea unei reveniri',
+'tog-useeditwarning' => 'Avertizează-mă când părăsesc o pagină fără a salva modificările',
'underline-always' => 'Întotdeauna',
'underline-never' => 'Niciodată',
'content-failed-to-parse' => 'Nu s-a putut analiza conținutul de tip $2 pentru modelul $1: $3',
'invalid-content-data' => 'Date de conținut invalide',
'content-not-allowed-here' => 'Conținutul de tip „$1” nu este permis pe pagina [[$2]]',
+'editwarning-warning' => 'Părăsind această pagină, există riscul pierderii modificărilor efectuate.
+Dacă sunteți autentificat, puteți dezactiva această avertizare în secțiunea „Modificare” a preferințelor dumneavoastră.',
# Content models
'content-model-wikitext' => 'wikitext',
'powersearch-togglenone' => 'Nimic',
'search-external' => 'Căutare externă',
'searchdisabled' => '<p>Ne pare rău! Căutarea după text a fost dezactivată temporar, din motive de performanță. Între timp puteți folosi căutarea prin Google mai jos, însă aceasta poate să dea rezultate învechite.</p>',
+'search-error' => 'A apărut o eroare în timpul căutării: $1',
# Preferences page
'preferences' => 'Preferințe',
'tog-showhiddencats' => 'Fa vedè le categorije scunnute',
'tog-noconvertlink' => "Disabbilite 'a conversione d'u titele de collegamende",
'tog-norollbackdiff' => "Non sce penzanne a le differenze apprisse l'esecuzione de 'nu rollback",
+'tog-useeditwarning' => "Avvisave quanne jie lasse 'na pàgene cangiate senze ca agghie sarvate le cangiaminde",
'underline-always' => 'Sembre',
'underline-never' => 'Maje',
'content-failed-to-parse' => "L'analise d'u condenute $2 pu modelle $1 ha fallite: $3",
'invalid-content-data' => "Condenute d'u date invalide",
'content-not-allowed-here' => '"$1" condenute non g\'è permesse sus \'a pàgene [[$2]]',
+'editwarning-warning' => 'Assenne da sta pàgene tu puè perdè tutte le date ca è cangiate.
+Ce tu è trasute, tu puè disabbilità st\'avvertimende jndr\'à sezione "Cangiaminde..." de le preferenze tune.',
# Content models
'content-model-wikitext' => 'Uicchiteste',
'searchdisabled' => "'A ricerche sus a {{SITENAME}} ha state disabbilitete.
Tu puè cercà ausanne Google.
Però fa attenzione purcè l'indice lore sus a {{SITENAME}} ponne condenè pàggene ca non ge sonde aggiornate.",
+'search-error' => "S'ha verificate 'n'errore mendre ste cercave: $1",
# Preferences page
'preferences' => 'Me piece accussì',
'htmlform-submit' => 'Conferme',
'htmlform-reset' => 'Annulle le cangiaminde',
'htmlform-selectorother-other' => 'Otre',
+'htmlform-no' => 'None',
+'htmlform-yes' => 'Sìne',
# SQLite database support
'sqlite-has-fts' => "$1 cu 'u supporte d'a ricerche full-text",
'tog-showhiddencats' => 'Показывать скрытые категории',
'tog-noconvertlink' => 'Отключить ссылку на преобразование заголовка',
'tog-norollbackdiff' => 'Не показывать разницу версий после выполнения отката',
+'tog-useeditwarning' => 'Предупреждать, когда я покидаю страницу с несохранёнными изменениями',
'underline-always' => 'Всегда',
'underline-never' => 'Никогда',
'content-failed-to-parse' => 'Содержимое $2 не соответствует типу $1: $3.',
'invalid-content-data' => 'Недопустимые данные',
'content-not-allowed-here' => 'Содержимое "$1" недопустимо на странице [[$2]]',
+'editwarning-warning' => 'Переход на другую страницу может привести к потере сделанных вами изменений.
+Если вы зарегистрированы в системе, то вы можете отключить это предупреждение в разделе «{{int:prefs-editing}}» ваших настроек.',
# Content models
'content-model-wikitext' => 'вики-текст',
'powersearch-togglenone' => 'Ничего',
'search-external' => 'Внешний поиск',
'searchdisabled' => 'Извините, но встроенный полнотекстовый поиск выключен. Вы можете воспользоваться поиском по сайту через поисковые системы общего назначения, однако имейте в виду, что копия сайта в их кэше может быть несколько устаревшей.',
+'search-error' => 'Произошла ошибка при поиске: $1',
# Preferences page
'preferences' => 'Настройки',
'tog-showhiddencats' => 'Visa dolda kategorier',
'tog-noconvertlink' => 'Stäng av konvertering av sidtitlar',
'tog-norollbackdiff' => 'Visa inte diff efter tillbakarullning',
+'tog-useeditwarning' => 'Varna mig om jag lämnar en redigeringssida där jag gjort ändringar men inte sparat.',
'underline-always' => 'Alltid',
'underline-never' => 'Aldrig',
'content-failed-to-parse' => 'Det gick inte att parsa $2 innehåll för $1 modell: $3',
'invalid-content-data' => 'Ogiltig innehållsdata',
'content-not-allowed-here' => 'innehåll av "$1" är inte tillåtet på sidan [[$2]]',
+'editwarning-warning' => 'Om du lämnar den här sidan kommer du att förlora alla ändringar du har gjort.
+Om du är inloggad kan du slå av den här varningen under "{{int:prefs-editing}}" i dina inställningar.',
# Content models
'content-model-wikitext' => 'wikitext',
'searchdisabled' => 'Sökfunktionen på {{SITENAME}} är avstängd.
Du kan istället göra sökningar med hjälp av Google.
Notera dock att deras indexering av {{SITENAME}} kan vara något föråldrad.',
+'search-error' => 'Ett fel uppstod under sökningen: $1',
# Preferences page
'preferences' => 'Inställningar',
'htmlform-submit' => 'Spara',
'htmlform-reset' => 'Ogör ändringar',
'htmlform-selectorother-other' => 'Andra',
+'htmlform-no' => 'Nej',
+'htmlform-yes' => 'Ja',
# SQLite database support
'sqlite-has-fts' => '$1 med stöd för fulltextsökning',
'tog-diffonly' => 'மாற்றங்களை ஒப்பிடும் போது அதன் கீழ் பக்க உள்ளடக்கத்தைக் காட்டாதே',
'tog-showhiddencats' => 'மறைக்கப்பட்ட பகுப்புகளைக் காட்டு',
'tog-norollbackdiff' => 'முன்பிருந்த நிலைக்குக் கொண்டுவந்தபின் வித்தியாசங்களை விட்டுவிடவும் (காட்டத்தேவையில்லை).',
+'tog-useeditwarning' => 'தொகுத்துக் கொண்டிருக்கும் பக்கத்தை சேமிக்காமல் வெளியேறினால் எனக்கு எச்சரிக்கை செய்',
'underline-always' => 'எப்பொழுதும்',
'underline-never' => 'எப்போதுமில்லை',
'undeletedrevisions' => '{{PLURAL:$1|1 திருத்தம் மீட்கப்பட்டது|$1 திருத்தங்கள் மீட்கப்பட்டன}}',
'undeletedrevisions-files' => '{{PLURAL:$1|1 திருத்தம்|$1 திருத்தங்கள்}} மற்றும் {{PLURAL:$2|1 கோப்பு|$2 கோப்புகள்}} மீட்கப்பட்டன.',
'undeletedfiles' => '{{PLURAL:$1|ஒரு கோப்பு மீட்டெடுக்கப்பட்டது|$1 கோப்புகள் மீட்டெடுக்கப்பட்டன}}',
-'cannotundelete' => 'நà¯\80à®\95à¯\8dà®\95à®®à¯\8d தà¯\8bலà¯\8dவி;',
+'cannotundelete' => 'à®®à¯\80ளà¯\8dவிதà¯\8dதலà¯\8d தà¯\8bலà¯\8dவி: $1',
'undeletedpage' => "'''$1 மீட்கப்பட்டது'''
அண்மைய நீக்கல்களுக்கும் மீட்புக்களுக்கும் [[Special:Log/delete|நீக்கல் பதிவைப்]] பார்க்கவும்.",
'tog-showhiddencats' => 'แสดงหมวดหมู่ที่ซ่อนอยู่',
'tog-noconvertlink' => 'ปิดใช้งานการแปลงชื่อเรื่องของลิงก์',
'tog-norollbackdiff' => 'ไม่แสดงการเปลี่ยนแปลงหลังดำเนินการย้อนกลับฉุกเฉิน',
+'tog-useeditwarning' => 'เตือนฉัน เมื่อฉันกำลังจะออกจากหน้าแก้ไขโดยมีข้อมูลที่ยังไม่ได้บันทึก',
'underline-always' => 'เสมอ',
'underline-never' => 'ไม่เคย',
'edit-already-exists' => 'ไม่สามารถสร้างหน้าใหม่ได้
เพราะมีหน้านี้แล้ว',
'defaultmessagetext' => 'ข้อความสารโดยปริยาย',
+'editwarning-warning' => 'การออกจากหน้านี้อาจทำให้ความเปลี่ยนแปลงที่คุณกระทำสูญหาย
+ถ้าคุณล็อกอินแล้ว คุณสามารถปิดคำเตือนนี้ได้ที่ส่วน "การแก้ไข" ในการตั้งค่าของคุณ',
# Content models
'content-model-wikitext' => 'ข้อความวิกิ',
'tog-showhiddencats' => 'Показувати приховані категорії',
'tog-noconvertlink' => 'Вимкнути конвертацію назви посилання',
'tog-norollbackdiff' => 'Не показувати різницю версій після виконання відкоту',
+'tog-useeditwarning' => 'Попереджати мене, якщо я залишаю сторінку редагування з незбереженими змінами',
'underline-always' => 'Завжди',
'underline-never' => 'Ніколи',
'content-failed-to-parse' => 'Не вдалось проаналізувати $2 як тип $1: $3',
'invalid-content-data' => 'Неприпустимі дані',
'content-not-allowed-here' => 'Вміст «$1» недопустимий на сторінці [[$2]]',
+'editwarning-warning' => 'Перехід на іншу сторінку призведе до втрати ваших змін.
+Якщо ви ввійшли до системи, то ви можете відключити це попередження в розділі «{{int:prefs-editing}}» ваших налаштувань.',
# Content models
'content-model-wikitext' => 'вікітекст',
'tog-showhiddencats' => 'Hiển thị thể loại ẩn',
'tog-noconvertlink' => 'Tắt liên kết chuyển đổi tựa đề',
'tog-norollbackdiff' => 'Không so sánh sau khi lùi sửa',
+'tog-useeditwarning' => 'Cảnh báo khi tôi thoát trang sửa đổi mà chưa lưu trang',
'underline-always' => 'Luôn luôn',
'underline-never' => 'Không bao giờ',
'content-failed-to-parse' => 'Thất bại phân tích nội dung $2 cho mô hình $1: $3',
'invalid-content-data' => 'Dữ liệu nội dung không hợp lệ',
'content-not-allowed-here' => 'Không cho phép đưa nội dung “$1” vào trang [[$2]]',
+'editwarning-warning' => 'Rời khỏi trang này sẽ khiến bạn mất các sửa đổi đã thực hiện.
+Nếu đã đăng nhập, bạn có thể tắt cảnh báo này tại mục “{{int:prefs-editing}}” trong tùy chọn cá nhân.',
# Content models
'content-model-wikitext' => 'mã wiki',
'powersearch-togglenone' => 'Không',
'search-external' => 'Tìm kiếm từ bên ngoài',
'searchdisabled' => 'Chức năng tìm kiếm tại {{SITENAME}} đã bị tắt. Bạn có tìm kiếm bằng Google trong thời gian này. Chú ý rằng các chỉ mục từ {{SITENAME}} của chúng có thể đã lỗi thời.',
+'search-error' => 'Đã xuất hiện lỗi khi tìm kiếm: $1',
# Preferences page
'preferences' => 'Tùy chọn',
'tog-shownumberswatching' => '显示监视用户数',
'tog-oldsig' => '当前签名:',
'tog-fancysig' => '将签名以wiki文本对待(不产生自动链接)',
-'tog-externaleditor' => '默认使用外部编辑器(供高级用户使用,需要在您的计算机上作出一些特别设置。[//www.mediawiki.org/wiki/Manual:External_editors 更多信息。])',
-'tog-externaldiff' => '默认使用外部差异分析(供高级用户使用,需要在您的计算机上作出一些特别设置。[//www.mediawiki.org/wiki/Manual:External_editors 更多信息。])',
+'tog-externaleditor' => '默认使用外部编辑器(供高级用户使用,需要在您的计算机上做特别设置。[//www.mediawiki.org/wiki/Manual:External_editors 更多信息。])',
+'tog-externaldiff' => '默认使用外部版本差异工具(供高级用户使用,需要在您的计算机上做特别设置。[//www.mediawiki.org/wiki/Manual:External_editors 更多信息。])',
'tog-showjumplinks' => '启用“跳转到”访问链接',
'tog-uselivepreview' => '使用实时预览(需要JavaScript)(实验功能)',
'tog-forceeditsummary' => '未输入编辑摘要时提醒我',
'tog-watchlisthideanons' => '在监视列表中隐藏匿名用户',
'tog-watchlisthidepatrolled' => '在监视列表中隐藏已巡查的编辑',
'tog-ccmeonemails' => '把我给其他用户发送的电子邮件的副本发送给我',
-'tog-diffonly' => '比较差异时不显示页面内容',
+'tog-diffonly' => '比较版本差异时不显示页面内容',
'tog-showhiddencats' => '显示隐藏分类',
'tog-noconvertlink' => '停用链接文字转换',
'tog-norollbackdiff' => '执行回退后不显示差异',
+'tog-useeditwarning' => '如在更改未保存时离开页面,则发出警告',
'underline-always' => '总是使用',
'underline-never' => '从不使用',
-'underline-default' => '浏览器默认设置',
+'underline-default' => '皮肤或浏览器默认设置',
# Font style option in Special:Preferences
'editfont-style' => '编辑区字体样式:',
'protect_change' => '更改',
'protectthispage' => '保护本页',
'unprotect' => '更改保护',
-'unprotectthispage' => '更改本页面的保护',
+'unprotectthispage' => '更改本页面保护设置',
'newpage' => '新页面',
'talkpage' => '讨论本页',
'talkpagelinktext' => '讨论',
'templatepage' => '查看模板页面',
'viewhelppage' => '查看帮助页面',
'categorypage' => '查看分类页面',
-'viewtalkpage' => '查看讨论页面',
+'viewtalkpage' => '查看讨论',
'otherlanguages' => '其他语言',
'redirectedfrom' => '(重定向自$1)',
'redirectpagesub' => '重定向页',
'jumpto' => '跳转至:',
'jumptonavigation' => '导航',
'jumptosearch' => '搜索',
-'view-pool-error' => '抱歉,服务器超负荷运转。
+'view-pool-error' => '抱歉,服务器目前正超负荷运转。
过多用户正尝试查看本页面。
-请在再次尝试访问本页面之前稍等片刻。
+请稍等片刻后再次尝试访问本页面。
$1',
'pool-timeout' => '等待锁超时',
'mainpage' => '首页',
'mainpage-description' => '首页',
'policy-url' => 'Project:方针',
-'portal' => '社å\8cºä¸\93页',
-'portal-url' => 'Project:社å\8cºä¸\93页',
+'portal' => '社å\8cºä¸»页',
+'portal-url' => 'Project:社å\8cºä¸»页',
'privacy' => '隐私政策',
'privacypage' => 'Project:隐私权政策',
'youhavenewmessages' => '你有$1($2)。',
'newmessageslink' => '新信息',
'newmessagesdifflink' => '最后更改',
-'youhavenewmessagesfromusers' => 'ä½ æ\9c\89æ\9d¥è\87ª{{PLURAL:$3|å\85¶ä»\96用户|$3个用户}}的$1($2)。',
+'youhavenewmessagesfromusers' => 'ä½ æ\9c\89æ\9d¥è\87ª{{PLURAL:$3|å\8f¦ä¸\80ä½\8d用户|$3个用户}}的$1($2)。',
'youhavenewmessagesmanyusers' => '你有来自多个用户的$1($2)。',
'newmessageslinkplural' => '{{PLURAL:$1|一条新信息|新信息}}',
'newmessagesdifflinkplural' => '最后{{PLURAL:$1|更改}}',
# Short words for each namespace, by default used in the namespace tab in monobook
'nstab-main' => '页面',
-'nstab-user' => '用户页面',
+'nstab-user' => '用户页',
'nstab-media' => '媒体页面',
'nstab-special' => '特殊页面',
'nstab-project' => '项目页面',
'remembermypassword' => '在该浏览器保存我的登录状态(最长$1日)',
'securelogin-stick-https' => '登录后继续使用HTTPS连接',
'yourdomainname' => '您的域名:',
-'password-change-forbidden' => '你不能在本wiki更改密码。',
-'externaldberror' => '这可能是由于验证数据库错误或您被禁止更新您的外部账号。',
+'password-change-forbidden' => '您不能在本wiki上更改密码。',
+'externaldberror' => '验证数据库出错或您被禁止更新您的外部账号。',
'login' => '登录',
'nav-login-createaccount' => '登录/创建账户',
'loginprompt' => '你必须启用Cookies才能登录{{SITENAME}}。',
'content-failed-to-parse' => '未能将 $2 内容转换为 $1:$3',
'invalid-content-data' => '无效的内容数据',
'content-not-allowed-here' => '[[$2]]页面上不允许“$1”内容',
+'editwarning-warning' => '离开这个页面会令您遗失之前的所有更改。若您已经登入,您可在您参数设置的“{{int:prefs-editing}}”节中关闭此警告。',
# Content models
'content-model-wikitext' => 'wiki语法',
'searchdisabled' => '{{SITENAME}}的搜索已被禁用。您可以暂时使用Google进行搜索,须注意他们索引的{{SITENAME}}内容可能会过时。',
# Preferences page
-'preferences' => '参数设置',
+'preferences' => '设置',
'mypreferences' => '系统设置',
'prefs-edits' => '编辑数:',
'prefsnologin' => '未登录',
'viewdeletedpage' => '查看被删页面',
'undeletepagetext' => '以下{{PLURAL:$1|页面|$1个页面}}已被删除,但依然在归档中并可以被恢复。归档可能会被定时清理。',
'undelete-fieldset-title' => '恢复版本',
-'undeleteextrahelp' => "恢复整个编辑历史时,请清除所有复选框后点击'''''{{int:undeletebtn}}'''''。恢复特定版本时,请选择相应版本前的复选框后点击'''''{{int:undeletebtn}}'''''。",
+'undeleteextrahelp' => "要恢复该页面的整个历史记录时,不选中任何复选框直接点击'''''{{int:undeletebtn}}'''''。要选择性地恢复部分版本时,请选中相应版本前的复选框再点击'''''{{int:undeletebtn}}'''''。",
'undeleterevisions' => '$1版本存档',
'undeletehistory' => '如果您恢复了该页面,所有版本都会被恢复到修订历史中。
如果本页删除后有一个同名的新页面建立,被恢复的版本将会出现在先前的历史中。',
'tog-showhiddencats' => '顯示隱藏分類',
'tog-noconvertlink' => '不轉換連結標題',
'tog-norollbackdiff' => '進行回退後略過差異比較',
+'tog-useeditwarning' => '當我在更改未儲存時離開頁面時警告我',
'underline-always' => '總是使用',
'underline-never' => '從不使用',
'content-failed-to-parse' => '未能轉換$2 內容成為$1:$3',
'invalid-content-data' => '內容資料無效',
'content-not-allowed-here' => '[[$2]]頁面上不允許「$1」內容',
+'editwarning-warning' => '離開這個頁面會令您所作的更改遺失。
+您可在您參數設置的「{{int:prefs-editing}}」一節中關閉此警告。',
# Content models
'content-model-wikitext' => 'wiki語法',
'powersearch-togglenone' => '無',
'search-external' => '外部搜索',
'searchdisabled' => '{{SITENAME}}由於性能方面的原因,全文搜索已被暫時停用。您可以暫時透過Google搜索。請留意他們的索引可能會過時。',
+'search-error' => '搜尋時發生錯誤:$1',
# Preferences page
'preferences' => '偏好設定',
'htmlform-submit' => '提交',
'htmlform-reset' => '撤銷更改',
'htmlform-selectorother-other' => '其他',
+'htmlform-no' => '否',
+'htmlform-yes' => '是',
# SQLite database support
'sqlite-has-fts' => '帶全文搜尋的版本$1',
--- /dev/null
+<?php
+/**
+ * Copy all jobs from one job queue system to another.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Copy all jobs from one job queue system to another.
+ * This uses an ad-hoc $wgJobQueueMigrationConfig setting,
+ * which is a map of queue system names to JobQueue::factory() parameters.
+ * The parameters should not have wiki or type settings and thus partial.
+ *
+ * @ingroup Maintenance
+ */
+class CopyJobQueue extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Copy jobs from one queue system to another.";
+ $this->addOption( 'src', 'Key to $wgJobQueueMigrationConfig for source', true, true );
+ $this->addOption( 'dst', 'Key to $wgJobQueueMigrationConfig for destination', true, true );
+ $this->addOption( 'type', 'Types of jobs to copy (use "all" for all)', true, true );
+ $this->setBatchSize( 500 );
+ }
+
+ public function execute() {
+ global $wgJobQueueMigrationConfig;
+
+ $srcKey = $this->getOption( 'src' );
+ $dstKey = $this->getOption( 'dst' );
+
+ if ( !isset( $wgJobQueueMigrationConfig[$srcKey] ) ) {
+ $this->error( "\$wgJobQueueMigrationConfig not set for '$srcKey'.", 1 );
+ } elseif ( !isset( $wgJobQueueMigrationConfig[$dstKey] ) ) {
+ $this->error( "\$wgJobQueueMigrationConfig not set for '$dstKey'.", 1 );
+ }
+
+ $types = ( $this->getOption( 'type' ) === 'all' )
+ ? JobQueueGroup::singleton()->getQueueTypes()
+ : array( $this->getOption( 'type' ) );
+
+ foreach ( $types as $type ) {
+ $baseConfig = array( 'type' => $type, 'wiki' => wfWikiID() );
+ $src = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$srcKey] );
+ $dst = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$dstKey] );
+
+ list( $total, $totalOK ) = $this->copyJobs( $src, $dst, $src->getAllQueuedJobs() );
+ $this->output( "Copied $totalOK/$total queued $type jobs.\n" );
+
+ list( $total, $totalOK ) = $this->copyJobs( $src, $dst, $src->getAllDelayedJobs() );
+ $this->output( "Copied $totalOK/$total delayed $type jobs.\n" );
+ }
+ }
+
+ protected function copyJobs( JobQueue $src, JobQueue $dst, $jobs ) {
+ $total = 0;
+ $totalOK = 0;
+ $batch = array();
+ foreach ( $jobs as $job ) {
+ ++$total;
+ $batch[] = $job;
+ if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( $dst->push( $batch ) ) {
+ $totalOK += count( $batch );
+ }
+ $batch = array();
+ $dst->waitForBackups();
+ }
+ }
+ if ( count( $batch ) ) {
+ if ( $dst->push( $batch ) ) {
+ $totalOK += count( $batch );
+ }
+ $dst->waitForBackups();
+ }
+ return array( $total, $totalOK );
+ }
+}
+
+$maintClass = 'CopyJobQueue';
+require_once( RUN_MAINTENANCE_IF_MAIN );
{
- "--title": "MediaWiki Code Documentation",
+ "--title": "MediaWiki core - Documentation",
+ "--footer": "Documentation for MediaWiki core. Generated on {DATE} by {JSDUCK} {VERSION}.",
"--categories": "./categories.json",
"--meta-tags": "./MetaTags.rb",
"--warnings": ["-no_doc"],
"../../resources/mediawiki.api",
"../../resources/jquery/jquery.localize.js"
]
-}
\ No newline at end of file
+}
'tog-shownumberswatching',
'tog-oldsig',
'tog-fancysig',
- 'tog-externaleditor',
- 'tog-externaldiff',
'tog-showjumplinks',
'tog-uselivepreview',
'tog-forceeditsummary',
'tog-showhiddencats',
'tog-noconvertlink',
'tog-norollbackdiff',
+ 'tog-useeditwarning',
),
'underline' => array(
'underline-always',
'content-failed-to-parse',
'invalid-content-data',
'content-not-allowed-here',
+ 'editwarning-warning',
),
'contentmodels' => array(
'content-model-wikitext',
'search-external',
'searchdisabled',
'googlesearch',
+ 'search-error',
),
'opensearch' => array(
'opensearch-desc',
'htmlform-submit',
'htmlform-reset',
'htmlform-selectorother-other',
+ 'htmlform-no',
+ 'htmlform-yes',
),
'sqlite' => array(
'sqlite-has-fts',
-#!/usr/bin/env sh
-jsduck --config=$(cd $(dirname $0)/..; pwd)/maintenance/jsduck/config.json && echo 'JSDuck execution finished.'
+#!/usr/bin/env bash
+
+JSDUCK_MWVERSION=master
+if [[ "$1" == "--version" && "$2" != "" ]]
+then
+ JSDUCK_MWVERSION="$2"
+elif [[ "$*" != "" ]]
+then
+ echo "Usage $0: [--version <mediawiki version>]"
+ echo
+ exit 1
+fi
+
+jsduck \
+--config=$(cd $(dirname $0)/..; pwd)/maintenance/jsduck/config.json \
+--footer="Documentation for MediaWiki core ($JSDUCK_MWVERSION). Generated on {DATE} by {JSDUCK} {VERSION}." \
+&& echo 'JSDuck execution finished.'
$group->ack( $job ); // done
}
- if ( !$status ) {
+ if ( $status === false ) {
$this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" );
} else {
$this->runJobsLog( $job->toString() . " t=$timeMs good" );
'mediawiki.action.view.rightClickEdit' => array(
'scripts' => 'resources/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
),
+ 'mediawiki.action.edit.editWarning' => array(
+ 'scripts' => 'resources/mediawiki.action/mediawiki.action.edit.editWarning.js',
+ 'messages' => array(
+ 'editwarning-warning',
+ ),
+ ),
// Alias for backwards compatibility
'mediawiki.action.watch.ajax' => array(
'dependencies' => 'mediawiki.page.watch.ajax'
--- /dev/null
+/*
+ * Javascript for module editWarning
+ */
+( function ( mw, $ ) {
+ $( document ).ready( function () {
+ // Check if EditWarning is enabled and if we need it
+ if ( $( '#wpTextbox1' ).length === 0 ) {
+ return true;
+ }
+ // Get the original values of some form elements
+ $( '#wpTextbox1, #wpSummary' ).each( function () {
+ $( this ).data( 'origtext', $( this ).val() );
+ });
+ var savedWindowOnBeforeUnload;
+ $( window )
+ .on( 'beforeunload.editwarning', function () {
+ var retval;
+
+ // Check if the current values of some form elements are the same as
+ // the original values
+ if (
+ mw.config.get( 'wgAction' ) === 'submit' ||
+ $( '#wpTextbox1' ).data( 'origtext' ) !== $( '#wpTextbox1' ).val() ||
+ $( '#wpSummary' ).data( 'origtext' ) !== $( '#wpSummary' ).val()
+ ) {
+ // Return our message
+ retval = mw.msg( 'editwarning-warning' );
+ }
+
+ // Unset the onbeforeunload handler so we don't break page caching in Firefox
+ savedWindowOnBeforeUnload = window.onbeforeunload;
+ window.onbeforeunload = null;
+ if ( retval !== undefined ) {
+ // ...but if the user chooses not to leave the page, we need to rebind it
+ setTimeout( function () {
+ window.onbeforeunload = savedWindowOnBeforeUnload;
+ }, 1 );
+ return retval;
+ }
+ } )
+ .on( 'pageshow.editwarning', function () {
+ // Re-add onbeforeunload handler
+ if ( !window.onbeforeunload ) {
+ window.onbeforeunload = savedWindowOnBeforeUnload;
+ }
+ } );
+
+ // Add form submission handler
+ $( '#editform' ).submit( function () {
+ // Unbind our handlers
+ $( window ).off( '.editwarning' );
+ } );
+ } );
+
+}( mediaWiki, jQuery ) );
+
uri = this,
matches = parser[ options.strictMode ? 'strict' : 'loose' ].exec( str );
$.each( properties, function ( i, property ) {
- uri[ property ] = matches[ i+1 ];
+ uri[ property ] = matches[ i + 1 ];
} );
// uri.query starts out as the query string; we will parse it into key-val pairs then make
q = {};
// using replace to iterate over a string
if ( uri.query ) {
- uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
+ uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ( $0, $1, $2, $3 ) {
var k, v;
if ( $1 ) {
k = Uri.decode( $1 );
$( '<colgroup>' ).css( 'width', 350 ).appendTo( $table );
- entryTypeText = function( entryType ) {
+ entryTypeText = function ( entryType ) {
switch ( entryType ) {
case 'log':
return 'Log';
* See: http://www.mediawiki.org/wiki/Extension:UploadWizard/MessageParser for docs
*
* @author neilk@wikimedia.org
+* @author mflaschen@wikimedia.org
*/
( function ( mw, $ ) {
var oldParser,
magic : {
'SITENAME' : mw.config.get( 'wgSiteName' )
},
+ // This is a whitelist based on, but simpler than, Sanitizer.php.
+ // Self-closing tags are not currently supported.
+ allowedHtmlElements : [
+ 'b',
+ 'i'
+ ],
+ // Key tag name, value allowed attributes for that tag.
+ // See Sanitizer::setupAttributeWhitelist
+ allowedHtmlCommonAttributes : [
+ // HTML
+ 'id',
+ 'class',
+ 'style',
+ 'lang',
+ 'dir',
+ 'title',
+
+ // WAI-ARIA
+ 'role'
+ ],
+
+ // Attributes allowed for specific elements.
+ // Key is element name in lower case
+ // Value is array of allowed attributes for that element
+ allowedHtmlAttributesByElement : {},
messages : mw.messages,
language : mw.language,
};
+ /**
+ * Wrapper around jQuery append that converts all non-objects to TextNode so append will not
+ * convert what it detects as an htmlString to an element.
+ *
+ * Object elements of children (jQuery, HTMLElement, TextNode, etc.) will be left as is.
+ *
+ * @param {jQuery} $parent Parent node wrapped by jQuery
+ * @param {Object|string|Array} children What to append, with the same possible types as jQuery
+ * @return {jQuery} $parent
+ */
+ function appendWithoutParsing( $parent, children ) {
+ var i, len;
+
+ if ( !$.isArray( children ) ) {
+ children = [children];
+ }
+
+ for ( i = 0, len = children.length; i < len; i++ ) {
+ if ( typeof children[i] !== 'object' ) {
+ children[i] = document.createTextNode( children[i] );
+ }
+ }
+
+ return $parent.append( children );
+ }
+
+ /**
+ * Decodes the main HTML entities, those encoded by mw.html.escape.
+ *
+ * @param {string} encode Encoded string
+ * @return {string} String with those entities decoded
+ */
+ function decodePrimaryHtmlEntities( encoded ) {
+ return encoded
+ .replace( /'/g, '\'' )
+ .replace( /"/g, '"' )
+ .replace( /</g, '<' )
+ .replace( />/g, '>' )
+ .replace( /&/g, '&' );
+ }
+
/**
* Given parser options, return a function that parses a key and replacements, returning jQuery object
* @param {Object} parser options
try {
return parser.parse( key, argsArray );
} catch ( e ) {
- return $( '<span>' ).append( key + ': ' + e.message );
+ return $( '<span>' ).text( key + ': ' + e.message );
}
};
}
*/
return function () {
var $target = this.empty();
- // TODO: Simply $target.append( failableParserFn( arguments ).contents() )
- // or Simply $target.append( failableParserFn( arguments ) )
+ // TODO: Simply appendWithoutParsing( $target, failableParserFn( arguments ).contents() )
+ // or Simply appendWithoutParsing( $target, failableParserFn( arguments ) )
$.each( failableParserFn( arguments ).contents(), function ( i, node ) {
- $target.append( node );
+ appendWithoutParsing( $target, node );
} );
return $target;
};
* @return {Mixed} abstract syntax tree
*/
wikiTextToAst: function ( input ) {
- var pos,
+ var pos, settings = this.settings, concat = Array.prototype.concat,
regularLiteral, regularLiteralWithoutBar, regularLiteralWithoutSpace, regularLiteralWithSquareBrackets,
- backslash, anyCharacter, escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
- whitespace, dollar, digits,
- openExtlink, closeExtlink, wikilinkPage, wikilinkContents, openLink, closeLink, templateName, pipe, colon,
+ doubleQuote, singleQuote, backslash, anyCharacter, asciiAlphabetLiteral,
+ escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
+ whitespace, dollar, digits, htmlDoubleQuoteAttributeValue, htmlSingleQuoteAttributeValue,
+ htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag,
+ openExtlink, closeExtlink, wikilinkPage, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
templateContents, openTemplate, closeTemplate,
nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result;
return result;
};
}
+
+ /**
+ * Makes a regex parser, given a RegExp object.
+ * The regex being passed in should start with a ^ to anchor it to the start
+ * of the string.
+ *
+ * @param {RegExp} regex anchored regex
+ * @return {Function} function to parse input based on the regex
+ */
function makeRegexParser( regex ) {
return function () {
var matches = input.substr( pos ).match( regex );
// but some debuggers can't tell you exactly where they come from. Also the mutually
// recursive functions seem not to work in all browsers then. (Tested IE6-7, Opera, Safari, FF)
// This may be because, to save code, memoization was removed
- regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
+
+ regularLiteral = makeRegexParser( /^[^{}\[\]$<\\]/ );
regularLiteralWithoutBar = makeRegexParser(/^[^{}\[\]$\\|]/);
regularLiteralWithoutSpace = makeRegexParser(/^[^{}\[\]$\s]/);
regularLiteralWithSquareBrackets = makeRegexParser( /^[^{}$\\]/ );
+
backslash = makeStringParser( '\\' );
+ doubleQuote = makeStringParser( '"' );
+ singleQuote = makeStringParser( '\'' );
anyCharacter = makeRegexParser( /^./ );
+
+ openHtmlStartTag = makeStringParser( '<' );
+ optionalForwardSlash = makeRegexParser( /^\/?/ );
+ openHtmlEndTag = makeStringParser( '</' );
+ htmlAttributeEquals = makeRegexParser( /^\s*=\s*/ );
+ closeHtmlTag = makeRegexParser( /^\s*>/ );
+
function escapedLiteral() {
var result = sequence( [
backslash,
return result === null ? null : result.join('');
}
+ asciiAlphabetLiteral = makeRegexParser( /[A-Za-z]+/ );
+ htmlDoubleQuoteAttributeValue = makeRegexParser( /^[^"]*/ );
+ htmlSingleQuoteAttributeValue = makeRegexParser( /^[^']*/ );
+
whitespace = makeRegexParser( /^\s+/ );
dollar = makeStringParser( '$' );
digits = makeRegexParser( /^\d+/ );
}
openExtlink = makeStringParser( '[' );
closeExtlink = makeStringParser( ']' );
- // this extlink MUST have inner text, e.g. [foo] not allowed; [foo bar] is allowed
+ // this extlink MUST have inner contents, e.g. [foo] not allowed; [foo bar] [foo <i>bar</i>], etc. are allowed
function extlink() {
var result, parsedResult;
result = null;
openExtlink,
nonWhitespaceExpression,
whitespace,
- expression,
+ nOrMore( 1, expression ),
closeExtlink
] );
if ( parsedResult !== null ) {
- result = [ 'LINK', parsedResult[1], parsedResult[3] ];
+ result = [ 'EXTLINK', parsedResult[1] ];
+ // TODO (mattflaschen, 2013-03-22): Clean this up if possible.
+ // It's avoiding CONCAT for single nodes, so they at least doesn't get the htmlEmitter span.
+ if ( parsedResult[3].length === 1 ) {
+ result.push( parsedResult[3][0] );
+ } else {
+ result.push( ['CONCAT'].concat( parsedResult[3] ) );
+ }
}
return result;
}
if ( result === null ) {
return null;
}
- return [ 'LINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ];
+ return [ 'EXTLINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ];
}
- openLink = makeStringParser( '[[' );
- closeLink = makeStringParser( ']]' );
+ openWikilink = makeStringParser( '[[' );
+ closeWikilink = makeStringParser( ']]' );
pipe = makeStringParser( '|' );
function template() {
wikilinkPage // unpiped link
] );
- function link() {
+ function wikilink() {
var result, parsedResult, parsedLinkContents;
result = null;
parsedResult = sequence( [
- openLink,
+ openWikilink,
wikilinkContents,
- closeLink
+ closeWikilink
] );
if ( parsedResult !== null ) {
parsedLinkContents = parsedResult[1];
- result = [ 'WLINK' ].concat( parsedLinkContents );
+ result = [ 'WIKILINK' ].concat( parsedLinkContents );
+ }
+ return result;
+ }
+
+ // TODO: Support data- if appropriate
+ function doubleQuotedHtmlAttributeValue() {
+ var parsedResult = sequence( [
+ doubleQuote,
+ htmlDoubleQuoteAttributeValue,
+ doubleQuote
+ ] );
+ return parsedResult === null ? null : parsedResult[1];
+ }
+
+ function singleQuotedHtmlAttributeValue() {
+ var parsedResult = sequence( [
+ singleQuote,
+ htmlSingleQuoteAttributeValue,
+ singleQuote
+ ] );
+ return parsedResult === null ? null : parsedResult[1];
+ }
+
+ function htmlAttribute() {
+ var parsedResult = sequence( [
+ whitespace,
+ asciiAlphabetLiteral,
+ htmlAttributeEquals,
+ choice( [
+ doubleQuotedHtmlAttributeValue,
+ singleQuotedHtmlAttributeValue
+ ] )
+ ] );
+ return parsedResult === null ? null : [parsedResult[1], parsedResult[3]];
+ }
+
+ /**
+ * Checks if HTML is allowed
+ *
+ * @param {string} startTagName HTML start tag name
+ * @param {string} endTagName HTML start tag name
+ * @param {Object} attributes array of consecutive key value pairs,
+ * with index 2 * n being a name and 2 * n + 1 the associated value
+ * @return {boolean} true if this is HTML is allowed, false otherwise
+ */
+ function isAllowedHtml( startTagName, endTagName, attributes ) {
+ var i, len, attributeName;
+
+ startTagName = startTagName.toLowerCase();
+ endTagName = endTagName.toLowerCase();
+ if ( startTagName !== endTagName || $.inArray( startTagName, settings.allowedHtmlElements ) === -1 ) {
+ return false;
+ }
+
+ for ( i = 0, len = attributes.length; i < len; i += 2 ) {
+ attributeName = attributes[i];
+ if ( $.inArray( attributeName, settings.allowedHtmlCommonAttributes ) === -1 &&
+ $.inArray( attributeName, settings.allowedHtmlAttributesByElement[startTagName] || [] ) === -1 ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function htmlAttributes() {
+ var parsedResult = nOrMore( 0, htmlAttribute )();
+ // Un-nest attributes array due to structure of jQueryMsg operations (see emit).
+ return concat.apply( ['HTMLATTRIBUTES'], parsedResult );
+ }
+
+ // Subset of allowed HTML markup.
+ // Most elements and many attributes allowed on the server are not supported yet.
+ function html() {
+ var result = null, parsedOpenTagResult, parsedHtmlContents,
+ parsedCloseTagResult, wrappedAttributes, attributes,
+ startTagName, endTagName, startOpenTagPos, startCloseTagPos,
+ endOpenTagPos, endCloseTagPos;
+
+ // Break into three sequence calls. That should allow accurate reconstruction of the original HTML, and requiring an exact tag name match.
+ // 1. open through closeHtmlTag
+ // 2. expression
+ // 3. openHtmlEnd through close
+ // This will allow recording the positions to reconstruct if HTML is to be treated as text.
+
+ startOpenTagPos = pos;
+ parsedOpenTagResult = sequence( [
+ openHtmlStartTag,
+ asciiAlphabetLiteral,
+ htmlAttributes,
+ optionalForwardSlash,
+ closeHtmlTag
+ ] );
+
+ if ( parsedOpenTagResult === null ) {
+ return null;
}
+
+ endOpenTagPos = pos;
+ startTagName = parsedOpenTagResult[1];
+
+ parsedHtmlContents = nOrMore( 0, expression )();
+
+ startCloseTagPos = pos;
+ parsedCloseTagResult = sequence( [
+ openHtmlEndTag,
+ asciiAlphabetLiteral,
+ closeHtmlTag
+ ] );
+
+ if ( parsedCloseTagResult === null ) {
+ // Closing tag failed. Return the start tag and contents.
+ return [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ].concat( parsedHtmlContents );
+ }
+
+ endCloseTagPos = pos;
+ endTagName = parsedCloseTagResult[1];
+ wrappedAttributes = parsedOpenTagResult[2];
+ attributes = wrappedAttributes.slice( 1 );
+ if ( isAllowedHtml( startTagName, endTagName, attributes) ) {
+ result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ].concat( parsedHtmlContents );
+ } else {
+ // HTML is not allowed, so contents will remain how
+ // it was, while HTML markup at this level will be
+ // treated as text
+ // E.g. assuming script tags are not allowed:
+ //
+ // <script>[[Foo|bar]]</script>
+ //
+ // results in '<script>' and '</script>'
+ // (not treated as an HTML tag), surrounding a fully
+ // parsed HTML link.
+ //
+ // Concatenate everything from the tag, flattening the contents.
+ result = [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ].concat( parsedHtmlContents, input.substring( startCloseTagPos, endCloseTagPos ) );
+ }
+
return result;
}
+
templateName = transform(
// see $wgLegalTitleChars
// not allowing : due to the need to catch "PLURAL:$1"
closeTemplate = makeStringParser('}}');
nonWhitespaceExpression = choice( [
template,
- link,
+ wikilink,
extLinkParam,
extlink,
replacement,
] );
paramExpression = choice( [
template,
- link,
+ wikilink,
extLinkParam,
extlink,
replacement,
expression = choice( [
template,
- link,
+ wikilink,
extLinkParam,
extlink,
replacement,
+ html,
literal
] );
$.each( nodes, function ( i, node ) {
if ( node instanceof jQuery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) {
$.each( node.contents(), function ( j, childNode ) {
- $span.append( childNode );
+ appendWithoutParsing( $span, childNode );
} );
} else {
// Let jQuery append nodes, arrays of nodes and jQuery objects
// other things (strings, numbers, ..) are appended as text nodes (not as HTML strings)
- $span.append( $.type( node ) === 'object' ? node : document.createTextNode( node ) );
+ appendWithoutParsing( $span, node );
}
} );
return $span;
*
* @param nodes
*/
- wlink: function ( nodes ) {
+ wikilink: function ( nodes ) {
var page, anchor, url;
page = nodes[0];
} ).text( anchor );
},
+ /**
+ * Converts array of HTML element key value pairs to object
+ *
+ * @param {Array} nodes array of consecutive key value pairs, with index 2 * n being a name and 2 * n + 1 the associated value
+ * @return {Object} object mapping attribute name to attribute value
+ */
+ htmlattributes: function ( nodes ) {
+ var i, len, mapping = {};
+ for ( i = 0, len = nodes.length; i < len; i += 2 ) {
+ mapping[nodes[i]] = decodePrimaryHtmlEntities( nodes[i + 1] );
+ }
+ return mapping;
+ },
+
+ /**
+ * Handles an (already-validated) HTML element.
+ *
+ * @param {Array} nodes nodes to process when creating element
+ * @return {jQuery|Array} jQuery node for valid HTML or array for disallowed element
+ */
+ htmlelement: function ( nodes ) {
+ var tagName, attributes, contents, $element;
+
+ tagName = nodes.shift();
+ attributes = nodes.shift();
+ contents = nodes;
+ $element = $( document.createElement( tagName ) ).attr( attributes );
+ return appendWithoutParsing( $element, contents );
+ },
+
/**
* Transform parsed structure into external link
* If the href is a jQuery object, treat it as "enclosing" the link text.
* @param {Array} of two elements, {jQuery|Function|String} and {String}
* @return {jQuery}
*/
- link: function ( nodes ) {
+ extlink: function ( nodes ) {
var $el,
arg = nodes[0],
contents = nodes[1];
$el.attr( 'href', arg.toString() );
}
}
- $el.append( contents );
- return $el;
+ return appendWithoutParsing( $el, contents );
},
/**
- * This is basically use a combination of replace + link (link with parameter
+ * This is basically use a combination of replace + external link (link with parameter
* as url), but we don't want to run the regular replace here-on: inserting a
* url as href-attribute of a link will automatically escape it already, so
* we don't want replace to (manually) escape it as well.
* @param {Array} of one element, integer, n >= 0
* @return {String} replacement
*/
- linkparam: function ( nodes, replacements ) {
+ extlinkparam: function ( nodes, replacements ) {
var replacement,
index = parseInt( nodes[0], 10 );
if ( index < replacements.length) {
} else {
replacement = '$' + ( index + 1 );
}
- return this.link( [ replacement, nodes[1] ] );
+ return this.extlink( [ replacement, nodes[1] ] );
},
/**
// Caching is somewhat problematic, because we do need different message functions for different maps, so
// we'd have to cache the parser as a member of this.map, which sounds a bit ugly.
// Do not use mw.jqueryMsg unless required
- if ( this.format === 'plain' || !/\{\{|\[/.test(this.map.get( this.key ) ) ) {
+ if ( this.format === 'plain' || !/\{\{|[\[<>]/.test(this.map.get( this.key ) ) ) {
// Fall back to mw.msg's simple parser
return oldParser.apply( this );
}
/**
* @param {string} [cssText=cssBuffer] If called without cssText,
* the internal buffer will be inserted instead.
- * @param {Function} callback
+ * @param {Function} [callback]
*/
function addEmbeddedCSS( cssText, callback ) {
var $style, styleEl;
* expiration time is reset each time the ID is queried, so in most cases this ID will
* persist until the browser's cookies are cleared or the user doesn't visit for 1 year.
*
- * @return String: User name or random session ID
+ * @return {string} User name or random session ID
*/
- this.id = function() {
+ this.id = function () {
var id,
name = user.getName();
if ( name ) {
*
* See also:
* - https://www.mediawiki.org/wiki/Compatibility#Browser
+ * - http://jquerymobile.com/gbs/
* - http://jquery.com/browser-support/
*/
return !(
// Internet Explorer < 6
( ua.indexOf( 'MSIE' ) !== -1 && parseFloat( ua.split( 'MSIE' )[1] ) < 6 ) ||
- // Firefox < 4
- ( ua.indexOf( 'Firefox/' ) !== -1 && parseFloat( ua.split( 'Firefox/' )[1] ) < 4 )
+ // Firefox < 3
+ ( ua.indexOf( 'Firefox/' ) !== -1 && parseFloat( ua.split( 'Firefox/' )[1] ) < 3 ) ||
+ // BlackBerry < 6
+ ua.match( /BlackBerry[^\/]*\/[1-5]\./ ) ||
+ // Open WebOS < 1.5
+ ua.match( /webOS\/1\.[0-4]/ ) ||
+ // Anything PlayStation based.
+ ua.match( /PlayStation/i ) ||
+ // Any Symbian based browsers
+ ua.match( /SymbianOS|Series60/ ) ||
+ // Any NetFront based browser
+ ua.match( /NetFront/ ) ||
+ // Opera Mini < 7
+ ua.match( /Opera Mini\/[0-6]\./ )
);
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.1"
+ width="12"
+ height="13.837458"
+ id="svg2108">
+ <metadata
+ id="metadata68">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient4356">
+ <stop
+ id="stop4358"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop4360"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4344">
+ <stop
+ id="stop4346"
+ style="stop-color:#727e0a;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop4348"
+ style="stop-color:#5b6508;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4338">
+ <stop
+ id="stop4340"
+ style="stop-color:#e9b15e;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop4342"
+ style="stop-color:#966416;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4163">
+ <stop
+ id="stop4165"
+ style="stop-color:#3b74bc;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop4167"
+ style="stop-color:#2d5990;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3824">
+ <stop
+ id="stop3826"
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop3828"
+ style="stop-color:#c9c9c9;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3816">
+ <stop
+ id="stop3818"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop3820"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3800">
+ <stop
+ id="stop3802"
+ style="stop-color:#f4d9b1;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop3804"
+ style="stop-color:#df9725;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <radialGradient
+ cx="29.344931"
+ cy="17.064077"
+ r="9.1620579"
+ fx="29.344931"
+ fy="17.064077"
+ id="radialGradient3806"
+ xlink:href="#linearGradient3800"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient3822"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient3830"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="28.089741"
+ cy="27.203083"
+ r="13.56536"
+ fx="28.089741"
+ fy="27.203083"
+ id="radialGradient4169"
+ xlink:href="#linearGradient4163"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.297564,0,0,0.884831,-8.358505,4.940469)" />
+ <radialGradient
+ cx="29.344931"
+ cy="17.064077"
+ r="9.1620579"
+ fx="29.344931"
+ fy="17.064077"
+ id="radialGradient4171"
+ xlink:href="#linearGradient3800"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient4175"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0.707108,0)" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient4179"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient4326"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-12.41789,-7)" />
+ <radialGradient
+ cx="29.344931"
+ cy="17.064077"
+ r="9.1620579"
+ fx="29.344931"
+ fy="17.064077"
+ id="radialGradient4328"
+ xlink:href="#linearGradient4338"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient4330"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient4332"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-13.125,-7)" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient4336"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="16.214741"
+ cy="19.836468"
+ r="13.56536"
+ fx="16.214741"
+ fy="19.836468"
+ id="radialGradient4350"
+ xlink:href="#linearGradient4344"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.681917,0,8.233773)" />
+ <linearGradient
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ id="linearGradient4362"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,6.231716,-2.651466)" />
+ <linearGradient
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ id="linearGradient4366"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,55.1096,-3.945209)" />
+ <linearGradient
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ id="linearGradient4372"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,-7.07212,-9.82492)" />
+ <linearGradient
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ id="linearGradient4374"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,41.80576,-11.11866)" />
+ <linearGradient
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ id="linearGradient1366"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,41.80576,-11.11866)" />
+ <linearGradient
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ id="linearGradient1369"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,-7.07212,-9.82492)" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient1372"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-12.41789,-7)" />
+ <radialGradient
+ cx="16.214741"
+ cy="19.836468"
+ r="13.56536"
+ fx="16.214741"
+ fy="19.836468"
+ id="radialGradient1381"
+ xlink:href="#linearGradient4344"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.681917,0,8.233773)" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient2243"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="28.089741"
+ cy="27.203083"
+ r="13.56536"
+ fx="28.089741"
+ fy="27.203083"
+ id="radialGradient2245"
+ xlink:href="#linearGradient4163"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.297564,0,0,0.884831,-8.358505,4.940469)" />
+ <linearGradient
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486"
+ id="linearGradient2247"
+ xlink:href="#linearGradient3824"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="31.112698"
+ cy="19.008621"
+ r="8.6620579"
+ fx="31.112698"
+ fy="19.008621"
+ id="radialGradient2249"
+ xlink:href="#linearGradient3816"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="29.344931"
+ cy="17.064077"
+ r="9.1620579"
+ fx="29.344931"
+ fy="17.064077"
+ id="radialGradient2251"
+ xlink:href="#linearGradient3800"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)" />
+ <linearGradient
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ id="linearGradient2253"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,6.231716,-2.651466)" />
+ <linearGradient
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ id="linearGradient2255"
+ xlink:href="#linearGradient4356"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,55.1096,-3.945209)" />
+ </defs>
+ <g
+ transform="translate(-5.0000039,-32.070112)"
+ id="layer1"
+ style="display:inline" />
+ <g
+ transform="translate(-5.0000039,-32.070112)"
+ id="layer2"
+ style="display:inline">
+ <g
+ transform="matrix(0.39012793,0,0,0.39012793,-1.0891578,28.22979)"
+ id="g2230">
+ <path
+ d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324115,0 8.6620579,8.6620579 0 1 1 17.324115,0 z"
+ transform="matrix(1.77551,0,0,0.959183,-24.25322,18.77153)"
+ id="path4306"
+ style="color:#000000;fill:url(#radialGradient2243);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 25.986174,41.636039 10.606602,0 c 3.005204,0 5.980484,-1.101932 7.071067,-4.242641 1.035639,-2.982476 0.176777,-8.662058 -6.540737,-13.258252 l -12.551146,0 c -6.717514,4.24264 -7.556991,10.044831 -6.010407,13.435028 1.575595,3.45379 4.24264,4.065865 7.424621,4.065865 z"
+ id="path4308"
+ style="color:#000000;fill:url(#radialGradient2245);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 26.693281,25.726136 c 3.18198,2.828427 4.596194,13.081476 4.596194,13.081476 0,0 1.414213,-10.253048 3.889087,-13.258252 l -8.485281,0.176776 z"
+ id="path4310"
+ style="color:#000000;fill:url(#linearGradient2247);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 28.972721,26.786797 c 0,0 -2.151323,1.660335 -1.965991,3.660533 -2.041226,-1.800794 -2.099873,-5.251524 -2.099873,-5.251524 l 4.065864,1.590991 z"
+ id="path4312"
+ style="color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 25.914862,40.593933 10.493447,-0.0221 c 2.639723,0 5.253161,-0.967919 6.211112,-3.726667 0.909689,-2.61976 -0.09472,-7.608614 -5.995279,-11.645837 L 25.099417,24.956264 c -5.900557,3.726667 -7.04262,8.823219 -5.662029,12.044182 1.380592,3.220963 3.395211,3.57139 6.477474,3.593487 z"
+ id="path4314"
+ style="opacity:0.21518986;color:#000000;fill:none;stroke:#ffffff;stroke-width:0.99999976px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 33.410795,26.786797 c 0,0 2.151323,1.660335 1.965991,3.660533 2.041226,-1.800794 2.099873,-5.251524 2.099873,-5.251524 l -4.065864,1.590991 z"
+ id="path4316"
+ style="color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324115,0 8.6620579,8.6620579 0 1 1 17.324115,0 z"
+ transform="translate(-0.125,3.5)"
+ id="path4318"
+ style="color:#000000;fill:url(#radialGradient2249);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324115,0 8.6620579,8.6620579 0 1 1 17.324115,0 z"
+ id="path4320"
+ style="color:#000000;fill:url(#radialGradient2251);fill-opacity:1;fill-rule:evenodd;stroke:#c17d11;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324115,0 8.6620579,8.6620579 0 1 1 17.324115,0 z"
+ transform="matrix(0.877095,0,0,0.877095,3.823927,2.336267)"
+ id="path4322"
+ style="opacity:0.19620254;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14012825px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 21.85179,40.775197 c -1.247607,-0.544969 -1.805994,-1.858277 -1.805994,-1.858277 0.841281,-4.069136 3.719925,-7.046216 3.719925,-7.046216 0,0 -2.279321,6.411514 -1.913931,8.904493 z"
+ id="path4354"
+ style="opacity:0.22784807;color:#000000;fill:url(#linearGradient2253);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="m 40.757497,39.916846 c 1.231251,-0.580978 1.80438,-2.002321 1.80438,-2.002321 -0.95912,-4.042983 -3.976149,-6.842821 -3.976149,-6.842821 0,0 2.464593,6.342602 2.171769,8.845142 z"
+ id="path4364"
+ style="opacity:0.22784807;color:#000000;fill:url(#linearGradient2255);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+</svg>
#pt-login {
/* @embed */
background: url(images/user-icon.png) left top no-repeat;
+ /* SVG support using a transparent gradient to guarantee cross-browser
+ * compatibility (browsers able to understand gradient syntax support also SVG) */
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/user-icon.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/user-icon.svg);
padding-left: 15px !important;
text-transform: none;
}
--- /dev/null
+<?php
+class CollationTest extends MediaWikiLangTestCase {
+ protected function setUp() {
+ parent::setUp();
+ if ( !extension_loaded( 'intl' ) ) {
+ $this->markTestSkipped( 'These tests require intl extension' );
+ }
+ }
+
+ /**
+ * Test to make sure, that if you
+ * have "X" and "XY", the binary
+ * sortkey also has "X" being a
+ * prefix of "XY". Our collation
+ * code makes this assumption.
+ *
+ * @param $lang String Language code for collator
+ * @param $base String Base string
+ * @param $extended String String containing base as a prefix.
+ *
+ * @dataProvider prefixDataProvider
+ */
+ function testIsPrefix( $lang, $base, $extended ) {
+ $cp = Collator::create( $lang );
+ $cp->setStrength( Collator::PRIMARY );
+ $baseBin = $cp->getSortKey( $base );
+ // Remove sortkey terminator
+ $baseBin = rtrim( $baseBin, "\0" );
+ $extendedBin = $cp->getSortKey( $extended );
+ $this->assertStringStartsWith( $baseBin, $extendedBin, "$base is not a prefix of $extended" );
+ }
+
+ function prefixDataProvider() {
+ return array(
+ array( 'en', 'A', 'AA' ),
+ array( 'en', 'A', 'AAA' ),
+ array( 'en', 'Д', 'ДЂ' ),
+ array( 'en', 'Д', 'ДA' ),
+ // 'Ʒ' should expand to 'Z ' (note space).
+ array( 'fi', 'Z', 'Ʒ' ),
+ // 'Þ' should expand to 'th'
+ array( 'sv', 't', 'Þ' ),
+ // Javanese is a limited use alphabet, so should have 3 bytes
+ // per character, so do some tests with it.
+ array( 'en', 'ꦲ', 'ꦲꦤ' ),
+ array( 'en', 'ꦲ', 'ꦲД' ),
+ array( 'en', 'A', 'Aꦲ' ),
+ );
+ }
+ /**
+ * Opposite of testIsPrefix
+ *
+ * @dataProvider notPrefixDataProvider
+ */
+ function testNotIsPrefix( $lang, $base, $extended ) {
+ $cp = Collator::create( $lang );
+ $cp->setStrength( Collator::PRIMARY );
+ $baseBin = $cp->getSortKey( $base );
+ // Remove sortkey terminator
+ $baseBin = rtrim( $baseBin, "\0" );
+ $extendedBin = $cp->getSortKey( $extended );
+ $this->assertStringStartsNotWith( $baseBin, $extendedBin, "$base is a prefix of $extended" );
+ }
+
+ function notPrefixDataProvider() {
+ return array(
+ array( 'en', 'A', 'B' ),
+ array( 'en', 'AC', 'ABC' ),
+ array( 'en', 'Z', 'Ʒ' ),
+ array( 'en', 'A', 'ꦲ' ),
+ );
+ }
+
+ /**
+ * Test correct first letter is fetched.
+ *
+ * @param $collation String Collation name (aka uca-en)
+ * @param $string String String to get first letter of
+ * @param $firstLetter String Expected first letter.
+ *
+ * @dataProvider firstLetterProvider
+ */
+ function testGetFirstLetter( $collation, $string, $firstLetter ) {
+ $col = Collation::factory( $collation );
+ $this->assertEquals( $firstLetter, $col->getFirstLetter( $string ) );
+ }
+ function firstLetterProvider() {
+ return array(
+ array( 'uppercase', 'Abc', 'A' ),
+ array( 'uppercase', 'abc', 'A' ),
+ array( 'identity', 'abc', 'a' ),
+ array( 'uca-en', 'abc', 'A' ),
+ array( 'uca-en', ' ', ' ' ),
+ array( 'uca-en', 'Êveryone', 'E' ),
+ array( 'uca-vi', 'Êveryone', 'Ê' ),
+ // Make sure thorn is not a first letter.
+ array( 'uca-sv', 'The', 'T' ),
+ array( 'uca-sv', 'Å', 'Å' ),
+ array( 'uca-hu', 'dzsdo', 'Dzs' ),
+ array( 'uca-hu', 'dzdso', 'Dz' ),
+ array( 'uca-hu', 'CSD', 'Cs' ),
+ array( 'uca-root', 'CSD', 'C' ),
+ array( 'uca-fi', 'Ǥ', 'G' ),
+ array( 'uca-fi', 'Ŧ', 'T' ),
+ array( 'uca-fi', 'Ʒ', 'Z' ),
+ array( 'uca-fi', 'Ŋ', 'N' ),
+ );
+ }
+}
$queue->flushCaches();
$this->assertEquals( 2, $queue->getSize(), "Queue size is correct ($desc)" );
$this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
+ $jobs = iterator_to_array( $queue->getAllQueuedJobs() );
+ $this->assertEquals( 2, count( $jobs ), "Queue iterator size is correct ($desc)" );
+
$job1 = $queue->pop();
$this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
}
if [ `id -u` -ne 0 ]; then
- echo '*** ERROR' Must be root to run
+ echo '*** ERROR: Must be root to run'
exit 1
fi
}
/**
- * bug 33454. sprintfDate should always use UTC.
+ * sprintfDate should always use UTC when no zone is given.
* @dataProvider provideSprintfDateSamples
*/
- function testSprintfDateTZ( $format, $ts, $expected, $msg ) {
+ function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
$oldTZ = date_default_timezone_get();
$res = date_default_timezone_set( 'Asia/Seoul' );
if ( !$res ) {
date_default_timezone_set( $oldTZ );
}
+ /**
+ * sprintfDate should use passed timezone
+ * @dataProvider provideSprintfDateSamples
+ */
+ function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
+ $tz = new DateTimeZone( 'Asia/Seoul' );
+ if ( !$tz ) {
+ $this->markTestSkipped( "Error getting Timezone" );
+ }
+
+ $this->assertEquals(
+ $expected,
+ $this->getLang()->sprintfDate( $format, $ts, $tz ),
+ "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
+ );
+ }
+
public static function provideSprintfDateSamples() {
return array(
array(
'xiY',
'20111212000000',
'1390', // note because we're testing English locale we get Latin-standard digits
+ '1390',
'Iranian calendar full year'
),
array(
'xiy',
'20111212000000',
'90',
+ '90',
'Iranian calendar short year'
),
array(
'o',
'20120101235000',
'2011',
+ '2011',
'ISO 8601 (week) year'
),
array(
'W',
'20120101235000',
'52',
+ '52',
'Week number'
),
array(
'W',
'20120102235000',
'1',
+ '1',
'Week number'
),
array(
'o-\\WW-N',
'20091231235000',
'2009-W53-4',
+ '2009-W53-4',
'leap week'
),
// What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
'Y',
'20120102090705',
'2012',
+ '2012',
'Full year'
),
array(
'y',
'20120102090705',
'12',
+ '12',
'2 digit year'
),
array(
'L',
'20120102090705',
'1',
+ '1',
'Leap year'
),
array(
'n',
'20120102090705',
'1',
+ '1',
'Month index, not zero pad'
),
array(
'N',
'20120102090705',
'01',
+ '01',
'Month index. Zero pad'
),
array(
'M',
'20120102090705',
'Jan',
+ 'Jan',
'Month abbrev'
),
array(
'F',
'20120102090705',
'January',
+ 'January',
'Full month'
),
array(
'xg',
'20120102090705',
'January',
+ 'January',
'Genitive month name (same in EN)'
),
array(
'j',
'20120102090705',
'2',
+ '2',
'Day of month (not zero pad)'
),
array(
'd',
'20120102090705',
'02',
+ '02',
'Day of month (zero-pad)'
),
array(
'z',
'20120102090705',
'1',
+ '1',
'Day of year (zero-indexed)'
),
array(
'D',
'20120102090705',
'Mon',
+ 'Mon',
'Day of week (abbrev)'
),
array(
'l',
'20120102090705',
'Monday',
+ 'Monday',
'Full day of week'
),
array(
'N',
'20120101090705',
'7',
+ '7',
'Day of week (Mon=1, Sun=7)'
),
array(
'w',
'20120101090705',
'0',
+ '0',
'Day of week (Sun=0, Sat=6)'
),
array(
'N',
'20120102090705',
'1',
+ '1',
'Day of week'
),
array(
'a',
'20120102090705',
'am',
+ 'am',
'am vs pm'
),
array(
'A',
'20120102120000',
'PM',
+ 'PM',
'AM vs PM'
),
array(
'a',
'20120102000000',
'am',
+ 'am',
'AM vs PM'
),
array(
'g',
'20120102090705',
'9',
+ '9',
'12 hour, not Zero'
),
array(
'h',
'20120102090705',
'09',
+ '09',
'12 hour, zero padded'
),
array(
'G',
'20120102090705',
'9',
+ '9',
'24 hour, not zero'
),
array(
'H',
'20120102090705',
'09',
+ '09',
'24 hour, zero'
),
array(
'H',
'20120102110705',
'11',
+ '11',
'24 hour, zero'
),
array(
'i',
'20120102090705',
'07',
+ '07',
'Minutes'
),
array(
's',
'20120102090705',
'05',
+ '05',
'seconds'
),
array(
'U',
'20120102090705',
'1325495225',
+ '1325462825',
'unix time'
),
array(
't',
'20120102090705',
'31',
+ '31',
'Days in current month'
),
array(
'c',
'20120102090705',
'2012-01-02T09:07:05+00:00',
+ '2012-01-02T09:07:05+09:00',
'ISO 8601 timestamp'
),
array(
'r',
'20120102090705',
'Mon, 02 Jan 2012 09:07:05 +0000',
+ 'Mon, 02 Jan 2012 09:07:05 +0900',
'RFC 5322'
),
+ array(
+ 'e',
+ '20120102090705',
+ 'UTC',
+ 'Asia/Seoul',
+ 'Timezone identifier'
+ ),
+ array(
+ 'I',
+ '19880602090705',
+ '0',
+ '1',
+ 'DST indicator'
+ ),
+ array(
+ 'O',
+ '20120102090705',
+ '+0000',
+ '+0900',
+ 'Timezone offset'
+ ),
+ array(
+ 'P',
+ '20120102090705',
+ '+00:00',
+ '+09:00',
+ 'Timezone offset with colon'
+ ),
+ array(
+ 'T',
+ '20120102090705',
+ 'UTC',
+ 'KST',
+ 'Timezone abbreviation'
+ ),
+ array(
+ 'Z',
+ '20120102090705',
+ '0',
+ '32400',
+ 'Timezone offset in seconds'
+ ),
array(
'xmj xmF xmn xmY',
'20120102090705',
'7 Safar 2 1433',
+ '7 Safar 2 1433',
'Islamic'
),
array(
'xij xiF xin xiY',
'20120102090705',
'12 Dey 10 1390',
+ '12 Dey 10 1390',
'Iranian'
),
array(
'xjj xjF xjn xjY',
'20120102090705',
'7 Tevet 4 5772',
+ '7 Tevet 4 5772',
'Hebrew'
),
array(
'xjt',
'20120102090705',
'29',
+ '29',
'Hebrew number of days in month'
),
array(
'xjx',
'20120102090705',
'Tevet',
+ 'Tevet',
'Hebrew genitive month name (No difference in EN)'
),
array(
'xkY',
'20120102090705',
'2555',
+ '2555',
'Thai year'
),
array(
'xoY',
'20120102090705',
'101',
+ '101',
'Minguo'
),
array(
'xtY',
'20120102090705',
'平成24',
+ '平成24',
'nengo'
),
array(
'xrxkYY',
'20120102090705',
'MMDLV2012',
+ 'MMDLV2012',
'Roman numerals'
),
array(
'xhxjYY',
'20120102090705',
'ה\'תשע"ב2012',
+ 'ה\'תשע"ב2012',
'Hebrew numberals'
),
array(
'xnY',
'20120102090705',
'2012',
+ '2012',
'Raw numerals (doesn\'t mean much in EN)'
),
array(
'[[Y "(yea"\\r)]] \\"xx\\"',
'20120102090705',
'[[2012 (year)]] "x"',
+ '[[2012 (year)]] "x"',
'Various escaping'
),
( function ( mw, $ ) {
- var mwLanguageCache = {}, formatnumTests, specialCharactersPageName,
+ var mwLanguageCache = {}, formatText, formatParse, formatnumTests, specialCharactersPageName,
expectedListUsers, expectedEntrypoints;
+ // When the expected result is the same in both modes
+ function assertBothModes( assert, parserArguments, expectedResult, assertMessage ) {
+ assert.equal( formatText.apply( null, parserArguments ), expectedResult, assertMessage + ' when format is \'text\'' );
+ assert.equal( formatParse.apply( null, parserArguments ), expectedResult, assertMessage + ' when format is \'parse\'' );
+ }
+
QUnit.module( 'mediawiki.jqueryMsg', QUnit.newMwEnvironment( {
setup: function () {
this.orgMwLangauge = mw.language;
expectedListUsers = '注册<a title="Special:ListUsers" href="/wiki/Special:ListUsers">用户</a>';
expectedEntrypoints = '<a href="https://www.mediawiki.org/wiki/Manual:index.php">index.php</a>';
+
+ formatText = mw.jqueryMsg.getMessageFunction( {
+ format: 'text'
+ } );
+
+ formatParse = mw.jqueryMsg.getMessageFunction( {
+ format: 'parse'
+ } );
},
teardown: function () {
mw.language = this.orgMwLangauge;
}
QUnit.test( 'Replace', 9, function ( assert ) {
- var parser = mw.jqueryMsg.getMessageFunction();
-
mw.messages.set( 'simple', 'Foo $1 baz $2' );
- assert.equal( parser( 'simple' ), 'Foo $1 baz $2', 'Replacements with no substitutes' );
- assert.equal( parser( 'simple', 'bar' ), 'Foo bar baz $2', 'Replacements with less substitutes' );
- assert.equal( parser( 'simple', 'bar', 'quux' ), 'Foo bar baz quux', 'Replacements with all substitutes' );
+ assert.equal( formatParse( 'simple' ), 'Foo $1 baz $2', 'Replacements with no substitutes' );
+ assert.equal( formatParse( 'simple', 'bar' ), 'Foo bar baz $2', 'Replacements with less substitutes' );
+ assert.equal( formatParse( 'simple', 'bar', 'quux' ), 'Foo bar baz quux', 'Replacements with all substitutes' );
mw.messages.set( 'plain-input', '<foo foo="foo">x$1y<</foo>z' );
assert.equal(
- parser( 'plain-input', 'bar' ),
+ formatParse( 'plain-input', 'bar' ),
'<foo foo="foo">xbary&lt;</foo>z',
'Input is not considered html'
);
mw.messages.set( 'plain-replace', 'Foo $1' );
assert.equal(
- parser( 'plain-replace', '<bar bar="bar">></bar>' ),
+ formatParse( 'plain-replace', '<bar bar="bar">></bar>' ),
'Foo <bar bar="bar">&gt;</bar>',
'Replacement is not considered html'
);
mw.messages.set( 'object-replace', 'Foo $1' );
assert.equal(
- parser( 'object-replace', $( '<div class="bar">></div>' ) ),
+ formatParse( 'object-replace', $( '<div class="bar">></div>' ) ),
'Foo <div class="bar">></div>',
'jQuery objects are preserved as raw html'
);
assert.equal(
- parser( 'object-replace', $( '<div class="bar">></div>' ).get( 0 ) ),
+ formatParse( 'object-replace', $( '<div class="bar">></div>' ).get( 0 ) ),
'Foo <div class="bar">></div>',
'HTMLElement objects are preserved as raw html'
);
assert.equal(
- parser( 'object-replace', $( '<div class="bar">></div>' ).toArray() ),
+ formatParse( 'object-replace', $( '<div class="bar">></div>' ).toArray() ),
'Foo <div class="bar">></div>',
'HTMLElement[] arrays are preserved as raw html'
);
assert.equal(
- parser( 'external-link-replace', 'http://example.org/?x=y&z' ),
+ formatParse( 'external-link-replace', 'http://example.org/?x=y&z' ),
'Foo <a href="http://example.org/?x=y&z">bar</a>',
'Href is not double-escaped in wikilink function'
);
} );
QUnit.test( 'Plural', 3, function ( assert ) {
- var parser = mw.jqueryMsg.getMessageFunction();
-
- assert.equal( parser( 'plural-msg', 0 ), 'Found 0 items', 'Plural test for english with zero as count' );
- assert.equal( parser( 'plural-msg', 1 ), 'Found 1 item', 'Singular test for english' );
- assert.equal( parser( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' );
+ assert.equal( formatParse( 'plural-msg', 0 ), 'Found 0 items', 'Plural test for english with zero as count' );
+ assert.equal( formatParse( 'plural-msg', 1 ), 'Found 1 item', 'Singular test for english' );
+ assert.equal( formatParse( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' );
} );
QUnit.test( 'Gender', 11, function ( assert ) {
// TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg
// TODO: English may not be the best language for these tests. Use a language like Arabic or Russian
- var user = mw.user,
- parser = mw.jqueryMsg.getMessageFunction();
+ var user = mw.user;
user.options.set( 'gender', 'male' );
assert.equal(
- parser( 'gender-msg', 'Bob', 'male' ),
+ formatParse( 'gender-msg', 'Bob', 'male' ),
'Bob: blue',
'Masculine from string "male"'
);
assert.equal(
- parser( 'gender-msg', 'Bob', user ),
+ formatParse( 'gender-msg', 'Bob', user ),
'Bob: blue',
'Masculine from mw.user object'
);
user.options.set( 'gender', 'unknown' );
assert.equal(
- parser( 'gender-msg', 'Foo', user ),
+ formatParse( 'gender-msg', 'Foo', user ),
'Foo: green',
'Neutral from mw.user object' );
assert.equal(
- parser( 'gender-msg', 'Alice', 'female' ),
+ formatParse( 'gender-msg', 'Alice', 'female' ),
'Alice: pink',
'Feminine from string "female"' );
assert.equal(
- parser( 'gender-msg', 'User' ),
+ formatParse( 'gender-msg', 'User' ),
'User: green',
'Neutral when no parameter given' );
assert.equal(
- parser( 'gender-msg', 'User', 'unknown' ),
+ formatParse( 'gender-msg', 'User', 'unknown' ),
'User: green',
'Neutral from string "unknown"'
);
mw.messages.set( 'gender-msg-one-form', '{{GENDER:$1|User}}: $2 {{PLURAL:$2|edit|edits}}' );
assert.equal(
- parser( 'gender-msg-one-form', 'male', 10 ),
+ formatParse( 'gender-msg-one-form', 'male', 10 ),
'User: 10 edits',
'Gender neutral and plural form'
);
assert.equal(
- parser( 'gender-msg-one-form', 'female', 1 ),
+ formatParse( 'gender-msg-one-form', 'female', 1 ),
'User: 1 edit',
'Gender neutral and singular form'
);
mw.messages.set( 'gender-msg-lowercase', '{{gender:$1|he|she}} is awesome' );
assert.equal(
- parser( 'gender-msg-lowercase', 'male' ),
+ formatParse( 'gender-msg-lowercase', 'male' ),
'he is awesome',
'Gender masculine'
);
assert.equal(
- parser( 'gender-msg-lowercase', 'female' ),
+ formatParse( 'gender-msg-lowercase', 'female' ),
'she is awesome',
'Gender feminine'
);
mw.messages.set( 'gender-msg-wrong', '{{gender}} test' );
assert.equal(
- parser( 'gender-msg-wrong', 'female' ),
+ formatParse( 'gender-msg-wrong', 'female' ),
' test',
'Invalid syntax should result in {{gender}} simply being stripped away'
);
} );
QUnit.test( 'Grammar', 2, function ( assert ) {
- var parser = mw.jqueryMsg.getMessageFunction();
-
- assert.equal( parser( 'grammar-msg' ), 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'Grammar Test with sitename' );
+ assert.equal( formatParse( 'grammar-msg' ), 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'Grammar Test with sitename' );
mw.messages.set( 'grammar-msg-wrong-syntax', 'Przeszukaj {{GRAMMAR:grammar_case_xyz}}' );
- assert.equal( parser( 'grammar-msg-wrong-syntax' ), 'Przeszukaj ', 'Grammar Test with wrong grammar template syntax' );
+ assert.equal( formatParse( 'grammar-msg-wrong-syntax' ), 'Przeszukaj ', 'Grammar Test with wrong grammar template syntax' );
} );
QUnit.test( 'Match PHP parser', mw.libs.phpParserData.tests.length, function ( assert ) {
} );
QUnit.test( 'Links', 6, function ( assert ) {
- var parser = mw.jqueryMsg.getMessageFunction(),
- expectedDisambiguationsText,
+ var expectedDisambiguationsText,
expectedMultipleBars,
expectedSpecialCharacters;
*/
assert.htmlEqual(
- parser( 'jquerymsg-test-statistics-users' ),
+ formatParse( 'jquerymsg-test-statistics-users' ),
expectedListUsers,
'Piped wikilink'
);
mw.messages.set( 'disambiguations-text', 'The following pages contain at least one link to a disambiguation page.\nThey may have to link to a more appropriate page instead.\nA page is treated as a disambiguation page if it uses a template that is linked from [[MediaWiki:Disambiguationspage]].' );
assert.htmlEqual(
- parser( 'disambiguations-text' ),
+ formatParse( 'disambiguations-text' ),
expectedDisambiguationsText,
'Wikilink without pipe'
);
assert.htmlEqual(
- parser( 'jquerymsg-test-version-entrypoints-index-php' ),
+ formatParse( 'jquerymsg-test-version-entrypoints-index-php' ),
expectedEntrypoints,
'External link'
);
// Pipe trick is not supported currently, but should not parse as text either.
mw.messages.set( 'pipe-trick', '[[Tampa, Florida|]]' );
assert.equal(
- parser( 'pipe-trick' ),
+ formatParse( 'pipe-trick' ),
'pipe-trick: Parse error at position 0 in input: [[Tampa, Florida|]]',
'Pipe trick should return error string.'
);
expectedMultipleBars = '<a title="Main Page" href="/wiki/Main_Page">Main|Page</a>';
mw.messages.set( 'multiple-bars', '[[Main Page|Main|Page]]' );
assert.htmlEqual(
- parser( 'multiple-bars' ),
+ formatParse( 'multiple-bars' ),
expectedMultipleBars,
'Bar in anchor'
);
mw.messages.set( 'special-characters', '[[' + specialCharactersPageName + ']]' );
assert.htmlEqual(
- parser( 'special-characters' ),
+ formatParse( 'special-characters' ),
expectedSpecialCharacters,
'Special characters'
);
// Tests that {{-transformation vs. general parsing are done as requested
QUnit.test( 'Curly brace transformation', 14, function ( assert ) {
- var formatText, formatParse, oldUserLang;
-
- oldUserLang = mw.config.get( 'wgUserLanguage' );
-
- formatText = mw.jqueryMsg.getMessageFunction( {
- format: 'text'
- } );
-
- formatParse = mw.jqueryMsg.getMessageFunction( {
- format: 'parse'
- } );
-
- // When the expected result is the same in both modes
- function assertBothModes( parserArguments, expectedResult, assertMessage ) {
- assert.equal( formatText.apply( null, parserArguments ), expectedResult, assertMessage + ' when format is \'text\'' );
- assert.equal( formatParse.apply( null, parserArguments ), expectedResult, assertMessage + ' when format is \'parse\'' );
- }
+ var oldUserLang = mw.config.get( 'wgUserLanguage' );
- assertBothModes( ['gender-msg', 'Bob', 'male'], 'Bob: blue', 'gender is resolved' );
+ assertBothModes( assert, ['gender-msg', 'Bob', 'male'], 'Bob: blue', 'gender is resolved' );
- assertBothModes( ['plural-msg', 5], 'Found 5 items', 'plural is resolved' );
+ assertBothModes( assert, ['plural-msg', 5], 'Found 5 items', 'plural is resolved' );
- assertBothModes( ['grammar-msg'], 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'grammar is resolved' );
+ assertBothModes( assert, ['grammar-msg'], 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'grammar is resolved' );
mw.config.set( 'wgUserLanguage', 'en' );
- assertBothModes( ['formatnum-msg', '987654321.654321'], '987,654,321.654', 'formatnum is resolved' );
+ assertBothModes( assert, ['formatnum-msg', '987654321.654321'], '987,654,321.654', 'formatnum is resolved' );
// Test non-{{ wikitext, where behavior differs
} );
QUnit.test( 'Int', 4, function ( assert ) {
- var parser = mw.jqueryMsg.getMessageFunction(),
- newarticletextSource = 'You have followed a link to a page that does not exist yet. To create the page, start typing in the box below (see the [[{{Int:Helppage}}|help page]] for more info). If you are here by mistake, click your browser\'s back button.',
+ var newarticletextSource = 'You have followed a link to a page that does not exist yet. To create the page, start typing in the box below (see the [[{{Int:Helppage}}|help page]] for more info). If you are here by mistake, click your browser\'s back button.',
expectedNewarticletext,
helpPageTitle = 'Help:Contents';
mw.messages.set( 'newarticletext', newarticletextSource );
assert.htmlEqual(
- parser( 'newarticletext' ),
+ formatParse( 'newarticletext' ),
expectedNewarticletext,
'Link with nested message'
);
assert.equal(
- parser( 'see-portal-url' ),
+ formatParse( 'see-portal-url' ),
'Project:Community portal is an important community page.',
'Nested message'
);
newarticletextSource.replace( 'Int:Helppage', 'int:helppage' ) );
assert.htmlEqual(
- parser( 'newarticletext-lowercase' ),
+ formatParse( 'newarticletext-lowercase' ),
expectedNewarticletext,
'Link with nested message, lowercase include'
);
mw.messages.set( 'uses-missing-int', '{{int:doesnt-exist}}' );
assert.equal(
- parser( 'uses-missing-int' ),
+ formatParse( 'uses-missing-int' ),
'[doesnt-exist]',
'int: where nested message does not exist'
);
} );
} );
+// HTML in wikitext
+QUnit.test( 'HTML', 26, function ( assert ) {
+ mw.messages.set( 'jquerymsg-italics-msg', '<i>Very</i> important' );
+
+ assertBothModes( assert, ['jquerymsg-italics-msg'], mw.messages.get( 'jquerymsg-italics-msg' ), 'Simple italics unchanged' );
+
+ mw.messages.set( 'jquerymsg-bold-msg', '<b>Strong</b> speaker' );
+ assertBothModes( assert, ['jquerymsg-bold-msg'], mw.messages.get( 'jquerymsg-bold-msg' ), 'Simple bold unchanged' );
+
+ mw.messages.set( 'jquerymsg-bold-italics-msg', 'It is <b><i>key</i></b>' );
+ assertBothModes( assert, ['jquerymsg-bold-italics-msg'], mw.messages.get( 'jquerymsg-bold-italics-msg' ), 'Bold and italics nesting order preserved' );
+
+ mw.messages.set( 'jquerymsg-italics-bold-msg', 'It is <i><b>vital</b></i>' );
+ assertBothModes( assert, ['jquerymsg-italics-bold-msg'], mw.messages.get( 'jquerymsg-italics-bold-msg' ), 'Italics and bold nesting order preserved' );
+
+ mw.messages.set( 'jquerymsg-italics-with-link', 'An <i>italicized [[link|wiki-link]]</i>' );
+
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-italics-with-link' ),
+ 'An <i>italicized <a title="link" href="' + mw.html.escape( mw.util.wikiGetlink( 'link' ) ) + '">wiki-link</i>',
+ 'Italics with link inside in parse mode'
+ );
+
+ assert.equal(
+ formatText( 'jquerymsg-italics-with-link' ),
+ mw.messages.get( 'jquerymsg-italics-with-link' ),
+ 'Italics with link unchanged in text mode'
+ );
+
+ mw.messages.set( 'jquerymsg-italics-id-class', '<i id="foo" class="bar">Foo</i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-italics-id-class' ),
+ mw.messages.get( 'jquerymsg-italics-id-class' ),
+ 'ID and class are allowed'
+ );
+
+ mw.messages.set( 'jquerymsg-italics-onclick', '<i onclick="alert(\'foo\')">Foo</i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-italics-onclick' ),
+ '<i onclick="alert(\'foo\')">Foo</i>',
+ 'element with onclick is escaped because it is not allowed'
+ );
+
+ mw.messages.set( 'jquerymsg-script-msg', '<script >alert( "Who put this tag here?" );</script>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-script-msg' ),
+ '<script >alert( "Who put this tag here?" );</script>',
+ 'Tag outside whitelist escaped in parse mode'
+ );
+
+ assert.equal(
+ formatText( 'jquerymsg-script-msg' ),
+ mw.messages.get( 'jquerymsg-script-msg' ),
+ 'Tag outside whitelist unchanged in text mode'
+ );
+
+ mw.messages.set( 'jquerymsg-script-link-msg', '<script>[[Foo|bar]]</script>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-script-link-msg' ),
+ '<script><a title="Foo" href="' + mw.html.escape( mw.util.wikiGetlink( 'Foo' ) ) + '">bar</a></script>',
+ 'Script tag text is escaped because that element is not allowed, but link inside is still HTML'
+ );
+
+ mw.messages.set( 'jquerymsg-mismatched-html', '<i class="important">test</b>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-mismatched-html' ),
+ '<i class="important">test</b>',
+ 'Mismatched HTML start and end tag treated as text'
+ );
+
+ // TODO (mattflaschen, 2013-03-18): It's not a security issue, but there's no real
+ // reason the htmlEmitter span needs to be here. It's an artifact of how emitting works.
+ mw.messages.set( 'jquerymsg-script-and-external-link', '<script>alert( "jquerymsg-script-and-external-link test" );</script> [http://example.com <i>Foo</i> bar]' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-script-and-external-link' ),
+ '<script>alert( "jquerymsg-script-and-external-link test" );</script> <a href="http://example.com"><span class="mediaWiki_htmlEmitter"><i>Foo</i> bar</span></a>',
+ 'HTML tags in external links not interfering with escaping of other tags'
+ );
+
+ mw.messages.set( 'jquerymsg-link-script', '[http://example.com <script>alert( "jquerymsg-link-script test" );</script>]' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-link-script' ),
+ '<a href="http://example.com"><span class="mediaWiki_htmlEmitter"><script>alert( "jquerymsg-link-script test" );</script></span></a>',
+ 'Non-whitelisted HTML tag in external link anchor treated as text'
+ );
+
+ // Intentionally not using htmlEqual for the quote tests
+ mw.messages.set( 'jquerymsg-double-quotes-preserved', '<i id="double">Double</i>' );
+ assert.equal(
+ formatParse( 'jquerymsg-double-quotes-preserved' ),
+ mw.messages.get( 'jquerymsg-double-quotes-preserved' ),
+ 'Attributes with double quotes are preserved as such'
+ );
+
+ mw.messages.set( 'jquerymsg-single-quotes-normalized-to-double', '<i id=\'single\'>Single</i>' );
+ assert.equal(
+ formatParse( 'jquerymsg-single-quotes-normalized-to-double' ),
+ '<i id="single">Single</i>',
+ 'Attributes with single quotes are normalized to double'
+ );
+
+ mw.messages.set( 'jquerymsg-escaped-double-quotes-attribute', '<i style="font-family:"Arial"">Styled</i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-escaped-double-quotes-attribute' ),
+ mw.messages.get( 'jquerymsg-escaped-double-quotes-attribute' ),
+ 'Escaped attributes are parsed correctly'
+ );
+
+ mw.messages.set( 'jquerymsg-escaped-single-quotes-attribute', '<i style=\'font-family:'Arial'\'>Styled</i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-escaped-single-quotes-attribute' ),
+ mw.messages.get( 'jquerymsg-escaped-single-quotes-attribute' ),
+ 'Escaped attributes are parsed correctly'
+ );
+
+
+ mw.messages.set( 'jquerymsg-wikitext-contents-parsed', '<i>[http://example.com Example]</i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-wikitext-contents-parsed' ),
+ '<i><a href="http://example.com">Example</a></i>',
+ 'Contents of valid tag are treated as wikitext, so external link is parsed'
+ );
+
+ mw.messages.set( 'jquerymsg-wikitext-contents-script', '<i><script>Script inside</script></i>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-wikitext-contents-script' ),
+ '<i><span class="mediaWiki_htmlEmitter"><script>Script inside</script></span></i>',
+ 'Contents of valid tag are treated as wikitext, so invalid HTML element is treated as text'
+ );
+
+ mw.messages.set( 'jquerymsg-unclosed-tag', 'Foo<tag>bar' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-unclosed-tag' ),
+ 'Foo<tag>bar',
+ 'Nonsupported unclosed tags are escaped'
+ );
+
+ mw.messages.set( 'jquerymsg-self-closing-tag', 'Foo<tag/>bar' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-self-closing-tag' ),
+ 'Foo<tag/>bar',
+ 'Self-closing tags don\'t cause a parse error'
+ );
+} );
+
}( mediaWiki, jQuery ) );
assert.ok( mw.config instanceof mw.Map, 'mw.config instance of mw.Map' );
} );
- QUnit.test( 'mw.message & mw.messages', 68, function ( assert ) {
+ QUnit.test( 'mw.message & mw.messages', 83, function ( assert ) {
var goodbye, hello;
// Convenience method for asserting the same result for multiple formats
assertMultipleFormats( ['int-msg'], ['text', 'parse', 'escaped'], 'Some Other Message', 'int is resolved' );
assert.equal( mw.message( 'int-msg' ).plain(), mw.messages.get( 'int-msg' ), 'int is not resolved in plain mode' );
+
+ assert.ok( mw.messages.set( 'mediawiki-italics-msg', '<i>Very</i> important' ), 'mw.messages.set: Register' );
+ assertMultipleFormats( ['mediawiki-italics-msg'], ['plain', 'text', 'parse'], mw.messages.get( 'mediawiki-italics-msg' ), 'Simple italics unchanged' );
+ assert.htmlEqual(
+ mw.message( 'mediawiki-italics-msg' ).escaped(),
+ '<i>Very</i> important',
+ 'Italics are escaped in escaped mode'
+ );
+
+ assert.ok( mw.messages.set( 'mediawiki-italics-with-link', 'An <i>italicized [[link|wiki-link]]</i>' ), 'mw.messages.set: Register' );
+ assertMultipleFormats( ['mediawiki-italics-with-link'], ['plain', 'text'], mw.messages.get( 'mediawiki-italics-with-link' ), 'Italics with link unchanged' );
+ assert.htmlEqual(
+ mw.message( 'mediawiki-italics-with-link' ).escaped(),
+ 'An <i>italicized [[link|wiki-link]]</i>',
+ 'Italics and link unchanged except for escaping in escaped mode'
+ );
+ assert.htmlEqual(
+ mw.message( 'mediawiki-italics-with-link' ).parse(),
+ 'An <i>italicized <a title="link" href="' + mw.util.wikiGetlink( 'link' ) + '">wiki-link</i>',
+ 'Italics with link inside in parse mode'
+ );
+
+ assert.ok( mw.messages.set( 'mediawiki-script-msg', '<script >alert( "Who put this script here?" );</script>' ), 'mw.messages.set: Register' );
+ assertMultipleFormats( ['mediawiki-script-msg'], ['plain', 'text'], mw.messages.get( 'mediawiki-script-msg' ), 'Script unchanged' );
+ assert.htmlEqual(
+ mw.message( 'mediawiki-script-msg' ).escaped(),
+ '<script >alert( "Who put this script here?" );</script>',
+ 'Script escaped when using escaped format'
+ );
+ assert.htmlEqual(
+ mw.message( 'mediawiki-script-msg' ).parse(),
+ '<script >alert( "Who put this script here?" );</script>',
+ 'Script escaped when using parse format'
+ );
+
+
} );
QUnit.test( 'mw.msg', 14, function ( assert ) {
'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4',
'Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0',
'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1',
+ // Kindle Fire
+ 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Kindle Fire Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1',
// Safari 5.0+
'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 10_6_7; ru-ru) AppleWebKit/534.31+ (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
// Opera 11+
'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; en-US)',
'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)',
- 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
+ // IE Mobile
+ 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800)',
+ // BlackBerry 6+
+ 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.570 Mobile Safari/534.8+',
+ 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.346 Mobile Safari/534.11+',
+ 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.386 Mobile Safari/537.3+',
+ // Open WebOS 1.4+ (HP Veer 4G)
+ 'Mozilla/5.0 (webOS/2.1.2; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 P160UNA/1.0',
+ // Firefox Mobile
+ 'Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0',
+ // iOS
+ 'Mozilla/5.0 (ipod: U;CPU iPhone OS 2_2 like Mac OS X: es_es) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
+ 'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
+ // Android
+ 'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17',
+ // Recent Opera Mini - JS mostly doesn't work, but serving jQuery doesn't hurt users
+ 'Opera/9.80 (Android; Opera Mini/7.29530/27.1407; U; en) Presto/2.8.119 Version/11.10'
],
// Supported: Uncompatible, serve basic content
gradeB: [
'Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)',
'Mozilla/4.0 (compatible; MSIE 5.0; Windows 98;)',
'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
- // Firefox < 4
+ // Firefox < 3.6
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2',
'Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1.1) Gecko/20070311 Firefox/2.0.0.1',
- 'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3'
-
+ // BlackBerry < 6
+ 'BlackBerry9300/5.0.0.716 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/133',
+ 'BlackBerry7250/4.0.0 Profile/MIDP-2.0 Configuration/CLDC-1.1',
+ // Open WebOS < 1.5 (Palm Pre, Palm Pixi)
+ 'Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0',
+ 'Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pixi/1.1 ',
+ // SymbianOS
+ 'NokiaN95_8GB-3;Mozilla/5.0 SymbianOS/9.2;U;Series60/3.1 NokiaN95_8GB-3/11.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 AppleWebKit/413 (KHTML, like Gecko)',
+ 'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0 ',
+ 'Mozilla/5.0 (SymbianOS/9.1; U; [en]; SymbianOS/91 Series60/3.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
+ 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-2/091.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.34 Mobile Safari/533.4',
+ // NetFront
+ 'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)',
+ 'Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.0 (screen 824x1200; rotate)',
+ 'Mozilla/4.08 (Windows; Mobile Content Viewer/1.0) NetFront/3.2',
+ // Opera Mini < 7
+ 'Opera/9.80 (J2ME/MIDP; Opera Mini/3.1.10423/22.387; U; en) Presto/2.5.25 Version/10.54',
+ 'Opera/9.50 (J2ME/MIDP; Opera Mini/4.0.10031/298; U; en)',
+ 'Opera/9.80 (J2ME/MIDP; Opera Mini/6.24093/26.1305; U; en) Presto/2.8.119 Version/10.54'
],
- // No special treatment blacklisting, benefit of doubt at own risk
+ // No explicit support for or against these browsers, they're
+ // given a shot at Grade A at their own risk.
gradeX: [
+ // Firefox 3.6
+ 'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3',
// Gecko
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14',
'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2',
}
);
} );
+
QUnit.test( 'isCompatible( Grade B )', testcases.gradeB.length, function ( assert ) {
$.each( testcases.gradeB, function ( i, ua ) {
assert.strictEqual( isCompatible( ua ), false, ua );
}
);
} );
+
QUnit.test( 'isCompatible( Grade X )', testcases.gradeX.length, function ( assert ) {
$.each( testcases.gradeX, function ( i, ua ) {
assert.strictEqual( isCompatible( ua ), true, ua );
}
);
} );
-}( jQuery ) );
+}( jQuery ) );