Translations - Crowdin, Set workspace member locale on signup, and optimizations (#10091)

More progress on translations:
- Migrate from translations.io to crowdin
- Optimize performance and robustness 
- Set workspaceMember/user locale upon signup
This commit is contained in:
Félix Malfait
2025-02-09 22:10:41 +01:00
committed by GitHub
parent fd3f01ab80
commit bb24c97f80
163 changed files with 84053 additions and 2554 deletions

View File

@ -197,6 +197,7 @@ export class AuthResolver {
const { userData } = this.authService.formatUserDataPayload(
{
email: signUpInput.email,
locale: signUpInput.locale,
},
existingUser,
);

View File

@ -18,8 +18,8 @@ import { GoogleProviderEnabledGuard } from 'src/engine/core-modules/auth/guards/
import { AuthService } from 'src/engine/core-modules/auth/services/auth.service';
import { GoogleRequest } from 'src/engine/core-modules/auth/strategies/google.auth.strategy';
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
import { User } from 'src/engine/core-modules/user/user.entity';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
import { User } from 'src/engine/core-modules/user/user.entity';
@Controller('auth/google')
@UseFilters(AuthRestApiExceptionFilter)
@ -51,6 +51,7 @@ export class GoogleAuthController {
workspaceInviteHash,
workspaceId,
billingCheckoutSessionState,
locale,
} = req.user;
const currentWorkspace = await this.authService.findWorkspaceForSignInUp({
@ -79,6 +80,7 @@ export class GoogleAuthController {
lastName,
email,
picture,
locale,
},
existingUser,
);

View File

@ -17,8 +17,8 @@ import { MicrosoftProviderEnabledGuard } from 'src/engine/core-modules/auth/guar
import { AuthService } from 'src/engine/core-modules/auth/services/auth.service';
import { MicrosoftRequest } from 'src/engine/core-modules/auth/strategies/microsoft.auth.strategy';
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
import { User } from 'src/engine/core-modules/user/user.entity';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
import { User } from 'src/engine/core-modules/user/user.entity';
@Controller('auth/microsoft')
@UseFilters(AuthRestApiExceptionFilter)
@ -52,6 +52,7 @@ export class MicrosoftAuthController {
workspaceInviteHash,
workspaceId,
billingCheckoutSessionState,
locale,
} = req.user;
const currentWorkspace = await this.authService.findWorkspaceForSignInUp({
@ -80,6 +81,7 @@ export class MicrosoftAuthController {
lastName,
email,
picture,
locale,
},
existingUser,
);

View File

@ -1,6 +1,7 @@
import { ArgsType, Field } from '@nestjs/graphql';
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { APP_LOCALES } from 'twenty-shared';
@ArgsType()
export class SignUpInput {
@ -33,4 +34,9 @@ export class SignUpInput {
@IsString()
@IsOptional()
captchaToken?: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
locale?: keyof typeof APP_LOCALES;
}

View File

@ -3,6 +3,7 @@ import { PassportStrategy } from '@nestjs/passport';
import { Request } from 'express';
import { Strategy, VerifyCallback } from 'passport-google-oauth20';
import { APP_LOCALES } from 'twenty-shared';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
@ -15,6 +16,7 @@ export type GoogleRequest = Omit<
lastName?: string | null;
email: string;
picture: string | null;
locale?: keyof typeof APP_LOCALES | null;
workspaceInviteHash?: string;
workspacePersonalInviteToken?: string;
workspaceId?: string;
@ -70,6 +72,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
workspacePersonalInviteToken: state.workspacePersonalInviteToken,
workspaceId: state.workspaceId,
billingCheckoutSessionState: state.billingCheckoutSessionState,
locale: state.locale,
};
done(null, user);

View File

@ -3,6 +3,7 @@ import { PassportStrategy } from '@nestjs/passport';
import { Request } from 'express';
import { VerifyCallback } from 'passport-google-oauth20';
import { Strategy } from 'passport-microsoft';
import { APP_LOCALES } from 'twenty-shared';
import {
AuthException,
@ -19,6 +20,7 @@ export type MicrosoftRequest = Omit<
lastName?: string | null;
email: string;
picture: string | null;
locale?: keyof typeof APP_LOCALES | null;
workspaceInviteHash?: string;
workspacePersonalInviteToken?: string;
workspaceId?: string;
@ -44,6 +46,7 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy, 'microsoft') {
state: JSON.stringify({
workspaceInviteHash: req.query.workspaceInviteHash,
workspaceId: req.params.workspaceId,
locale: req.query.locale,
billingCheckoutSessionState: req.query.billingCheckoutSessionState,
workspacePersonalInviteToken: req.query.workspacePersonalInviteToken,
}),
@ -84,6 +87,7 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy, 'microsoft') {
workspacePersonalInviteToken: state.workspacePersonalInviteToken,
workspaceId: state.workspaceId,
billingCheckoutSessionState: state.billingCheckoutSessionState,
locale: state.locale,
};
done(null, user);

View File

@ -1,6 +1,8 @@
import { APP_LOCALES } from 'twenty-shared';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { User } from 'src/engine/core-modules/user/user.entity';
import { WorkspaceAuthProvider } from 'src/engine/core-modules/workspace/types/workspace.type';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
export type SignInUpBaseParams = {
@ -15,6 +17,7 @@ export type SignInUpNewUserPayload = {
lastName?: string | null;
picture?: string | null;
passwordHash?: string | null;
locale?: keyof typeof APP_LOCALES | null;
};
export type PartialUserWithPicture = {

View File

@ -0,0 +1,20 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import { i18n } from '@lingui/core';
import { NextFunction, Request, Response } from 'express';
import { APP_LOCALES } from 'twenty-shared';
@Injectable()
export class I18nMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const locale = req.headers['x-locale'] as keyof typeof APP_LOCALES;
if (locale && Object.values(APP_LOCALES).includes(locale)) {
i18n.activate(locale);
} else {
i18n.activate('en');
}
next();
}
}

View File

@ -1,5 +1,6 @@
import { Global, Module } from '@nestjs/common';
import { Global, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { I18nMiddleware } from 'src/engine/core-modules/i18n/i18n.middleware';
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
@Global()
@ -7,4 +8,8 @@ import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
providers: [I18nService],
exports: [I18nService],
})
export class I18nModule {}
export class I18nModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(I18nMiddleware).forRoutes('*');
}
}

View File

@ -1,35 +1,44 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { i18n } from '@lingui/core';
import { APP_LOCALES } from 'twenty-shared';
import { messages as deMessages } from 'src/engine/core-modules/i18n/locales/generated/de';
import { messages as deMessages } from 'src/engine/core-modules/i18n/locales/generated/de-DE';
import { messages as enMessages } from 'src/engine/core-modules/i18n/locales/generated/en';
import { messages as esMessages } from 'src/engine/core-modules/i18n/locales/generated/es';
import { messages as frMessages } from 'src/engine/core-modules/i18n/locales/generated/fr';
import { messages as itMessages } from 'src/engine/core-modules/i18n/locales/generated/it';
import { messages as jaMessages } from 'src/engine/core-modules/i18n/locales/generated/ja';
import { messages as koMessages } from 'src/engine/core-modules/i18n/locales/generated/ko';
import { messages as esMessages } from 'src/engine/core-modules/i18n/locales/generated/es-ES';
import { messages as frMessages } from 'src/engine/core-modules/i18n/locales/generated/fr-FR';
import { messages as itMessages } from 'src/engine/core-modules/i18n/locales/generated/it-IT';
import { messages as jaMessages } from 'src/engine/core-modules/i18n/locales/generated/ja-JP';
import { messages as koMessages } from 'src/engine/core-modules/i18n/locales/generated/ko-KR';
import { messages as pseudoEnMessages } from 'src/engine/core-modules/i18n/locales/generated/pseudo-en';
import { messages as ptBRMessages } from 'src/engine/core-modules/i18n/locales/generated/pt-BR';
import { messages as ptPTMessages } from 'src/engine/core-modules/i18n/locales/generated/pt-PT';
import { messages as zhHansMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-Hans';
import { messages as zhHantMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-Hant';
import { messages as zhHansMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-CN';
import { messages as zhHantMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-TW';
@Injectable()
export class I18nService implements OnModuleInit {
async loadTranslations() {
i18n.load('en', enMessages);
i18n.load('fr', frMessages);
i18n.load('pseudo-en', pseudoEnMessages);
i18n.load('ko', koMessages);
i18n.load('de', deMessages);
i18n.load('it', itMessages);
i18n.load('es', esMessages);
i18n.load('ja', jaMessages);
i18n.load('pt-PT', ptPTMessages);
i18n.load('pt-BR', ptBRMessages);
i18n.load('zh-Hans', zhHansMessages);
i18n.load('zh-Hant', zhHantMessages);
const messages: Record<keyof typeof APP_LOCALES, any> = {
en: enMessages,
'pseudo-en': pseudoEnMessages,
'fr-FR': frMessages,
'ko-KR': koMessages,
'de-DE': deMessages,
'it-IT': itMessages,
'es-ES': esMessages,
'ja-JP': jaMessages,
'pt-PT': ptPTMessages,
'pt-BR': ptBRMessages,
'zh-CN': zhHansMessages,
'zh-TW': zhHantMessages,
};
(Object.entries(messages) as [keyof typeof APP_LOCALES, any][]).forEach(
([locale, message]) => {
i18n.load(locale, message);
},
);
i18n.activate('en');
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: de\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: de\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "Ihr Teammitglied, das für die Verwaltung des Unternehmenskontos verantwortlich ist"

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: es\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Spanish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: es\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "Miembro de su equipo responsable de gestionar la cuenta de la empresa"

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: fr\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "Le membre de votre équipe responsable de la gestion du compte entreprise"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: it\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Italian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: it\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "Il membro del team responsabile della gestione dell'account aziendale"

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: ja\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Japanese\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: ja\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr ""
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr ""

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: ko\n"
"Project-Id-Version: \n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Korean\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: ko\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "회사 계정을 관리하는 팀원"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: pt-BR\n"
"Project-Id-Version: \n"
"Language: pt\n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Portuguese, Brazilian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: pt-BR\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "Seu membro da equipe responsável por gerenciar a conta da empresa"

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: pt-PT\n"
"Project-Id-Version: \n"
"Language: pt\n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Portuguese\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: pt\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "O membro da sua equipa responsável pela gestão da conta da empresa"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: zh-Hans\n"
"Project-Id-Version: \n"
"Language: zh\n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Chinese Simplified\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "负责管理公司账户的团队成员"

View File

@ -1,17 +1,22 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2025-02-01 10:10+0100\n"
"POT-Creation-Date: 2025-01-29 18:14+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: zh-Hant\n"
"Project-Id-Version: \n"
"Language: zh\n"
"Project-Id-Version: cf448e737e0d6d7b78742f963d761c61\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"PO-Revision-Date: 2025-02-09 12:39\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: Chinese Traditional\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: cf448e737e0d6d7b78742f963d761c61\n"
"X-Crowdin-Project-ID: 1\n"
"X-Crowdin-Language: zh-TW\n"
"X-Crowdin-File: /packages/twenty-server/src/engine/core-modules/i18n/locales/en.po\n"
"X-Crowdin-File-ID: 31\n"
#: src/modules/view/standard-objects/view-field.workspace-entity.ts:32
msgid "(System) View Fields"
@ -2240,3 +2245,4 @@ msgstr "X"
#: src/modules/company/standard-objects/company.workspace-entity.ts:177
msgid "Your team member responsible for managing the company account"
msgstr "負責管理公司帳戶的團隊成員"

View File

@ -13,6 +13,7 @@ import {
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { AvailableWorkspaceOutput } from 'src/engine/core-modules/auth/dto/available-workspaces.output';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { User } from 'src/engine/core-modules/user/user.entity';
import { userValidator } from 'src/engine/core-modules/user/user.validate';
@ -24,7 +25,6 @@ import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { assert } from 'src/utils/assert';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> {
constructor(
@ -70,14 +70,15 @@ export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> {
await workspaceDataSource?.query(
`INSERT INTO ${dataSourceMetadata.schema}."workspaceMember"
("nameFirstName", "nameLastName", "colorScheme", "userId", "userEmail", "avatarUrl")
VALUES ($1, $2, 'System', $3, $4, $5)`,
("nameFirstName", "nameLastName", "colorScheme", "userId", "userEmail", "avatarUrl", "locale")
VALUES ($1, $2, 'System', $3, $4, $5, $6)`,
[
user.firstName,
user.lastName,
user.id,
user.email,
user.defaultAvatarUrl ?? '',
user.locale ?? 'en',
],
);
const workspaceMember = await workspaceDataSource?.query(

View File

@ -81,6 +81,10 @@ export class User {
@DeleteDateColumn({ type: 'timestamptz' })
deletedAt: Date;
@Field(() => String, { nullable: false })
@Column({ nullable: false, default: 'en' })
locale: string;
@OneToMany(() => AppToken, (appToken) => appToken.user, {
cascade: true,
})

View File

@ -2,10 +2,10 @@ import { Field, InputType } from '@nestjs/graphql';
import {
IsBoolean,
IsNotIn,
IsOptional,
IsString,
Matches,
IsNotIn,
} from 'class-validator';
@InputType()
@ -92,11 +92,48 @@ export class UpdateWorkspaceInput {
'au',
'nz',
'za',
'uk',
'eu',
'uk',
'ru',
'ua',
'pl',
'ro',
'bg',
'gr',
'cz',
'sk',
'hu',
'hr',
'si',
'rs',
'me',
'ba',
'mk',
'al',
'az',
'tr',
'cy',
'lv',
'lt',
'ee',
'fi',
'is',
'no',
'se',
'dk',
'asia',
'africa',
'america',
'europe',
'north-america',
'south-africa',
'north-africa',
'south-america',
'oceania',
'paris',
'london',
'new-york',
'san-francisco',
])
subdomain?: string;