Upgrade of modules and webpack.
Support for localization in progress.
This commit is contained in:
parent
d8b56fff0d
commit
4862d6cac4
52 changed files with 5870 additions and 23064 deletions
|
|
@ -1,10 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {translate} from 'react-i18next';
|
||||
import { withNamespaces } from 'react-i18next';
|
||||
import { requiresAuthenticatedUser } from './lib/page';
|
||||
|
||||
@translate()
|
||||
@withNamespaces()
|
||||
@requiresAuthenticatedUser
|
||||
export default class List extends Component {
|
||||
constructor(props) {
|
||||
|
|
@ -16,7 +16,7 @@ export default class List extends Component {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<h2>{t('Welcome to Mailtrain...')}</h2>
|
||||
<h2>{t('home.welcome')}</h2>
|
||||
<div>TODO: some dashboard</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ export default class Account extends Component {
|
|||
const emailServerValidation = state.getIn(['email', 'serverValidation']);
|
||||
|
||||
if (!email) {
|
||||
state.setIn(['email', 'error'], t('Email must not be empty.'));
|
||||
state.setIn(['email', 'error'], t('emailMustNotBeEmpty'));
|
||||
} else if (emailServerValidation && emailServerValidation.invalid) {
|
||||
state.setIn(['email', 'error'], t('Invalid email address.'));
|
||||
state.setIn(['email', 'error'], t('invalidEmailAddress'));
|
||||
} else if (emailServerValidation && emailServerValidation.exists) {
|
||||
state.setIn(['email', 'error'], t('The email is already associated with another user in the system.'));
|
||||
state.setIn(['email', 'error'], t('account.emailAlreadyRegistered'));
|
||||
} else if (!emailServerValidation) {
|
||||
state.setIn(['email', 'error'], t('Validation is in progress...'));
|
||||
state.setIn(['email', 'error'], t('validationInProgress'));
|
||||
} else {
|
||||
state.setIn(['email', 'error'], null);
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ export default class Account extends Component {
|
|||
const name = state.getIn(['name', 'value']);
|
||||
|
||||
if (!name) {
|
||||
state.setIn(['name', 'error'], t('Full name must not be empty'));
|
||||
state.setIn(['name', 'error'], t('account.fullNameMustNotBeEmpty'));
|
||||
} else {
|
||||
state.setIn(['name', 'error'], null);
|
||||
}
|
||||
|
|
@ -88,11 +88,11 @@ export default class Account extends Component {
|
|||
const currentPasswordServerValidation = state.getIn(['currentPassword', 'serverValidation']);
|
||||
|
||||
if (!currentPassword) {
|
||||
state.setIn(['currentPassword', 'error'], t('Current password must not be empty.'));
|
||||
state.setIn(['currentPassword', 'error'], t('account.currentPasswordMustNotBeEmpty'));
|
||||
} else if (currentPasswordServerValidation && currentPasswordServerValidation.incorrect) {
|
||||
state.setIn(['currentPassword', 'error'], t('Incorrect password.'));
|
||||
state.setIn(['currentPassword', 'error'], t('account.incorrectPassword'));
|
||||
} else if (!currentPasswordServerValidation) {
|
||||
state.setIn(['email', 'error'], t('Validation is in progress...'));
|
||||
state.setIn(['email', 'error'], t('validationInProgress'));
|
||||
} else {
|
||||
state.setIn(['currentPassword', 'error'], null);
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ export default class Account extends Component {
|
|||
}
|
||||
|
||||
state.setIn(['password', 'error'], passwordMsgs.length > 0 ? passwordMsgs : null);
|
||||
state.setIn(['password2', 'error'], password !== password2 ? t('Passwords must match') : null);
|
||||
state.setIn(['password2', 'error'], password !== password2 ? t('account.passwordsMustMatch') : null);
|
||||
}
|
||||
|
||||
async submitHandler() {
|
||||
|
|
@ -112,14 +112,14 @@ export default class Account extends Component {
|
|||
|
||||
try {
|
||||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('Updating user profile ...'));
|
||||
this.setFormStatusMessage('info', t('account.updatingUserProfile'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(FormSendMethod.POST, 'rest/account', data => {
|
||||
delete data.password2;
|
||||
});
|
||||
|
||||
if (submitSuccessful) {
|
||||
this.setFlashMessage('success', t('User profile updated'));
|
||||
this.setFlashMessage('success', t('account.userProfileUpdated'));
|
||||
this.hideFormValidation();
|
||||
this.updateFormValue('password', '');
|
||||
this.updateFormValue('password2', '');
|
||||
|
|
@ -130,7 +130,7 @@ export default class Account extends Component {
|
|||
|
||||
} else {
|
||||
this.enableForm();
|
||||
this.setFormStatusMessage('warning', t('There are errors in the form. Please fix them and submit again.'));
|
||||
this.setFormStatusMessage('warning', t('errorsInForm'));
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof interoperableErrors.IncorrectPasswordError) {
|
||||
|
|
@ -138,8 +138,8 @@ export default class Account extends Component {
|
|||
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('The password is incorrect (possibly just changed in another window / session). Enter correct password and try again.')}
|
||||
<strong>{t('updatesCannotBeSaved')}</strong>{' '}
|
||||
{t('account.passwordPossiblyChanged')}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
|
@ -152,8 +152,8 @@ export default class Account extends Component {
|
|||
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('The email is already assigned to another user. Enter another email and try again.')}
|
||||
<strong>{t('updatesCannotBeSaved')}</strong>{' '}
|
||||
{t('account.emailAlreadyRegisteredTryAgain')}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
|
@ -171,23 +171,23 @@ export default class Account extends Component {
|
|||
if (mailtrainConfig.isAuthMethodLocal) {
|
||||
return (
|
||||
<div>
|
||||
<Title>{t('Account')}</Title>
|
||||
<Title>{t('root.account')}</Title>
|
||||
|
||||
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
|
||||
<Fieldset label={t('General Settings')}>
|
||||
<InputField id="name" label={t('Full Name')}/>
|
||||
<InputField id="email" label={t('Email')} help={t('This address is used for account recovery in case you loose your password')}/>
|
||||
<Fieldset label={t('account.generalSettings')}>
|
||||
<InputField id="name" label={t('account.fullName')}/>
|
||||
<InputField id="email" label={t('email')} help={t('account.addressUsedForAccountRecovery')}/>
|
||||
</Fieldset>
|
||||
|
||||
<Fieldset label={t('Password Change')}>
|
||||
<p>{t('You only need to fill out this form if you want to change your current password')}</p>
|
||||
<InputField id="currentPassword" label={t('Current Password')} type="password" />
|
||||
<InputField id="password" label={t('New Password')} type="password" />
|
||||
<InputField id="password2" label={t('Confirm Password')} type="password" />
|
||||
<Fieldset label={t('account.passwordChange')}>
|
||||
<p>{t('account.fillOnlyForPasswordChange')}</p>
|
||||
<InputField id="currentPassword" label={t('account.currentPassword')} type="password" />
|
||||
<InputField id="password" label={t('account.newPassword')} type="password" />
|
||||
<InputField id="password2" label={t('account.confirmPassword')} type="password" />
|
||||
</Fieldset>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Update')}/>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('update')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
@ -195,11 +195,11 @@ export default class Account extends Component {
|
|||
} else {
|
||||
return (
|
||||
<div>
|
||||
<Title>{t('Account')}</Title>
|
||||
<Title>{t('root.account')}</Title>
|
||||
|
||||
<p>{t('Account management is not possible because Mailtrain is configured to use externally managed users.')}</p>
|
||||
<p>{t('account.accountManagementNotPossible')}</p>
|
||||
|
||||
{mailtrainConfig.externalPasswordResetLink && <p><Trans>If you want to change the password, use <a href={mailtrainConfig.externalPasswordResetLink}>this link</a>.</Trans></p>}
|
||||
{mailtrainConfig.externalPasswordResetLink && <p><Trans i18nKey="useThisLinkToChangePassword">If you want to change the password, use <a href={mailtrainConfig.externalPasswordResetLink}>this link</a>.</Trans></p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,6 @@ class SendControls extends Component {
|
|||
const t = this.props.t;
|
||||
const entity = this.props.entity;
|
||||
|
||||
console.log(entity);
|
||||
if (entity.status === CampaignStatus.IDLE || entity.status === CampaignStatus.PAUSED || (entity.status === CampaignStatus.SCHEDULED && entity.scheduled)) {
|
||||
|
||||
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers')})`;
|
||||
|
|
|
|||
6
client/src/lib/bootstrap-components.js
vendored
6
client/src/lib/bootstrap-components.js
vendored
|
|
@ -25,7 +25,7 @@ class DismissibleAlert extends Component {
|
|||
|
||||
return (
|
||||
<div className={`alert alert-${this.props.severity} alert-dismissible`} role="alert">
|
||||
<button type="button" className="close" aria-label={t('Close')} onClick={::this.onClose}><span aria-hidden="true">×</span></button>
|
||||
<button type="button" className="close" aria-label={t('close')} onClick={::this.onClose}><span aria-hidden="true">×</span></button>
|
||||
{this.props.children}
|
||||
</div>
|
||||
)
|
||||
|
|
@ -201,7 +201,7 @@ class ModalDialog extends Component {
|
|||
const t = props.t;
|
||||
|
||||
this.state = {
|
||||
buttons: this.props.buttons || [ { label: t('Close'), className: 'btn-default', onClickAsync: null } ]
|
||||
buttons: this.props.buttons || [ { label: t('close'), className: 'btn-default', onClickAsync: null } ]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ class ModalDialog extends Component {
|
|||
<div className="modal-dialog" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<button type="button" className="close" aria-label={t('Close')} onClick={::this.onClose}><span aria-hidden="true">×</span></button>
|
||||
<button type="button" className="close" aria-label={t('close')} onClick={::this.onClose}><span aria-hidden="true">×</span></button>
|
||||
<h4 className="modal-title">{this.props.title}</h4>
|
||||
</div>
|
||||
<div className="modal-body">{this.props.children}</div>
|
||||
|
|
|
|||
|
|
@ -50,22 +50,22 @@ export default class Files extends Component {
|
|||
const t = this.props.t;
|
||||
const details = [];
|
||||
if (response.data.added) {
|
||||
details.push(t('{{count}} file(s) added', {count: response.data.added}));
|
||||
details.push(t('files.filesAdded', {count: response.data.added}));
|
||||
}
|
||||
if (response.data.replaced) {
|
||||
details.push(t('{{count}} file(s) replaced', {count: response.data.replaced}));
|
||||
details.push(t('files.filesReplaced', {count: response.data.replaced}));
|
||||
}
|
||||
if (response.data.ignored) {
|
||||
details.push(t('{{count}} file(s) ignored', {count: response.data.ignored}));
|
||||
details.push(t('files.filesIgnored', {count: response.data.ignored}));
|
||||
}
|
||||
const detailsMessage = details ? ' (' + details.join(', ') + ')' : '';
|
||||
return t('{{count}} file(s) uploaded', {count: response.data.uploaded}) + detailsMessage;
|
||||
return t('files.filesUploaded', {count: response.data.uploaded}) + detailsMessage;
|
||||
}
|
||||
|
||||
onDrop(files){
|
||||
const t = this.props.t;
|
||||
if (files.length > 0) {
|
||||
this.setFlashMessage('info', t('Uploading {{count}} file(s)', files.length));
|
||||
this.setFlashMessage('info', t('files.uploadingFiles', {count: files.length}));
|
||||
const data = new FormData();
|
||||
for (const file of files) {
|
||||
data.append('files[]', file)
|
||||
|
|
@ -76,10 +76,10 @@ export default class Files extends Component {
|
|||
const message = this.getFilesUploadedMessage(res);
|
||||
this.setFlashMessage('info', message);
|
||||
})
|
||||
.catch(res => this.setFlashMessage('danger', t('File upload failed: ') + res.message));
|
||||
.catch(res => this.setFlashMessage('danger', t('files.fileUploadFailed') + ' ' + res.message));
|
||||
}
|
||||
else{
|
||||
this.setFlashMessage('info', t('No files to upload'));
|
||||
this.setFlashMessage('info', t('files.noFilesToUpload'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,13 +97,13 @@ export default class Files extends Component {
|
|||
await this.hideDeleteFile();
|
||||
|
||||
try {
|
||||
this.setFlashMessage('info', t('Deleting file ...'));
|
||||
this.setFlashMessage('info', t('files.deletingFile'));
|
||||
await axios.delete(getUrl(`rest/files/${this.props.entityTypeId}/${this.props.entitySubTypeId}/${fileToDeleteId}`));
|
||||
this.filesTable.refresh();
|
||||
this.setFlashMessage('info', t('File deleted'));
|
||||
this.setFlashMessage('info', t('files.fileDeleted'));
|
||||
} catch (err) {
|
||||
this.filesTable.refresh();
|
||||
this.setFlashMessage('danger', t('Delete file failed: ') + err.message);
|
||||
this.setFlashMessage('danger', t('files.deleteFileFailed') + ' ' + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +111,8 @@ export default class Files extends Component {
|
|||
const t = this.props.t;
|
||||
|
||||
const columns = [
|
||||
{ data: 1, title: "Name" },
|
||||
{ data: 3, title: "Size" },
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 3, title: t('size') },
|
||||
{
|
||||
actions: data => {
|
||||
const actions = [];
|
||||
|
|
@ -125,13 +125,13 @@ export default class Files extends Component {
|
|||
}
|
||||
|
||||
actions.push({
|
||||
label: <Icon icon="download" title={t('Download')}/>,
|
||||
label: <Icon icon="download" title={t('download')}/>,
|
||||
href: downloadUrl
|
||||
});
|
||||
|
||||
if (this.props.entity.permissions.includes(this.props.managePermission)) {
|
||||
actions.push({
|
||||
label: <Icon icon="remove" title={t('Delete')}/>,
|
||||
label: <Icon icon="remove" title={t('delete')}/>,
|
||||
action: () => this.deleteFile(data[0], data[1])
|
||||
});
|
||||
}
|
||||
|
|
@ -145,13 +145,13 @@ export default class Files extends Component {
|
|||
<div>
|
||||
<ModalDialog
|
||||
hidden={this.state.fileToDeleteId === null}
|
||||
title={t('Confirm file deletion')}
|
||||
title={t('files.confirmFileDeletion')}
|
||||
onCloseAsync={::this.hideDeleteFile}
|
||||
buttons={[
|
||||
{ label: t('No'), className: 'btn-primary', onClickAsync: ::this.hideDeleteFile },
|
||||
{ label: t('Yes'), className: 'btn-danger', onClickAsync: ::this.performDeleteFile }
|
||||
{ label: t('no'), className: 'btn-primary', onClickAsync: ::this.hideDeleteFile },
|
||||
{ label: t('yes'), className: 'btn-danger', onClickAsync: ::this.performDeleteFile }
|
||||
]}>
|
||||
{t('Are you sure you want to delete file "{{name}}"?', {name: this.state.fileToDeleteName})}
|
||||
{t('files:areYouSureToDeleteFile', {name: this.state.fileToDeleteName})}
|
||||
</ModalDialog>
|
||||
|
||||
{this.props.title && <Title>{this.props.title}</Title>}
|
||||
|
|
@ -161,7 +161,7 @@ export default class Files extends Component {
|
|||
{
|
||||
this.props.entity.permissions.includes(this.props.managePermission) &&
|
||||
<Dropzone onDrop={::this.onDrop} className={styles.dropZone} activeClassName={styles.dropZoneActive}>
|
||||
{state => state.isDragActive ? t('Drop {{count}} file(s)', {count:state.draggedFiles.length}) : t('Drop files here')}
|
||||
{state => state.isDragActive ? t('files.dropFiles', {count: state.draggedFiles.length}) : t('files.dropFilesHere')}
|
||||
</Dropzone>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class Form extends Component {
|
|||
|
||||
if (!owner.isFormReady()) {
|
||||
if (owner.isFormWithLoadingNotice()) {
|
||||
return <p className={`alert alert-info ${styles.formStatus}`} role="alert">{t('Loading ...')}</p>
|
||||
return <p className={`alert alert-info ${styles.formStatus}`} role="alert">{t('loading')}</p>
|
||||
} else {
|
||||
return <div></div>;
|
||||
}
|
||||
|
|
@ -568,7 +568,7 @@ class DatePicker extends Component {
|
|||
<div>
|
||||
<div className="input-group">
|
||||
<input type="text" value={selectedDateStr} placeholder={placeholder} id={htmlId} className="form-control" aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
<span className="input-group-addon" onClick={::this.toggleDayPicker}><Icon icon="calendar" title={t('Open calendar')}/></span>
|
||||
<span className="input-group-addon" onClick={::this.toggleDayPicker}><Icon icon="calendar" title={t('form.openCalendar')}/></span>
|
||||
</div>
|
||||
{this.state.opened &&
|
||||
<div className={styles.dayPickerWrapper}>
|
||||
|
|
@ -803,7 +803,7 @@ class TableSelect extends Component {
|
|||
<input type="text" className="form-control" value={this.state.selectedLabel} onClick={::this.toggleOpen} readOnly={!props.disabled} disabled={props.disabled}/>
|
||||
{!props.disabled &&
|
||||
<span className="input-group-btn">
|
||||
<Button label={t('Select')} className="btn-default" onClickAsync={::this.toggleOpen}/>
|
||||
<Button label={t('form.select')} className="btn-default" onClickAsync={::this.toggleOpen}/>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -1305,8 +1305,8 @@ function withForm(target) {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('Someone else has introduced modification in the meantime. Refresh your page to start anew with fresh data. Please note that your changes will be lost.')}
|
||||
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
|
||||
{t('form.modificationsInTheMeantime')}
|
||||
</span>
|
||||
);
|
||||
return;
|
||||
|
|
@ -1316,8 +1316,8 @@ function withForm(target) {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('It seems that someone else has deleted the target namespace in the meantime. Refresh your page to start anew with fresh data. Please note that your changes will be lost.')}
|
||||
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
|
||||
{t('form.namespaceDeletedInTheMeantime')}
|
||||
</span>
|
||||
);
|
||||
return;
|
||||
|
|
@ -1327,8 +1327,8 @@ function withForm(target) {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('danger',
|
||||
<span>
|
||||
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
|
||||
{t('It seems that someone else has deleted the entity in the meantime.')}
|
||||
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
|
||||
{t('form.deletionInTheMeantime')}
|
||||
</span>
|
||||
);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,35 +1,34 @@
|
|||
import i18n from 'i18next';
|
||||
import XHR from 'i18next-xhr-backend';
|
||||
// import Cache from 'i18next-localstorage-cache';
|
||||
import { reactI18nextModule } from "react-i18next";
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import mailtrainConfig from 'mailtrainConfig';
|
||||
import {getUrl} from "./urls";
|
||||
|
||||
import commonEn from "../../../locales/common/en";
|
||||
|
||||
i18n
|
||||
.use(XHR)
|
||||
// .use(Cache)
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
lng: mailtrainConfig.language,
|
||||
resources: {
|
||||
en: {
|
||||
common: commonEn
|
||||
}
|
||||
},
|
||||
|
||||
wait: true, // globally set to wait for loaded translations in translate hoc
|
||||
|
||||
// have a common namespace used around the full app
|
||||
ns: ['common'],
|
||||
fallbackLng: "en",
|
||||
defaultNS: 'common',
|
||||
|
||||
debug: false,
|
||||
|
||||
// cache: {
|
||||
// enabled: true
|
||||
// },
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false // not needed for react
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: getUrl('locales/{{lng}}/{{ns}}.json')
|
||||
}
|
||||
});
|
||||
react: {
|
||||
wait: true
|
||||
},
|
||||
|
||||
debug: true
|
||||
})
|
||||
|
||||
|
||||
export default i18n;
|
||||
|
|
@ -87,8 +87,8 @@ export class RestActionModalDialog extends Component {
|
|||
|
||||
return (
|
||||
<ModalDialog hidden={!this.props.visible} title={this.props.title} onCloseAsync={() => this.hideModal(true)} buttons={[
|
||||
{ label: t('No'), className: 'btn-primary', onClickAsync: () => this.hideModal(true) },
|
||||
{ label: t('Yes'), className: 'btn-danger', onClickAsync: ::this.performAction }
|
||||
{ label: t('no'), className: 'btn-primary', onClickAsync: () => this.hideModal(true) },
|
||||
{ label: t('yes'), className: 'btn-danger', onClickAsync: ::this.performAction }
|
||||
]}>
|
||||
{this.props.message}
|
||||
</ModalDialog>
|
||||
|
|
@ -105,15 +105,15 @@ export class DeleteModalDialog extends Component {
|
|||
const t = props.t;
|
||||
|
||||
this.entityTypeLabels = {
|
||||
'namespace': t('Namespace'),
|
||||
'list': t('List'),
|
||||
'customForm': t('Custom forms'),
|
||||
'campaign': t('Campaign'),
|
||||
'template': t('Template'),
|
||||
'sendConfiguration': t('Send configuration'),
|
||||
'report': t('Report'),
|
||||
'reportTemplate': t('Report template'),
|
||||
'mosaicoTemplate': t('Mosaico template')
|
||||
'namespace': t('namespace'),
|
||||
'list': t('list'),
|
||||
'customForm': t('customForms'),
|
||||
'campaign': t('campaign'),
|
||||
'template': t('template'),
|
||||
'sendConfiguration': t('sendConfiguration'),
|
||||
'report': t('report'),
|
||||
'reportTemplate': t('reportTemplate'),
|
||||
'mosaicoTemplate': t('mosaicoTemplate')
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ export class DeleteModalDialog extends Component {
|
|||
const name = this.props.name !== undefined ? this.props.name : (owner ? owner.getFormValue('name') : '');
|
||||
this.setFlashMessage('danger',
|
||||
<div>
|
||||
<p>{t('Cannote delete "{{name}}" due to the following dependencies:', {name, nsSeparator: '|'})}</p>
|
||||
<p>{t('deleteDialog.cannotDeleteDueToDependencies', {name})}</p>
|
||||
<ul className={styles.dependenciesList}>
|
||||
{err.data.dependencies.map(dep =>
|
||||
dep.link ?
|
||||
|
|
@ -153,7 +153,7 @@ export class DeleteModalDialog extends Component {
|
|||
: // if no dep.link is present, it means the user has no permission to view the entity, thus only id without the link is shown
|
||||
<li key={dep.id}>{this.entityTypeLabels[dep.entityTypeId]}: [{dep.id}]</li>
|
||||
)}
|
||||
{err.data.andMore && <li>{t('... and more')}</li>}
|
||||
{err.data.andMore && <li>{t('deleteDialog.andMore')}</li>}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -180,8 +180,8 @@ export class DeleteModalDialog extends Component {
|
|||
const name = this.props.name !== undefined ? this.props.name : (owner ? owner.getFormValue('name') : '');
|
||||
|
||||
return <RestActionModalDialog
|
||||
title={t('Confirm deletion')}
|
||||
message={t('Are you sure you want to delete "{{name}}"?', {name})}
|
||||
title={t('deleteDialog.confirmDeletion')}
|
||||
message={t('deleteDialog.areYouSureToDelete', {name})}
|
||||
stateOwner={this.props.stateOwner}
|
||||
visible={this.props.visible}
|
||||
actionMethod={HTTPMethod.DELETE}
|
||||
|
|
@ -209,11 +209,11 @@ export function tableDeleteDialogAddDeleteButton(actions, owner, perms, id, name
|
|||
if (!perms || perms.includes('delete')) {
|
||||
if (owner.deleteDialogData.id) {
|
||||
actions.push({
|
||||
label: <Icon className={styles.iconDisabled} icon="remove" title={t('Delete')}/>
|
||||
label: <Icon className={styles.iconDisabled} icon="remove" title={t('delete')}/>
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
label: <Icon icon="remove" title={t('Delete')}/>,
|
||||
label: <Icon icon="remove" title={t('delete')}/>,
|
||||
action: () => {
|
||||
owner.deleteDialogData = {name, id};
|
||||
owner.setState({
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ class NamespaceSelect extends Component {
|
|||
const t = this.props.t;
|
||||
|
||||
return (
|
||||
<TreeTableSelect id="namespace" label={t('Namespace')} dataUrl="rest/namespaces-tree"/>
|
||||
<TreeTableSelect id="namespace" label={t('namespace')} dataUrl="rest/namespaces-tree"/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateNamespace(t, state) {
|
||||
if (!state.getIn(['namespace', 'value'])) {
|
||||
state.setIn(['namespace', 'error'], t('Namespace must be selected'));
|
||||
state.setIn(['namespace', 'error'], t('namespace.mustBeSelected'));
|
||||
} else {
|
||||
state.setIn(['namespace', 'error'], null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ class RouteContent extends Component {
|
|||
<div>
|
||||
{primaryMenuComponent}
|
||||
<div className="container-fluid">
|
||||
{t('Loading...')}
|
||||
{t('loading')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ export const CodeEditorSourceType = {
|
|||
};
|
||||
|
||||
export const getCodeEditorSourceTypeOptions = t => [
|
||||
{key: CodeEditorSourceType.MJML, label: t('MJML')},
|
||||
{key: CodeEditorSourceType.HTML, label: t('HTML')}
|
||||
{key: CodeEditorSourceType.MJML, label: t('mjml')},
|
||||
{key: CodeEditorSourceType.HTML, label: t('html')}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ export const GrapesJSSourceType = {
|
|||
};
|
||||
|
||||
export const getGrapesJSSourceTypeOptions = t => [
|
||||
{key: GrapesJSSourceType.MJML, label: t('MJML')},
|
||||
{key: GrapesJSSourceType.HTML, label: t('HTML')}
|
||||
{key: GrapesJSSourceType.MJML, label: t('mjml')},
|
||||
{key: GrapesJSSourceType.HTML, label: t('html')}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export class UntrustedContentHost extends Component {
|
|||
}
|
||||
|
||||
sendMessage(type, data) {
|
||||
if (this.contentNodeIsLoaded) { // This is to avoid errors "common.js:45744 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://localhost:8081') does not match the recipient window's origin ('http://localhost:3000')"
|
||||
if (this.contentNodeIsLoaded) { // This is to avoid errors: Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://localhost:8081') does not match the recipient window's origin ('http://localhost:3000')"
|
||||
this.contentNode.contentWindow.postMessage({type, data}, getSandboxUrl());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import React, {Component} from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import {
|
||||
I18nextProvider,
|
||||
translate
|
||||
withNamespaces
|
||||
} from 'react-i18next';
|
||||
import i18n from './lib/i18n';
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ import axios from './lib/axios';
|
|||
import {getUrl} from "./lib/urls";
|
||||
|
||||
|
||||
@translate()
|
||||
@withNamespaces()
|
||||
class Root extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
@ -58,7 +58,7 @@ class Root extends Component {
|
|||
const link = entry.link || entry.externalLink;
|
||||
|
||||
if (link && path.startsWith(link)) {
|
||||
topLevelMenu.push(<MenuLink key={entryKey} className="active" to={link}>{entry.title} <span className="sr-only">{t('(current)')}</span></MenuLink>);
|
||||
topLevelMenu.push(<MenuLink key={entryKey} className="active" to={link}>{entry.title} <span className="sr-only">{t('root.current')}</span></MenuLink>);
|
||||
} else {
|
||||
topLevelMenu.push(<MenuLink key={entryKey} to={link}>{entry.title}</MenuLink>);
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ class Root extends Component {
|
|||
<div className="container-fluid">
|
||||
<div className="navbar-header">
|
||||
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
||||
<span className="sr-only">{t('Toggle navigation')}</span>
|
||||
<span className="sr-only">{t('root.toggleNavigation')}</span>
|
||||
<span className="icon-bar"></span>
|
||||
<span className="icon-bar"></span>
|
||||
<span className="icon-bar"></span>
|
||||
|
|
@ -81,22 +81,22 @@ class Root extends Component {
|
|||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul className="nav navbar-nav">
|
||||
{topLevelMenu}
|
||||
<DropdownMenuItem label={t('Administration')}>
|
||||
<MenuLink to="/users"><Icon icon='cog'/> {t('Users')}</MenuLink>
|
||||
<MenuLink to="/namespaces"><Icon icon='cog'/> {t('Namespaces')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageSettings && <MenuLink to="/settings"><Icon icon='cog'/> {t('Global Settings')}</MenuLink>}
|
||||
<MenuLink to="/send-configurations"><Icon icon='cog'/> {t('Send Configurations')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageBlacklist && <MenuLink to="/blacklist"><Icon icon='ban-circle'/> {t('Blacklist')}</MenuLink>}
|
||||
<MenuLink to="/account/api"><Icon icon='retweet'/> {t('API')}</MenuLink>
|
||||
<DropdownMenuItem label={t('root.administration')}>
|
||||
<MenuLink to="/users"><Icon icon='cog'/> {t('user_plural')}</MenuLink>
|
||||
<MenuLink to="/namespaces"><Icon icon='cog'/> {t('namespace_plural')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageSettings && <MenuLink to="/settings"><Icon icon='cog'/> {t('globalSetting_plural')}</MenuLink>}
|
||||
<MenuLink to="/send-configurations"><Icon icon='cog'/> {t('sendConfiguration_plural')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageBlacklist && <MenuLink to="/blacklist"><Icon icon='ban-circle'/> {t('blacklist')}</MenuLink>}
|
||||
<MenuLink to="/account/api"><Icon icon='retweet'/> {t('api')}</MenuLink>
|
||||
</DropdownMenuItem>
|
||||
</ul>
|
||||
|
||||
|
||||
<ul className="nav navbar-nav navbar-right">
|
||||
<DropdownMenuItem label={mailtrainConfig.user.username} icon="user">
|
||||
<MenuLink to="/account"><Icon icon='user'/> {t('Account')}</MenuLink>
|
||||
<MenuLink to="/account"><Icon icon='user'/> {t('root.account')}</MenuLink>
|
||||
<li>
|
||||
<ActionLink onClickAsync={::self.logout}><Icon icon='log-out'/> {t('Log out')}</ActionLink>
|
||||
<ActionLink onClickAsync={::self.logout}><Icon icon='log-out'/> {t('logout')}</ActionLink>
|
||||
</li>
|
||||
</DropdownMenuItem>
|
||||
</ul>
|
||||
|
|
@ -145,7 +145,7 @@ class Root extends Component {
|
|||
|
||||
<footer className="footer">
|
||||
<div className="container-fluid">
|
||||
<p className="text-muted">© 2018 <a href="https://mailtrain.org">Mailtrain.org</a>, <a href="mailto:info@mailtrain.org">info@mailtrain.org</a>. <a href="https://github.com/Mailtrain-org/mailtrain">{t('Source on GitHub')}</a></p>
|
||||
<p className="text-muted">© 2018 <a href="https://mailtrain.org">Mailtrain.org</a>, <a href="mailto:info@mailtrain.org">info@mailtrain.org</a>. <a href="https://github.com/Mailtrain-org/mailtrain">{t('sourceOnGithub')}</a></p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue