Set up localization with feature flag control (#9649)
Refers #8128 Changes Introduced: - Added i18n configuration. - Added a feature flag for localization. - Enabled language switching based on the flag. --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
committed by
GitHub
parent
b81ffcc77c
commit
f44b31573a
@ -5,29 +5,41 @@ import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserve
|
||||
import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary';
|
||||
import { ExceptionHandlerProvider } from '@/error-handler/components/ExceptionHandlerProvider';
|
||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||
import { i18n } from '@lingui/core';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { RecoilURLSyncJSON } from 'recoil-sync';
|
||||
import { IconsProvider } from 'twenty-ui';
|
||||
import { messages as enMessages } from '../../../locales/en/messages';
|
||||
import { messages as frMessages } from '../../../locales/fr/messages';
|
||||
|
||||
i18n.load({
|
||||
en: enMessages,
|
||||
fr: frMessages,
|
||||
});
|
||||
i18n.activate('fr');
|
||||
|
||||
export const App = () => {
|
||||
return (
|
||||
<RecoilRoot>
|
||||
<RecoilURLSyncJSON location={{ part: 'queryParams' }}>
|
||||
<AppErrorBoundary>
|
||||
<CaptchaProvider>
|
||||
<RecoilDebugObserverEffect />
|
||||
<ApolloDevLogEffect />
|
||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||
<IconsProvider>
|
||||
<ExceptionHandlerProvider>
|
||||
<HelmetProvider>
|
||||
<AppRouter />
|
||||
</HelmetProvider>
|
||||
</ExceptionHandlerProvider>
|
||||
</IconsProvider>
|
||||
</SnackBarProviderScope>
|
||||
</CaptchaProvider>
|
||||
<I18nProvider i18n={i18n}>
|
||||
<CaptchaProvider>
|
||||
<RecoilDebugObserverEffect />
|
||||
<ApolloDevLogEffect />
|
||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||
<IconsProvider>
|
||||
<ExceptionHandlerProvider>
|
||||
<HelmetProvider>
|
||||
<AppRouter />
|
||||
</HelmetProvider>
|
||||
</ExceptionHandlerProvider>
|
||||
</IconsProvider>
|
||||
</SnackBarProviderScope>
|
||||
</CaptchaProvider>
|
||||
</I18nProvider>
|
||||
</AppErrorBoundary>
|
||||
</RecoilURLSyncJSON>
|
||||
</RecoilRoot>
|
||||
|
||||
@ -123,11 +123,11 @@ const SettingsProfile = lazy(() =>
|
||||
})),
|
||||
);
|
||||
|
||||
const SettingsAppearance = lazy(() =>
|
||||
const SettingsExperience = lazy(() =>
|
||||
import(
|
||||
'~/pages/settings/profile/appearance/components/SettingsAppearance'
|
||||
'~/pages/settings/profile/appearance/components/SettingsExperience'
|
||||
).then((module) => ({
|
||||
default: module.SettingsAppearance,
|
||||
default: module.SettingsExperience,
|
||||
})),
|
||||
);
|
||||
|
||||
@ -278,7 +278,7 @@ export const SettingsRoutes = ({
|
||||
<Suspense fallback={<SettingsSkeletonLoader />}>
|
||||
<Routes>
|
||||
<Route path={SettingsPath.ProfilePage} element={<SettingsProfile />} />
|
||||
<Route path={SettingsPath.Appearance} element={<SettingsAppearance />} />
|
||||
<Route path={SettingsPath.Experience} element={<SettingsExperience />} />
|
||||
<Route path={SettingsPath.Accounts} element={<SettingsAccounts />} />
|
||||
<Route path={SettingsPath.NewAccount} element={<SettingsNewAccount />} />
|
||||
<Route
|
||||
|
||||
@ -60,6 +60,7 @@ import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirect
|
||||
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
|
||||
import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState';
|
||||
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
|
||||
import { i18n } from '@lingui/core';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export const useAuth = () => {
|
||||
@ -279,6 +280,7 @@ export const useAuth = () => {
|
||||
)
|
||||
: TimeFormat[detectTimeFormat()],
|
||||
});
|
||||
i18n.activate(workspaceMember.locale ?? 'en');
|
||||
}
|
||||
|
||||
const workspace = user.currentWorkspace ?? null;
|
||||
|
||||
@ -76,6 +76,6 @@ export const Main: Story = {};
|
||||
export const Settings: Story = {
|
||||
args: {
|
||||
mobileNavigationDrawer: 'settings',
|
||||
routePath: '/settings/appearance',
|
||||
routePath: '/settings/experience',
|
||||
},
|
||||
};
|
||||
|
||||
@ -16,8 +16,8 @@ import {
|
||||
IconPrinter,
|
||||
IconSettings,
|
||||
} from 'twenty-ui';
|
||||
import { FeatureFlag, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { FeatureFlag, FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
export const useRecordShowContainerTabs = (
|
||||
loading: boolean,
|
||||
|
||||
@ -106,7 +106,7 @@ export const SettingsNavigationDrawerItems = () => {
|
||||
/>
|
||||
<SettingsNavigationDrawerItem
|
||||
label="Experience"
|
||||
path={SettingsPath.Appearance}
|
||||
path={SettingsPath.Experience}
|
||||
Icon={IconColorSwatch}
|
||||
/>
|
||||
<NavigationDrawerItemGroup>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export enum SettingsPath {
|
||||
ProfilePage = 'profile',
|
||||
Appearance = 'appearance',
|
||||
Experience = 'experience',
|
||||
Accounts = 'accounts',
|
||||
NewAccount = 'accounts/new',
|
||||
AccountsCalendars = 'accounts/calendars',
|
||||
|
||||
@ -142,7 +142,7 @@ export const Settings: Story = {
|
||||
/>
|
||||
<NavigationDrawerItem
|
||||
label="Appearance"
|
||||
to={getSettingsPagePath(SettingsPath.Appearance)}
|
||||
to={getSettingsPagePath(SettingsPath.Experience)}
|
||||
Icon={IconColorSwatch}
|
||||
/>
|
||||
<NavigationDrawerItemGroup>
|
||||
|
||||
@ -16,6 +16,7 @@ import { detectTimeZone } from '@/localization/utils/detectTimeZone';
|
||||
import { getDateFormatFromWorkspaceDateFormat } from '@/localization/utils/getDateFormatFromWorkspaceDateFormat';
|
||||
import { getTimeFormatFromWorkspaceTimeFormat } from '@/localization/utils/getTimeFormatFromWorkspaceTimeFormat';
|
||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||
import { i18n } from '@lingui/core';
|
||||
import { WorkspaceMember } from '~/generated-metadata/graphql';
|
||||
import { useGetCurrentUserQuery } from '~/generated/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
@ -91,6 +92,8 @@ export const UserProviderEffect = () => {
|
||||
? getTimeFormatFromWorkspaceTimeFormat(workspaceMember.timeFormat)
|
||||
: TimeFormat[detectTimeFormat()],
|
||||
});
|
||||
|
||||
i18n.activate(workspaceMember.locale ?? 'en');
|
||||
}
|
||||
|
||||
if (isDefined(workspaceMembers)) {
|
||||
|
||||
Reference in New Issue
Block a user