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
@ -7,15 +7,15 @@ import {
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
|
||||
import { userEvent, within } from '@storybook/test';
|
||||
import { SettingsAppearance } from '../profile/appearance/components/SettingsAppearance';
|
||||
import { SettingsExperience } from '../profile/appearance/components/SettingsExperience';
|
||||
|
||||
Date.now = () => new Date('2022-06-13T12:33:37.000Z').getTime();
|
||||
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/SettingsAppearance',
|
||||
component: SettingsAppearance,
|
||||
title: 'Pages/Settings/SettingsExperience',
|
||||
component: SettingsExperience,
|
||||
decorators: [PageDecorator],
|
||||
args: { routePath: '/settings/appearance' },
|
||||
args: { routePath: '/settings/experience' },
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
date: new Date(2021, 1, 1),
|
||||
@ -24,13 +24,13 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof SettingsAppearance>;
|
||||
export type Story = StoryObj<typeof SettingsExperience>;
|
||||
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Appearance', undefined, {
|
||||
await canvas.findAllByText('Experience', undefined, {
|
||||
timeout: 3000,
|
||||
});
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
|
||||
import { i18n } from '@lingui/core';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
export const LocalePicker = () => {
|
||||
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
||||
currentWorkspaceMemberState,
|
||||
);
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
});
|
||||
|
||||
const updateWorkspaceMember = async (changedFields: any) => {
|
||||
if (!currentWorkspaceMember?.id) {
|
||||
throw new Error('User is not logged in');
|
||||
}
|
||||
|
||||
try {
|
||||
await updateOneRecord({
|
||||
idToUpdate: currentWorkspaceMember.id,
|
||||
updateOneRecordInput: changedFields,
|
||||
});
|
||||
} catch (error) {
|
||||
logError(error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isDefined(currentWorkspaceMember)) return;
|
||||
|
||||
const handleLocaleChange = (value: string) => {
|
||||
setCurrentWorkspaceMember({
|
||||
...currentWorkspaceMember,
|
||||
...{ locale: value },
|
||||
});
|
||||
updateWorkspaceMember({ locale: value });
|
||||
|
||||
i18n.activate(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Select
|
||||
dropdownId="preferred-locale"
|
||||
dropdownWidthAuto
|
||||
fullWidth
|
||||
value={i18n.locale}
|
||||
options={[
|
||||
{
|
||||
label: 'Portuguese',
|
||||
value: 'pt',
|
||||
},
|
||||
{
|
||||
label: 'French',
|
||||
value: 'fr',
|
||||
},
|
||||
{
|
||||
label: 'German',
|
||||
value: 'de',
|
||||
},
|
||||
{
|
||||
label: 'Italian',
|
||||
value: 'it',
|
||||
},
|
||||
{
|
||||
label: 'Spanish',
|
||||
value: 'es',
|
||||
},
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en',
|
||||
},
|
||||
{
|
||||
label: 'Chinese',
|
||||
value: 'zh',
|
||||
},
|
||||
]}
|
||||
onChange={(value) => handleLocaleChange(value)}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -5,11 +5,22 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
|
||||
import { DateTimeSettings } from '~/pages/settings/profile/appearance/components/DateTimeSettings';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
|
||||
export const SettingsAppearance = () => {
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { DateTimeSettings } from '~/pages/settings/profile/appearance/components/DateTimeSettings';
|
||||
import { LocalePicker } from '~/pages/settings/profile/appearance/components/LocalePicker';
|
||||
|
||||
export const SettingsExperience = () => {
|
||||
const { colorScheme, setColorScheme } = useColorScheme();
|
||||
|
||||
const isLocalizationEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsLocalizationEnabled,
|
||||
);
|
||||
|
||||
const { t } = useLingui();
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer
|
||||
title="Experience"
|
||||
@ -33,6 +44,16 @@ export const SettingsAppearance = () => {
|
||||
/>
|
||||
<DateTimeSettings />
|
||||
</Section>
|
||||
|
||||
{isLocalizationEnabled && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Language`}
|
||||
description={t`Select your preferred language`}
|
||||
/>
|
||||
<LocalePicker />
|
||||
</Section>
|
||||
)}
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
);
|
||||
Reference in New Issue
Block a user