Fixed: Improve translation loading

pull/5821/head
Mark McDowall 2 years ago
parent bb8fed94eb
commit 73c5ec1da4

@ -7,13 +7,13 @@ import PageConnector from 'Components/Page/PageConnector';
import ApplyTheme from './ApplyTheme'; import ApplyTheme from './ApplyTheme';
import AppRoutes from './AppRoutes'; import AppRoutes from './AppRoutes';
function App({ store, history, hasTranslationsError }) { function App({ store, history }) {
return ( return (
<DocumentTitle title={window.Sonarr.instanceName}> <DocumentTitle title={window.Sonarr.instanceName}>
<Provider store={store}> <Provider store={store}>
<ConnectedRouter history={history}> <ConnectedRouter history={history}>
<ApplyTheme> <ApplyTheme>
<PageConnector hasTranslationsError={hasTranslationsError}> <PageConnector>
<AppRoutes app={App} /> <AppRoutes app={App} />
</PageConnector> </PageConnector>
</ApplyTheme> </ApplyTheme>
@ -25,8 +25,7 @@ function App({ store, history, hasTranslationsError }) {
App.propTypes = { App.propTypes = {
store: PropTypes.object.isRequired, store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired, history: PropTypes.object.isRequired
hasTranslationsError: PropTypes.bool.isRequired
}; };
export default App; export default App;

@ -7,7 +7,7 @@ function ErrorPage(props) {
const { const {
version, version,
isLocalStorageSupported, isLocalStorageSupported,
hasTranslationsError, translationsError,
seriesError, seriesError,
customFiltersError, customFiltersError,
tagsError, tagsError,
@ -20,8 +20,8 @@ function ErrorPage(props) {
if (!isLocalStorageSupported) { if (!isLocalStorageSupported) {
errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.'; errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.';
} else if (hasTranslationsError) { } else if (translationsError) {
errorMessage = 'Failed to load translations from API'; errorMessage = getErrorMessage(translationsError, 'Failed to load translations from API');
} else if (seriesError) { } else if (seriesError) {
errorMessage = getErrorMessage(seriesError, 'Failed to load series from API'); errorMessage = getErrorMessage(seriesError, 'Failed to load series from API');
} else if (customFiltersError) { } else if (customFiltersError) {
@ -52,7 +52,7 @@ function ErrorPage(props) {
ErrorPage.propTypes = { ErrorPage.propTypes = {
version: PropTypes.string.isRequired, version: PropTypes.string.isRequired,
isLocalStorageSupported: PropTypes.bool.isRequired, isLocalStorageSupported: PropTypes.bool.isRequired,
hasTranslationsError: PropTypes.bool.isRequired, translationsError: PropTypes.object,
seriesError: PropTypes.object, seriesError: PropTypes.object,
customFiltersError: PropTypes.object, customFiltersError: PropTypes.object,
tagsError: PropTypes.object, tagsError: PropTypes.object,

@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { createSelector } from 'reselect'; 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 { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchSeries } from 'Store/Actions/seriesActions'; import { fetchSeries } from 'Store/Actions/seriesActions';
import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions'; import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
@ -52,6 +52,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.languages.isPopulated, (state) => state.settings.languages.isPopulated,
(state) => state.settings.importLists.isPopulated, (state) => state.settings.importLists.isPopulated,
(state) => state.system.status.isPopulated, (state) => state.system.status.isPopulated,
(state) => state.app.translations.isPopulated,
( (
seriesIsPopulated, seriesIsPopulated,
customFiltersIsPopulated, customFiltersIsPopulated,
@ -60,7 +61,8 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated, qualityProfilesIsPopulated,
languagesIsPopulated, languagesIsPopulated,
importListsIsPopulated, importListsIsPopulated,
systemStatusIsPopulated systemStatusIsPopulated,
translationsIsPopulated
) => { ) => {
return ( return (
seriesIsPopulated && seriesIsPopulated &&
@ -70,7 +72,8 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated && qualityProfilesIsPopulated &&
languagesIsPopulated && languagesIsPopulated &&
importListsIsPopulated && importListsIsPopulated &&
systemStatusIsPopulated systemStatusIsPopulated &&
translationsIsPopulated
); );
} }
); );
@ -84,6 +87,7 @@ const selectErrors = createSelector(
(state) => state.settings.languages.error, (state) => state.settings.languages.error,
(state) => state.settings.importLists.error, (state) => state.settings.importLists.error,
(state) => state.system.status.error, (state) => state.system.status.error,
(state) => state.app.translations.error,
( (
seriesError, seriesError,
customFiltersError, customFiltersError,
@ -92,7 +96,8 @@ const selectErrors = createSelector(
qualityProfilesError, qualityProfilesError,
languagesError, languagesError,
importListsError, importListsError,
systemStatusError systemStatusError,
translationsError
) => { ) => {
const hasError = !!( const hasError = !!(
seriesError || seriesError ||
@ -102,7 +107,8 @@ const selectErrors = createSelector(
qualityProfilesError || qualityProfilesError ||
languagesError || languagesError ||
importListsError || importListsError ||
systemStatusError systemStatusError ||
translationsError
); );
return { return {
@ -114,7 +120,8 @@ const selectErrors = createSelector(
qualityProfilesError, qualityProfilesError,
languagesError, languagesError,
importListsError, importListsError,
systemStatusError systemStatusError,
translationsError
}; };
} }
); );
@ -173,6 +180,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchStatus() { dispatchFetchStatus() {
dispatch(fetchStatus()); dispatch(fetchStatus());
}, },
dispatchFetchTranslations() {
dispatch(fetchTranslations());
},
onResize(dimensions) { onResize(dimensions) {
dispatch(saveDimensions(dimensions)); dispatch(saveDimensions(dimensions));
}, },
@ -205,6 +215,7 @@ class PageConnector extends Component {
this.props.dispatchFetchImportLists(); this.props.dispatchFetchImportLists();
this.props.dispatchFetchUISettings(); this.props.dispatchFetchUISettings();
this.props.dispatchFetchStatus(); this.props.dispatchFetchStatus();
this.props.dispatchFetchTranslations();
} }
} }
@ -220,7 +231,6 @@ class PageConnector extends Component {
render() { render() {
const { const {
hasTranslationsError,
isPopulated, isPopulated,
hasError, hasError,
dispatchFetchSeries, dispatchFetchSeries,
@ -230,15 +240,15 @@ class PageConnector extends Component {
dispatchFetchImportLists, dispatchFetchImportLists,
dispatchFetchUISettings, dispatchFetchUISettings,
dispatchFetchStatus, dispatchFetchStatus,
dispatchFetchTranslations,
...otherProps ...otherProps
} = this.props; } = this.props;
if (hasTranslationsError || hasError || !this.state.isLocalStorageSupported) { if (hasError || !this.state.isLocalStorageSupported) {
return ( return (
<ErrorPage <ErrorPage
{...this.state} {...this.state}
{...otherProps} {...otherProps}
hasTranslationsError={hasTranslationsError}
/> />
); );
} }
@ -259,7 +269,6 @@ class PageConnector extends Component {
} }
PageConnector.propTypes = { PageConnector.propTypes = {
hasTranslationsError: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired,
hasError: PropTypes.bool.isRequired, hasError: PropTypes.bool.isRequired,
isSidebarVisible: PropTypes.bool.isRequired, isSidebarVisible: PropTypes.bool.isRequired,
@ -271,6 +280,7 @@ PageConnector.propTypes = {
dispatchFetchImportLists: PropTypes.func.isRequired, dispatchFetchImportLists: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired, dispatchFetchUISettings: PropTypes.func.isRequired,
dispatchFetchStatus: PropTypes.func.isRequired, dispatchFetchStatus: PropTypes.func.isRequired,
dispatchFetchTranslations: PropTypes.func.isRequired,
onSidebarVisibleChange: PropTypes.func.isRequired onSidebarVisibleChange: PropTypes.func.isRequired
}; };

@ -21,16 +21,22 @@ const SIDEBAR_WIDTH = parseInt(dimensions.sidebarWidth);
const links = [ const links = [
{ {
iconName: icons.SERIES_CONTINUING, iconName: icons.SERIES_CONTINUING,
title: translate('Series'), get title() {
return translate('Series');
},
to: '/', to: '/',
alias: '/series', alias: '/series',
children: [ children: [
{ {
title: translate('AddNew'), get title() {
return translate('AddNew');
},
to: '/add/new' to: '/add/new'
}, },
{ {
title: translate('LibraryImport'), get title() {
return translate('LibraryImport');
},
to: '/add/import' to: '/add/import'
} }
] ]
@ -38,26 +44,36 @@ const links = [
{ {
iconName: icons.CALENDAR, iconName: icons.CALENDAR,
title: translate('Calendar'), get title() {
return translate('Calendar');
},
to: '/calendar' to: '/calendar'
}, },
{ {
iconName: icons.ACTIVITY, iconName: icons.ACTIVITY,
title: translate('Activity'), get title() {
return translate('Activity');
},
to: '/activity/queue', to: '/activity/queue',
children: [ children: [
{ {
title: translate('Queue'), get title() {
return translate('Queue');
},
to: '/activity/queue', to: '/activity/queue',
statusComponent: QueueStatusConnector statusComponent: QueueStatusConnector
}, },
{ {
title: translate('History'), get title() {
return translate('History');
},
to: '/activity/history' to: '/activity/history'
}, },
{ {
title: translate('Blocklist'), get title() {
return translate('Blocklist');
},
to: '/activity/blocklist' to: '/activity/blocklist'
} }
] ]
@ -65,15 +81,21 @@ const links = [
{ {
iconName: icons.WARNING, iconName: icons.WARNING,
title: translate('Wanted'), get title() {
return translate('Wanted');
},
to: '/wanted/missing', to: '/wanted/missing',
children: [ children: [
{ {
title: translate('Missing'), get title() {
return translate('Missing');
},
to: '/wanted/missing' to: '/wanted/missing'
}, },
{ {
title: translate('CutoffUnmet'), get title() {
return translate('CutoffUnmet');
},
to: '/wanted/cutoffunmet' to: '/wanted/cutoffunmet'
} }
] ]
@ -81,59 +103,87 @@ const links = [
{ {
iconName: icons.SETTINGS, iconName: icons.SETTINGS,
title: translate('Settings'), get title() {
return translate('Settings');
},
to: '/settings', to: '/settings',
children: [ children: [
{ {
title: translate('MediaManagement'), get title() {
return translate('MediaManagement');
},
to: '/settings/mediamanagement' to: '/settings/mediamanagement'
}, },
{ {
title: translate('Profiles'), get title() {
return translate('Profiles');
},
to: '/settings/profiles' to: '/settings/profiles'
}, },
{ {
title: translate('Quality'), get title() {
return translate('Quality');
},
to: '/settings/quality' to: '/settings/quality'
}, },
{ {
title: translate('CustomFormats'), get title() {
return translate('CustomFormats');
},
to: '/settings/customformats' to: '/settings/customformats'
}, },
{ {
title: translate('Indexers'), get title() {
return translate('Indexers');
},
to: '/settings/indexers' to: '/settings/indexers'
}, },
{ {
title: translate('DownloadClients'), get title() {
return translate('DownloadClients');
},
to: '/settings/downloadclients' to: '/settings/downloadclients'
}, },
{ {
title: translate('ImportLists'), get title() {
return translate('ImportLists');
},
to: '/settings/importlists' to: '/settings/importlists'
}, },
{ {
title: translate('Connect'), get title() {
return translate('Connect');
},
to: '/settings/connect' to: '/settings/connect'
}, },
{ {
title: translate('Metadata'), get title() {
return translate('Metadata');
},
to: '/settings/metadata' to: '/settings/metadata'
}, },
{ {
title: translate('MetadataSource'), get title() {
return translate('MetadataSource');
},
to: '/settings/metadatasource' to: '/settings/metadatasource'
}, },
{ {
title: translate('Tags'), get title() {
return translate('Tags');
},
to: '/settings/tags' to: '/settings/tags'
}, },
{ {
title: translate('General'), get title() {
return translate('General');
},
to: '/settings/general' to: '/settings/general'
}, },
{ {
title: translate('UI'), get title() {
return translate('UI');
},
to: '/settings/ui' to: '/settings/ui'
} }
] ]
@ -141,32 +191,46 @@ const links = [
{ {
iconName: icons.SYSTEM, iconName: icons.SYSTEM,
title: translate('System'), get title() {
return translate('System');
},
to: '/system/status', to: '/system/status',
children: [ children: [
{ {
title: translate('Status'), get title() {
return translate('Status');
},
to: '/system/status', to: '/system/status',
statusComponent: HealthStatusConnector statusComponent: HealthStatusConnector
}, },
{ {
title: translate('Tasks'), get title() {
return translate('Tasks');
},
to: '/system/tasks' to: '/system/tasks'
}, },
{ {
title: translate('Backup'), get title() {
return translate('Backup');
},
to: '/system/backup' to: '/system/backup'
}, },
{ {
title: translate('Updates'), get title() {
return translate('Updates');
},
to: '/system/updates' to: '/system/updates'
}, },
{ {
title: translate('Events'), get title() {
return translate('Events');
},
to: '/system/events' to: '/system/events'
}, },
{ {
title: translate('LogFiles'), get title() {
return translate('LogFiles');
},
to: '/system/logs/files' to: '/system/logs/files'
} }
] ]

@ -27,9 +27,25 @@ interface ManageDownloadClientsEditModalContentProps {
const NO_CHANGE = 'noChange'; const NO_CHANGE = 'noChange';
const enableOptions = [ const enableOptions = [
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true }, {
{ key: 'enabled', value: translate('Enabled') }, key: NO_CHANGE,
{ key: 'disabled', value: translate('Disabled') }, get value() {
return translate('NoChange');
},
disabled: true,
},
{
key: 'enabled',
get value() {
return translate('Enabled');
},
},
{
key: 'disabled',
get value() {
return translate('Disabled');
},
},
]; ];
function ManageDownloadClientsEditModalContent( function ManageDownloadClientsEditModalContent(

@ -36,37 +36,49 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [ const COLUMNS = [
{ {
name: 'name', name: 'name',
label: translate('Name'), get label() {
return translate('Name');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'implementation', name: 'implementation',
label: translate('Implementation'), get label() {
return translate('Implementation');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'enable', name: 'enable',
label: translate('Enabled'), get label() {
return translate('Enabled');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'priority', name: 'priority',
label: translate('Priority'), get label() {
return translate('Priority');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'removeCompletedDownloads', name: 'removeCompletedDownloads',
label: translate('RemoveCompleted'), get label() {
return translate('RemoveCompleted');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'removeFailedDownloads', name: 'removeFailedDownloads',
label: translate('RemoveFailed'), get label() {
return translate('RemoveFailed');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },

@ -72,9 +72,24 @@ function TagsModalContent(props: TagsModalContentProps) {
}, [tags, applyTags, onApplyTagsPress]); }, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [ const applyTagsOptions = [
{ key: 'add', value: translate('Add') }, {
{ key: 'remove', value: translate('Remove') }, key: 'add',
{ key: 'replace', value: translate('Replace') }, get value() {
return translate('Add');
},
},
{
key: 'remove',
get value() {
return translate('Remove');
},
},
{
key: 'replace',
get value() {
return translate('Replace');
},
},
]; ];
return ( return (

@ -26,9 +26,25 @@ interface ManageImportListsEditModalContentProps {
const NO_CHANGE = 'noChange'; const NO_CHANGE = 'noChange';
const autoAddOptions = [ const autoAddOptions = [
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true }, {
{ key: 'enabled', value: translate('Enabled') }, key: NO_CHANGE,
{ key: 'disabled', value: translate('Disabled') }, get value() {
return translate('NoChange');
},
disabled: true,
},
{
key: 'enabled',
get value() {
return translate('Enabled');
},
},
{
key: 'disabled',
get value() {
return translate('Disabled');
},
},
]; ];
function ManageImportListsEditModalContent( function ManageImportListsEditModalContent(

@ -36,37 +36,49 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [ const COLUMNS = [
{ {
name: 'name', name: 'name',
label: translate('Name'), get label() {
return translate('Name');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'implementation', name: 'implementation',
label: translate('Implementation'), get label() {
return translate('Implementation');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'qualityProfileId', name: 'qualityProfileId',
label: translate('QualityProfile'), get label() {
return translate('QualityProfile');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'rootFolderPath', name: 'rootFolderPath',
label: translate('RootFolder'), get label() {
return translate('RootFolder');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'enableAutomaticAdd', name: 'enableAutomaticAdd',
label: translate('AutoAdd'), get label() {
return translate('AutoAdd');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'tags', name: 'tags',
label: translate('Tags'), get label() {
return translate('Tags');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },

@ -70,9 +70,24 @@ function TagsModalContent(props: TagsModalContentProps) {
}, [tags, applyTags, onApplyTagsPress]); }, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [ const applyTagsOptions = [
{ key: 'add', value: translate('Add') }, {
{ key: 'remove', value: translate('Remove') }, key: 'add',
{ key: 'replace', value: translate('Replace') }, get value() {
return translate('Add');
},
},
{
key: 'remove',
get value() {
return translate('Remove');
},
},
{
key: 'replace',
get value() {
return translate('Replace');
},
},
]; ];
return ( return (

@ -27,9 +27,25 @@ interface ManageIndexersEditModalContentProps {
const NO_CHANGE = 'noChange'; const NO_CHANGE = 'noChange';
const enableOptions = [ const enableOptions = [
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true }, {
{ key: 'enabled', value: translate('Enabled') }, key: NO_CHANGE,
{ key: 'disabled', value: translate('Disabled') }, get value() {
return translate('NoChange');
},
disabled: true,
},
{
key: 'enabled',
get value() {
return translate('Enabled');
},
},
{
key: 'disabled',
get value() {
return translate('Disabled');
},
},
]; ];
function ManageIndexersEditModalContent( function ManageIndexersEditModalContent(

@ -36,43 +36,57 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [ const COLUMNS = [
{ {
name: 'name', name: 'name',
label: translate('Name'), get label() {
return translate('Name');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'implementation', name: 'implementation',
label: translate('Implementation'), get label() {
return translate('Implementation');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'enableRss', name: 'enableRss',
label: translate('EnableRSS'), get label() {
return translate('EnableRSS');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'enableAutomaticSearch', name: 'enableAutomaticSearch',
label: translate('EnableAutomaticSearch'), get label() {
return translate('EnableAutomaticSearch');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'enableInteractiveSearch', name: 'enableInteractiveSearch',
label: translate('EnableInteractiveSearch'), get label() {
return translate('EnableInteractiveSearch');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'priority', name: 'priority',
label: translate('Priority'), get label() {
return translate('Priority');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'tags', name: 'tags',
label: translate('Tags'), get label() {
return translate('Tags');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },

@ -70,9 +70,24 @@ function TagsModalContent(props: TagsModalContentProps) {
}, [tags, applyTags, onApplyTagsPress]); }, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [ const applyTagsOptions = [
{ key: 'add', value: translate('Add') }, {
{ key: 'remove', value: translate('Remove') }, key: 'add',
{ key: 'replace', value: translate('Replace') }, get value() {
return translate('Add');
},
},
{
key: 'remove',
get value() {
return translate('Remove');
},
},
{
key: 'replace',
get value() {
return translate('Replace');
},
},
]; ];
return ( return (

@ -4,6 +4,7 @@ import { createThunk, handleThunks } from 'Store/thunks';
import createAjaxRequest from 'Utilities/createAjaxRequest'; import createAjaxRequest from 'Utilities/createAjaxRequest';
import getSectionState from 'Utilities/State/getSectionState'; import getSectionState from 'Utilities/State/getSectionState';
import updateSectionState from 'Utilities/State/updateSectionState'; import updateSectionState from 'Utilities/State/updateSectionState';
import { fetchTranslations as fetchAppTranslations } from 'Utilities/String/translate';
import createHandleActions from './Creators/createHandleActions'; import createHandleActions from './Creators/createHandleActions';
function getDimensions(width, height) { function getDimensions(width, height) {
@ -41,7 +42,12 @@ export const defaultState = {
isReconnecting: false, isReconnecting: false,
isDisconnected: false, isDisconnected: false,
isRestarting: 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_VERSION = 'app/setVersion';
export const SET_APP_VALUE = 'app/setAppValue'; export const SET_APP_VALUE = 'app/setAppValue';
export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible'; export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible';
export const FETCH_TRANSLATIONS = 'app/fetchTranslations';
export const PING_SERVER = 'app/pingServer'; 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 showMessage = createAction(SHOW_MESSAGE);
export const hideMessage = createAction(HIDE_MESSAGE); export const hideMessage = createAction(HIDE_MESSAGE);
export const pingServer = createThunk(PING_SERVER); export const pingServer = createThunk(PING_SERVER);
export const fetchTranslations = createThunk(FETCH_TRANSLATIONS);
// //
// Helpers // Helpers
@ -127,6 +135,17 @@ function pingServerAfterTimeout(getState, dispatch) {
export const actionHandlers = handleThunks({ export const actionHandlers = handleThunks({
[PING_SERVER]: function(getState, payload, dispatch) { [PING_SERVER]: function(getState, payload, dispatch) {
pingServerAfterTimeout(getState, 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', name: 'customFormatScore',
columnLabel: translate('CustomFormatScore'), get columnLabel() {
return translate('CustomFormatScore');
},
label: React.createElement(Icon, { label: React.createElement(Icon, {
name: icons.SCORE, name: icons.SCORE,
title: translate('CustomFormatScore') get title() {
return translate('CustomFormatScore');
}
}), }),
isVisible: false isVisible: false
}, },

@ -4,14 +4,14 @@ function getTranslations() {
return createAjaxRequest({ return createAjaxRequest({
global: false, global: false,
dataType: 'json', dataType: 'json',
url: '/localization' url: '/localization',
}).request; }).request;
} }
let translations = {}; let translations: Record<string, string> = {};
export function fetchTranslations() { export async function fetchTranslations(): Promise<boolean> {
return new Promise(async(resolve) => { return new Promise(async (resolve) => {
try { try {
const data = await getTranslations(); const data = await getTranslations();
translations = data.strings; 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; const translation = translations[key] || key;
if (tokens) { if (tokens) {

@ -2,7 +2,6 @@ import { createBrowserHistory } from 'history';
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import createAppStore from 'Store/createAppStore'; import createAppStore from 'Store/createAppStore';
import { fetchTranslations } from 'Utilities/String/translate';
import App from './App/App'; import App from './App/App';
import 'Diag/ConsoleApi'; import 'Diag/ConsoleApi';
@ -10,14 +9,9 @@ import 'Diag/ConsoleApi';
export async function bootstrap() { export async function bootstrap() {
const history = createBrowserHistory(); const history = createBrowserHistory();
const store = createAppStore(history); const store = createAppStore(history);
const hasTranslationsError = !(await fetchTranslations());
render( render(
<App <App store={store} history={history} />,
store={store}
history={history}
hasTranslationsError={hasTranslationsError}
/>,
document.getElementById('root') document.getElementById('root')
); );
} }

Loading…
Cancel
Save