From 1a40924db30958def3ec93518da3c0c387df56c2 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 18 Jul 2023 20:20:27 -0700 Subject: [PATCH] Fixed: Improve translation loading (cherry picked from commit 73c5ec1da4dd00301e1b0dddbcea37590a99b045) --- frontend/src/App/App.js | 7 ++--- frontend/src/Components/Page/ErrorPage.js | 8 ++--- frontend/src/Components/Page/PageConnector.js | 30 ++++++++++++------- frontend/src/Store/Actions/appActions.js | 21 ++++++++++++- frontend/src/bootstrap.tsx | 8 +---- 5 files changed, 48 insertions(+), 26 deletions(-) diff --git a/frontend/src/App/App.js b/frontend/src/App/App.js index e7b226a5d..1eea6e082 100644 --- a/frontend/src/App/App.js +++ b/frontend/src/App/App.js @@ -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 ( - + @@ -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; diff --git a/frontend/src/Components/Page/ErrorPage.js b/frontend/src/Components/Page/ErrorPage.js index 7c8f4a8c3..a2b0fca32 100644 --- a/frontend/src/Components/Page/ErrorPage.js +++ b/frontend/src/Components/Page/ErrorPage.js @@ -7,7 +7,7 @@ function ErrorPage(props) { const { version, isLocalStorageSupported, - hasTranslationsError, + translationsError, indexersError, indexerStatusError, indexerCategoriesError, @@ -22,8 +22,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 (indexersError) { errorMessage = getErrorMessage(indexersError, 'Failed to load indexers from API'); } else if (indexerStatusError) { @@ -58,7 +58,7 @@ function ErrorPage(props) { ErrorPage.propTypes = { version: PropTypes.string.isRequired, isLocalStorageSupported: PropTypes.bool.isRequired, - hasTranslationsError: PropTypes.bool.isRequired, + translationsError: PropTypes.object, indexersError: PropTypes.object, indexerStatusError: PropTypes.object, indexerCategoriesError: PropTypes.object, diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js index d584933e8..5c1f6f42e 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -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 { fetchIndexers } from 'Store/Actions/indexerActions'; import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions'; @@ -54,6 +54,7 @@ const selectIsPopulated = createSelector( (state) => state.indexerStatus.isPopulated, (state) => state.settings.indexerCategories.isPopulated, (state) => state.system.status.isPopulated, + (state) => state.app.translations.isPopulated, ( customFiltersIsPopulated, tagsIsPopulated, @@ -63,7 +64,8 @@ const selectIsPopulated = createSelector( indexersIsPopulated, indexerStatusIsPopulated, indexerCategoriesIsPopulated, - systemStatusIsPopulated + systemStatusIsPopulated, + translationsIsPopulated ) => { return ( customFiltersIsPopulated && @@ -74,7 +76,8 @@ const selectIsPopulated = createSelector( indexersIsPopulated && indexerStatusIsPopulated && indexerCategoriesIsPopulated && - systemStatusIsPopulated + systemStatusIsPopulated && + translationsIsPopulated ); } ); @@ -89,6 +92,7 @@ const selectErrors = createSelector( (state) => state.indexerStatus.error, (state) => state.settings.indexerCategories.error, (state) => state.system.status.error, + (state) => state.app.translations.error, ( customFiltersError, tagsError, @@ -98,7 +102,8 @@ const selectErrors = createSelector( indexersError, indexerStatusError, indexerCategoriesError, - systemStatusError + systemStatusError, + translationsError ) => { const hasError = !!( customFiltersError || @@ -109,7 +114,8 @@ const selectErrors = createSelector( indexersError || indexerStatusError || indexerCategoriesError || - systemStatusError + systemStatusError || + translationsError ); return { @@ -122,7 +128,8 @@ const selectErrors = createSelector( indexersError, indexerStatusError, indexerCategoriesError, - systemStatusError + systemStatusError, + translationsError }; } ); @@ -184,6 +191,9 @@ function createMapDispatchToProps(dispatch, props) { dispatchFetchStatus() { dispatch(fetchStatus()); }, + dispatchFetchTranslations() { + dispatch(fetchTranslations()); + }, onResize(dimensions) { dispatch(saveDimensions(dimensions)); }, @@ -217,6 +227,7 @@ class PageConnector extends Component { this.props.dispatchFetchUISettings(); this.props.dispatchFetchGeneralSettings(); this.props.dispatchFetchStatus(); + this.props.dispatchFetchTranslations(); } } @@ -232,7 +243,6 @@ class PageConnector extends Component { render() { const { - hasTranslationsError, isPopulated, hasError, dispatchFetchTags, @@ -243,15 +253,15 @@ class PageConnector extends Component { dispatchFetchUISettings, dispatchFetchGeneralSettings, dispatchFetchStatus, + dispatchFetchTranslations, ...otherProps } = this.props; - if (hasTranslationsError || hasError || !this.state.isLocalStorageSupported) { + if (hasError || !this.state.isLocalStorageSupported) { return ( ); } @@ -272,7 +282,6 @@ class PageConnector extends Component { } PageConnector.propTypes = { - hasTranslationsError: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, hasError: PropTypes.bool.isRequired, isSidebarVisible: PropTypes.bool.isRequired, @@ -285,6 +294,7 @@ PageConnector.propTypes = { dispatchFetchUISettings: PropTypes.func.isRequired, dispatchFetchGeneralSettings: PropTypes.func.isRequired, dispatchFetchStatus: PropTypes.func.isRequired, + dispatchFetchTranslations: PropTypes.func.isRequired, onSidebarVisibleChange: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/appActions.js b/frontend/src/Store/Actions/appActions.js index a273c7292..2b779d1b0 100644 --- a/frontend/src/Store/Actions/appActions.js +++ b/frontend/src/Store/Actions/appActions.js @@ -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' + } + })); } }); diff --git a/frontend/src/bootstrap.tsx b/frontend/src/bootstrap.tsx index c07e581b5..5e9985ba3 100644 --- a/frontend/src/bootstrap.tsx +++ b/frontend/src/bootstrap.tsx @@ -2,20 +2,14 @@ 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'; export async function bootstrap() { const history = createBrowserHistory(); const store = createAppStore(history); - const hasTranslationsError = !(await fetchTranslations()); render( - , + , document.getElementById('root') ); }