Extracted strings and fixes on localization support

Language chooser in the UI
This commit is contained in:
Tomas Bures 2018-11-18 21:31:22 +01:00
parent 9f449c0a2f
commit dc7789c17b
126 changed files with 2919 additions and 2028 deletions

View file

@ -1,11 +1,11 @@
'use strict';
import React, { Component } from 'react';
import { translate } from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes from 'prop-types';
import { withErrorHandling, withAsyncErrorHandler } from './error-handling';
@translate()
@withTranslation()
@withErrorHandling
class DismissibleAlert extends Component {
static propTypes = {
@ -192,7 +192,7 @@ class ActionLink extends Component {
}
@translate()
@withTranslation()
@withErrorHandling
class ModalDialog extends Component {
constructor(props) {

View file

@ -2,7 +2,7 @@
import React, {Component} from "react";
import PropTypes from "prop-types";
import {translate} from "react-i18next";
import { withTranslation } from './i18n';
import {
requiresAuthenticatedUser,
Title
@ -16,7 +16,7 @@ import styles from "./styles.scss";
import {withPageHelpers} from "./page";
import {getUrl, getPublicUrl} from "./urls";
@translate()
@withTranslation()
@withErrorHandling
@withPageHelpers
@requiresAuthenticatedUser
@ -50,22 +50,22 @@ export default class Files extends Component {
const t = this.props.t;
const details = [];
if (response.data.added) {
details.push(t('files.filesAdded', {count: response.data.added}));
details.push(t('countFileAdded', {count: response.data.added}));
}
if (response.data.replaced) {
details.push(t('files.filesReplaced', {count: response.data.replaced}));
details.push(t('countFileReplaced', {count: response.data.replaced}));
}
if (response.data.ignored) {
details.push(t('files.filesIgnored', {count: response.data.ignored}));
details.push(t('countFileIgnored', {count: response.data.ignored}));
}
const detailsMessage = details ? ' (' + details.join(', ') + ')' : '';
return t('files.filesUploaded', {count: response.data.uploaded}) + detailsMessage;
return t('countFileUploaded', {count: response.data.uploaded}) + detailsMessage;
}
onDrop(files){
const t = this.props.t;
if (files.length > 0) {
this.setFlashMessage('info', t('files.uploadingFiles', {count: files.length}));
this.setFlashMessage('info', t('uploadingCountFile', {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('files.fileUploadFailed') + ' ' + res.message));
.catch(res => this.setFlashMessage('danger', t('fileUploadFailed') + ' ' + res.message));
}
else{
this.setFlashMessage('info', t('files.noFilesToUpload'));
this.setFlashMessage('info', t('noFilesToUpload'));
}
}
@ -97,13 +97,13 @@ export default class Files extends Component {
await this.hideDeleteFile();
try {
this.setFlashMessage('info', t('files.deletingFile'));
this.setFlashMessage('info', t('deletingFile'));
await axios.delete(getUrl(`rest/files/${this.props.entityTypeId}/${this.props.entitySubTypeId}/${fileToDeleteId}`));
this.filesTable.refresh();
this.setFlashMessage('info', t('files.fileDeleted'));
this.setFlashMessage('info', t('fileDeleted'));
} catch (err) {
this.filesTable.refresh();
this.setFlashMessage('danger', t('files.deleteFileFailed') + ' ' + err.message);
this.setFlashMessage('danger', t('deleteFileFailed') + ' ' + err.message);
}
}
@ -145,13 +145,13 @@ export default class Files extends Component {
<div>
<ModalDialog
hidden={this.state.fileToDeleteId === null}
title={t('files.confirmFileDeletion')}
title={t('confirmFileDeletion')}
onCloseAsync={::this.hideDeleteFile}
buttons={[
{ label: t('no'), className: 'btn-primary', onClickAsync: ::this.hideDeleteFile },
{ label: t('yes'), className: 'btn-danger', onClickAsync: ::this.performDeleteFile }
]}>
{t('files:areYouSureToDeleteFile', {name: this.state.fileToDeleteName})}
{t('filesareYouSureToDeleteFile', {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('files.dropFiles', {count: state.draggedFiles.length}) : t('files.dropFilesHere')}
{state => state.isDragActive ? t('dropCountFile', {count: state.draggedFiles.length}) : t('dropFilesHere')}
</Dropzone>
}

View file

@ -1,9 +1,9 @@
'use strict';
import React, { Component } from 'react';
import { withTranslation } from './i18n';
import axios, {HTTPMethod} from './axios';
import Immutable from 'immutable';
import { translate } from 'react-i18next';
import PropTypes from 'prop-types';
import interoperableErrors from '../../../shared/interoperable-errors';
import { withPageHelpers } from './page'
@ -36,7 +36,7 @@ const FormState = {
const FormSendMethod = HTTPMethod;
@translate()
@withTranslation()
@withPageHelpers
@withErrorHandling
class Form extends Component {
@ -462,7 +462,7 @@ class TextArea extends Component {
}
@translate()
@withTranslation()
class DatePicker extends Component {
constructor(props) {
super(props);
@ -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('form.openCalendar')}/></span>
<span className="input-group-addon" onClick={::this.toggleDayPicker}><Icon icon="calendar" title={t('openCalendar')}/></span>
</div>
{this.state.opened &&
<div className={styles.dayPickerWrapper}>
@ -712,7 +712,7 @@ class TreeTableSelect extends Component {
}
}
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['refresh']})
class TableSelect extends Component {
constructor(props) {
super(props);
@ -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('form.select')} className="btn-default" onClickAsync={::this.toggleOpen}/>
<Button label={t('select')} className="btn-default" onClickAsync={::this.toggleOpen}/>
</span>
}
</div>
@ -824,14 +824,6 @@ class TableSelect extends Component {
}
}
/*
Refreshes the table. This method is provided to allow programmatic refresh from a handler outside the table.
The reference to the table can be obtained by ref.
*/
TableSelect.prototype.refresh = function() {
this.getWrappedInstance().refresh()
};
class ACEEditor extends Component {
static propTypes = {
@ -1305,8 +1297,8 @@ function withForm(target) {
this.disableForm();
this.setFormStatusMessage('danger',
<span>
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
{t('form.modificationsInTheMeantime')}
<strong>{t('yourUpdatesCannotBeSaved')}</strong>{' '}
{t('someoneElseHasIntroducedModificationIn')}
</span>
);
return;
@ -1316,8 +1308,8 @@ function withForm(target) {
this.disableForm();
this.setFormStatusMessage('danger',
<span>
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
{t('form.namespaceDeletedInTheMeantime')}
<strong>{t('yourUpdatesCannotBeSaved')}</strong>{' '}
{t('itSeemsThatSomeoneElseHasDeletedThe')}
</span>
);
return;
@ -1327,8 +1319,8 @@ function withForm(target) {
this.disableForm();
this.setFormStatusMessage('danger',
<span>
<strong>{t('form.yourUpdatesCannotBeSaved')}</strong>{' '}
{t('form.deletionInTheMeantime')}
<strong>{t('yourUpdatesCannotBeSaved')}</strong>{' '}
{t('itSeemsThatSomeoneElseHasDeletedThe-1')}
</span>
);
return;

View file

@ -1,62 +1,43 @@
import i18n from 'i18next';
import { reactI18nextModule } from "react-i18next";
import LanguageDetector from 'i18next-browser-languagedetector';
import mailtrainConfig from 'mailtrainConfig';
import {getUrl} from "./urls";
'use strict';
import commonEn from "../../../locales/common/en";
import React, {Component} from 'react';
import i18n
from 'i18next';
import {withNamespaces} from "react-i18next";
import LanguageDetector
from 'i18next-browser-languagedetector';
import mailtrainConfig
from 'mailtrainConfig';
function convertToFake(dict) {
function convertValueToFakeLang(str) {
let from = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+\\|`~[{]};:'\",<.>/?";
let to = "ɐqɔpǝɟƃɥıɾʞʅɯuodbɹsʇnʌʍxʎz∀ԐↃᗡƎℲ⅁HIſӼ⅂WNOԀÒᴚS⊥∩ɅX⅄Z0123456789¡@#$%ᵥ⅋⁎()-_=+\\|,~[{]};:,„´<.>/¿";
import hoistStatics
from 'hoist-non-react-statics';
return str.replace(/(\{\{[^\}]+\}\}|%s)/g, '\x00\x04$1\x00').split('\x00').map(c => {
if (c.charAt(0) === '\x04') {
return c;
}
let r = '';
for (let i = 0, len = c.length; i < len; i++) {
let pos = from.indexOf(c.charAt(i));
if (pos < 0) {
r += c.charAt(i);
} else {
r += to.charAt(pos);
}
}
return r;
}).join('\x00').replace(/[\x00\x04]/g, '');
}
import {convertToFake, langCodes} from '../../../shared/langs';
function _convertToFake(dict) {
for (const key in dict) {
const val = dict[key];
import commonEn from "../../../locales/en/common";
import commonEs from "../../../locales/es/common";
if (typeof val === 'string') {
dict[key] = convertValueToFakeLang(val);
} else {
_convertToFake(val);
}
}
}
const resourcesCommon = {
en: commonEn,
es: commonEs,
fake: convertToFake(commonEn)
};
return _convertToFake(dict);
const resources = {};
for (const lng of mailtrainConfig.enabledLanguages) {
const shortCode = langCodes[lng].shortCode;
resources[shortCode] = {
common: resourcesCommon[shortCode]
};
}
i18n
.use(LanguageDetector)
.init({
lng: mailtrainConfig.language,
resources: {
en: {
common: commonEn
},
en_fake: {
common: convertToFake(commonEn)
}
},
resources,
fallbackLng: "en",
fallbackLng: mailtrainConfig.defaultLanguage,
defaultNS: 'common',
interpolation: {
@ -79,4 +60,35 @@ i18n
})
export default i18n;
export default i18n;
export function withTranslation(opts) {
if (opts && opts.delegateFuns) {
return function (WrappedComponent) {
class Wrapper extends Component {
constructor(props) {
super(props);
this.WrappedComponentWithNamespaces = withNamespaces(null, {innerRef: ref => this.wrappedComponent = ref})(WrappedComponent);
}
render() {
const WrappedComponentWithNamespaces = this.WrappedComponentWithNamespaces;
return <WrappedComponentWithNamespaces {...this.props}/>;
}
}
for (const fun of opts.delegateFuns) {
Wrapper.prototype[fun] = function (...args) {
return this.wrappedComponent[fun](...args);
}
}
return hoistStatics(Wrapper, WrappedComponent);
}
} else {
return withNamespaces();
}
}

View file

@ -2,7 +2,7 @@
import React, { Component } from 'react';
import axios, { HTTPMethod } from './axios';
import { translate } from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes from 'prop-types';
import {
Icon,
@ -14,7 +14,7 @@ import styles from './styles.scss';
import interoperableErrors from '../../../shared/interoperable-errors';
import {Link} from "react-router-dom";
@translate()
@withTranslation()
@withPageHelpers
export class RestActionModalDialog extends Component {
static propTypes = {
@ -97,7 +97,7 @@ export class RestActionModalDialog extends Component {
}
@translate()
@withTranslation()
@withPageHelpers
export class DeleteModalDialog extends Component {
constructor(props) {
@ -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('deleteDialog.cannotDeleteDueToDependencies', {name})}</p>
<p>{t('cannoteDeleteNameDueToTheFollowing', {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('deleteDialog.andMore')}</li>}
{err.data.andMore && <li>{t('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('deleteDialog.confirmDeletion')}
message={t('deleteDialog.areYouSureToDelete', {name})}
title={t('confirmDeletion')}
message={t('areYouSureYouWantToDeleteName?', {name})}
stateOwner={this.props.stateOwner}
visible={this.props.visible}
actionMethod={HTTPMethod.DELETE}

View file

@ -1,11 +1,11 @@
'use strict';
import React, { Component } from 'react';
import { translate } from 'react-i18next';
import { withTranslation } from './i18n';
import { TreeTableSelect } from './form';
@translate()
@withTranslation()
class NamespaceSelect extends Component {
render() {
const t = this.props.t;
@ -18,7 +18,7 @@ class NamespaceSelect extends Component {
function validateNamespace(t, state) {
if (!state.getIn(['namespace', 'value'])) {
state.setIn(['namespace', 'error'], t('namespace.mustBeSelected'));
state.setIn(['namespace', 'error'], t('namespacemustBeSelected'));
} else {
state.setIn(['namespace', 'error'], null);
}

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from "react";
import {translate} from "react-i18next";
import { withTranslation } from './i18n';
import PropTypes from "prop-types";
import {withRouter} from "react-router";
import {BrowserRouter as Router, Link, Redirect, Route, Switch} from "react-router-dom";
@ -14,6 +14,10 @@ import {getRoutes, needsResolve, resolve, withPageHelpers} from "./page-common";
import {getBaseDir} from "./urls";
class Breadcrumb extends Component {
constructor(props) {
super(props);
}
static propTypes = {
route: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
@ -67,6 +71,7 @@ class Breadcrumb extends Component {
class SecondaryNavBar extends Component {
static propTypes = {
route: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
resolved: PropTypes.object.isRequired,
className: PropTypes.string
@ -144,7 +149,7 @@ class SecondaryNavBar extends Component {
}
}
@translate()
@withTranslation()
@withErrorHandling
class RouteContent extends Component {
constructor(props) {
@ -367,17 +372,10 @@ class SectionContent extends Component {
}
}
@translate()
@withTranslation()
class Section extends Component {
constructor(props) {
super(props);
let structure = props.structure;
if (typeof structure === 'function') {
structure = structure(props.t);
}
this.structure = structure;
}
static propTypes = {
@ -386,9 +384,14 @@ class Section extends Component {
}
render() {
let structure = this.props.structure;
if (typeof structure === 'function') {
structure = structure(this.props.t);
}
return (
<Router basename={getBaseDir()}>
<SectionContent root={this.props.root} structure={this.structure} />
<SectionContent root={this.props.root} structure={structure} />
</Router>
);
}

View file

@ -5,12 +5,8 @@ import './public-path';
import React, {Component} from 'react';
import ReactDOM
from 'react-dom';
import {
I18nextProvider,
translate,
} from 'react-i18next';
import i18n
from './i18n';
import {I18nextProvider} from 'react-i18next';
import i18n, {withTranslation} from './i18n';
import {
parentRPC,
UntrustedContentRoot
@ -32,10 +28,10 @@ import {
import CKEditor
from "react-ckeditor-component";
import { initialHeight } from "./sandboxed-ckeditor-shared";
import {initialHeight} from "./sandboxed-ckeditor-shared";
@translate(null, { withRef: true })
@withTranslation()
class CKEditorSandbox extends Component {
constructor(props) {
super(props);

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from 'react';
import {translate} from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes
from "prop-types";
import styles
@ -14,7 +14,7 @@ import {getTrustedUrl} from "./urls";
import { initialHeight } from "./sandboxed-ckeditor-shared";
const navbarHeight = 34; // Sync this with navbarheight in sandboxed-ckeditor.scss
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['exportState']})
export class CKEditorHost extends Component {
constructor(props) {
super(props);
@ -97,9 +97,3 @@ export class CKEditorHost extends Component {
);
}
}
CKEditorHost.prototype.exportState = async function() {
return await this.getWrappedInstance().exportState();
};

View file

@ -5,12 +5,8 @@ import './public-path';
import React, {Component} from 'react';
import ReactDOM
from 'react-dom';
import {
I18nextProvider,
translate,
} from 'react-i18next';
import i18n
from './i18n';
import {I18nextProvider} from 'react-i18next';
import i18n, {withTranslation} from './i18n';
import {
parentRPC,
UntrustedContentRoot
@ -28,20 +24,21 @@ import {
base,
unbase
} from "../../../shared/templates";
import brace from 'brace';
import ACEEditorRaw from 'react-ace';
import ACEEditorRaw
from 'react-ace';
import 'brace/theme/github';
import 'brace/ext/searchbox';
import 'brace/mode/html';
import {CodeEditorSourceType} from "./sandboxed-codeeditor-shared";
import mjml2html from "mjml4-in-browser";
import juice from "juice";
import mjml2html
from "mjml4-in-browser";
import juice
from "juice";
const refreshTimeout = 1000;
@translate(null, { withRef: true })
@withTranslation()
class CodeEditorSandbox extends Component {
constructor(props) {
super(props);

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from 'react';
import {translate} from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes
from "prop-types";
import styles
@ -11,7 +11,7 @@ import {UntrustedContentHost} from './untrusted';
import {Icon} from "./bootstrap-components";
import {getTrustedUrl} from "./urls";
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['exportState']})
export class CodeEditorHost extends Component {
constructor(props) {
super(props);
@ -83,7 +83,3 @@ export class CodeEditorHost extends Component {
);
}
}
CodeEditorHost.prototype.exportState = async function() {
return await this.getWrappedInstance().exportState();
};

View file

@ -5,12 +5,8 @@ import './public-path';
import React, {Component} from 'react';
import ReactDOM
from 'react-dom';
import {
I18nextProvider,
translate,
} from 'react-i18next';
import i18n
from './i18n';
import {I18nextProvider} from 'react-i18next';
import i18n, {withTranslation} from './i18n';
import {
parentRPC,
UntrustedContentRoot
@ -20,17 +16,18 @@ import PropTypes
import {
getPublicUrl,
getSandboxUrl,
getTrustedUrl,
getUrl
getTrustedUrl
} from "./urls";
import {
base,
unbase
} from "../../../shared/templates";
import mjml2html from "mjml4-in-browser";
import mjml2html
from "mjml4-in-browser";
import 'grapesjs/dist/css/grapes.min.css';
import grapesjs from 'grapesjs';
import grapesjs
from 'grapesjs';
import 'grapesjs-mjml';
@ -39,7 +36,8 @@ import 'grapesjs-preset-newsletter/dist/grapesjs-preset-newsletter.css';
import "./sandboxed-grapesjs.scss";
import axios from './axios';
import axios
from './axios';
import {GrapesJSSourceType} from "./sandboxed-grapesjs-shared";
@ -54,7 +52,7 @@ grapesjs.plugins.add('mailtrain-remove-buttons', (editor, opts = {}) => {
});
@translate(null, { withRef: true })
@withTranslation()
export class GrapesJSSandbox extends Component {
constructor(props) {
super(props);

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from 'react';
import {translate} from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes
from "prop-types";
import styles
@ -11,7 +11,7 @@ import {UntrustedContentHost} from './untrusted';
import {Icon} from "./bootstrap-components";
import {getTrustedUrl} from "./urls";
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['exportState']})
export class GrapesJSHost extends Component {
constructor(props) {
super(props);
@ -73,7 +73,3 @@ export class GrapesJSHost extends Component {
);
}
}
GrapesJSHost.prototype.exportState = async function() {
return await this.getWrappedInstance().exportState();
};

View file

@ -5,12 +5,8 @@ import './public-path';
import React, {Component} from 'react';
import ReactDOM
from 'react-dom';
import {
I18nextProvider,
translate,
} from 'react-i18next';
import i18n
from './i18n';
import {I18nextProvider} from 'react-i18next';
import i18n, {withTranslation} from './i18n';
import {
parentRPC,
UntrustedContentRoot
@ -28,7 +24,7 @@ import {
} from "../../../shared/templates";
@translate(null, { withRef: true })
@withTranslation()
class MosaicoSandbox extends Component {
constructor(props) {
super(props);

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from 'react';
import {translate} from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes
from "prop-types";
import styles
@ -12,7 +12,7 @@ import {Icon} from "./bootstrap-components";
import {getTrustedUrl} from "./urls";
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['exportState']})
export class MosaicoHost extends Component {
constructor(props) {
super(props);
@ -76,8 +76,3 @@ export class MosaicoHost extends Component {
);
}
}
MosaicoHost.prototype.exportState = async function() {
return await this.getWrappedInstance().exportState();
};

View file

@ -2,8 +2,8 @@
import React, { Component } from 'react';
import ReactDOMServer from 'react-dom/server';
import { translate } from 'react-i18next';
import PropTypes from 'prop-types';
import { withTranslation } from './i18n';
import jQuery from 'jquery';
@ -28,8 +28,7 @@ const TableSelectMode = {
MULTI: 2
};
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['refresh']})
@withPageHelpers
@withErrorHandling
class Table extends Component {
@ -111,7 +110,7 @@ class Table extends Component {
const count = this.selectionMap.size;
if (this.selectionMap.size > 0) {
const jqInfo = jQuery('<span>' + t('{{ count }} entries selected.', { count }) + ' </span>');
const jqInfo = jQuery('<span>' + t('countEntriesSelected', { count }) + ' </span>');
const jqDeselectLink = jQuery('<a href="">Deselect all.</a>').on('click', ::this.deselectAll);
this.jqSelectInfo.empty().append(jqInfo).append(jqDeselectLink);
@ -404,14 +403,6 @@ class Table extends Component {
}
}
/*
Refreshes the table. This method is provided to allow programmatic refresh from a handler outside the table.
The reference to the table can be obtained by ref.
*/
Table.prototype.refresh = function() {
this.getWrappedInstance().refresh();
};
export {
Table,
TableSelectMode

View file

@ -2,7 +2,7 @@
import React, { Component } from 'react';
import ReactDOMServer from 'react-dom/server';
import { translate } from 'react-i18next';
import { withTranslation } from './i18n';
import PropTypes from 'prop-types';
import jQuery from 'jquery';
@ -23,7 +23,7 @@ const TreeSelectMode = {
MULTI: 2
};
@translate(null, { withRef: true })
@withTranslation({delegateFuns: ['refresh']})
@withPageHelpers
@withErrorHandling
class TreeTable extends Component {
@ -327,8 +327,8 @@ class TreeTable extends Component {
{props.withHeader &&
<thead>
<tr>
<th className="mt-treetable-title">{t('Name')}</th>
{withDescription && <th>{t('Description')}</th>}
<th className="mt-treetable-title">{t('name')}</th>
{withDescription && <th>{t('description')}</th>}
{actions && <th></th>}
</tr>
</thead>
@ -348,14 +348,6 @@ class TreeTable extends Component {
}
}
/*
Refreshes the table. This method is provided to allow programmatic refresh from a handler outside the table.
The reference to the table can be obtained by ref.
*/
TreeTable.prototype.refresh = function() {
this.getWrappedInstance().refresh();
};
export {
TreeTable,

View file

@ -2,7 +2,7 @@
import React, {Component} from "react";
import PropTypes from "prop-types";
import {translate} from "react-i18next";
import { withTranslation } from './i18n';
import {
requiresAuthenticatedUser,
withPageHelpers
@ -170,7 +170,7 @@ export class UntrustedContentHost extends Component {
}
@translate()
@withTranslation()
export class UntrustedContentRoot extends Component {
constructor(props) {
super(props);
@ -243,7 +243,7 @@ export class UntrustedContentRoot extends Component {
} else {
return (
<div>
{t('Loading...')}
{t('loading-1')}
</div>
);
}