Fixed: Improve translation loading
This commit is contained in:
parent
bb8fed94eb
commit
73c5ec1da4
|
@ -7,13 +7,13 @@ import PageConnector from 'Components/Page/PageConnector';
|
|||
import ApplyTheme from './ApplyTheme';
|
||||
import AppRoutes from './AppRoutes';
|
||||
|
||||
function App({ store, history, hasTranslationsError }) {
|
||||
function App({ store, history }) {
|
||||
return (
|
||||
<DocumentTitle title={window.Sonarr.instanceName}>
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
<ApplyTheme>
|
||||
<PageConnector hasTranslationsError={hasTranslationsError}>
|
||||
<PageConnector>
|
||||
<AppRoutes app={App} />
|
||||
</PageConnector>
|
||||
</ApplyTheme>
|
||||
|
@ -25,8 +25,7 @@ function App({ store, history, hasTranslationsError }) {
|
|||
|
||||
App.propTypes = {
|
||||
store: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
hasTranslationsError: PropTypes.bool.isRequired
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -7,7 +7,7 @@ function ErrorPage(props) {
|
|||
const {
|
||||
version,
|
||||
isLocalStorageSupported,
|
||||
hasTranslationsError,
|
||||
translationsError,
|
||||
seriesError,
|
||||
customFiltersError,
|
||||
tagsError,
|
||||
|
@ -20,8 +20,8 @@ function ErrorPage(props) {
|
|||
|
||||
if (!isLocalStorageSupported) {
|
||||
errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.';
|
||||
} else if (hasTranslationsError) {
|
||||
errorMessage = 'Failed to load translations from API';
|
||||
} else if (translationsError) {
|
||||
errorMessage = getErrorMessage(translationsError, 'Failed to load translations from API');
|
||||
} else if (seriesError) {
|
||||
errorMessage = getErrorMessage(seriesError, 'Failed to load series from API');
|
||||
} else if (customFiltersError) {
|
||||
|
@ -52,7 +52,7 @@ function ErrorPage(props) {
|
|||
ErrorPage.propTypes = {
|
||||
version: PropTypes.string.isRequired,
|
||||
isLocalStorageSupported: PropTypes.bool.isRequired,
|
||||
hasTranslationsError: PropTypes.bool.isRequired,
|
||||
translationsError: PropTypes.object,
|
||||
seriesError: PropTypes.object,
|
||||
customFiltersError: PropTypes.object,
|
||||
tagsError: PropTypes.object,
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { Component } from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { createSelector } from 'reselect';
|
||||
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
|
||||
import { fetchTranslations, saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
|
||||
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
||||
import { fetchSeries } from 'Store/Actions/seriesActions';
|
||||
import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||
|
@ -52,6 +52,7 @@ const selectIsPopulated = createSelector(
|
|||
(state) => state.settings.languages.isPopulated,
|
||||
(state) => state.settings.importLists.isPopulated,
|
||||
(state) => state.system.status.isPopulated,
|
||||
(state) => state.app.translations.isPopulated,
|
||||
(
|
||||
seriesIsPopulated,
|
||||
customFiltersIsPopulated,
|
||||
|
@ -60,7 +61,8 @@ const selectIsPopulated = createSelector(
|
|||
qualityProfilesIsPopulated,
|
||||
languagesIsPopulated,
|
||||
importListsIsPopulated,
|
||||
systemStatusIsPopulated
|
||||
systemStatusIsPopulated,
|
||||
translationsIsPopulated
|
||||
) => {
|
||||
return (
|
||||
seriesIsPopulated &&
|
||||
|
@ -70,7 +72,8 @@ const selectIsPopulated = createSelector(
|
|||
qualityProfilesIsPopulated &&
|
||||
languagesIsPopulated &&
|
||||
importListsIsPopulated &&
|
||||
systemStatusIsPopulated
|
||||
systemStatusIsPopulated &&
|
||||
translationsIsPopulated
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -84,6 +87,7 @@ const selectErrors = createSelector(
|
|||
(state) => state.settings.languages.error,
|
||||
(state) => state.settings.importLists.error,
|
||||
(state) => state.system.status.error,
|
||||
(state) => state.app.translations.error,
|
||||
(
|
||||
seriesError,
|
||||
customFiltersError,
|
||||
|
@ -92,7 +96,8 @@ const selectErrors = createSelector(
|
|||
qualityProfilesError,
|
||||
languagesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
systemStatusError,
|
||||
translationsError
|
||||
) => {
|
||||
const hasError = !!(
|
||||
seriesError ||
|
||||
|
@ -102,7 +107,8 @@ const selectErrors = createSelector(
|
|||
qualityProfilesError ||
|
||||
languagesError ||
|
||||
importListsError ||
|
||||
systemStatusError
|
||||
systemStatusError ||
|
||||
translationsError
|
||||
);
|
||||
|
||||
return {
|
||||
|
@ -114,7 +120,8 @@ const selectErrors = createSelector(
|
|||
qualityProfilesError,
|
||||
languagesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
systemStatusError,
|
||||
translationsError
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -173,6 +180,9 @@ function createMapDispatchToProps(dispatch, props) {
|
|||
dispatchFetchStatus() {
|
||||
dispatch(fetchStatus());
|
||||
},
|
||||
dispatchFetchTranslations() {
|
||||
dispatch(fetchTranslations());
|
||||
},
|
||||
onResize(dimensions) {
|
||||
dispatch(saveDimensions(dimensions));
|
||||
},
|
||||
|
@ -205,6 +215,7 @@ class PageConnector extends Component {
|
|||
this.props.dispatchFetchImportLists();
|
||||
this.props.dispatchFetchUISettings();
|
||||
this.props.dispatchFetchStatus();
|
||||
this.props.dispatchFetchTranslations();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +231,6 @@ class PageConnector extends Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
hasTranslationsError,
|
||||
isPopulated,
|
||||
hasError,
|
||||
dispatchFetchSeries,
|
||||
|
@ -230,15 +240,15 @@ class PageConnector extends Component {
|
|||
dispatchFetchImportLists,
|
||||
dispatchFetchUISettings,
|
||||
dispatchFetchStatus,
|
||||
dispatchFetchTranslations,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
if (hasTranslationsError || hasError || !this.state.isLocalStorageSupported) {
|
||||
if (hasError || !this.state.isLocalStorageSupported) {
|
||||
return (
|
||||
<ErrorPage
|
||||
{...this.state}
|
||||
{...otherProps}
|
||||
hasTranslationsError={hasTranslationsError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -259,7 +269,6 @@ class PageConnector extends Component {
|
|||
}
|
||||
|
||||
PageConnector.propTypes = {
|
||||
hasTranslationsError: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
hasError: PropTypes.bool.isRequired,
|
||||
isSidebarVisible: PropTypes.bool.isRequired,
|
||||
|
@ -271,6 +280,7 @@ PageConnector.propTypes = {
|
|||
dispatchFetchImportLists: PropTypes.func.isRequired,
|
||||
dispatchFetchUISettings: PropTypes.func.isRequired,
|
||||
dispatchFetchStatus: PropTypes.func.isRequired,
|
||||
dispatchFetchTranslations: PropTypes.func.isRequired,
|
||||
onSidebarVisibleChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
|
|
@ -21,16 +21,22 @@ const SIDEBAR_WIDTH = parseInt(dimensions.sidebarWidth);
|
|||
const links = [
|
||||
{
|
||||
iconName: icons.SERIES_CONTINUING,
|
||||
title: translate('Series'),
|
||||
get title() {
|
||||
return translate('Series');
|
||||
},
|
||||
to: '/',
|
||||
alias: '/series',
|
||||
children: [
|
||||
{
|
||||
title: translate('AddNew'),
|
||||
get title() {
|
||||
return translate('AddNew');
|
||||
},
|
||||
to: '/add/new'
|
||||
},
|
||||
{
|
||||
title: translate('LibraryImport'),
|
||||
get title() {
|
||||
return translate('LibraryImport');
|
||||
},
|
||||
to: '/add/import'
|
||||
}
|
||||
]
|
||||
|
@ -38,26 +44,36 @@ const links = [
|
|||
|
||||
{
|
||||
iconName: icons.CALENDAR,
|
||||
title: translate('Calendar'),
|
||||
get title() {
|
||||
return translate('Calendar');
|
||||
},
|
||||
to: '/calendar'
|
||||
},
|
||||
|
||||
{
|
||||
iconName: icons.ACTIVITY,
|
||||
title: translate('Activity'),
|
||||
get title() {
|
||||
return translate('Activity');
|
||||
},
|
||||
to: '/activity/queue',
|
||||
children: [
|
||||
{
|
||||
title: translate('Queue'),
|
||||
get title() {
|
||||
return translate('Queue');
|
||||
},
|
||||
to: '/activity/queue',
|
||||
statusComponent: QueueStatusConnector
|
||||
},
|
||||
{
|
||||
title: translate('History'),
|
||||
get title() {
|
||||
return translate('History');
|
||||
},
|
||||
to: '/activity/history'
|
||||
},
|
||||
{
|
||||
title: translate('Blocklist'),
|
||||
get title() {
|
||||
return translate('Blocklist');
|
||||
},
|
||||
to: '/activity/blocklist'
|
||||
}
|
||||
]
|
||||
|
@ -65,15 +81,21 @@ const links = [
|
|||
|
||||
{
|
||||
iconName: icons.WARNING,
|
||||
title: translate('Wanted'),
|
||||
get title() {
|
||||
return translate('Wanted');
|
||||
},
|
||||
to: '/wanted/missing',
|
||||
children: [
|
||||
{
|
||||
title: translate('Missing'),
|
||||
get title() {
|
||||
return translate('Missing');
|
||||
},
|
||||
to: '/wanted/missing'
|
||||
},
|
||||
{
|
||||
title: translate('CutoffUnmet'),
|
||||
get title() {
|
||||
return translate('CutoffUnmet');
|
||||
},
|
||||
to: '/wanted/cutoffunmet'
|
||||
}
|
||||
]
|
||||
|
@ -81,59 +103,87 @@ const links = [
|
|||
|
||||
{
|
||||
iconName: icons.SETTINGS,
|
||||
title: translate('Settings'),
|
||||
get title() {
|
||||
return translate('Settings');
|
||||
},
|
||||
to: '/settings',
|
||||
children: [
|
||||
{
|
||||
title: translate('MediaManagement'),
|
||||
get title() {
|
||||
return translate('MediaManagement');
|
||||
},
|
||||
to: '/settings/mediamanagement'
|
||||
},
|
||||
{
|
||||
title: translate('Profiles'),
|
||||
get title() {
|
||||
return translate('Profiles');
|
||||
},
|
||||
to: '/settings/profiles'
|
||||
},
|
||||
{
|
||||
title: translate('Quality'),
|
||||
get title() {
|
||||
return translate('Quality');
|
||||
},
|
||||
to: '/settings/quality'
|
||||
},
|
||||
{
|
||||
title: translate('CustomFormats'),
|
||||
get title() {
|
||||
return translate('CustomFormats');
|
||||
},
|
||||
to: '/settings/customformats'
|
||||
},
|
||||
{
|
||||
title: translate('Indexers'),
|
||||
get title() {
|
||||
return translate('Indexers');
|
||||
},
|
||||
to: '/settings/indexers'
|
||||
},
|
||||
{
|
||||
title: translate('DownloadClients'),
|
||||
get title() {
|
||||
return translate('DownloadClients');
|
||||
},
|
||||
to: '/settings/downloadclients'
|
||||
},
|
||||
{
|
||||
title: translate('ImportLists'),
|
||||
get title() {
|
||||
return translate('ImportLists');
|
||||
},
|
||||
to: '/settings/importlists'
|
||||
},
|
||||
{
|
||||
title: translate('Connect'),
|
||||
get title() {
|
||||
return translate('Connect');
|
||||
},
|
||||
to: '/settings/connect'
|
||||
},
|
||||
{
|
||||
title: translate('Metadata'),
|
||||
get title() {
|
||||
return translate('Metadata');
|
||||
},
|
||||
to: '/settings/metadata'
|
||||
},
|
||||
{
|
||||
title: translate('MetadataSource'),
|
||||
get title() {
|
||||
return translate('MetadataSource');
|
||||
},
|
||||
to: '/settings/metadatasource'
|
||||
},
|
||||
{
|
||||
title: translate('Tags'),
|
||||
get title() {
|
||||
return translate('Tags');
|
||||
},
|
||||
to: '/settings/tags'
|
||||
},
|
||||
{
|
||||
title: translate('General'),
|
||||
get title() {
|
||||
return translate('General');
|
||||
},
|
||||
to: '/settings/general'
|
||||
},
|
||||
{
|
||||
title: translate('UI'),
|
||||
get title() {
|
||||
return translate('UI');
|
||||
},
|
||||
to: '/settings/ui'
|
||||
}
|
||||
]
|
||||
|
@ -141,32 +191,46 @@ const links = [
|
|||
|
||||
{
|
||||
iconName: icons.SYSTEM,
|
||||
title: translate('System'),
|
||||
get title() {
|
||||
return translate('System');
|
||||
},
|
||||
to: '/system/status',
|
||||
children: [
|
||||
{
|
||||
title: translate('Status'),
|
||||
get title() {
|
||||
return translate('Status');
|
||||
},
|
||||
to: '/system/status',
|
||||
statusComponent: HealthStatusConnector
|
||||
},
|
||||
{
|
||||
title: translate('Tasks'),
|
||||
get title() {
|
||||
return translate('Tasks');
|
||||
},
|
||||
to: '/system/tasks'
|
||||
},
|
||||
{
|
||||
title: translate('Backup'),
|
||||
get title() {
|
||||
return translate('Backup');
|
||||
},
|
||||
to: '/system/backup'
|
||||
},
|
||||
{
|
||||
title: translate('Updates'),
|
||||
get title() {
|
||||
return translate('Updates');
|
||||
},
|
||||
to: '/system/updates'
|
||||
},
|
||||
{
|
||||
title: translate('Events'),
|
||||
get title() {
|
||||
return translate('Events');
|
||||
},
|
||||
to: '/system/events'
|
||||
},
|
||||
{
|
||||
title: translate('LogFiles'),
|
||||
get title() {
|
||||
return translate('LogFiles');
|
||||
},
|
||||
to: '/system/logs/files'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -27,9 +27,25 @@ interface ManageDownloadClientsEditModalContentProps {
|
|||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const enableOptions = [
|
||||
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
|
||||
{ key: 'enabled', value: translate('Enabled') },
|
||||
{ key: 'disabled', value: translate('Disabled') },
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
},
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
get value() {
|
||||
return translate('Enabled');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'disabled',
|
||||
get value() {
|
||||
return translate('Disabled');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function ManageDownloadClientsEditModalContent(
|
||||
|
|
|
@ -36,37 +36,49 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
|||
const COLUMNS = [
|
||||
{
|
||||
name: 'name',
|
||||
label: translate('Name'),
|
||||
get label() {
|
||||
return translate('Name');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'implementation',
|
||||
label: translate('Implementation'),
|
||||
get label() {
|
||||
return translate('Implementation');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enable',
|
||||
label: translate('Enabled'),
|
||||
get label() {
|
||||
return translate('Enabled');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
label: translate('Priority'),
|
||||
get label() {
|
||||
return translate('Priority');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'removeCompletedDownloads',
|
||||
label: translate('RemoveCompleted'),
|
||||
get label() {
|
||||
return translate('RemoveCompleted');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'removeFailedDownloads',
|
||||
label: translate('RemoveFailed'),
|
||||
get label() {
|
||||
return translate('RemoveFailed');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
|
|
|
@ -72,9 +72,24 @@ function TagsModalContent(props: TagsModalContentProps) {
|
|||
}, [tags, applyTags, onApplyTagsPress]);
|
||||
|
||||
const applyTagsOptions = [
|
||||
{ key: 'add', value: translate('Add') },
|
||||
{ key: 'remove', value: translate('Remove') },
|
||||
{ key: 'replace', value: translate('Replace') },
|
||||
{
|
||||
key: 'add',
|
||||
get value() {
|
||||
return translate('Add');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'remove',
|
||||
get value() {
|
||||
return translate('Remove');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'replace',
|
||||
get value() {
|
||||
return translate('Replace');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
@ -26,9 +26,25 @@ interface ManageImportListsEditModalContentProps {
|
|||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const autoAddOptions = [
|
||||
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
|
||||
{ key: 'enabled', value: translate('Enabled') },
|
||||
{ key: 'disabled', value: translate('Disabled') },
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
},
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
get value() {
|
||||
return translate('Enabled');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'disabled',
|
||||
get value() {
|
||||
return translate('Disabled');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function ManageImportListsEditModalContent(
|
||||
|
|
|
@ -36,37 +36,49 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
|||
const COLUMNS = [
|
||||
{
|
||||
name: 'name',
|
||||
label: translate('Name'),
|
||||
get label() {
|
||||
return translate('Name');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'implementation',
|
||||
label: translate('Implementation'),
|
||||
get label() {
|
||||
return translate('Implementation');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'qualityProfileId',
|
||||
label: translate('QualityProfile'),
|
||||
get label() {
|
||||
return translate('QualityProfile');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'rootFolderPath',
|
||||
label: translate('RootFolder'),
|
||||
get label() {
|
||||
return translate('RootFolder');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enableAutomaticAdd',
|
||||
label: translate('AutoAdd'),
|
||||
get label() {
|
||||
return translate('AutoAdd');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
label: translate('Tags'),
|
||||
get label() {
|
||||
return translate('Tags');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
|
|
|
@ -70,9 +70,24 @@ function TagsModalContent(props: TagsModalContentProps) {
|
|||
}, [tags, applyTags, onApplyTagsPress]);
|
||||
|
||||
const applyTagsOptions = [
|
||||
{ key: 'add', value: translate('Add') },
|
||||
{ key: 'remove', value: translate('Remove') },
|
||||
{ key: 'replace', value: translate('Replace') },
|
||||
{
|
||||
key: 'add',
|
||||
get value() {
|
||||
return translate('Add');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'remove',
|
||||
get value() {
|
||||
return translate('Remove');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'replace',
|
||||
get value() {
|
||||
return translate('Replace');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
@ -27,9 +27,25 @@ interface ManageIndexersEditModalContentProps {
|
|||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const enableOptions = [
|
||||
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
|
||||
{ key: 'enabled', value: translate('Enabled') },
|
||||
{ key: 'disabled', value: translate('Disabled') },
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
},
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
get value() {
|
||||
return translate('Enabled');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'disabled',
|
||||
get value() {
|
||||
return translate('Disabled');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function ManageIndexersEditModalContent(
|
||||
|
|
|
@ -36,43 +36,57 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
|||
const COLUMNS = [
|
||||
{
|
||||
name: 'name',
|
||||
label: translate('Name'),
|
||||
get label() {
|
||||
return translate('Name');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'implementation',
|
||||
label: translate('Implementation'),
|
||||
get label() {
|
||||
return translate('Implementation');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enableRss',
|
||||
label: translate('EnableRSS'),
|
||||
get label() {
|
||||
return translate('EnableRSS');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enableAutomaticSearch',
|
||||
label: translate('EnableAutomaticSearch'),
|
||||
get label() {
|
||||
return translate('EnableAutomaticSearch');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enableInteractiveSearch',
|
||||
label: translate('EnableInteractiveSearch'),
|
||||
get label() {
|
||||
return translate('EnableInteractiveSearch');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
label: translate('Priority'),
|
||||
get label() {
|
||||
return translate('Priority');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
label: translate('Tags'),
|
||||
get label() {
|
||||
return translate('Tags');
|
||||
},
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
|
|
|
@ -70,9 +70,24 @@ function TagsModalContent(props: TagsModalContentProps) {
|
|||
}, [tags, applyTags, onApplyTagsPress]);
|
||||
|
||||
const applyTagsOptions = [
|
||||
{ key: 'add', value: translate('Add') },
|
||||
{ key: 'remove', value: translate('Remove') },
|
||||
{ key: 'replace', value: translate('Replace') },
|
||||
{
|
||||
key: 'add',
|
||||
get value() {
|
||||
return translate('Add');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'remove',
|
||||
get value() {
|
||||
return translate('Remove');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'replace',
|
||||
get value() {
|
||||
return translate('Replace');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
@ -4,6 +4,7 @@ import { createThunk, handleThunks } from 'Store/thunks';
|
|||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { fetchTranslations as fetchAppTranslations } from 'Utilities/String/translate';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
function getDimensions(width, height) {
|
||||
|
@ -41,7 +42,12 @@ export const defaultState = {
|
|||
isReconnecting: false,
|
||||
isDisconnected: false,
|
||||
isRestarting: false,
|
||||
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen
|
||||
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen,
|
||||
translations: {
|
||||
isFetching: true,
|
||||
isPopulated: false,
|
||||
error: null
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -53,6 +59,7 @@ export const SAVE_DIMENSIONS = 'app/saveDimensions';
|
|||
export const SET_VERSION = 'app/setVersion';
|
||||
export const SET_APP_VALUE = 'app/setAppValue';
|
||||
export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible';
|
||||
export const FETCH_TRANSLATIONS = 'app/fetchTranslations';
|
||||
|
||||
export const PING_SERVER = 'app/pingServer';
|
||||
|
||||
|
@ -66,6 +73,7 @@ export const setAppValue = createAction(SET_APP_VALUE);
|
|||
export const showMessage = createAction(SHOW_MESSAGE);
|
||||
export const hideMessage = createAction(HIDE_MESSAGE);
|
||||
export const pingServer = createThunk(PING_SERVER);
|
||||
export const fetchTranslations = createThunk(FETCH_TRANSLATIONS);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
@ -127,6 +135,17 @@ function pingServerAfterTimeout(getState, dispatch) {
|
|||
export const actionHandlers = handleThunks({
|
||||
[PING_SERVER]: function(getState, payload, dispatch) {
|
||||
pingServerAfterTimeout(getState, dispatch);
|
||||
},
|
||||
[FETCH_TRANSLATIONS]: async function(getState, payload, dispatch) {
|
||||
const isFetchingComplete = await fetchAppTranslations();
|
||||
|
||||
dispatch(setAppValue({
|
||||
translations: {
|
||||
isFetching: false,
|
||||
isPopulated: isFetchingComplete,
|
||||
error: isFetchingComplete ? null : 'Failed to load translations from API'
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -114,10 +114,14 @@ export const defaultState = {
|
|||
},
|
||||
{
|
||||
name: 'customFormatScore',
|
||||
columnLabel: translate('CustomFormatScore'),
|
||||
get columnLabel() {
|
||||
return translate('CustomFormatScore');
|
||||
},
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.SCORE,
|
||||
title: translate('CustomFormatScore')
|
||||
get title() {
|
||||
return translate('CustomFormatScore');
|
||||
}
|
||||
}),
|
||||
isVisible: false
|
||||
},
|
||||
|
|
|
@ -4,14 +4,14 @@ function getTranslations() {
|
|||
return createAjaxRequest({
|
||||
global: false,
|
||||
dataType: 'json',
|
||||
url: '/localization'
|
||||
url: '/localization',
|
||||
}).request;
|
||||
}
|
||||
|
||||
let translations = {};
|
||||
let translations: Record<string, string> = {};
|
||||
|
||||
export function fetchTranslations() {
|
||||
return new Promise(async(resolve) => {
|
||||
export async function fetchTranslations(): Promise<boolean> {
|
||||
return new Promise(async (resolve) => {
|
||||
try {
|
||||
const data = await getTranslations();
|
||||
translations = data.strings;
|
||||
|
@ -23,7 +23,10 @@ export function fetchTranslations() {
|
|||
});
|
||||
}
|
||||
|
||||
export default function translate(key, tokens) {
|
||||
export default function translate(
|
||||
key: string,
|
||||
tokens?: Record<string, string | number | boolean>
|
||||
) {
|
||||
const translation = translations[key] || key;
|
||||
|
||||
if (tokens) {
|
|
@ -2,7 +2,6 @@ import { createBrowserHistory } from 'history';
|
|||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import createAppStore from 'Store/createAppStore';
|
||||
import { fetchTranslations } from 'Utilities/String/translate';
|
||||
import App from './App/App';
|
||||
|
||||
import 'Diag/ConsoleApi';
|
||||
|
@ -10,14 +9,9 @@ import 'Diag/ConsoleApi';
|
|||
export async function bootstrap() {
|
||||
const history = createBrowserHistory();
|
||||
const store = createAppStore(history);
|
||||
const hasTranslationsError = !(await fetchTranslations());
|
||||
|
||||
render(
|
||||
<App
|
||||
store={store}
|
||||
history={history}
|
||||
hasTranslationsError={hasTranslationsError}
|
||||
/>,
|
||||
<App store={store} history={history} />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue