From cef9ade10e49e776eb51b69584045a476baaff0a Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Fri, 4 Mar 2022 23:29:20 +0800 Subject: [PATCH] Render whole app on language change ## Issues 1. We were manually adding `selectLanguage(state)` as a prop to components used in Settings Page to trigger a render. Flaws: - Unclear that the unused prop is just to trigger a render. - Manually adding on a case-by-case basis will break over time (missed component). 2. The translation file fetching is delayed (at least in Odysee) and also takes time, so the GUI will end up having mixed strings on F5, depending on when the fetch completed. ## Approach Make the app wrapper have a key that's tied to the language and translation data, so the entire app renders when language changes. Seems like a common design in most apps. ## Ticket odysee 921 --- ui/component/app/view.jsx | 7 +++++++ ui/component/settingAccount/index.js | 2 -- ui/component/settingAccountPassword/index.js | 4 +--- ui/component/settingAppearance/index.js | 3 +-- ui/component/settingAutoLaunch/index.js | 3 +-- ui/component/settingContent/index.js | 3 +-- ui/component/settingSystem/index.js | 8 +------- ui/component/settingUnauthenticated/index.js | 3 +-- ui/component/sideNavigation/index.js | 3 +-- ui/component/syncEnableFlow/index.js | 3 +-- ui/component/syncToggle/index.js | 3 +-- ui/component/wunderbarSuggestions/index.js | 3 +-- ui/page/settings/index.js | 3 +-- 13 files changed, 18 insertions(+), 30 deletions(-) diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index 6d9eba94c..2a3ddefe7 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -128,6 +128,7 @@ function App(props: Props) { const [upgradeNagClosed, setUpgradeNagClosed] = useState(false); const [resolvedSubscriptions, setResolvedSubscriptions] = useState(false); // const [retryingSync, setRetryingSync] = useState(false); + const [langRenderKey, setLangRenderKey] = useState(0); const [sidebarOpen] = usePersistedState('sidebar', true); const showUpgradeButton = (autoUpdateDownloaded || isUpgradeAvailable) && !upgradeNagClosed; // referral claiming @@ -327,6 +328,11 @@ function App(props: Props) { } }, [sidebarOpen, isPersonalized, resolvedSubscriptions, subscriptions, resolveUris, setResolvedSubscriptions]); + useEffect(() => { + // When language is changed or translations are fetched, we render. + setLangRenderKey(Date.now()); + }, [language, languages]); + if (syncFatalError) { return ; } @@ -338,6 +344,7 @@ function App(props: Props) { [`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar, })} ref={appRef} + key={langRenderKey} onContextMenu={(e) => openContextMenu(e)} > diff --git a/ui/component/settingAccount/index.js b/ui/component/settingAccount/index.js index 51f0c4c81..38e30f9b4 100644 --- a/ui/component/settingAccount/index.js +++ b/ui/component/settingAccount/index.js @@ -3,7 +3,6 @@ import { selectHasChannels } from 'redux/selectors/claims'; import { selectWalletIsEncrypted } from 'redux/selectors/wallet'; import { doWalletStatus } from 'redux/actions/wallet'; import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user'; -import { selectLanguage } from 'redux/selectors/settings'; import SettingAccount from './view'; @@ -12,7 +11,6 @@ const select = (state) => ({ walletEncrypted: selectWalletIsEncrypted(state), user: selectUser(state), hasChannels: selectHasChannels(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/settingAccountPassword/index.js b/ui/component/settingAccountPassword/index.js index 44dc35f4b..df5fbb5ce 100644 --- a/ui/component/settingAccountPassword/index.js +++ b/ui/component/settingAccountPassword/index.js @@ -1,15 +1,13 @@ import { connect } from 'react-redux'; import { selectUser, selectPasswordSetSuccess, selectPasswordSetError } from 'redux/selectors/user'; -import { selectLanguage } from 'redux/selectors/settings'; import { doUserPasswordSet, doClearPasswordEntry } from 'redux/actions/user'; import { doToast } from 'redux/actions/notifications'; import UserSignIn from './view'; -const select = state => ({ +const select = (state) => ({ user: selectUser(state), passwordSetSuccess: selectPasswordSetSuccess(state), passwordSetError: selectPasswordSetError(state), - language: selectLanguage(state), }); export default connect(select, { diff --git a/ui/component/settingAppearance/index.js b/ui/component/settingAppearance/index.js index 4a42fad39..45d1b44e8 100644 --- a/ui/component/settingAppearance/index.js +++ b/ui/component/settingAppearance/index.js @@ -1,14 +1,13 @@ import { connect } from 'react-redux'; import * as SETTINGS from 'constants/settings'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectLanguage, makeSelectClientSetting } from 'redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import SettingAppearance from './view'; const select = (state) => ({ clock24h: makeSelectClientSetting(SETTINGS.CLOCK_24H)(state), searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state), hideBalance: makeSelectClientSetting(SETTINGS.HIDE_BALANCE)(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/settingAutoLaunch/index.js b/ui/component/settingAutoLaunch/index.js index ef8a0f5a7..cb1eb37be 100644 --- a/ui/component/settingAutoLaunch/index.js +++ b/ui/component/settingAutoLaunch/index.js @@ -1,13 +1,12 @@ import { connect } from 'react-redux'; import * as SETTINGS from 'constants/settings'; import { doSetAutoLaunch } from 'redux/actions/settings'; -import { makeSelectClientSetting, selectLanguage } from 'redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import { doToast } from 'redux/actions/notifications'; import SettingAutoLaunch from './view'; const select = (state) => ({ autoLaunch: makeSelectClientSetting(SETTINGS.AUTO_LAUNCH)(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/settingContent/index.js b/ui/component/settingContent/index.js index 9dbb09467..c0315f279 100644 --- a/ui/component/settingContent/index.js +++ b/ui/component/settingContent/index.js @@ -3,7 +3,7 @@ import { selectMyChannelUrls } from 'redux/selectors/claims'; import * as SETTINGS from 'constants/settings'; import { doSetPlayingUri } from 'redux/actions/content'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectShowMatureContent, selectLanguage, makeSelectClientSetting } from 'redux/selectors/settings'; +import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import SettingContent from './view'; @@ -19,7 +19,6 @@ const select = (state) => ({ instantPurchaseEnabled: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED)(state), instantPurchaseMax: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_MAX)(state), enablePublishPreview: makeSelectClientSetting(SETTINGS.ENABLE_PUBLISH_PREVIEW)(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/settingSystem/index.js b/ui/component/settingSystem/index.js index f2b66a1ba..e4b44c0d1 100644 --- a/ui/component/settingSystem/index.js +++ b/ui/component/settingSystem/index.js @@ -10,12 +10,7 @@ import { } from 'redux/actions/app'; import { doSetDaemonSetting, doClearDaemonSetting, doFindFFmpeg } from 'redux/actions/settings'; import { selectAllowAnalytics } from 'redux/selectors/app'; -import { - selectDaemonSettings, - selectFfmpegStatus, - selectFindingFFmpeg, - selectLanguage, -} from 'redux/selectors/settings'; +import { selectDaemonSettings, selectFfmpegStatus, selectFindingFFmpeg } from 'redux/selectors/settings'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import SettingSystem from './view'; @@ -27,7 +22,6 @@ const select = (state) => ({ walletEncrypted: selectWalletIsEncrypted(state), isAuthenticated: selectUserVerifiedEmail(state), allowAnalytics: selectAllowAnalytics(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/settingUnauthenticated/index.js b/ui/component/settingUnauthenticated/index.js index d99adcc73..815da575e 100644 --- a/ui/component/settingUnauthenticated/index.js +++ b/ui/component/settingUnauthenticated/index.js @@ -1,13 +1,12 @@ import { connect } from 'react-redux'; import * as SETTINGS from 'constants/settings'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectLanguage, makeSelectClientSetting } from 'redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import SettingUnauthenticated from './view'; const select = (state) => ({ searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/sideNavigation/index.js b/ui/component/sideNavigation/index.js index 5fbd7ac62..07f99cd6f 100644 --- a/ui/component/sideNavigation/index.js +++ b/ui/component/sideNavigation/index.js @@ -3,7 +3,7 @@ import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { doClearPurchasedUriSuccess } from 'redux/actions/file'; import { selectFollowedTags } from 'redux/selectors/tags'; import { selectUserVerifiedEmail, selectUser } from 'redux/selectors/user'; -import { selectHomepageData, selectLanguage } from 'redux/selectors/settings'; +import { selectHomepageData } from 'redux/selectors/settings'; import { doSignOut } from 'redux/actions/app'; import { selectUnseenNotificationCount } from 'redux/selectors/notifications'; import { selectPurchaseUriSuccess } from 'redux/selectors/claims'; @@ -13,7 +13,6 @@ import SideNavigation from './view'; const select = (state) => ({ subscriptions: selectSubscriptions(state), followedTags: selectFollowedTags(state), - language: selectLanguage(state), // trigger redraw on language change email: selectUserVerifiedEmail(state), purchaseSuccess: selectPurchaseUriSuccess(state), unseenCount: selectUnseenNotificationCount(state), diff --git a/ui/component/syncEnableFlow/index.js b/ui/component/syncEnableFlow/index.js index 3c7f06e16..cb6f3636a 100644 --- a/ui/component/syncEnableFlow/index.js +++ b/ui/component/syncEnableFlow/index.js @@ -8,7 +8,7 @@ import { selectHashChanged, } from 'redux/selectors/sync'; import { doCheckSync, doGetSync } from 'redux/actions/sync'; -import { makeSelectClientSetting, selectLanguage } from 'redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import { doSetWalletSyncPreference } from 'redux/actions/settings'; import SyncToggle from './view'; import { doGetAndPopulatePreferences } from 'redux/actions/app'; @@ -20,7 +20,6 @@ const select = (state) => ({ verifiedEmail: selectUserVerifiedEmail(state), getSyncError: selectGetSyncErrorMessage(state), getSyncPending: selectGetSyncIsPending(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/syncToggle/index.js b/ui/component/syncToggle/index.js index 26c5f6673..2dc20c582 100644 --- a/ui/component/syncToggle/index.js +++ b/ui/component/syncToggle/index.js @@ -2,7 +2,7 @@ import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectGetSyncErrorMessage } from 'redux/selectors/sync'; -import { makeSelectClientSetting, selectLanguage } from 'redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import { doSetWalletSyncPreference } from 'redux/actions/settings'; import { doOpenModal } from 'redux/actions/app'; import SyncToggle from './view'; @@ -11,7 +11,6 @@ const select = (state) => ({ syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state), verifiedEmail: selectUserVerifiedEmail(state), getSyncError: selectGetSyncErrorMessage(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/wunderbarSuggestions/index.js b/ui/component/wunderbarSuggestions/index.js index 7964b9ec7..2794ef6f1 100644 --- a/ui/component/wunderbarSuggestions/index.js +++ b/ui/component/wunderbarSuggestions/index.js @@ -1,6 +1,6 @@ import * as MODALS from 'constants/modal_types'; import { connect } from 'react-redux'; -import { selectLanguage, selectShowMatureContent } from 'redux/selectors/settings'; +import { selectShowMatureContent } from 'redux/selectors/settings'; import { doToast } from 'redux/actions/notifications'; import { doOpenModal, doHideModal } from 'redux/actions/app'; import { withRouter } from 'react-router'; @@ -9,7 +9,6 @@ import analytics from 'analytics'; import Wunderbar from './view'; const select = (state, props) => ({ - language: selectLanguage(state), showMature: selectShowMatureContent(state), }); diff --git a/ui/page/settings/index.js b/ui/page/settings/index.js index 35df01630..884395b9f 100644 --- a/ui/page/settings/index.js +++ b/ui/page/settings/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { doEnterSettingsPage, doExitSettingsPage } from 'redux/actions/settings'; -import { selectDaemonSettings, selectLanguage } from 'redux/selectors/settings'; +import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import SettingsPage from './view'; @@ -8,7 +8,6 @@ import SettingsPage from './view'; const select = (state) => ({ daemonSettings: selectDaemonSettings(state), isAuthenticated: selectUserVerifiedEmail(state), - language: selectLanguage(state), }); const perform = (dispatch) => ({