// Gets preferred variant (note that user preference is
// only possible for wiki content language variant)
$preferred = $pageLang->getPreferredVariant();
+ if ( Action::getActionName( $this ) === 'view' ) {
+ $params = $request->getQueryValues();
+ unset( $params['title'] );
+ } else {
+ $params = array();
+ }
// Loops over each variant
foreach( $variants as $code ) {
// Gets variant name from language code
$content_navigation['variants'][] = array(
'class' => ( $code == $preferred ) ? 'selected' : false,
'text' => $varname,
- 'href' => $title->getLocalURL( array( 'variant' => $code ) ),
+ 'href' => $title->getLocalURL( array( 'variant' => $code ) + $params ),
'lang' => $code,
'hreflang' => $code
);
'config-support-postgres' => '* $1 is a popular open source database system as an alternative to MySQL ([http://www.php.net/manual/en/pgsql.installation.php how to compile PHP with PostgreSQL support]). There may be some minor outstanding bugs, and it is not recommended for use in a production environment.',
'config-support-sqlite' => '* $1 is a lightweight database system which is very well supported. ([http://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], uses PDO)',
'config-support-oracle' => '* $1 is a commercial enterprise database. ([http://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])',
- 'config-support-ibm_db2' => '* $1 is a commercial enterprise database.',
+ 'config-support-ibm_db2' => '* $1 is a commercial enterprise database. ([http://www.php.net/manual/en/ibm-db2.installation.php How to compile PHP with IBM DB2 support])',
'config-header-mysql' => 'MySQL settings',
'config-header-postgres' => 'PostgreSQL settings',
'config-header-sqlite' => 'SQLite settings',
$site->setGlobalId( $siteRow->getField( 'global_key' ) );
+ $site->setInternalId( $siteRow->getField( 'id' ) );
+
if ( $siteRow->hasField( 'forward' ) ) {
$site->setForward( $siteRow->getField( 'forward' ) );
}
$this->mReason = $request->getText( 'wpReason' );
$this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
$this->mPosted = $request->wasPosted();
- $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
$this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
&& $wgEnableEmail;
+ $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
$this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
$this->mAction = $request->getVal( 'action' );
$this->mRemember = $request->getCheck( 'wpRemember' );
$q = 'action=submitlogin&type=signup';
$linkq = 'type=login';
$linkmsg = 'gotaccount';
+ $this->getOutput()->addModules( 'mediawiki.special.userlogin.signup' );
} else {
$template = new UserloginTemplate();
$q = 'action=submitlogin&type=login';
$template->set( 'name', $this->mUsername );
$template->set( 'password', $this->mPassword );
$template->set( 'retype', $this->mRetype );
+ $template->set( 'createemailset', $this->mCreateaccountMail );
$template->set( 'email', $this->mEmail );
$template->set( 'realname', $this->mRealName );
$template->set( 'domain', $this->mDomain );
</td>
</tr>
<tr>
+ <td></td>
+ <td class="mw-input">
+ <?php if( $this->data['createemail'] ) {
+ echo Xml::checkLabel(
+ wfMessage( 'createaccountmail' )->text(),
+ 'wpCreateaccountMail',
+ 'wpCreateaccountMail',
+ $this->data['createemailset'],
+ array( 'tabindex' => '2' )
+ );
+ } ?>
+ </td>
+ </tr>
+ <tr class="mw-row-password">
<td class="mw-label"><label for='wpPassword2'><?php $this->msg('yourpassword') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpPassword', null, 'password', array(
'class' => 'loginPassword',
'id' => 'wpPassword2',
- 'tabindex' => '2',
+ 'tabindex' => '3',
'size' => '20'
) + User::passwordChangeInputAttribs() ); ?>
</td>
<td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
<td class="mw-input">
<select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
- tabindex="3">
+ tabindex="4">
<?php echo $doms ?>
</select>
</td>
</tr>
<?php } ?>
- <tr>
+ <tr class="mw-row-password">
<td class="mw-label"><label for='wpRetype'><?php $this->msg('yourpasswordagain') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpRetype', null, 'password', array(
'class' => 'loginPassword',
'id' => 'wpRetype',
- 'tabindex' => '4',
+ 'tabindex' => '5',
'size' => '20'
) + User::passwordChangeInputAttribs() ); ?>
</td>
echo Html::input( 'wpEmail', $this->data['email'], 'email', array(
'class' => 'loginText',
'id' => 'wpEmail',
- 'tabindex' => '5',
+ 'tabindex' => '6',
'size' => '20'
) ); ?>
<div class="prefsectiontip">
<td class="mw-label"><label for='wpRealName'><?php $this->msg('yourrealname') ?></label></td>
<td class="mw-input">
<input type='text' class='loginText' name="wpRealName" id="wpRealName"
- tabindex="6"
+ tabindex="7"
value="<?php $this->text('realname') ?>" size='20' />
<div class="prefsectiontip">
<?php $this->msgWiki('prefs-help-realname'); ?>
<td class="mw-label"><label for='wpReason'><?php $this->msg('createaccountreason') ?></label></td>
<td class="mw-input">
<input type='text' class='loginText' name="wpReason" id="wpReason"
- tabindex="7"
+ tabindex="8"
value="<?php $this->text('reason') ?>" size='20' />
</td>
<?php } ?>
'wpRemember',
'wpRemember',
$this->data['remember'],
- array( 'tabindex' => '8' )
+ array( 'tabindex' => '9' )
)
?>
</td>
</tr>
<?php }
- $tabIndex = 9;
+ $tabIndex = 10;
if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
foreach ( $this->data['extraInput'] as $inputItem ) { ?>
<tr>
<input type='submit' name="wpCreateaccount" id="wpCreateaccount"
tabindex="<?php echo $tabIndex++; ?>"
value="<?php $this->msg('createaccount') ?>" />
- <?php if( $this->data['createemail'] ) { ?>
- <input type='submit' name="wpCreateaccountMail" id="wpCreateaccountMail"
- tabindex="<?php echo $tabIndex++; ?>"
- value="<?php $this->msg('createaccountmail') ?>" />
- <?php } ?>
</td>
</tr>
</table>
return is_readable( self::getMessagesFileName( $code ) );
}
+ /**
+ * Returns true if a language code string is a well-formed language tag
+ * according to RFC 5646.
+ * This function only checks well-formedness; it doesn't check that
+ * language, script or variant codes actually exist in the repositories.
+ *
+ * Based on regexes by Mark Davis of the Unicode Consortium:
+ * http://unicode.org/repos/cldr/trunk/tools/java/org/unicode/cldr/util/data/langtagRegex.txt
+ *
+ * @param $code string
+ * @param $lenient boolean Whether to allow '_' as separator. The default is only '-'.
+ *
+ * @return bool
+ * @since 1.21
+ */
+ public static function isWellFormedLanguageTag( $code, $lenient = false ) {
+ $alpha = '[a-z]';
+ $digit = '[0-9]';
+ $alphanum = '[a-z0-9]';
+ $x = 'x' ; # private use singleton
+ $singleton = '[a-wy-z]'; # other singleton
+ $s = $lenient ? '[-_]' : '-';
+
+ $language = "$alpha{2,8}|$alpha{2,3}$s$alpha{3}";
+ $script = "$alpha{4}"; # ISO 15924
+ $region = "(?:$alpha{2}|$digit{3})"; # ISO 3166-1 alpha-2 or UN M.49
+ $variant = "(?:$alphanum{5,8}|$digit$alphanum{3})";
+ $extension = "$singleton(?:$s$alphanum{2,8})+";
+ $privateUse = "$x(?:$s$alphanum{1,8})+";
+
+ # Define certain grandfathered codes, since otherwise the regex is pretty useless.
+ # Since these are limited, this is safe even later changes to the registry --
+ # the only oddity is that it might change the type of the tag, and thus
+ # the results from the capturing groups.
+ # http://www.iana.org/assignments/language-subtag-registry
+
+ $grandfathered = "en{$s}GB{$s}oed"
+ . "|i{$s}(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)"
+ . "|no{$s}(?:bok|nyn)"
+ . "|sgn{$s}(?:BE{$s}(?:fr|nl)|CH{$s}de)"
+ . "|zh{$s}min{$s}nan";
+
+ $variantList = "$variant(?:$s$variant)*";
+ $extensionList = "$extension(?:$s$extension)*";
+
+ $langtag = "(?:($language)"
+ . "(?:$s$script)?"
+ . "(?:$s$region)?"
+ . "(?:$s$variantList)?"
+ . "(?:$s$extensionList)?"
+ . "(?:$s$privateUse)?)";
+
+ # The final breakdown, with capturing groups for each of these components
+ # The variants, extensions, grandfathered, and private-use may have interior '-'
+
+ $root = "^(?:$langtag|$privateUse|$grandfathered)$";
+
+ return (bool)preg_match( "/$root/", strtolower( $code ) );
+ }
+
/**
* Returns true if a language code string is of a valid form, whether or
* not it exists. This includes codes which are used solely for
$form = CLDRPluralRuleEvaluator::evaluateCompiled( $number, $pluralRules );
return $form;
}
-
}
'gotaccount' => 'Already have an account? $1.',
'gotaccountlink' => 'Log in',
'userlogin-resetlink' => 'Forgotten your login details?',
-'createaccountmail' => 'By e-mail',
+'createaccountmail' => 'Use a temporary random password and send it to the e-mail address specified below',
'createaccountreason' => 'Reason:',
'badretype' => 'The passwords you entered do not match.',
'userexists' => 'Username entered already in use.
'activeusers' => 'Active users list',
'activeusers-summary' => '', # do not translate or duplicate this message to other languages
'activeusers-intro' => 'This is a list of users who had some kind of activity within the last $1 {{PLURAL:$1|day|days}}.',
-'activeusers-count' => '$1 {{PLURAL:$1|edit|edits}} in the last {{PLURAL:$3|day|$3 days}}',
+'activeusers-count' => '$1 {{PLURAL:$1|action|actions}} in the last {{PLURAL:$3|day|$3 days}}',
'activeusers-from' => 'Display users starting at:',
'activeusers-hidebots' => 'Hide bots',
'activeusers-hidesysops' => 'Hide administrators',
'activeusers' => 'Title of [[Special:ActiveUsers]]',
'activeusers-intro' => 'Used as introduction in [[Special:ActiveUsers]]. Parameters:
* $1 - number of days (<code>$wgActiveUserDays</code>)',
-'activeusers-count' => "Used in [[Special:ActiveUsers]] to show the active user's recent edit count in brackets ([]).
-* $1 is the number of recent edits
+'activeusers-count' => "Used in [[Special:ActiveUsers]] to show the active user's recent action count in brackets ([]).
+* $1 is the number of recent actions
* $2 is the user's name for use with GENDER (optional)
* $3 is the maximum number of days of the RecentChangesList",
'activeusers-from' => 'Used as label for checkbox in the form on [[Special:ActiveUsers]].
),
'dependencies' => array( 'mediawiki.libs.jpegmeta', 'mediawiki.util' ),
),
+ 'mediawiki.special.userlogin.signup' => array(
+ 'scripts' => 'resources/mediawiki.special/mediawiki.special.userLogin.signup.js',
+ ),
'mediawiki.special.javaScriptTest' => array(
'scripts' => 'resources/mediawiki.special/mediawiki.special.javaScriptTest.js',
'messages' => array_merge( Skin::getSkinNameMessages(), array(
--- /dev/null
+/**
+ * JavaScript for Special:UserLogin/signup
+ */
+jQuery( document ).ready( function ( $ ) {
+ $( '#wpCreateaccountMail' )
+ .on( 'change', function() {
+ $( '.mw-row-password' ).toggle( !$( this ).attr( 'checked' ) );
+ } )
+ .trigger( 'change' );
+} );
$site = $store->getSite( 'ertrywuutr' );
$this->assertInstanceOf( 'Site', $site );
$this->assertEquals( 'en', $site->getLanguageCode() );
+ $this->assertTrue( is_integer( $site->getInternalId() ) );
+ $this->assertTrue( $site->getInternalId() >= 0 );
$site = $store->getSite( 'sdfhxujgkfpth' );
$this->assertInstanceOf( 'Site', $site );
$this->assertEquals( 'nl', $site->getLanguageCode() );
+ $this->assertTrue( is_integer( $site->getInternalId() ) );
+ $this->assertTrue( $site->getInternalId() >= 0 );
}
public function testReset() {
);
}
+ /**
+ * Test Language::isWellFormedLanguageTag()
+ * @dataProvider provideWellFormedLanguageTags
+ */
+ function testWellFormedLanguageTag( $code, $message = '' ) {
+ $this->assertTrue(
+ Language::isWellFormedLanguageTag( $code ),
+ "validating code $code $message"
+ );
+ }
+
+ /**
+ * The test cases are based on the tests in the GaBuZoMeu parser
+ * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
+ * and distributed as free software, under the GNU General Public Licence.
+ * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
+ */
+ function provideWellFormedLanguageTags() {
+ return array(
+ array( 'fr', 'two-letter code' ),
+ array( 'fr-latn', 'two-letter code with lower case script code' ),
+ array( 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ),
+ array( 'fr-Latn-419', 'two-letter code with title case script code and region number' ),
+ array( 'fr-FR', 'two-letter code with uppercase' ),
+ array( 'ax-TZ', 'Not in the registry, but well-formed' ),
+ array( 'fr-shadok', 'two-letter code with variant' ),
+ array( 'fr-y-myext-myext2', 'non-x singleton' ),
+ array( 'fra-Latn', 'ISO 639 can be 3-letters' ),
+ array( 'fra', 'three-letter language code' ),
+ array( 'fra-FX', 'three-letter language code with country code' ),
+ array( 'i-klingon', 'grandfathered with singleton' ),
+ array( 'I-kLINgon', 'tags are case-insensitive...' ),
+ array( 'no-bok', 'grandfathered without singleton' ),
+ array( 'i-enochian', 'Grandfathered' ),
+ array( 'x-fr-CH', 'private use' ),
+ array( 'es-419', 'two-letter code with region number' ),
+ array( 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ),
+ array( 'ab-x-abc-x-abc', 'anything goes after x' ),
+ array( 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ),
+ array( 'i-default', 'grandfathered' ),
+ array( 'abcd-Latn', 'Language of 4 chars reserved for future use' ),
+ array( 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ),
+ array( 'de-CH-1901', 'with country and year' ),
+ array( 'en-US-x-twain', 'with country and singleton' ),
+ array( 'zh-cmn', 'three-letter variant' ),
+ array( 'zh-cmn-Hant', 'three-letter variant and script' ),
+ array( 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ),
+ array( 'xr-p-lze', 'Extension' ),
+ );
+ }
+
+ /**
+ * Negative test for Language::isWellFormedLanguageTag()
+ * @dataProvider provideMalformedLanguageTags
+ */
+ function testMalformedLanguageTag( $code, $message = '' ) {
+ $this->assertFalse(
+ Language::isWellFormedLanguageTag( $code ),
+ "validating that code $code is a malformed language tag - $message"
+ );
+ }
+
+ /**
+ * The test cases are based on the tests in the GaBuZoMeu parser
+ * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
+ * and distributed as free software, under the GNU General Public Licence.
+ * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
+ */
+ function provideMalformedLanguageTags() {
+ return array(
+ array( 'f', 'language too short' ),
+ array( 'f-Latn', 'language too short with script' ),
+ array( 'xr-lxs-qut', 'variants too short' ), # extlangS
+ array( 'fr-Latn-F', 'region too short' ),
+ array( 'a-value', 'language too short with region' ),
+ array( 'tlh-a-b-foo', 'valid three-letter with wrong variant' ),
+ array( 'i-notexist', 'grandfathered but not registered: invalid, even if we only test well-formedness' ),
+ array( 'abcdefghi-012345678', 'numbers too long' ),
+ array( 'ab-abc-abc-abc-abc', 'invalid extensions' ),
+ array( 'ab-abcd-abc', 'invalid extensions' ),
+ array( 'ab-ab-abc', 'invalid extensions' ),
+ array( 'ab-123-abc', 'invalid extensions' ),
+ array( 'a-Hant-ZH', 'short language with valid extensions' ),
+ array( 'a1-Hant-ZH', 'invalid character in language' ),
+ array( 'ab-abcde-abc', 'invalid extensions' ),
+ array( 'ab-1abc-abc', 'invalid characters in extensions' ),
+ array( 'ab-ab-abcd', 'invalid order of extensions' ),
+ array( 'ab-123-abcd', 'invalid order of extensions' ),
+ array( 'ab-abcde-abcd', 'invalid extensions' ),
+ array( 'ab-1abc-abcd', 'invalid characters in extensions' ),
+ array( 'ab-a-b', 'extensions too short' ),
+ array( 'ab-a-x', 'extensions too short, even with singleton' ),
+ array( 'ab--ab', 'two separators' ),
+ array( 'ab-abc-', 'separator in the end' ),
+ array( '-ab-abc', 'separator in the beginning' ),
+ array( 'abcd-efg', 'language too long' ),
+ array( 'aabbccddE', 'tag too long' ),
+ array( 'pa_guru', 'A tag with underscore is invalid in strict mode' ),
+ array( 'de-f', 'subtag too short' ),
+ );
+ }
+
+ /**
+ * Negative test for Language::isWellFormedLanguageTag()
+ */
+ function testLenientLanguageTag() {
+ $this->assertTrue(
+ Language::isWellFormedLanguageTag( 'pa_guru', true ),
+ 'pa_guru is a well-formed language tag in lenient mode'
+ );
+ }
+
/**
* Test Language::isValidBuiltInCode()
* @dataProvider provideLanguageCodes