VAN-130: Add translation strings (#44)

This commit is contained in:
Zainab Amir
2020-12-15 15:12:41 +05:00
committed by GitHub
parent 2d39f3cc52
commit 631eb26fa0
10 changed files with 287 additions and 75 deletions

View File

@@ -71,6 +71,7 @@ LoginFailureMessage.defaultProps = {
errors: '',
errorCode: null,
};
LoginFailureMessage.propTypes = {
errors: PropTypes.string,
errorCode: PropTypes.string,

View File

@@ -5,7 +5,7 @@ import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import SwitchContent from './SwitchContent';
import { REGISTER_PAGE, RESET_PAGE } from '../data/constants';
import { LOGIN_PAGE, REGISTER_PAGE, RESET_PAGE } from '../data/constants';
import messages from './messages';
const LoginHelpLinks = (props) => {
@@ -31,7 +31,7 @@ const LoginHelpLinks = (props) => {
const getHelpButtonMessage = () => {
let mid = 'logistration.need.other.help.signing.in.collapsible.menu';
if (page === 'login') {
if (page === LOGIN_PAGE) {
mid = 'logistration.need.help.signing.in.collapsible.menu';
}
@@ -40,7 +40,7 @@ const LoginHelpLinks = (props) => {
const renderLoginHelp = () => (
<div className="login-help">
{ page === 'login' ? forgotPasswordLink() : signUpLink()}
{ page === LOGIN_PAGE ? forgotPasswordLink() : signUpLink()}
<a className="field-link" href="https://support.edx.org/hc/en-us/sections/115004153367-Solve-a-Sign-in-Problem">
{intl.formatMessage(messages['logistration.other.sign.in.issues'])}
</a>

View File

@@ -16,7 +16,9 @@ import { RedirectLogistration } from '../common-components';
import SocialAuthProviders from './SocialAuthProviders';
import ThirdPartyAuthAlert from './ThirdPartyAuthAlert';
import { DEFAULT_REDIRECT_URL, DEFAULT_STATE, REGISTER_PAGE } from '../data/constants';
import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, REGISTER_PAGE,
} from '../data/constants';
import { forgotPasswordResultSelector } from '../forgot-password';
class LoginPage extends React.Component {
@@ -146,7 +148,10 @@ class LoginPage extends React.Component {
{this.props.forgotPassword.status === 'complete' ? <ConfirmationAlert email={this.props.forgotPassword.email} /> : null}
<div className="d-flex flex-row">
<p>
First time here?<a className="ml-1" href={REGISTER_PAGE}>Create an Account.</a>
{intl.formatMessage(messages['logistration.first.time.here'])}
<a className="ml-1" href={REGISTER_PAGE}>
{intl.formatMessage(messages['logistration.create.an.account'])}.
</a>
</p>
</div>
<h2 className="text-left mt-2 mb-3">
@@ -160,7 +165,7 @@ class LoginPage extends React.Component {
buttonTitle={intl.formatMessage(messages['logistration.login.institution.login.button'])}
/>
<div className="section-heading-line mb-4">
<h4>{intl.formatMessage(messages['logistration.login.institution.login.sign.in.with'])}</h4>
<h4>{intl.formatMessage(messages['logistration.or.sign.in.with'])}</h4>
</div>
</>
) : null }
@@ -170,9 +175,11 @@ class LoginPage extends React.Component {
<ValidationFormGroup
for="email"
invalid={this.state.errors.email !== ''}
invalidMessage="The email address you've provided isn't formatted correctly."
invalidMessage={intl.formatMessage(messages['logistration.email.format.validation.message'])}
>
<label htmlFor="loginEmail" className="h6 mr-1">Email</label>
<label htmlFor="loginEmail" className="h6 mr-1">
{intl.formatMessage(messages['logistration.login.page.email.label'])}
</label>
<Input
name="email"
id="loginEmail"
@@ -184,15 +191,17 @@ class LoginPage extends React.Component {
/>
</ValidationFormGroup>
</div>
<p className="mb-4">The email address you used to register with edX.</p>
<p className="mb-4">{intl.formatMessage(messages['logistration.email.help.message'])}</p>
<div className="d-flex flex-column align-items-start">
<ValidationFormGroup
for="password"
invalid={this.state.errors.password !== ''}
invalidMessage="Please enter your password."
invalidMessage={intl.formatMessage(messages['logistration.login.page.password.validation.message'])}
className="mb-0"
>
<label htmlFor="loginPassword" className="h6 mr-1">Password</label>
<label htmlFor="loginPassword" className="h6 mr-1">
{intl.formatMessage(messages['logistration.password'])}
</label>
<Input
name="password"
id="loginPassword"
@@ -203,7 +212,7 @@ class LoginPage extends React.Component {
/>
</ValidationFormGroup>
</div>
<LoginHelpLinks page="login" />
<LoginHelpLinks page={LOGIN_PAGE} />
</div>
<StatefulButton
type="submit"
@@ -218,7 +227,7 @@ class LoginPage extends React.Component {
{thirdPartyAuthContext.providers.length && !thirdPartyAuthContext.currentProvider ? (
<>
<div className="section-heading-line mb-4">
<h4>or sign in with</h4>
<h4>{intl.formatMessage(messages['logistration.or.sign.in.with'])}</h4>
</div>
<div className="row tpa-container">
<SocialAuthProviders socialAuthProviders={thirdPartyAuthContext.providers} />

View File

@@ -46,6 +46,7 @@ const RegistrationFailureMessage = (props) => {
RegistrationFailureMessage.defaultProps = {
errors: '',
};
RegistrationFailureMessage.propTypes = {
errors: PropTypes.shape({
email: PropTypes.array,

View File

@@ -103,6 +103,7 @@ class RegistrationPage extends React.Component {
payload[key] = this.state[camelCase(key)];
}
});
const next = params.get('next');
const courseId = params.get('course_id');
if (next) {
@@ -363,7 +364,7 @@ class RegistrationPage extends React.Component {
onSubmitHandler={this.handleInstitutionLogin}
secondaryProviders={this.props.thirdPartyAuthContext.secondaryProviders}
headingTitle={intl.formatMessage(messages['logistration.register.institution.login.page.title'])}
buttonTitle={intl.formatMessage(messages['logistration.register.institution.login.page.back.button'])}
buttonTitle={intl.formatMessage(messages['logistration.create.an.account'])}
/>
);
}
@@ -410,9 +411,11 @@ class RegistrationPage extends React.Component {
<ValidationFormGroup
for="name"
invalid={this.state.errors.name !== ''}
invalidMessage="Enter your full name."
invalidMessage={intl.formatMessage(messages['logistration.fullname.validation.message'])}
>
<label htmlFor="name" className="h6 pt-3">Full Name (required)</label>
<label htmlFor="name" className="h6 pt-3">
{intl.formatMessage(messages['logistration.fullname.label'])}
</label>
<Input
name="name"
id="name"
@@ -426,9 +429,11 @@ class RegistrationPage extends React.Component {
<ValidationFormGroup
for="username"
invalid={this.state.errors.username !== ''}
invalidMessage="Username must be between 2 and 30 characters long."
invalidMessage={intl.formatMessage(messages['logistration.username.validation.message'])}
>
<label htmlFor="username" className="h6 pt-3">Public Username (required)</label>
<label htmlFor="username" className="h6 pt-3">
{intl.formatMessage(messages['logistration.username.label'])}
</label>
<Input
name="username"
id="username"
@@ -442,9 +447,11 @@ class RegistrationPage extends React.Component {
<ValidationFormGroup
for="email"
invalid={this.state.errors.email !== ''}
invalidMessage="Enter a valid email address that contains at least 3 characters."
invalidMessage={intl.formatMessage(messages['logistration.email.validation.message'])}
>
<label htmlFor="email" className="h6 pt-3">Email (required)</label>
<label htmlFor="email" className="h6 pt-3">
{intl.formatMessage(messages['logistration.register.page.email.label'])}
</label>
<Input
name="email"
id="email"
@@ -458,9 +465,11 @@ class RegistrationPage extends React.Component {
<ValidationFormGroup
for="password"
invalid={this.state.errors.password !== ''}
invalidMessage="This password is too short. It must contain at least 8 characters. This password must contain at least 1 number."
invalidMessage={intl.formatMessage(messages['logistration.register.page.password.validation.message'])}
>
<label htmlFor="password" className="h6 pt-3">Password (required)</label>
<label htmlFor="password" className="h6 pt-3">
{intl.formatMessage(messages['logistration.password.label'])}
</label>
<Input
name="password"
id="password"
@@ -485,7 +494,9 @@ class RegistrationPage extends React.Component {
onChange={e => this.handleOnOptional(e)}
required
/>
<p role="presentation" id="additionalFields" onClick={e => this.handleOnOptional(e)}>Support education research by providing additional information</p>
<p role="presentation" id="additionalFields" onClick={e => this.handleOnOptional(e)}>
{intl.formatMessage(messages['logistration.support.education.research'])}
</p>
</ValidationFormGroup>
{ this.state.enableOptionalField ? this.addExtraOptionalFields() : null}
<StatefulButton

View File

@@ -86,26 +86,101 @@ const messages = defineMessages({
defaultMessage: 'Register with Institution/Campus Credentials',
description: 'Heading of institution page',
},
'logistration.register.institution.login.page.back.button': {
id: 'logistration.register.institution.login.page.back.button',
'logistration.create.an.account': {
id: 'logistration.create.an.account',
defaultMessage: 'Create an Account',
description: 'return to login page',
description: 'Message on button to return to register page',
},
'logistration.login.institution.login.sign.in': {
id: 'logistration.login.institution.login.sign.in',
defaultMessage: 'Sign In',
description: 'Sign In text',
},
'logistration.login.institution.login.sign.in.with': {
id: 'logistration.login.institution.login.sign.in.with',
'logistration.or.sign.in.with': {
id: 'logistration.or.sign.in.with',
defaultMessage: 'or sign in with',
description: 'gives hint about other sign options',
description: 'gives hint about other sign in options',
},
'logistration.non.compliant.password.title': {
id: 'logistration.non.compliant.password.title',
defaultMessage: 'We recently changed our password requirements',
description: 'A title that appears in bold before error message for non-compliant password',
},
'logistration.first.time.here': {
id: 'logistration.first.time.here',
defaultMessage: 'First time here?',
description: 'A question that appears before sign up link',
},
'logistration.login.page.email.label': {
id: 'logistration.login.page.email.label',
defaultMessage: 'Email',
description: 'Label that appears above email field',
},
'logistration.register.page.email.label': {
id: 'logistration.register.page.email.label',
defaultMessage: 'Email (required)',
description: 'Label that appears above email field on register page',
},
'logistration.email.format.validation.message': {
id: 'logistration.email.format.validation.message',
defaultMessage: 'The email address you\'ve provided isn\'t formatted correctly.',
description: 'Validation message that appears when email address format is incorrect',
},
'logistration.email.validation.message': {
id: 'logistration.email.validation.message',
defaultMessage: 'Enter a valid email address that contains at least 3 characters.',
description: 'Validation message that appears when email address is empty',
},
'logistration.email.help.message': {
id: 'logistration.email.help.message',
defaultMessage: 'The email address you used to register with edX.',
description: 'Message that appears below email field on login page',
},
'logistration.password': {
id: 'logistration.password',
defaultMessage: 'Password',
description: 'Text that appears above password field or as a placeholder',
},
'logistration.password.label': {
id: 'logistration.password.label',
defaultMessage: 'Password (required)',
description: 'Label that appears above password field',
},
'logistration.login.page.password.validation.message': {
id: 'logistration.login.page.password.validation.message',
defaultMessage: 'Please enter your password.',
description: 'Validation message that appears when password is empty',
},
'logistration.register.page.password.validation.message': {
id: 'logistration.register.page.password.validation.message',
defaultMessage: 'This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.',
description: 'Validation message that appears when password is non compliant with edX requirement',
},
'logistration.fullname.label': {
id: 'logistration.fullname.label',
defaultMessage: 'Full Name (required)',
description: 'Label that appears above fullname field',
},
'logistration.fullname.validation.message': {
id: 'logistration.fullname.validation.message',
defaultMessage: 'Enter your full name.',
description: 'Validation message that appears when fullname is empty',
},
'logistration.username.label': {
id: 'logistration.username.label',
defaultMessage: 'Public Username (required)',
description: 'Label that appears above username field',
},
'logistration.username.validation.message': {
id: 'logistration.username.validation.message',
defaultMessage: 'Username must be between 2 and 30 characters long.',
description: 'Validation message that appears when username is invalid',
},
'logistration.support.education.research': {
id: 'logistration.support.education.research',
defaultMessage: 'Support education research by providing additional information',
description: 'Text for a checkbox to ask user for if they are willing to provide extra information for education research',
},
});
export default messages;

View File

@@ -3,6 +3,7 @@ import { IntlProvider } from '@edx/frontend-platform/i18n';
import { mount } from 'enzyme';
import LoginHelpLinks from '../LoginHelpLinks';
import { LOGIN_PAGE } from '../../data/constants';
describe('LoginHelpLinks', () => {
let props = {};
@@ -17,7 +18,7 @@ describe('LoginHelpLinks', () => {
it('renders help links on button click', () => {
props = {
...props,
page: 'login',
page: LOGIN_PAGE,
};
const loginHelpLinks = mount(reduxWrapper(<LoginHelpLinks {...props} />));
@@ -29,7 +30,7 @@ describe('LoginHelpLinks', () => {
it('should display login page help links', () => {
props = {
...props,
page: 'login',
page: LOGIN_PAGE,
};
const wrapper = mount(reduxWrapper(<LoginHelpLinks {...props} />));

View File

@@ -33,6 +33,7 @@ describe('./RegistrationPage.js', () => {
errorMessages: {
required: 'You must agree to the Your Platform Name Here Honor Code',
},
required: true,
}],
},
},
@@ -153,25 +154,12 @@ describe('./RegistrationPage.js', () => {
...initialState.logistration,
formData: {
fields: [
{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: validationMessage.honorCode,
},
required: true,
},
...initialState.logistration.formData.fields,
{
label: 'The country or region where you live.',
name: 'country',
type: 'select',
options: [{
value: '', name: '--',
},
{
value: 'AF', name: 'Afghanistan',
}],
options: [{ value: '', name: '--' }, { value: 'AF', name: 'Afghanistan' }],
errorMessages: {
required: validationMessage.country,
},
@@ -193,15 +181,16 @@ describe('./RegistrationPage.js', () => {
});
it('should toggle optional fields state on checkbox click', () => {
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional').simulate('change', { target: { checked: true } });
registrationPage.update();
expect(registrationPage.find('RegistrationPage').state('enableOptionalField')).toEqual(true);
});
it('should toggle optional fields state on text click', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('#additionalFields').simulate('click');
expect(registrationPage.find('RegistrationPage').state('enableOptionalField')).toEqual(true);
});
@@ -211,28 +200,27 @@ describe('./RegistrationPage.js', () => {
logistration: {
...initialState.logistration,
formData: {
fields: [{
label: 'Tell us why you\'re interested in edX',
name: 'goals',
type: 'textarea',
required: false,
},
{
label: 'Highest level of Education completed.',
name: 'level_of_education',
type: 'select',
options: [{
value: '', name: '--',
fields: [
{
label: 'Tell us why you\'re interested in edX',
name: 'goals',
type: 'textarea',
required: false,
},
{
value: 'p', name: 'Doctorate',
}],
required: false,
}],
label: 'Highest level of Education completed.',
name: 'level_of_education',
type: 'select',
options: [{ value: '', name: '--' }, { value: 'p', name: 'Doctorate' }],
required: false,
},
],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional').simulate('change', { target: { checked: true } });
registrationPage.update();
expect(registrationPage.find('textarea#goals').length).toEqual(1);

View File

@@ -21,7 +21,8 @@ exports[`LoginPage should match TPA provider snapshot 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>
@@ -225,7 +226,8 @@ exports[`LoginPage should match default section snapshot 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>
@@ -395,7 +397,8 @@ exports[`LoginPage should match forget password alert message snapshot 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>
@@ -565,7 +568,8 @@ exports[`LoginPage should match pending button state snapshot 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>
@@ -767,7 +771,8 @@ exports[`LoginPage should show error message on 400 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>
@@ -968,7 +973,8 @@ exports[`LoginPage should show error message on 400 on receiving link 1`] = `
className="ml-1"
href="/register"
>
Create an Account.
Create an Account
.
</a>
</p>
</div>

View File

@@ -167,6 +167,36 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.
</strong>
</div>
<div
className="form-group custom-control"
>
<input
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
>
Honor Code
</a>
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
</strong>
</div>
<div
className="form-group custom-control"
>
@@ -334,6 +364,36 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.
</strong>
</div>
<div
className="form-group custom-control"
>
<input
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
>
Honor Code
</a>
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
</strong>
</div>
<div
className="form-group custom-control"
>
@@ -501,6 +561,36 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.
</strong>
</div>
<div
className="form-group custom-control"
>
<input
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
>
Honor Code
</a>
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
</strong>
</div>
<div
className="form-group custom-control"
>
@@ -715,6 +805,36 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.
</strong>
</div>
<div
className="form-group custom-control"
>
<input
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
>
Honor Code
</a>
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
</strong>
</div>
<div
className="form-group custom-control"
>