Extracted strings and fixes on localization support
Language chooser in the UI
This commit is contained in:
parent
9f449c0a2f
commit
dc7789c17b
126 changed files with 2919 additions and 2028 deletions
|
|
@ -1,24 +1,40 @@
|
|||
'use strict';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes
|
||||
from 'prop-types';
|
||||
import {HTTPMethod} from '../../lib/axios';
|
||||
import { translate, Trans } from 'react-i18next';
|
||||
import {requiresAuthenticatedUser, withPageHelpers, Title, NavButton} from '../../lib/page';
|
||||
import {withTranslation} from '../../lib/i18n';
|
||||
import {
|
||||
withForm, Form, FormSendMethod, InputField, TextArea, TableSelect, ButtonRow, Button,
|
||||
Fieldset, Dropdown, AlignedRow, ACEEditor, StaticField, CheckBox
|
||||
NavButton,
|
||||
requiresAuthenticatedUser,
|
||||
Title,
|
||||
withPageHelpers
|
||||
} from '../../lib/page';
|
||||
import {
|
||||
AlignedRow,
|
||||
Button,
|
||||
ButtonRow,
|
||||
CheckBox,
|
||||
Dropdown,
|
||||
Form,
|
||||
FormSendMethod,
|
||||
InputField,
|
||||
withForm
|
||||
} from '../../lib/form';
|
||||
import { withErrorHandling, withAsyncErrorHandler } from '../../lib/error-handling';
|
||||
import {DeleteModalDialog, RestActionModalDialog} from "../../lib/modals";
|
||||
import interoperableErrors from '../../../../shared/interoperable-errors';
|
||||
import validators from '../../../../shared/validators';
|
||||
import { parseDate, parseBirthday, DateFormat } from '../../../../shared/date';
|
||||
import { SubscriptionStatus } from '../../../../shared/lists';
|
||||
import {getFieldTypes, getSubscriptionStatusLabels} from './helpers';
|
||||
import moment from 'moment-timezone';
|
||||
import {withErrorHandling} from '../../lib/error-handling';
|
||||
import {RestActionModalDialog} from "../../lib/modals";
|
||||
import interoperableErrors
|
||||
from '../../../../shared/interoperable-errors';
|
||||
import {SubscriptionStatus} from '../../../../shared/lists';
|
||||
import {
|
||||
getFieldTypes,
|
||||
getSubscriptionStatusLabels
|
||||
} from './helpers';
|
||||
import moment
|
||||
from 'moment-timezone';
|
||||
|
||||
@translate()
|
||||
@withTranslation()
|
||||
@withForm
|
||||
@withPageHelpers
|
||||
@withErrorHandling
|
||||
|
|
@ -82,11 +98,11 @@ export default class CUD extends Component {
|
|||
|
||||
const emailServerValidation = state.getIn(['email', 'serverValidation']);
|
||||
if (!state.getIn(['email', 'value'])) {
|
||||
state.setIn(['email', 'error'], t('Email must not be empty'));
|
||||
state.setIn(['email', 'error'], t('emailMustNotBeEmpty-1'));
|
||||
} else if (!emailServerValidation) {
|
||||
state.setIn(['email', 'error'], t('Validation is in progress...'));
|
||||
state.setIn(['email', 'error'], t('validationIsInProgress'));
|
||||
} else if (emailServerValidation.exists) {
|
||||
state.setIn(['email', 'error'], t('Another subscription with the same email already exists.'));
|
||||
state.setIn(['email', 'error'], t('anotherSubscriptionWithTheSameEmail'));
|
||||
} else {
|
||||
state.setIn(['email', 'error'], null);
|
||||
}
|
||||
|
|
@ -110,7 +126,7 @@ export default class CUD extends Component {
|
|||
|
||||
try {
|
||||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('Saving ...'));
|
||||
this.setFormStatusMessage('info', t('saving'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
data.status = parseInt(data.status);
|
||||
|
|
@ -122,17 +138,17 @@ export default class CUD extends Component {
|
|||
});
|
||||
|
||||
if (submitSuccessful) {
|
||||
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('Susbscription saved'));
|
||||
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('susbscriptionSaved'));
|
||||
} else {
|
||||
this.enableForm();
|
||||
this.setFormStatusMessage('warning', t('There are errors in the form. Please fix them and submit again.'));
|
||||
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof interoperableErrors.DuplicitEmailError) {
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('It seems that another subscription with the same email has been created in the meantime. Refresh your page to start anew. Please note that your changes will be lost.')}
|
||||
<strong>{t('yourUpdatesCannotBeSaved')}</strong>{' '}
|
||||
{t('itSeemsThatAnotherSubscriptionWithThe')}
|
||||
</span>
|
||||
);
|
||||
return;
|
||||
|
|
@ -152,7 +168,7 @@ export default class CUD extends Component {
|
|||
.map(key => ({key, label: this.subscriptionStatusLabels[key]}));
|
||||
|
||||
const tzOptions = [
|
||||
{ key: '', label: t('Not selected') },
|
||||
{ key: '', label: t('notSelected') },
|
||||
...moment.tz.names().map(tz => ({ key: tz.toLowerCase(), label: tz }))
|
||||
];
|
||||
|
||||
|
|
@ -166,33 +182,33 @@ export default class CUD extends Component {
|
|||
{isEdit &&
|
||||
<div>
|
||||
<RestActionModalDialog
|
||||
title={t('Confirm deletion')}
|
||||
message={t('Are you sure you want to delete subscription for "{{email}}"?', {name: this.getFormValue('email')})}
|
||||
title={t('confirmDeletion')}
|
||||
message={t('areYouSureYouWantToDeleteSubscriptionFor', {email: this.getFormValue('email') || ''})}
|
||||
stateOwner={this}
|
||||
visible={this.props.action === 'delete'}
|
||||
actionMethod={HTTPMethod.DELETE}
|
||||
actionUrl={`rest/subscriptions/${this.props.list.id}/${this.props.entity.id}`}
|
||||
backUrl={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/edit`}
|
||||
successUrl={`/lists/${this.props.list.id}/subscriptions`}
|
||||
actionInProgressMsg={t('Deleting subscription ...')}
|
||||
actionDoneMsg={t('Subscription deleted')}/>
|
||||
actionInProgressMsg={t('deletingSubscription')}
|
||||
actionDoneMsg={t('subscriptionDeleted')}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<Title>{isEdit ? t('Edit Subscription') : t('Create Subscription')}</Title>
|
||||
<Title>{isEdit ? t('editSubscription') : t('createSubscription')}</Title>
|
||||
|
||||
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
|
||||
<InputField id="email" label={t('Email')}/>
|
||||
<InputField id="email" label={t('email')}/>
|
||||
|
||||
{customFields}
|
||||
|
||||
<hr />
|
||||
|
||||
<Dropdown id="tz" label={t('Timezone')} options={tzOptions}/>
|
||||
<Dropdown id="tz" label={t('timezone')} options={tzOptions}/>
|
||||
|
||||
<Dropdown id="status" label={t('Subscription status')} options={statusOptions}/>
|
||||
<Dropdown id="status" label={t('subscriptionStatus')} options={statusOptions}/>
|
||||
|
||||
<CheckBox id="is_test" text={t('Test user?')} help={t('If checked then this subscription can be used for previewing campaign messages')}/>
|
||||
<CheckBox id="is_test" text={t('testUser?')} help={t('ifCheckedThenThisSubscriptionCanBeUsed')}/>
|
||||
|
||||
{!isEdit &&
|
||||
<AlignedRow>
|
||||
|
|
@ -203,8 +219,8 @@ export default class CUD extends Component {
|
|||
</AlignedRow>
|
||||
}
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Save')}/>
|
||||
{isEdit && <NavButton className="btn-danger" icon="remove" label={t('Delete')} linkTo={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/delete`}/>}
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
{isEdit && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate } from 'react-i18next';
|
||||
import { withTranslation } from '../../lib/i18n';
|
||||
import {requiresAuthenticatedUser, withPageHelpers, Title, Toolbar, NavButton} from '../../lib/page';
|
||||
import {withAsyncErrorHandler, withErrorHandling} from '../../lib/error-handling';
|
||||
import { Table } from '../../lib/table';
|
||||
|
|
@ -22,7 +22,7 @@ import {
|
|||
tableDeleteDialogRender
|
||||
} from "../../lib/modals";
|
||||
|
||||
@translate()
|
||||
@withTranslation()
|
||||
@withForm
|
||||
@withPageHelpers
|
||||
@withErrorHandling
|
||||
|
|
@ -86,10 +86,10 @@ export default class List extends Component {
|
|||
const segments = this.props.segments;
|
||||
|
||||
const columns = [
|
||||
{ data: 1, title: t('ID'), render: data => <code>{data}</code> },
|
||||
{ data: 2, title: t('Email') },
|
||||
{ data: 3, title: t('Status'), render: (data, display, rowData) => this.subscriptionStatusLabels[data] + (rowData[5] ? ', ' + t('Blacklisted') : '') },
|
||||
{ data: 4, title: t('Created'), render: data => data ? moment(data).fromNow() : '' }
|
||||
{ data: 1, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 2, title: t('email') },
|
||||
{ data: 3, title: t('status'), render: (data, display, rowData) => this.subscriptionStatusLabels[data] + (rowData[5] ? ', ' + t('blacklisted') : '') },
|
||||
{ data: 4, title: t('created'), render: data => data ? moment(data).fromNow() : '' }
|
||||
];
|
||||
|
||||
let colIdx = 6;
|
||||
|
|
@ -114,20 +114,20 @@ export default class List extends Component {
|
|||
const actions = [];
|
||||
|
||||
actions.push({
|
||||
label: <Icon icon="edit" title={t('Edit')}/>,
|
||||
label: <Icon icon="edit" title={t('edit')}/>,
|
||||
link: `/lists/${this.props.list.id}/subscriptions/${data[0]}/edit`
|
||||
});
|
||||
|
||||
if (data[3] === SubscriptionStatus.SUBSCRIBED) {
|
||||
actions.push({
|
||||
label: <Icon icon="off" title={t('Unsubscribe')}/>,
|
||||
label: <Icon icon="off" title={t('unsubscribe')}/>,
|
||||
action: () => this.unsubscribeSubscription(data[0])
|
||||
});
|
||||
}
|
||||
|
||||
if (!data[5]) {
|
||||
actions.push({
|
||||
label: <Icon icon="ban-circle" title={t('Blacklist')}/>,
|
||||
label: <Icon icon="ban-circle" title={t('blacklist')}/>,
|
||||
action: () => this.blacklistSubscription(data[2])
|
||||
});
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ export default class List extends Component {
|
|||
}
|
||||
|
||||
const segmentOptions = [
|
||||
{key: '', label: t('All subscriptions')},
|
||||
{key: '', label: t('allSubscriptions')},
|
||||
...segments.map(x => ({ key: x.id.toString(), label: x.name}))
|
||||
];
|
||||
|
||||
|
|
@ -154,14 +154,14 @@ export default class List extends Component {
|
|||
// FIXME - presents segments in a data table as in campaign edit
|
||||
return (
|
||||
<div>
|
||||
{tableDeleteDialogRender(this, `rest/subscriptions/${this.props.list.id}`, t('Deleting subscription ...'), t('Subscription deleted'))}
|
||||
{tableDeleteDialogRender(this, `rest/subscriptions/${this.props.list.id}`, t('deletingSubscription'), t('subscriptionDeleted'))}
|
||||
<Toolbar>
|
||||
<a href={getPublicUrl(`subscription/${this.props.list.cid}`)}><Button label={t('Subscription Form')} className="btn-default"/></a>
|
||||
<a href={getUrl(`subscriptions/export/${this.props.list.id}/`+ (this.props.segmentId || 0))}><Button label={t('Export as CSV')} className="btn-primary"/></a>
|
||||
<NavButton linkTo={`/lists/${this.props.list.id}/subscriptions/create`} className="btn-primary" icon="plus" label={t('Add Subscriber')}/>
|
||||
<a href={getPublicUrl(`subscription/${this.props.list.cid}`)}><Button label={t('subscriptionForm')} className="btn-default"/></a>
|
||||
<a href={getUrl(`subscriptions/export/${this.props.list.id}/`+ (this.props.segmentId || 0))}><Button label={t('exportAsCsv')} className="btn-primary"/></a>
|
||||
<NavButton linkTo={`/lists/${this.props.list.id}/subscriptions/create`} className="btn-primary" icon="plus" label={t('addSubscriber')}/>
|
||||
</Toolbar>
|
||||
|
||||
<Title>{t('Subscribers')}</Title>
|
||||
<Title>{t('subscribers')}</Title>
|
||||
|
||||
{list.description &&
|
||||
<div className="well well-sm">{list.description}</div>
|
||||
|
|
@ -169,7 +169,7 @@ export default class List extends Component {
|
|||
|
||||
<div className="well well-sm">
|
||||
<Form format="inline" stateOwner={this}>
|
||||
<Dropdown format="inline" className="input-sm" id="segment" label={t('Segment')} options={segmentOptions}/>
|
||||
<Dropdown format="inline" className="input-sm" id="segment" label={t('segment')} options={segmentOptions}/>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ import 'brace/mode/json';
|
|||
export function getSubscriptionStatusLabels(t) {
|
||||
|
||||
const subscriptionStatusLabels = {
|
||||
[SubscriptionStatus.SUBSCRIBED]: t('Subscribed'),
|
||||
[SubscriptionStatus.UNSUBSCRIBED]: t('Unubscribed'),
|
||||
[SubscriptionStatus.BOUNCED]: t('Bounced'),
|
||||
[SubscriptionStatus.COMPLAINED]: t('Complained'),
|
||||
[SubscriptionStatus.SUBSCRIBED]: t('subscribed'),
|
||||
[SubscriptionStatus.UNSUBSCRIBED]: t('unubscribed'),
|
||||
[SubscriptionStatus.BOUNCED]: t('bounced'),
|
||||
[SubscriptionStatus.COMPLAINED]: t('complained'),
|
||||
};
|
||||
|
||||
return subscriptionStatusLabels;
|
||||
|
|
@ -52,7 +52,7 @@ export function getFieldTypes(t) {
|
|||
validate: (groupedField, state) => {
|
||||
const value = state.getIn([getFieldColumn(groupedField), 'value']).trim();
|
||||
if (value !== '' && isNaN(value)) {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('Value must be a number'));
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('valueMustBeANumber'));
|
||||
} else {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], null);
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ export function getFieldTypes(t) {
|
|||
const value = state.getIn([getFieldColumn(groupedField), 'value']);
|
||||
const date = parseDate(groupedField.settings.dateFormat, value);
|
||||
if (value !== '' && !date) {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('Date is invalid'));
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('dateIsInvalid'));
|
||||
} else {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], null);
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ export function getFieldTypes(t) {
|
|||
const value = state.getIn([getFieldColumn(groupedField), 'value']);
|
||||
const date = parseBirthday(groupedField.settings.dateFormat, value);
|
||||
if (value !== '' && !date) {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('Date is invalid'));
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], t('dateIsInvalid'));
|
||||
} else {
|
||||
state.setIn([getFieldColumn(groupedField), 'error'], null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue