From 5e52627799d4bde176c2101e11a5bb9aa24d45d7 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Jul 2023 16:55:25 -0700 Subject: [PATCH] Fixed: Ensure translations are fetched before loading app (cherry picked from commit ad2721dc55f3233e4c299babe5744418bc530418) --- frontend/build/webpack.config.js | 4 +++ frontend/src/App/App.js | 7 +++-- frontend/src/Components/Page/ErrorPage.js | 4 +++ frontend/src/Components/Page/PageConnector.js | 5 +++- frontend/src/Utilities/String/translate.js | 29 +++++++++++-------- frontend/src/index.js | 9 ++++-- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/frontend/build/webpack.config.js b/frontend/build/webpack.config.js index 7c1dcba83..f331cbc0b 100644 --- a/frontend/build/webpack.config.js +++ b/frontend/build/webpack.config.js @@ -82,6 +82,10 @@ module.exports = (env) => { hints: false }, + experiments: { + topLevelAwait: true + }, + plugins: [ new webpack.DefinePlugin({ __DEV__: !isProduction, diff --git a/frontend/src/App/App.js b/frontend/src/App/App.js index 1eea6e082..e7b226a5d 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 }) { +function App({ store, history, hasTranslationsError }) { return ( - + @@ -25,7 +25,8 @@ function App({ store, history }) { App.propTypes = { store: PropTypes.object.isRequired, - history: PropTypes.object.isRequired + history: PropTypes.object.isRequired, + hasTranslationsError: PropTypes.bool.isRequired }; export default App; diff --git a/frontend/src/Components/Page/ErrorPage.js b/frontend/src/Components/Page/ErrorPage.js index 77bed6a31..7c8f4a8c3 100644 --- a/frontend/src/Components/Page/ErrorPage.js +++ b/frontend/src/Components/Page/ErrorPage.js @@ -7,6 +7,7 @@ function ErrorPage(props) { const { version, isLocalStorageSupported, + hasTranslationsError, indexersError, indexerStatusError, indexerCategoriesError, @@ -21,6 +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 (indexersError) { errorMessage = getErrorMessage(indexersError, 'Failed to load indexers from API'); } else if (indexerStatusError) { @@ -55,6 +58,7 @@ function ErrorPage(props) { ErrorPage.propTypes = { version: PropTypes.string.isRequired, isLocalStorageSupported: PropTypes.bool.isRequired, + hasTranslationsError: PropTypes.bool.isRequired, 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 5ac032c0f..d584933e8 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -232,6 +232,7 @@ class PageConnector extends Component { render() { const { + hasTranslationsError, isPopulated, hasError, dispatchFetchTags, @@ -245,11 +246,12 @@ class PageConnector extends Component { ...otherProps } = this.props; - if (hasError || !this.state.isLocalStorageSupported) { + if (hasTranslationsError || hasError || !this.state.isLocalStorageSupported) { return ( ); } @@ -270,6 +272,7 @@ class PageConnector extends Component { } PageConnector.propTypes = { + hasTranslationsError: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, hasError: PropTypes.bool.isRequired, isSidebarVisible: PropTypes.bool.isRequired, diff --git a/frontend/src/Utilities/String/translate.js b/frontend/src/Utilities/String/translate.js index 7483b27aa..fb0ec0cb5 100644 --- a/frontend/src/Utilities/String/translate.js +++ b/frontend/src/Utilities/String/translate.js @@ -1,22 +1,27 @@ import createAjaxRequest from 'Utilities/createAjaxRequest'; function getTranslations() { - let localization = null; - const ajaxOptions = { - async: false, + return createAjaxRequest({ + global: false, dataType: 'json', - url: '/localization', - success: function(data) { - localization = data.Strings; - } - }; + url: '/localization' + }).request; +} - createAjaxRequest(ajaxOptions); +let translations = {}; - return localization; -} +export function fetchTranslations() { + return new Promise(async(resolve) => { + try { + const data = await getTranslations(); + translations = data.Strings; -const translations = getTranslations(); + resolve(true); + } catch (error) { + resolve(false); + } + }); +} export default function translate(key, args = []) { const translation = translations[key] || key; diff --git a/frontend/src/index.js b/frontend/src/index.js index 59911154e..acdfc6517 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -1,8 +1,7 @@ import { createBrowserHistory } from 'history'; import React from 'react'; import { render } from 'react-dom'; -import createAppStore from 'Store/createAppStore'; -import App from './App/App'; +import { fetchTranslations } from 'Utilities/String/translate'; import './preload'; import './polyfills'; @@ -10,12 +9,18 @@ import 'Styles/globals.css'; import './index.css'; const history = createBrowserHistory(); +const hasTranslationsError = !await fetchTranslations(); + +const { default: createAppStore } = await import('Store/createAppStore'); +const { default: App } = await import('./App/App'); + const store = createAppStore(history); render( , document.getElementById('root') );