setup localization for twenty-emails (#9806)
One of the steps to address #8128 How to test: Please change the locale in the settings and click on change password button. A password reset email in the preferred locale will be sent.   Todo: - Remove the hardcoded locales for invitation, warn suspended workspace email, clean suspended workspace emails - Need to test invitation, email verification, warn suspended workspace email, clean suspended workspace emails - The duration variable `5 minutes` is always in english. Do we need to do something about that? It does seems odd in case of chinese translations. Notes: - Only tested the password reset , password update notify templates. - Cant test email verification due to error during sign up `Internal server error: New workspace setup is disabled` --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
committed by
GitHub
parent
4b9414a002
commit
39e7f6cec3
@ -492,6 +492,7 @@ export enum FeatureFlagKey {
|
||||
IsLocalizationEnabled = 'IsLocalizationEnabled',
|
||||
IsMicrosoftSyncEnabled = 'IsMicrosoftSyncEnabled',
|
||||
IsNewRelationEnabled = 'IsNewRelationEnabled',
|
||||
IsPermissionsEnabled = 'IsPermissionsEnabled',
|
||||
IsPostgreSQLIntegrationEnabled = 'IsPostgreSQLIntegrationEnabled',
|
||||
IsRichTextV2Enabled = 'IsRichTextV2Enabled',
|
||||
IsStripeIntegrationEnabled = 'IsStripeIntegrationEnabled',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as Apollo from '@apollo/client';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
@ -217,6 +217,11 @@ export type BooleanFieldComparison = {
|
||||
isNot?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type BuildDraftServerlessFunctionInput = {
|
||||
/** The id of the function. */
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export enum CalendarChannelVisibility {
|
||||
METADATA = 'METADATA',
|
||||
SHARE_EVERYTHING = 'SHARE_EVERYTHING'
|
||||
@ -689,6 +694,7 @@ export type Mutation = {
|
||||
activateWorkflowVersion: Scalars['Boolean'];
|
||||
activateWorkspace: Workspace;
|
||||
authorizeApp: AuthorizeApp;
|
||||
buildDraftServerlessFunction: ServerlessFunction;
|
||||
checkoutSession: BillingSessionOutput;
|
||||
computeStepOutputSchema: Scalars['JSON'];
|
||||
createDraftFromWorkflowVersion: WorkflowVersion;
|
||||
@ -763,6 +769,11 @@ export type MutationAuthorizeAppArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationBuildDraftServerlessFunctionArgs = {
|
||||
input: BuildDraftServerlessFunctionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCheckoutSessionArgs = {
|
||||
plan?: BillingPlanKey;
|
||||
recurringInterval: SubscriptionInterval;
|
||||
@ -1444,6 +1455,7 @@ export type ServerlessFunctionExecutionResult = {
|
||||
/** Status of the serverless function execution */
|
||||
export enum ServerlessFunctionExecutionStatus {
|
||||
ERROR = 'ERROR',
|
||||
IDLE = 'IDLE',
|
||||
SUCCESS = 'SUCCESS'
|
||||
}
|
||||
|
||||
@ -1454,6 +1466,7 @@ export type ServerlessFunctionIdInput = {
|
||||
|
||||
/** SyncStatus of the serverlessFunction */
|
||||
export enum ServerlessFunctionSyncStatus {
|
||||
BUILDING = 'BUILDING',
|
||||
NOT_READY = 'NOT_READY',
|
||||
READY = 'READY'
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ import { clientConfigApiStatusState } from '@/client-config/states/clientConfigA
|
||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
||||
import { supportChatState } from '@/client-config/states/supportChatState';
|
||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { APP_LOCALES, isDefined } from 'twenty-shared';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
import {
|
||||
useCheckUserExistsLazyQuery,
|
||||
@ -280,7 +280,9 @@ export const useAuth = () => {
|
||||
)
|
||||
: TimeFormat[detectTimeFormat()],
|
||||
});
|
||||
dynamicActivate(workspaceMember.locale ?? 'en');
|
||||
dynamicActivate(
|
||||
(workspaceMember.locale as keyof typeof APP_LOCALES) ?? 'en',
|
||||
);
|
||||
}
|
||||
|
||||
const workspace = user.currentWorkspace ?? null;
|
||||
|
||||
@ -16,7 +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 { isDefined } from 'twenty-shared';
|
||||
import { APP_LOCALES, isDefined } from 'twenty-shared';
|
||||
import { WorkspaceMember } from '~/generated-metadata/graphql';
|
||||
import { useGetCurrentUserQuery } from '~/generated/graphql';
|
||||
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
||||
@ -70,7 +70,7 @@ export const UserProviderEffect = () => {
|
||||
return {
|
||||
...workspaceMember,
|
||||
colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light',
|
||||
locale: workspaceMember.locale ?? 'en',
|
||||
locale: (workspaceMember.locale as keyof typeof APP_LOCALES) ?? 'en',
|
||||
};
|
||||
};
|
||||
|
||||
@ -93,7 +93,9 @@ export const UserProviderEffect = () => {
|
||||
: TimeFormat[detectTimeFormat()],
|
||||
});
|
||||
|
||||
dynamicActivate(workspaceMember.locale ?? 'en');
|
||||
dynamicActivate(
|
||||
(workspaceMember.locale as keyof typeof APP_LOCALES) ?? 'en',
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(workspaceMembers)) {
|
||||
|
||||
@ -51,7 +51,7 @@ export const LocalePicker = () => {
|
||||
|
||||
if (!isDefined(currentWorkspaceMember)) return;
|
||||
|
||||
const handleLocaleChange = async (value: string) => {
|
||||
const handleLocaleChange = async (value: keyof typeof APP_LOCALES) => {
|
||||
setCurrentWorkspaceMember({
|
||||
...currentWorkspaceMember,
|
||||
...{ locale: value },
|
||||
@ -126,7 +126,9 @@ export const LocalePicker = () => {
|
||||
fullWidth
|
||||
value={i18n.locale}
|
||||
options={localeOptions}
|
||||
onChange={(value) => handleLocaleChange(value)}
|
||||
onChange={(value) =>
|
||||
handleLocaleChange(value as keyof typeof APP_LOCALES)
|
||||
}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { i18n } from '@lingui/core';
|
||||
import { APP_LOCALES } from 'twenty-shared';
|
||||
|
||||
export const dynamicActivate = async (locale: string) => {
|
||||
export const dynamicActivate = async (locale: keyof typeof APP_LOCALES) => {
|
||||
const { messages } = await import(`../../locales/generated/${locale}.ts`);
|
||||
i18n.load(locale, messages);
|
||||
i18n.activate(locale);
|
||||
|
||||
Reference in New Issue
Block a user