From 94a19ae75e71b59d01a37cc1c0415d5796d45440 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Fri, 29 Jan 2016 00:24:43 -0300 Subject: PLT-7: Refactoring frontend (chunk 5) - Signup Team Complete - Signup User Complete - Email Verify --- web/react/components/email_verify.jsx | 54 +++++++- web/react/components/signup_team_complete.jsx | 11 +- web/react/components/signup_user_complete.jsx | 151 ++++++++++++++++++--- .../components/team_signup_display_name_page.jsx | 45 +++++- web/react/components/team_signup_email_item.jsx | 29 +++- web/react/components/team_signup_password_page.jsx | 83 +++++++++-- .../components/team_signup_send_invites_page.jsx | 46 +++++-- web/react/components/team_signup_url_page.jsx | 74 ++++++++-- web/react/components/team_signup_username_page.jsx | 69 ++++++++-- web/react/components/team_signup_welcome_page.jsx | 75 ++++++++-- web/static/i18n/en.json | 80 +++++++++++ web/static/i18n/es.json | 82 ++++++++++- 12 files changed, 700 insertions(+), 99 deletions(-) diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx index 9c07853b7..ef1a62130 100644 --- a/web/react/components/email_verify.jsx +++ b/web/react/components/email_verify.jsx @@ -1,6 +1,8 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + export default class EmailVerify extends React.Component { constructor(props) { super(props); @@ -19,21 +21,61 @@ export default class EmailVerify extends React.Component { var resend = ''; var resendConfirm = ''; if (this.props.isVerified === 'true') { - title = global.window.mm_config.SiteName + ' Email Verified'; - body =

Your email has been verified! Click + ); + body = ( + Please verify your email address. Check your inbox for an email.

; + title = ( + + ); + body = ( +

+ +

+ ); resend = ( ); if (this.props.resendSuccess) { - resendConfirm =

{' Verification email sent.'}

; + resendConfirm = ( +

+ +

); } } diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx index 6c7fd57b3..16553daeb 100644 --- a/web/react/components/signup_team_complete.jsx +++ b/web/react/components/signup_team_complete.jsx @@ -9,6 +9,8 @@ import UsernamePage from './team_signup_username_page.jsx'; import PasswordPage from './team_signup_password_page.jsx'; import BrowserStore from '../stores/browser_store.jsx'; +import {FormattedMessage} from 'mm-intl'; + export default class SignupTeamComplete extends React.Component { constructor(props) { super(props); @@ -96,7 +98,14 @@ export default class SignupTeamComplete extends React.Component { ); } - return (
You've already completed the signup process for this invitation or this invitation has expired.
); + return ( +
+ +
+ ); } } diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index ace0d28ae..47ec58e98 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -7,7 +7,32 @@ import UserStore from '../stores/user_store.jsx'; import BrowserStore from '../stores/browser_store.jsx'; import Constants from '../utils/constants.jsx'; -export default class SignupUserComplete extends React.Component { +import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + required: { + id: 'signup_user_completed.required', + defaultMessage: 'This field is required' + }, + validEmail: { + id: 'signup_user_completed.validEmail', + defaultMessage: 'Please enter a valid email address' + }, + reserved: { + id: 'signup_user_completed.reserved', + defaultMessage: 'This username is reserved, please choose a new one.' + }, + usernameLength: { + id: 'signup_user_completed.usernameLength', + defaultMessage: 'Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols \'.\', \'-\' and \'_\'.' + }, + passwordLength: { + id: 'signup_user_completed.passwordLength', + defaultMessage: 'Please enter at least {min} characters' + } +}); + +class SignupUserComplete extends React.Component { constructor(props) { super(props); @@ -29,30 +54,31 @@ export default class SignupUserComplete extends React.Component { handleSubmit(e) { e.preventDefault(); + const {formatMessage} = this.props.intl; const providedEmail = ReactDOM.findDOMNode(this.refs.email).value.trim(); if (!providedEmail) { - this.setState({nameError: '', emailError: 'This field is required', passwordError: ''}); + this.setState({nameError: '', emailError: formatMessage(holders.required), passwordError: ''}); return; } if (!Utils.isEmail(providedEmail)) { - this.setState({nameError: '', emailError: 'Please enter a valid email address', passwordError: ''}); + this.setState({nameError: '', emailError: formatMessage(holders.validEmail), passwordError: ''}); return; } const providedUsername = ReactDOM.findDOMNode(this.refs.name).value.trim().toLowerCase(); if (!providedUsername) { - this.setState({nameError: 'This field is required', emailError: '', passwordError: '', serverError: ''}); + this.setState({nameError: formatMessage(holders.required), emailError: '', passwordError: '', serverError: ''}); return; } const usernameError = Utils.isValidUsername(providedUsername); if (usernameError === 'Cannot use a reserved word as a username.') { - this.setState({nameError: 'This username is reserved, please choose a new one.', emailError: '', passwordError: '', serverError: ''}); + this.setState({nameError: formatMessage(holders.reserved), emailError: '', passwordError: '', serverError: ''}); return; } else if (usernameError) { this.setState({ - nameError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + ' lowercase characters made up of numbers, letters, and the symbols \'.\', \'-\' and \'_\'.', + nameError: formatMessage(holders.usernameLength, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH}), emailError: '', passwordError: '', serverError: '' @@ -62,7 +88,7 @@ export default class SignupUserComplete extends React.Component { const providedPassword = ReactDOM.findDOMNode(this.refs.password).value.trim(); if (!providedPassword || providedPassword.length < Constants.MIN_PASSWORD_LENGTH) { - this.setState({nameError: '', emailError: '', passwordError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters', serverError: ''}); + this.setState({nameError: '', emailError: '', passwordError: formatMessage(holders.passwordLength, {min: Constants.MIN_PASSWORD_LENGTH}), serverError: ''}); return; } @@ -95,7 +121,7 @@ export default class SignupUserComplete extends React.Component { window.location.href = '/' + this.props.teamName + '/channels/town-square'; }, (err) => { - if (err.message === 'Login failed because email address has not been verified') { + if (err.id === 'api.user.login.not_verified.app_error') { window.location.href = '/verify_email?email=' + encodeURIComponent(user.email) + '&teamname=' + encodeURIComponent(this.props.teamName); } else { this.setState({serverError: err.message}); @@ -112,7 +138,14 @@ export default class SignupUserComplete extends React.Component { client.track('signup', 'signup_user_01_welcome'); if (this.state.wizard === 'finished') { - return
{"You've already completed the signup process for this invitation or this invitation has expired."}
; + return ( +
+ +
+ ); } // set up error labels @@ -124,7 +157,18 @@ export default class SignupUserComplete extends React.Component { } var nameError = null; - var nameHelpText = {'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'"}; + var nameHelpText = ( + + + + ); var nameDivStyle = 'form-group'; if (this.state.nameError) { nameError = ; @@ -151,7 +195,16 @@ export default class SignupUserComplete extends React.Component { // set up the email entry and hide it if an email was provided var yourEmailIs = ''; if (this.state.user.email) { - yourEmailIs = {'Your email address is '}{this.state.user.email}{". You'll use this address to sign in to " + global.window.mm_config.SiteName + '.'}; + yourEmailIs = ( + + ); } var emailContainerStyle = 'margin--extra'; @@ -161,7 +214,12 @@ export default class SignupUserComplete extends React.Component { var email = (
-
{"What's your email address?"}
+
+ +
- {'with GitLab'} + + + ); } @@ -195,10 +259,16 @@ export default class SignupUserComplete extends React.Component { signupMessage.push( - {'with Google'} + + + ); } @@ -211,7 +281,12 @@ export default class SignupUserComplete extends React.Component { {email} {yourEmailIs}
-
{'Choose your username'}
+
+ +
-
{'Choose your password'}
+
+ +
- {'Create Account'} +

@@ -258,7 +341,12 @@ export default class SignupUserComplete extends React.Component {
{signupMessage}
- {'or'} + + +
); @@ -271,10 +359,28 @@ export default class SignupUserComplete extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -
{'Welcome to:'}
+
+ +

{this.props.teamDisplayName}

-

{'on ' + global.window.mm_config.SiteName}

-

{"Let's create your account"}

+

+ +

+

+ +

{signupMessage} {emailSignup} {serverError} @@ -293,6 +399,7 @@ SignupUserComplete.defaultProps = { teamDisplayName: '' }; SignupUserComplete.propTypes = { + intl: intlShape.isRequired, teamName: React.PropTypes.string, hash: React.PropTypes.string, teamId: React.PropTypes.string, @@ -300,3 +407,5 @@ SignupUserComplete.propTypes = { data: React.PropTypes.string, teamDisplayName: React.PropTypes.string }; + +export default injectIntl(SignupUserComplete); \ No newline at end of file diff --git a/web/react/components/team_signup_display_name_page.jsx b/web/react/components/team_signup_display_name_page.jsx index f4d5ea162..f07b50756 100644 --- a/web/react/components/team_signup_display_name_page.jsx +++ b/web/react/components/team_signup_display_name_page.jsx @@ -4,7 +4,20 @@ import * as utils from '../utils/utils.jsx'; import * as client from '../utils/client.jsx'; -export default class TeamSignupDisplayNamePage extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + required: { + id: 'team_signup_display_name.required', + defaultMessage: 'This field is required' + }, + charLength: { + id: 'team_signup_display_name.charLength', + defaultMessage: 'Name must be 4 or more characters up to a maximum of 15' + } +}); + +class TeamSignupDisplayNamePage extends React.Component { constructor(props) { super(props); @@ -21,12 +34,13 @@ export default class TeamSignupDisplayNamePage extends React.Component { submitNext(e) { e.preventDefault(); + const {formatMessage} = this.props.intl; var displayName = ReactDOM.findDOMNode(this.refs.name).value.trim(); if (!displayName) { - this.setState({nameError: 'This field is required'}); + this.setState({nameError: formatMessage(holders.required)}); return; } else if (displayName.length < 4 || displayName.length > 15) { - this.setState({nameError: 'Name must be 4 or more characters up to a maximum of 15'}); + this.setState({nameError: formatMessage(holders.charLength)}); return; } @@ -56,7 +70,12 @@ export default class TeamSignupDisplayNamePage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

{'Team Name'}

+

+ +

@@ -76,21 +95,30 @@ export default class TeamSignupDisplayNamePage extends React.Component { {nameError}
- {'Name your team in any language. Your team name shows in menus and headings.'} +
@@ -100,6 +128,9 @@ export default class TeamSignupDisplayNamePage extends React.Component { } TeamSignupDisplayNamePage.propTypes = { + intl: intlShape.isRequired, state: React.PropTypes.object, updateParent: React.PropTypes.func }; + +export default injectIntl(TeamSignupDisplayNamePage); \ No newline at end of file diff --git a/web/react/components/team_signup_email_item.jsx b/web/react/components/team_signup_email_item.jsx index 59c4771d7..feb70dc71 100644 --- a/web/react/components/team_signup_email_item.jsx +++ b/web/react/components/team_signup_email_item.jsx @@ -3,7 +3,24 @@ import * as Utils from '../utils/utils.jsx'; -export default class TeamSignupEmailItem extends React.Component { +import {intlShape, injectIntl, defineMessages} from 'mm-intl'; + +const holders = defineMessages({ + validEmail: { + id: 'team_signup_email.validEmail', + defaultMessage: 'Please enter a valid email address' + }, + different: { + id: 'team_signup_email.different', + defaultMessage: 'Please use a different email than the one used at signup' + }, + address: { + id: 'team_signup_email.address', + defaultMessage: 'Email Address' + } +}); + +class TeamSignupEmailItem extends React.Component { constructor(props) { super(props); @@ -16,6 +33,7 @@ export default class TeamSignupEmailItem extends React.Component { return ReactDOM.findDOMNode(this.refs.email).value.trim(); } validate(teamEmail) { + const {formatMessage} = this.props.intl; const email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase(); if (!email) { @@ -23,10 +41,10 @@ export default class TeamSignupEmailItem extends React.Component { } if (!Utils.isEmail(email)) { - this.setState({emailError: 'Please enter a valid email address'}); + this.setState({emailError: formatMessage(holders.validEmail)}); return false; } else if (email === teamEmail) { - this.setState({emailError: 'Please use a different email than the one used at signup'}); + this.setState({emailError: formatMessage(holders.different)}); return false; } @@ -48,7 +66,7 @@ export default class TeamSignupEmailItem extends React.Component { type='email' ref='email' className='form-control' - placeholder='Email Address' + placeholder={this.props.intl.formatMessage(holders.address)} defaultValue={this.props.email} maxLength='128' spellCheck='false' @@ -60,6 +78,9 @@ export default class TeamSignupEmailItem extends React.Component { } TeamSignupEmailItem.propTypes = { + intl: intlShape.isRequired, focus: React.PropTypes.bool, email: React.PropTypes.string }; + +export default injectIntl(TeamSignupEmailItem); \ No newline at end of file diff --git a/web/react/components/team_signup_password_page.jsx b/web/react/components/team_signup_password_page.jsx index 7e11d38c3..06c04854f 100644 --- a/web/react/components/team_signup_password_page.jsx +++ b/web/react/components/team_signup_password_page.jsx @@ -6,7 +6,20 @@ import BrowserStore from '../stores/browser_store.jsx'; import UserStore from '../stores/user_store.jsx'; import Constants from '../utils/constants.jsx'; -export default class TeamSignupPasswordPage extends React.Component { +import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + passwordError: { + id: 'team_signup_password.passwordError', + defaultMessage: 'Please enter at least {chars} characters' + }, + creating: { + id: 'team_signup_password.creating', + defaultMessage: 'Creating team...' + } +}); + +class TeamSignupPasswordPage extends React.Component { constructor(props) { super(props); @@ -25,7 +38,7 @@ export default class TeamSignupPasswordPage extends React.Component { var password = ReactDOM.findDOMNode(this.refs.password).value.trim(); if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) { - this.setState({passwordError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters'}); + this.setState({passwordError: this.props.intl.formatMessage(holders.passwordError, {chars: Constants.MIN_PASSWORD_LENGTH})}); return; } @@ -56,7 +69,7 @@ export default class TeamSignupPasswordPage extends React.Component { window.location.href = '/' + teamSignup.team.name + '/channels/town-square'; }, (err) => { - if (err.message === 'Login failed because email address has not been verified') { + if (err.id === 'api.user.login.not_verified.app_error') { window.location.href = '/verify_email?email=' + encodeURIComponent(teamSignup.team.email) + '&teamname=' + encodeURIComponent(teamSignup.team.name); } else { this.setState({serverError: err.message}); @@ -93,15 +106,35 @@ export default class TeamSignupPasswordPage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

{'Your password'}

-
{"Select a password that you'll use to login with your email address:"}
+

+ +

+
+ +
-
{'Email'}
+
+ +
{this.props.state.team.email}
-
{'Choose your password'}
+
+ +
- {'Passwords must contain ' + Constants.MIN_PASSWORD_LENGTH + ' to ' + Constants.MAX_PASSWORD_LENGTH + ' characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.'} + + +
{passwordError} @@ -123,19 +165,33 @@ export default class TeamSignupPasswordPage extends React.Component { type='submit' className='btn btn-primary margin--extra' id='finish-button' - data-loading-text={' Creating team...'} + data-loading-text={' ' + this.props.intl.formatMessage(holders.creating)} onClick={this.submitNext} > - {'Finish'} +
-

By proceeding to create your account and use {global.window.mm_config.SiteName}, you agree to our Terms of Service and Privacy Policy. If you do not agree, you cannot use {global.window.mm_config.SiteName}.

+

+ +

@@ -149,7 +205,10 @@ TeamSignupPasswordPage.defaultProps = { hash: '' }; TeamSignupPasswordPage.propTypes = { + intl: intlShape.isRequired, state: React.PropTypes.object, hash: React.PropTypes.string, updateParent: React.PropTypes.func }; + +export default injectIntl(TeamSignupPasswordPage); \ No newline at end of file diff --git a/web/react/components/team_signup_send_invites_page.jsx b/web/react/components/team_signup_send_invites_page.jsx index a580623e4..46a6bc68e 100644 --- a/web/react/components/team_signup_send_invites_page.jsx +++ b/web/react/components/team_signup_send_invites_page.jsx @@ -4,6 +4,8 @@ import EmailItem from './team_signup_email_item.jsx'; import * as Client from '../utils/client.jsx'; +import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + export default class TeamSignupSendInvitesPage extends React.Component { constructor(props) { super(props); @@ -117,7 +119,10 @@ export default class TeamSignupSendInvitesPage extends React.Component { href='#' onClick={this.submitAddInvite} > - Add Invitation +
@@ -125,22 +130,32 @@ export default class TeamSignupSendInvitesPage extends React.Component { bottomContent = (

- {'if you prefer, you can invite team members later'} -
- {' and '} + - {'skip this step '} + - {'for now.'} +

); } else { content = (
- {'Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.'} +
); } @@ -152,7 +167,12 @@ export default class TeamSignupSendInvitesPage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

{'Invite Team Members'}

+

+ +

{content}
@@ -170,7 +193,10 @@ export default class TeamSignupSendInvitesPage extends React.Component { href='#' onClick={this.submitBack} > - Back to previous step +
diff --git a/web/react/components/team_signup_url_page.jsx b/web/react/components/team_signup_url_page.jsx index 30459fc67..2f6c3df49 100644 --- a/web/react/components/team_signup_url_page.jsx +++ b/web/react/components/team_signup_url_page.jsx @@ -5,7 +5,32 @@ import * as Utils from '../utils/utils.jsx'; import * as Client from '../utils/client.jsx'; import Constants from '../utils/constants.jsx'; -export default class TeamSignupUrlPage extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + required: { + id: 'team_signup_url.required', + defaultMessage: 'This field is required' + }, + regex: { + id: 'team_signup_url.regex', + defaultMessage: "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash." + }, + charLength: { + id: 'team_signup_url.charLength', + defaultMessage: 'Name must be 4 or more characters up to a maximum of 15' + }, + taken: { + id: 'team_signup_url.taken', + defaultMessage: 'URL is taken or contains a reserved word' + }, + unavailable: { + id: 'team_signup_url.unavailable', + defaultMessage: 'This URL is unavailable. Please try another.' + } +}); + +class TeamSignupUrlPage extends React.Component { constructor(props) { super(props); @@ -23,9 +48,10 @@ export default class TeamSignupUrlPage extends React.Component { submitNext(e) { e.preventDefault(); + const {formatMessage} = this.props.intl; const name = ReactDOM.findDOMNode(this.refs.name).value.trim(); if (!name) { - this.setState({nameError: 'This field is required'}); + this.setState({nameError: formatMessage(holders.required)}); return; } @@ -33,17 +59,17 @@ export default class TeamSignupUrlPage extends React.Component { const urlRegex = /^[a-z]+([a-z\-0-9]+|(__)?)[a-z0-9]+$/g; if (cleanedName !== name || !urlRegex.test(name)) { - this.setState({nameError: "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash."}); + this.setState({nameError: formatMessage(holders.regex)}); return; } else if (cleanedName.length < 4 || cleanedName.length > 15) { - this.setState({nameError: 'Name must be 4 or more characters up to a maximum of 15'}); + this.setState({nameError: formatMessage(holders.charLength)}); return; } if (global.window.mm_config.RestrictTeamNames === 'true') { for (let index = 0; index < Constants.RESERVED_TEAM_NAMES.length; index++) { if (cleanedName.indexOf(Constants.RESERVED_TEAM_NAMES[index]) === 0) { - this.setState({nameError: 'URL is taken or contains a reserved word'}); + this.setState({nameError: formatMessage(holders.taken)}); return; } } @@ -52,7 +78,7 @@ export default class TeamSignupUrlPage extends React.Component { Client.findTeamByName(name, (data) => { if (data) { - this.setState({nameError: 'This URL is unavailable. Please try another.'}); + this.setState({nameError: formatMessage(holders.unavailable)}); } else { if (global.window.mm_config.SendEmailNotifications === 'true') { this.props.state.wizard = 'send_invites'; @@ -96,7 +122,12 @@ export default class TeamSignupUrlPage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

{`Team URL`}

+

+ +

@@ -124,25 +155,39 @@ export default class TeamSignupUrlPage extends React.Component {
{nameError}
-

{`Choose the web address of your new team:`}

+

+ +

    -
  • Short and memorable is best
  • -
  • Use lowercase letters, numbers and dashes
  • -
  • Must start with a letter and can't end in a dash
  • +
@@ -152,6 +197,9 @@ export default class TeamSignupUrlPage extends React.Component { } TeamSignupUrlPage.propTypes = { + intl: intlShape.isRequired, state: React.PropTypes.object, updateParent: React.PropTypes.func }; + +export default injectIntl(TeamSignupUrlPage); \ No newline at end of file diff --git a/web/react/components/team_signup_username_page.jsx b/web/react/components/team_signup_username_page.jsx index 6ccab6656..a7332975d 100644 --- a/web/react/components/team_signup_username_page.jsx +++ b/web/react/components/team_signup_username_page.jsx @@ -5,7 +5,20 @@ import * as Utils from '../utils/utils.jsx'; import * as Client from '../utils/client.jsx'; import Constants from '../utils/constants.jsx'; -export default class TeamSignupUsernamePage extends React.Component { +import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + reserved: { + id: 'team_signup_username.reserved', + defaultMessage: 'This username is reserved, please choose a new one.' + }, + invalid: { + id: 'team_signup_username.invalid', + defaultMessage: 'Username must begin with a letter, and contain between {min} to {max} characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\'' + } +}); + +class TeamSignupUsernamePage extends React.Component { constructor(props) { super(props); @@ -27,14 +40,15 @@ export default class TeamSignupUsernamePage extends React.Component { submitNext(e) { e.preventDefault(); + const {formatMessage} = this.props.intl; var name = ReactDOM.findDOMNode(this.refs.name).value.trim().toLowerCase(); var usernameError = Utils.isValidUsername(name); - if (usernameError === 'Cannot use a reserved word as a username.') { - this.setState({nameError: 'This username is reserved, please choose a new one.'}); + if (usernameError === 'Cannot use a reserved word as a username.') { //this should be change to some kind of ID + this.setState({nameError: formatMessage(holders.reserved)}); return; } else if (usernameError) { - this.setState({nameError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + ' characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\''}); + this.setState({nameError: formatMessage(holders.invalid, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH})}); return; } @@ -46,7 +60,18 @@ export default class TeamSignupUsernamePage extends React.Component { Client.track('signup', 'signup_team_06_username'); var nameError = null; - var nameHelpText = {'Usernames must begin with a letter and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'"}; + var nameHelpText = ( + + + + ); var nameDivClass = 'form-group'; if (this.state.nameError) { nameError = ; @@ -61,13 +86,28 @@ export default class TeamSignupUsernamePage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

{'Your username'}

-
{'Select a memorable username that makes it easy for teammates to identify you:'}
+

+ +

+
+ +
-
{'Choose your username'}
+
+ +
- {'Next'} +
@@ -97,7 +140,10 @@ export default class TeamSignupUsernamePage extends React.Component { href='#' onClick={this.submitBack} > - {'Back to previous step'} +
@@ -110,6 +156,9 @@ TeamSignupUsernamePage.defaultProps = { state: null }; TeamSignupUsernamePage.propTypes = { + intl: intlShape.isRequired, state: React.PropTypes.object, updateParent: React.PropTypes.func }; + +export default injectIntl(TeamSignupUsernamePage); \ No newline at end of file diff --git a/web/react/components/team_signup_welcome_page.jsx b/web/react/components/team_signup_welcome_page.jsx index a374dd363..18951be72 100644 --- a/web/react/components/team_signup_welcome_page.jsx +++ b/web/react/components/team_signup_welcome_page.jsx @@ -5,7 +5,24 @@ import * as Utils from '../utils/utils.jsx'; import * as Client from '../utils/client.jsx'; import BrowserStore from '../stores/browser_store.jsx'; -export default class TeamSignupWelcomePage extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + storageError: { + id: 'team_signup_welcome.storageError', + defaultMessage: 'This service requires local storage to be enabled. Please enable it or exit private browsing.' + }, + validEmailError: { + id: 'team_signup_welcome.validEmailError', + defaultMessage: 'Please enter a valid email address' + }, + address: { + id: 'team_signup_welcome.address', + defaultMessage: 'Email Address' + } +}); + +class TeamSignupWelcomePage extends React.Component { constructor(props) { super(props); @@ -20,7 +37,7 @@ export default class TeamSignupWelcomePage extends React.Component { } submitNext(e) { if (!BrowserStore.isLocalStorageSupported()) { - this.setState({storageError: 'This service requires local storage to be enabled. Please enable it or exit private browsing.'}); + this.setState({storageError: this.props.intl.formatMessage(holders.storageError)}); return; } e.preventDefault(); @@ -34,15 +51,16 @@ export default class TeamSignupWelcomePage extends React.Component { handleDiffSubmit(e) { e.preventDefault(); + const {formatMessage} = this.props.intl; var state = {useDiff: true, serverError: ''}; var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase(); if (!email || !Utils.isEmail(email)) { - state.emailError = 'Please enter a valid email address'; + state.emailError = formatMessage(holders.validEmailError); this.setState(state); return; } else if (!BrowserStore.isLocalStorageSupported()) { - state.emailError = 'This service requires local storage to be enabled. Please enable it or exit private browsing.'; + state.emailError = formatMessage(holders.storageError); this.setState(state); return; } @@ -62,7 +80,7 @@ export default class TeamSignupWelcomePage extends React.Component { let errorMsg = err.message; if (err.detailed_error.indexOf('Invalid RCPT TO address provided') >= 0) { - errorMsg = 'Please enter a valid email address'; + errorMsg = formatMessage(holders.validEmailError); } this.setState({emailError: '', serverError: errorMsg}); @@ -114,18 +132,35 @@ export default class TeamSignupWelcomePage extends React.Component { className='signup-team-logo' src='/static/images/logo.png' /> -

Welcome to:

+

+ +

{global.window.mm_config.SiteName}

-

Let's set up your new team

+

+ +

- Please confirm your email address:
+ +
{this.props.state.team.email}

- Your account will administer the new team site.
- You can add other administrators later. +

{storageError}
@@ -147,7 +185,7 @@ export default class TeamSignupWelcomePage extends React.Component { type='email' ref='email' className='form-control' - placeholder='Email Address' + placeholder={this.props.intl.formatMessage(holders.address)} maxLength='128' spellCheck='false' /> @@ -161,7 +199,10 @@ export default class TeamSignupWelcomePage extends React.Component { type='button' onClick={this.handleDiffSubmit} > - Use this instead +
- Use a different email +
); @@ -180,6 +224,9 @@ TeamSignupWelcomePage.defaultProps = { state: {} }; TeamSignupWelcomePage.propTypes = { + intl: intlShape.isRequired, updateParent: React.PropTypes.func.isRequired, state: React.PropTypes.object }; + +export default injectIntl(TeamSignupWelcomePage); \ No newline at end of file diff --git a/web/static/i18n/en.json b/web/static/i18n/en.json index 5127d38d5..1a82660fd 100644 --- a/web/static/i18n/en.json +++ b/web/static/i18n/en.json @@ -416,6 +416,12 @@ "claim.sso_to_email.description": "Upon changing your account type, you will only be able to login with your email and password.", "claim.sso_to_email_newPwd": "Enter a new password for your {team} {site} account", "claim.sso_to_email.switchTo": "Switch {type} to email and password", + "email_verify.verified": "{siteName} Email Verified", + "email_verify.verifiedBody": "

Your email has been verified! Click here to log in.

", + "email_verify.almost": "{siteName}: You are almost done", + "email_verify.notVerifiedBody": "Please verify your email address. Check your inbox for an email.", + "email_verify.resend": "Resend Email", + "email_verify.sent": " Verification email sent.", "error_bar.preview_mode": "Preview Mode: Email notifications have not been configured", "find_team.submitError": "Please enter a valid email address", "find_team.placeholder": "you@domain.com", @@ -463,11 +469,30 @@ "password_send.title": "Password Reset", "password_send.description": "To reset your password, enter the email address you used to sign up for {teamName}.", "password_send.reset": "Reset my password", + "signup_team_complete.completed": "You've already completed the signup process for this invitation or this invitation has expired.", "signup_team.noTeams": "There are no teams include in the Team Directory and team creation has been disabled.", "signup_team.choose": "Choose a Team", "signup_team.createTeam": "Or Create a Team", "signup_team.disabled": "Team creation has been disabled. Please contact an administrator for access.", "signup_team.none": "No team creation method has been enabled. Please contact an administrator for access.", + "signup_user_completed.required": "This field is required", + "signup_user_completed.validEmail": "Please enter a valid email address", + "signup_user_completed.reserved": "This username is reserved, please choose a new one.", + "signup_user_completed.usernameLength": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", + "signup_user_completed.passwordLength": "Please enter at least {min} characters", + "signup_user_completed.expired": "You've already completed the signup process for this invitation or this invitation has expired.", + "signup_user_completed.userHelp": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'", + "signup_user_completed.emailIs": "Your email address is {email}. You'll use this address to sign in to {siteName}.", + "signup_user_completed.whatis": "What's your email address?", + "signup_user_completed.gitlab": "with GitLab", + "signup_user_completed.google": "with Google", + "signup_user_completed.chooseUser": "Choose your username", + "signup_user_completed.choosePwd": "Choose your password", + "signup_user_completed.create": "Create Account", + "signup_user_completed.or": "or", + "signup_user_completed.welcome": "Welcome to:", + "signup_user_completed.onSite": "on {siteName}", + "signup_user_completed.lets": "Let's create your account", "suggestion.mention.all": "Notifies everyone in the team", "suggestion.mention.channel": "Notifies everyone in the channel", "suggestion.search.public": "Public Channels", @@ -477,6 +502,61 @@ "choose_auth_page.emailCreate": "Create new team with email address", "choose_auth_page.noSignup": "No sign-up methods configured, please contact your system administrator.", "choose_auth_page.find": "Find my teams", + "team_signup_display_name.required": "This field is required", + "team_signup_display_name.charLength": "Name must be 4 or more characters up to a maximum of 15", + "team_signup_display_name.teamName": "Team Name", + "team_signup_display_name.nameHelp": "Name your team in any language. Your team name shows in menus and headings.", + "team_signup_display_name.next": "Next", + "team_signup_display_name.back": "Back to previous step", + "team_signup_email.validEmail": "Please enter a valid email address", + "team_signup_email.different": "Please use a different email than the one used at signup", + "team_signup_email.address": "Email Address", + "team_signup_password.passwordError": "Please enter at least {chars} characters", + "team_signup_password.creating": "Creating team...", + "team_signup_password.yourPassword": "Your password", + "team_signup_password.selectPassword": "Select a password that you'll use to login with your email address:", + "team_signup_password.email": "Email", + "team_signup_password.choosePwd": "Choose your password", + "team_signup_password.hint": "Passwords must contain {min} to {max} characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.", + "team_signup_password.finish": "Finish", + "team_signup_password.agreement": "By proceeding to create your account and use {siteName}, you agree to our Terms of Service and Privacy Policy. If you do not agree, you cannot use {siteName}.", + "team_signup_password.back": "Back to previous step", + "team_signup_send_invites.addInvitation": "Add Invitation", + "team_signup_send_invites.prefer": "if you prefer, you can invite team members later
and ", + "team_signup_send_invites.skip": "skip this step ", + "team_signup_send_invites.forNow": "for now.", + "team_signup_send_invites.disabled": "Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.", + "team_signup_send_invites.title": "Invite Team Members", + "team_signup_send_invites.next": "Next", + "team_signup_send_invites.back": "Back to previous step", + "team_signup_url.required": "This field is required", + "team_signup_url.regex": "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash.", + "team_signup_url.charLength": "Name must be 4 or more characters up to a maximum of 15", + "team_signup_url.taken": "URL is taken or contains a reserved word", + "team_signup_url.unavailable": "This URL is unavailable. Please try another.", + "team_signup_url.teamUrl": "Team URL", + "team_signup_url.webAddress": "Choose the web address of your new team:", + "team_signup_url.hint": "
  • Short and memorable is best
  • \n
  • Use lowercase letters, numbers and dashes
  • \n
  • Must start with a letter and can't end in a dash
  • ", + "team_signup_url.next": "Next", + "team_signup_url.back": "Back to previous step", + "team_signup_username.reserved": "This username is reserved, please choose a new one.", + "team_signup_username.invalid": "Username must begin with a letter, and contain between {min} to {max} characters in total, which may be numbers, lowercase letters, or any of the symbols '.', '-', or '_'", + "team_signup_username.hint": "Usernames must begin with a letter and contain between {min} to {max} characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'", + "team_signup_username.username": "Your username", + "team_signup_username.memorable": "Select a memorable username that makes it easy for teammates to identify you:", + "team_signup_username.chooseUsername": "Choose your username", + "team_signup_username.next": "Next", + "team_signup_username.back": "Back to previous step", + "team_signup_welcome.storageError": "This service requires local storage to be enabled. Please enable it or exit private browsing.", + "team_signup_welcome.validEmailError": "Please enter a valid email address", + "team_signup_welcome.address": "Email Address", + "team_signup_welcome.welcome": "Welcome to:", + "team_signup_welcome.lets": "Let's set up your new team", + "team_signup_welcome.confirm": "Please confirm your email address:", + "team_signup_welcome.admin": "Your account will administer the new team site.
    \n You can add other administrators later.", + "team_signup_welcome.yes": "Yes, this address is correct", + "team_signup_welcome.instead": "Use this instead", + "team_signup_welcome.different": "Use a different email", "email_signup.emailError": "Please enter a valid email address", "email_signup.address": "Email Address", "email_signup.createTeam": "Create Team", diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json index 8743a9b4f..d54c99535 100644 --- a/web/static/i18n/es.json +++ b/web/static/i18n/es.json @@ -425,6 +425,12 @@ "email_signup.createTeam": "Crear Equipo", "email_signup.emailError": "Por favor ingresa una dirección de correos válida", "email_signup.find": "Encontrar mi equipo", + "email_verify.almost": "{siteName}: Ya casi estás listo", + "email_verify.notVerifiedBody": "Por favor verifica tu correo electrónico. Revisa tu bandeja de entrada, hemos enviado un correo de verificación.", + "email_verify.resend": "Reenviar Correo", + "email_verify.sent": " Correo de verificación enviado.", + "email_verify.verified": "{siteName} Correo electrónico verificado", + "email_verify.verifiedBody": "

    Tu correo electrónico ha sido verificado!! Pincha aquí para iniciar sesión.

    ", "error_bar.preview_mode": "Modo de prueba: Las notificaciones por correo electrónico no han sido configuradas", "find_team.email": "Correo electrónico", "find_team.findDescription": "Enviamos un correo electrónico con los equipos a los que perteneces.", @@ -435,7 +441,7 @@ "find_team.submitError": "Por favor ingresa una dirección válida", "loading_screen.loading": "Cargando", "login.changed": " Cambiado el método de inicio de sesión satisfactoriamente", - "login.create": "Crea uno ahora", + "login.create": "Crea una ahora", "login.createTeam": "Crear un nuevo equipo", "login.find": "Encuentra tus otros equipos", "login.forgot": "Olvide mi contraseña", @@ -477,6 +483,25 @@ "signup_team.disabled": "La creación de Equipos ha sido deshabilitada.", "signup_team.noTeams": "No hay equipos en el Directorio de Equipos y la creación de equipos ha sido deshabilitada.", "signup_team.none": "No se ha habilitado ningún método para creación de equipos. Por favor contacta a un administrador de sistema para solicitar acceso.", + "signup_team_complete.completed": "Ya haz completado el proceso de entrada para esta invitación, o esta invitación ya ha expirado.", + "signup_user_completed.choosePwd": "Escoge tu contraseña", + "signup_user_completed.chooseUser": "Escoge tu nombre de usuario", + "signup_user_completed.create": "Crea una Cuenta", + "signup_user_completed.emailIs": "Tu dirección de correo electrónico es {email}. Utiliza está dirección para ingresar a {siteName}.", + "signup_user_completed.expired": "Ya haz completado el proceso de registro para esta invitación, o esta invitación ya ha expirado.", + "signup_user_completed.gitlab": "con GitLab", + "signup_user_completed.google": "con Google", + "signup_user_completed.lets": "Vamos a crear tu cuenta", + "signup_user_completed.onSite": "en {siteName}", + "signup_user_completed.or": "o", + "signup_user_completed.passwordLength": "Por favor ingresa al menos {min} caracteres", + "signup_user_completed.required": "Este campo es obligatorio", + "signup_user_completed.reserved": "Este nombre de usuario está reservado, por favor escoge uno nuevo.", + "signup_user_completed.userHelp": "El nombre de usuario debe empezar con una letra, y contener entre {min} a {max} caracteres en minúscula con números, letras, y los símbolos '.', '-' y '_'.", + "signup_user_completed.usernameLength": "El nombre de usuario debe comenzar con una letra, y debe contener entre {min} y {max} caracteres en minúscula y confeccionado por numeros, letras y los simbolos '.', '-' and '_'.", + "signup_user_completed.validEmail": "Por favor ingresa una dirección de correo electrónico válida", + "signup_user_completed.welcome": "Bienvenido a:", + "signup_user_completed.whatis": "¿Cuál es tu dirección de correo electrónico?", "sso_signup.find": "Encontrar mi equipo", "sso_signup.gitlab": "Crea un equipo con una cuenta de GitLab", "sso_signup.google": "Crea un equipo con una cuenta de Google Apps", @@ -487,6 +512,61 @@ "suggestion.mention.channel": "Notifica a todas las personas en el canal", "suggestion.search.private": "Grupos Privados", "suggestion.search.public": "Canales Públicos", + "team_signup_display_name.back": "Volver al paso previo", + "team_signup_display_name.charLength": "El nombre debe tener 4 o más caracteres hasta un máximo de 15", + "team_signup_display_name.nameHelp": "Nombre tu equipo en cualquier idioma. El nombre de tu equipo aparecerá en menús y en inicios", + "team_signup_display_name.next": "Siguiente", + "team_signup_display_name.required": "Este campo es obligatorio", + "team_signup_display_name.teamName": "Nombre del Equipo", + "team_signup_email.address": "Dirección de correo electrónico", + "team_signup_email.different": "Please use a different email than the one used at signup", + "team_signup_email.validEmail": "Por favor ingresa una dirección de correo electrónico válida", + "team_signup_password.agreement": "Procediendo a crear tu cuenta y el uso de {siteName}, indicas que estás de acuerdo con nuestros Términos de Servicio y Políticas de Privacidad. Si no estás de acuerdo, no debes utilizar {siteName}.", + "team_signup_password.back": "Volver al paso previo", + "team_signup_password.choosePwd": "Escoge tu contraseña", + "team_signup_password.creating": "Creando equipo...", + "team_signup_password.email": "Correo electrónico", + "team_signup_password.finish": "Finalizar", + "team_signup_password.hint": "Las contraseñas deben contener de {min} a {max} caracteres. Su contraseña será más fuerte si contiene una mezcla de símbolos, números y caracteres en mayúsculas y minúsculas.", + "team_signup_password.passwordError": "Por favor ingrese al menos {chars} caracteres", + "team_signup_password.selectPassword": "Selecciona la contraseña que estás usando con tu dirección de correos:", + "team_signup_password.yourPassword": "Tu contraseña", + "team_signup_send_invites.addInvitation": "Agrega una Invitación", + "team_signup_send_invites.back": "Volver al paso previo", + "team_signup_send_invites.disabled": "Este correo electrónico está actualmente deshabilitado para tu equipo, y los correos no podrán ser enviados. Contacta a tu administrador de sistemas", + "team_signup_send_invites.forNow": "por ahora.", + "team_signup_send_invites.next": "Siguiente", + "team_signup_send_invites.prefer": "Si prefieres, puedes invitar a miembros de equipo más tarde
    y ", + "team_signup_send_invites.skip": "saltarte este paso ", + "team_signup_send_invites.title": "Invita Miembros al Equipo", + "team_signup_url.back": "Volver al paso previo", + "team_signup_url.charLength": "El nombre debe tener 4 o más caracteres hasta un máximo de 15", + "team_signup_url.hint": "
  • Corto y memorizable es mejor
  • Use letras en minúsculas, números y guiones
  • Debe empezar con una letra y no puede finalizar con un guión
  • ", + "team_signup_url.next": "Siguiente", + "team_signup_url.regex": "Sólo utiliza letras en minúsculas, numeros y guiones. Debe comenzar con una letra y no puede terminar en un guión.", + "team_signup_url.required": "Este campo es obligatorio", + "team_signup_url.taken": "Este URL ya fue asignado o contiene una palabra reservada", + "team_signup_url.teamUrl": "URL de Equipo", + "team_signup_url.unavailable": "Este URL no está disponible. Por favor intenta con otro.", + "team_signup_url.webAddress": "Escoge la dirección web de tu nuevo equipo:", + "team_signup_username.back": "Volver al paso previo", + "team_signup_username.chooseUsername": "Escoge un nombre de usuario", + "team_signup_username.hint": "El nombre de usuario debe empezar con una letra, y contener entre {min} a {max} caracteres en minúscula con números, letras, y los símbolos '.', '-' y '_'.", + "team_signup_username.invalid": "El nombre de usuario debe comenzar con una letra, y tener entre {min} y {max} de caracteres en total, los cuales pueden ser numeros, letras en minúsculas, o cualquiera de los simbolos '.', '-', o '_'", + "team_signup_username.memorable": "Selecciona un nombre de usuario sencillo de recordar y que sea fácil para a tus compañeros de equipo identificarte:", + "team_signup_username.next": "Siguiente", + "team_signup_username.reserved": "Este nombre de usuario está reservado. Por favor escoge otro.", + "team_signup_username.username": "Tu nombre de usuario", + "team_signup_welcome.address": "Dirección de correo", + "team_signup_welcome.admin": "Tu cuenta administrará un nuevo sitio del equipo.
    Puedes agregar otros administradores más adelante.", + "team_signup_welcome.confirm": "Por favor confirma tu dirección de correos:", + "team_signup_welcome.different": "Usa un correo diferente", + "team_signup_welcome.instead": "Usa este en vez de", + "team_signup_welcome.lets": "permítenos setear tu nuevo equipo", + "team_signup_welcome.storageError": "Este servicio requiere de almacenamiento local para ser habilitado. Por favor habilítalo o sale de la navegación privad.", + "team_signup_welcome.validEmailError": "Por favor ingresa una dirección de correo electrónico válida", + "team_signup_welcome.welcome": "Bienvenido a:", + "team_signup_welcome.yes": "Sí, esta dirección es correcta", "tutorial_intro.allSet": "Ya estás listo para comenzar", "tutorial_intro.end": "Pincha “Siguiente” para entrar al Canal General. Este es el primer canal que ven tus compañeros cuando ingresan. Utilizalo para mandar mensajes que todos deben leer.", "tutorial_intro.invite": "Invitar compañeros", -- cgit v1.2.3-1-g7c22