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
This commit is contained in:
parent
33e5318a29
commit
cef9ade10e
13 changed files with 18 additions and 30 deletions
|
@ -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 <SyncFatalError />;
|
||||
}
|
||||
|
@ -338,6 +344,7 @@ function App(props: Props) {
|
|||
[`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar,
|
||||
})}
|
||||
ref={appRef}
|
||||
key={langRenderKey}
|
||||
onContextMenu={(e) => openContextMenu(e)}
|
||||
>
|
||||
<Router />
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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),
|
||||
});
|
||||
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
Loading…
Reference in a new issue