snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
---
title: CLI
description: Les commandes `yarn twenty` pour exécuter des fonctions, diffuser en continu les journaux, gérer les installations d'applications et basculer entre des remotes.
icon: terminal
---
Le CLI `yarn twenty` est votre interface pour tout ce qui concerne les applications. Liste complète des commandes :
| Commande | Ce que cela fait | Documenté dans |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `dev` | Surveille les fichiers sources et synchronise en direct les modifications | [Prise en main rapide](/l/fr/developers/extend/apps/getting-started/quick-start) |
| `plan` | Prévisualiser les modifications de métadonnées sans les appliquer | [Synchronisation et récupération](/l/fr/developers/extend/apps/operations/sync-and-recovery#previewing-changes-plan) |
| `appliquer` | Appliquer les modifications de métadonnées après avoir affiché le plan | [Synchronisation et récupération](/l/fr/developers/extend/apps/operations/sync-and-recovery) |
| `dev:build` | Compiler l’application et générer le client d’API (`--tarball` pour empaqueter un `.tgz`) | [Publication](/l/fr/developers/extend/apps/operations/publishing) |
| `dev:typecheck` | Exécuter la vérification des types TypeScript | [Tests](/l/fr/developers/extend/apps/operations/testing) |
| `dev:add` | Générer la structure d’une nouvelle entité | [Génération de structure](/l/fr/developers/extend/apps/getting-started/scaffolding) |
| `dev:generate-client` | Régénérer le client d’API typé | cette page |
| `dev:function:exec` / `dev:function:logs` | Exécuter des fonctions et afficher leurs journaux en continu | cette page |
| `dev:translations-extract` | Extraire les chaînes traduisibles dans les catalogues `locales/` | [Traductions](/l/fr/developers/extend/apps/operations/translations) |
| `dev:catalog-sync` | Déclencher la synchronisation du catalogue de la place de marché | [Publication](/l/fr/developers/extend/apps/operations/publishing#how-marketplace-discovery-works) |
| `app:publish` / `app:install` / `app:uninstall` | Cycle de vie de publication | [Publication](/l/fr/developers/extend/apps/operations/publishing) et cette page |
| `docker:*` | Gérer le conteneur du serveur Twenty local | [Serveur local](/l/fr/developers/extend/apps/getting-started/local-server) |
| `remote:*` | Gérer les connexions serveur | cette page |
Chaque commande accepte `-r, --remote \<name>` pour cibler un serveur distant spécifique au lieu de celui par défaut.
## Exécuter des fonctions (`yarn twenty dev:function:exec`)
Exécutez une fonction logique manuellement sans la déclencher via HTTP, cron ou un événement de base de données :
```bash filename="Terminal"
# Execute by function name
yarn twenty dev:function:exec -n create-new-post-card
# Execute by universalIdentifier
yarn twenty dev:function:exec -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
# Pass a JSON payload
yarn twenty dev:function:exec -n create-new-post-card -p '{"name": "Hello"}'
# Execute the install and uninstall hooks
yarn twenty dev:function:exec --postInstall
yarn twenty dev:function:exec --preInstall
yarn twenty dev:function:exec --uninstall
```
## Afficher les journaux des fonctions (`yarn twenty dev:function:logs`)
Diffuser en continu les journaux d'exécution des fonctions logiques de votre application :
```bash filename="Terminal"
# Stream all function logs
yarn twenty dev:function:logs
# Filter by function name
yarn twenty dev:function:logs -n create-new-post-card
# Filter by universalIdentifier
yarn twenty dev:function:logs -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
```
<Note>
Ceci est différent de `yarn twenty docker:logs`, qui affiche les journaux du conteneur Docker. `yarn twenty dev:function:logs` affiche les journaux d'exécution des fonctions de votre application depuis le serveur Twenty.
</Note>
## Génération du client typé (`yarn twenty dev:generate-client`)
Régénérez le client API typé (`twenty-client-sdk`) à partir du schéma du remote actif, sans compiler ni synchroniser une application. Utilisez-le pour obtenir un client typé dans n’importe quel projet — comme un service back-end hébergé dans un dépôt distinct — qui communique avec votre instance Twenty :
```bash filename="Terminal"
# In your project (no Twenty app definition required)
yarn add twenty-sdk twenty-client-sdk
# Connect to the Twenty instance to generate the client from
yarn twenty remote:add
# Generate the typed client into node_modules/twenty-client-sdk
yarn twenty dev:generate-client
```
Puis importez le client dans votre code :
```typescript
import { CoreApiClient } from 'twenty-client-sdk/core';
```
Relancez la commande chaque fois que votre modèle de données change afin d’actualiser les types générés.
<Note>
Le client est généré dans `node_modules`, il n’est donc pas versionné avec votre code. Exécutez `yarn twenty dev:generate-client` après chaque installation (par exemple dans un script `postinstall` ou dans un pipeline CI).
</Note>
## Désinstaller une application (`yarn twenty app:uninstall`)
Supprimez votre application de l'espace de travail actif :
```bash filename="Terminal"
yarn twenty app:uninstall
# Skip the confirmation prompt
yarn twenty app:uninstall --yes
```
## Gestion des remotes
Un remote est un serveur Twenty auquel votre application se connecte. Lors de la configuration, le générateur en crée un automatiquement pour vous. Vous pouvez ajouter d’autres remotes ou basculer entre eux à tout moment.
```bash filename="Terminal"
# Add a new remote (opens a browser for OAuth login)
yarn twenty remote:add
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
yarn twenty remote:add --local
# Add a remote non-interactively (useful for CI)
yarn twenty remote:add --url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
# List all configured remotes
yarn twenty remote:list
# Set the active remote
yarn twenty remote:use <name>
# Check that the active remote's authentication is still valid
yarn twenty remote:status
# Remove a remote
yarn twenty remote:remove <name>
```
Vos identifiants sont stockés dans `~/.twenty/config.json`.

View File

@@ -0,0 +1,32 @@
---
title: Vue d'ensemble
description: Créez, testez et livrez votre application — commandes CLI, tests d’intégration, CI et publication sur un serveur ou sur npm.
icon: rocket
---
La **couche d’opérations** regroupe tout ce que vous faites *à* votre application plutôt qu’*avec* elle : lancer des commandes CLI, exécuter des tests d’intégration sur un véritable serveur Twenty, configurer la CI et livrer des versions — soit sous la forme d’une archive tar déployée sur un seul serveur, soit sous la forme d’un package npm répertorié sur la place de marché.
```text
develop ─▶ test ─▶ build ─▶ deploy / publish
─────── ──── ───── ─────────────────
yarn yarn yarn yarn twenty app:publish --private (tarball → one server)
twenty test twenty
dev dev:build yarn twenty app:publish (npm → marketplace)
```
## Dans cette section
<CardGroup cols={2}>
<Card title="CLI" icon="terminal" href="/l/fr/developers/extend/apps/operations/cli">
Référence `yarn twenty` — exec, logs, uninstall, remotes.
</Card>
<Card title="Synchronisation et récupération" icon="compass" href="/l/fr/developers/extend/apps/operations/sync-and-recovery">
Quelle commande utiliser et quand, comment lire le diff de synchronisation, et une procédure de récupération.
</Card>
<Card title="Tests" icon="flask" href="/l/fr/developers/extend/apps/operations/testing">
Configuration de Vitest, tests d’intégration, vérification des types, flux de travail CI.
</Card>
<Card title="Publication" icon="upload" href="/l/fr/developers/extend/apps/operations/publishing">
Générer, déployer une archive tar, publier sur npm, installer.
</Card>
</CardGroup>

View File

@@ -0,0 +1,293 @@
---
title: Publication
icon: upload
description: Distribuez votre application Twenty sur la marketplace ou déployez-la en interne.
---
## Vue d'ensemble
Une fois que votre application est [créée et testée en local](/l/fr/developers/extend/apps/getting-started/concepts), vous avez deux options pour sa distribution :
* **Déployer une archive tar** — téléversez votre application directement sur un serveur Twenty spécifique pour un usage interne ou privé.
* **Publier sur npm** — répertoriez votre application dans la marketplace Twenty pour que tout espace de travail puisse la découvrir et l'installer.
Les deux parcours commencent à la même étape de **build**.
## Compilation de votre application
Exécutez la commande `build` pour compiler votre application et générer un `manifest.json` prêt pour la distribution :
```bash filename="Terminal"
yarn twenty dev:build
```
Cela compile les sources TypeScript, transpile les fonctions de logique et les composants front-end, et écrit le tout dans `.twenty/output/`. Ajoutez `--tarball` pour produire également un paquet `.tgz` pour la distribution manuelle ou la commande `publish`.
## Déploiement sur un serveur (archive tar)
Pour les applications que vous ne souhaitez pas rendre publiques — outils propriétaires, intégrations réservées aux entreprises ou versions expérimentales — vous pouvez déployer une archive tar directement sur un serveur Twenty.
### Prérequis
Avant le déploiement, vous avez besoin d'un remote configuré pointant vers le serveur cible. Les remotes stockent localement l'URL du serveur et les informations d'authentification dans `~/.twenty/config.json`.
Ajouter un remote :
```bash filename="Terminal"
yarn twenty remote:add --url https://your-twenty-server.com --as production
```
### Déploiement
Compilez et téléversez votre application sur le serveur en une seule étape :
```bash filename="Terminal"
yarn twenty app:publish --private
# To deploy to a specific remote:
# yarn twenty app:publish --private --remote production
```
### Partage d'une application déployée
Les applications au format tarball ne sont pas répertoriées dans la place de marché publique, donc les autres espaces de travail sur le même serveur ne les découvriront pas en parcourant. Pour partager une application déployée :
1. Allez dans **Paramètres > Applications > Inscriptions** et ouvrez votre application
2. Dans l'onglet **Distribution**, cliquez sur **Copier le lien de partage**
3. Partagez ce lien avec des utilisateurs sur d'autres espaces de travail — il les amène directement à la page d'installation de l'application
Le lien de partage utilise l'URL de base du serveur (sans sous-domaine d'espace de travail) afin qu'il fonctionne pour tout espace de travail sur le serveur.
### Gestion des versions
Lors de la mise à jour d'une application au format tarball déjà déployée, le serveur exige que la `version` dans `package.json` soit **strictement supérieure** (selon l'ordre [SemVer](https://semver.org)) à la version actuellement déployée. Le redéploiement de la même version, ou la tentative d’en pousser une inférieure, est refusé avant que l’archive tar ne soit stockée — vous verrez une erreur `VERSION_ALREADY_EXISTS` émise par la CLI.
Pour publier une mise à jour :
1. Incrémentez le champ `version` dans votre `package.json` (par ex. `1.2.3` → `1.2.4`, `1.3.0` ou `2.0.0`)
2. Exécutez `yarn twenty app:publish --private` (ou `yarn twenty app:publish --private --remote production`)
3. Les espaces de travail qui ont installé l’application et y ont activé la mise à niveau automatique (dans l’onglet Paramètres de l’application) sont mis à niveau automatiquement en arrière-plan ; les autres verront la mise à niveau disponible dans leurs paramètres
<Note>
Les tags de préversion fonctionnent comme prévu : incrémenter `1.0.0-rc.1` → `1.0.0-rc.2` est autorisé, et une version finale telle que `1.0.0` est correctement reconnue comme supérieure à `1.0.0-rc.5`. La version dans `package.json` doit elle-même être une chaîne SemVer valide.
</Note>
{/* TODO: add screenshot of the Upgrade button */}
### Compatibilité des versions du serveur
Si votre application utilise une fonctionnalité introduite dans une version spécifique du serveur Twenty (par exemple, des fournisseurs OAuth ajoutés en v2.3.0), vous devez déclarer la version minimale du serveur requise par votre application en utilisant le champ `engines.twenty` dans `package.json`:
```json filename="package.json"
{
"name": "twenty-my-app",
"version": "1.0.0",
"engines": {
"node": "^24.5.0",
"twenty": ">=2.3.0"
}
}
```
La valeur est une [plage semver](https://github.com/npm/node-semver#ranges) standard. Modèles courants:
| Plage | Signification |
| ---------------------------------- | ------------------------------------------------------------------- |
| `>=2.3.0` | Tout serveur à partir de 2.3.0 |
| `>=2.3.0 \<3.0.0` | 2.3.0 ou ultérieure, mais inférieure à la prochaine version majeure |
| `^2.3.0` | Identique à `>=2.3.0 \<3.0.0` |
**Ce qui se passe lors du déploiement et de l'installation:**
* Si `engines.twenty` est défini et que la version du serveur cible ne satisfait pas la plage, le déploiement (chargement du tarball) ou l'installation est refusé avec une erreur `SERVER_VERSION_INCOMPATIBLE` et un message indiquant à la fois la plage requise et la version réelle du serveur.
* Si `engines.twenty` est **non défini**, l'application est acceptée sur n'importe quelle version du serveur (rétrocompatible avec les applications existantes).
* Si le serveur n'a pas de `APP_VERSION` configuré, la vérification est ignorée.
<Note>
Le serveur est l'autorité de référence pour la vérification — il valide `engines.twenty` tant lors du chargement du tarball que lors de l'installation dans l'espace de travail. Si vous déployez un tarball hors bande ou installez depuis la place de marché, le serveur applique toujours la compatibilité.
</Note>
## CI/CD automatisés (workflows préconfigurés)
Les applications générées avec `create-twenty-app` sont livrées avec trois workflows GitHub Actions prêts à l’emploi, sous `.github/workflows/`. L’intégration continue (CI) s’exécute sans configuration, le déploiement continu (CD) ne nécessite qu’un seul secret, et la publication sur npm requiert une configuration unique de npm trusted-publisher.
### CI — `ci.yml`
Il exécute automatiquement vos tests d’intégration à chaque push sur `main` et sur les pull requests.
**Ce que cela fait:**
1. Récupère le code source de votre application.
2. Lance une instance de test Twenty isolée à l’aide de l’action composite `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main` (l’équivalent CI de `yarn twenty docker:start --test`).
3. Active Corepack, configure Node.js à partir de votre `.nvmrc` et installe les dépendances avec `yarn install --immutable`.
4. Exécute `yarn test`, en passant `TWENTY_API_URL` et `TWENTY_API_KEY` depuis l’instance lancée pour que vos tests puissent communiquer avec un serveur réel.
**Paramètres de configuration:**
* `TWENTY_VERSION` (variable d’environnement, par défaut `latest`) — figez la version du serveur Twenty utilisée en CI en la modifiant dans `ci.yml`.
* La concurrence est regroupée par `github.ref` et annule les exécutions en cours lors de nouveaux push.
Aucun secret n’est requis — l’instance de test est éphémère et n’existe que pendant la durée du job.
### CD — `cd.yml`
Déploie votre application vers un serveur Twenty configuré à chaque push sur `main`, et éventuellement depuis une pull request lorsque le label `deploy` est appliqué.
**Ce que cela fait:**
1. Récupère la tête de la PR (pour les PR étiquetées) ou le commit poussé.
2. Exécute `twentyhq/twenty/.github/actions/deploy-twenty-app@main` — l’équivalent CI de `yarn twenty app:publish --private`.
3. Exécute `twentyhq/twenty/.github/actions/install-twenty-app@main` afin que la version nouvellement déployée soit installée dans l’espace de travail cible.
**Configuration requise:**
| Paramètre | Où | Objectif |
| ----------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `TWENTY_DEPLOY_URL` | `env` dans `cd.yml` (par défaut `http://localhost:3000`) | Le serveur Twenty vers lequel déployer. Remplacez ceci par l’URL réelle de votre serveur avant la première utilisation. |
| `TWENTY_DEPLOY_API_KEY` | Dépôt GitHub **Settings → Secrets and variables → Actions** | Clé API avec la permission de déployer sur le serveur cible. |
<Note>
La valeur par défaut de `TWENTY_DEPLOY_URL`, `http://localhost:3000`, est un espace réservé — elle n’atteindra rien depuis un runner hébergé par GitHub. Remplacez-la par l’URL publique de votre serveur (ou utilisez un runner auto-hébergé avec accès réseau) avant d’activer la CD.
</Note>
**Déclencher un déploiement de prévisualisation depuis une PR:**
Ajoutez le label `deploy` à une pull request. La condition `if:` dans `cd.yml` exécutera le job pour cette PR en utilisant le commit de tête de la PR, vous permettant de valider une modification sur le serveur cible avant la fusion.
### Publication — `publish.yml`
Publie votre application sur npm avec provenance lorsque vous poussez une étiquette de version (par exemple `v1.0.0`), ou lorsque vous exécutez manuellement le workflow depuis l’onglet Actions.
**Ce que cela fait:**
1. Récupère votre application, configure Node.js et met à jour npm (la publication de confiance nécessite npm 11.5.1 ou une version ultérieure).
2. Exécute `yarn twenty app:publish`, qui génère l’application et publie `.twenty/output` sur npm. En CI, il ajoute automatiquement `--provenance` et `--access public`, de sorte qu’aucun indicateur n’est nécessaire dans le workflow.
**Configuration unique :**
Sur npmjs.com, ouvrez votre package > **Settings → Trusted Publisher** et enregistrez ce dépôt avec le workflow `publish.yml` (voir la [documentation npm sur la publication de confiance](https://docs.npmjs.com/trusted-publishers)). La publication avec provenance certifie quel dépôt GitHub a construit le package, ce qui est aussi la façon de revendiquer la propriété de votre application dans une marketplace Twenty.
<Note>
npm n’accepte la provenance que depuis des dépôts sources **publics**. Si vous publiez depuis un dépôt privé, npm rejette le bundle de provenance OIDC avec une erreur `E422 ... Erreur « Unsupported GitHub Actions source repository visibility: "private"` ». Pour publier depuis un dépôt privé, désactivez la provenance en définissant `TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'` dans la variable `env` de l’étape de publication (un indice commenté est inclus dans le fichier `publish.yml` généré automatiquement) :
```yaml filename=".github/workflows/publish.yml"
- name: Publish to npm
env:
TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'
run: yarn twenty app:publish
```
</Note>
### Épingler les actions réutilisables
Les workflows `ci.yml` et `cd.yml` référencent des actions réutilisables sur `@main`, de sorte que les mises à jour des actions dans le dépôt `twentyhq/twenty` sont récupérées automatiquement. Si vous souhaitez des builds déterministes, remplacez `@main` par un SHA de commit ou un tag de version sur chaque ligne `uses:`.
## Publication sur npm
Publier sur npm rend votre application découvrable dans la marketplace Twenty. N'importe quel espace de travail Twenty peut parcourir, installer et mettre à niveau des applications de la marketplace directement depuis l'interface utilisateur.
### Prérequis
* Un compte [npm](https://www.npmjs.com)
* Le mot-clé `twenty-app` dans le tableau `keywords` de votre `package.json` (à ajouter manuellement — il n'est pas inclus par défaut dans le modèle `create-twenty-app`)
```json filename="package.json"
{
"name": "twenty-app-postcard-sender",
"version": "1.0.0",
"keywords": ["twenty-app"]
}
```
### Métadonnées de la marketplace
La configuration `defineApplication()` prend en charge des champs optionnels qui contrôlent la façon dont votre application apparaît sur la place de marché. Utilisez `logo` et `galleryImages` pour référencer des images depuis le dossier `public/` :
```ts src/application-config.ts
export default defineApplication({
universalIdentifier: '...',
displayName: 'My App',
description: 'A great app',
logo: 'public/logo.png',
galleryImages: [
'public/screenshot-1.png',
'public/screenshot-2.png',
],
});
```
Voir l'[accordéon defineApplication](/l/fr/developers/extend/apps/config/application#marketplace-metadata) dans la page Building Apps pour la liste complète des champs de la place de marché (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, etc.).
#### Dimensions recommandées pour les images de la galerie
La place de marché affiche `galleryImages` dans un conteneur fixe `8:5` (par exemple, `1600×1000 px`).
<Note>
Les images de la galerie, quel que soit leur ratio d'aspect, sont affichées en entier et ne sont jamais recadrées, mais tout ce qui est nettement plus haut ou plus étroit que `8:5` affichera des bandes vides sur les côtés.
</Note>
#### Limite de taille d’image
Le `logo` et chaque fichier `galleryImages` ne doivent pas dépasser **10 Mo**. Les fichiers plus volumineux sont ignorés lorsque la place de marché réhéberge vos ressources publiées, ils ne seront donc pas affichés.
### Publier
```bash filename="Terminal"
yarn twenty app:publish
```
Pour publier sous un dist-tag spécifique (par exemple, `beta` ou `next`) :
```bash filename="Terminal"
yarn twenty app:publish --tag beta
```
### Comment fonctionne la découverte de la place de marché
Le serveur Twenty synchronise son catalogue de la place de marché à partir du registre npm **toutes les heures**.
Vous pouvez déclencher la synchronisation immédiatement au lieu d'attendre :
```bash filename="Terminal"
yarn twenty dev:catalog-sync
# To target a specific remote:
# yarn twenty dev:catalog-sync --remote production
```
Les métadonnées affichées dans la marketplace proviennent de votre configuration `defineApplication()` — voir [Métadonnées de la marketplace](#marketplace-metadata) ci-dessus.
<Note>
Si votre application ne définit pas de `aboutDescription` dans `defineApplication()`, la place de marché utilisera automatiquement le `README.md` de votre package depuis npm comme contenu de la page À propos. Cela signifie que vous pouvez maintenir un seul README à la fois pour npm et pour la place de marché Twenty. Si vous souhaitez une description différente dans la place de marché, définissez explicitement `aboutDescription`.
</Note>
### Publication via CI
Le workflow `publish.yml` préconfiguré décrit ci-dessus publie automatiquement sur npm lors des tags de version, avec provenance. Comme `yarn twenty app:publish` ajoute `--provenance` et `--access public` pour vous lorsqu’il s’exécute en CI, le workflow n’a besoin d’aucune option npm — seulement de la configuration unique de Trusted Publisher.
Pour d’autres systèmes de CI (GitLab CI, CircleCI, etc.), exécutez `yarn install` puis `yarn twenty app:publish`. La provenance est émise lorsque l’environnement peut générer un jeton OIDC et est ignorée automatiquement dans le cas contraire.
<Note>
La **provenance npm** ajoute un badge de confiance à votre fiche npm, permettant aux utilisateurs de vérifier que le package a été construit à partir d’un commit spécifique dans un pipeline CI public. C’est également ce qui vous permet de revendiquer la propriété de votre application dans une marketplace Twenty. Voir la [documentation npm sur la provenance](https://docs.npmjs.com/generating-provenance-statements) pour plus de détails.
</Note>
## Installation des applications
Une fois qu'une application est publiée (npm) ou déployée (tarball), les espaces de travail peuvent l'installer via l'interface utilisateur.
Accédez à la page **Paramètres > Applications** dans Twenty, où les applications de la place de marché et celles déployées en tarball peuvent être parcourues et installées.
{/* TODO: add screenshot of the UI when the app is registered */}
Vous pouvez également installer des applications depuis la ligne de commande :
```bash filename="Terminal"
yarn twenty app:install
```
<Note>
Le serveur applique le versionnement SemVer à l’installation, en reprenant les mêmes règles que lors du déploiement :
* L’installation de la même version déjà installée dans votre espace de travail est refusée avec une erreur `APP_ALREADY_INSTALLED`.
* L’installation d’une version inférieure à celle actuellement installée est refusée avec une erreur `CANNOT_DOWNGRADE_APPLICATION`.
Pour installer une version plus récente, déployez-la ou publiez-la d’abord, puis relancez `yarn twenty app:install`.
</Note>

View File

@@ -0,0 +1,126 @@
---
title: Synchronisation et récupération
description: Quelle commande utiliser et quand, comment lire la sortie de synchronisation, et une échelle de récupération pour les cas où les métadonnées locales dérivent — avant d'en arriver à une réinitialisation complète.
icon: compass
---
Le développement local d'applications tourne autour de la **synchronisation** : le CLI reconstruit votre manifeste et le serveur applique uniquement la différence entre celui-ci et les métadonnées déjà présentes dans votre espace de travail. Cette page explique vers quelle commande se tourner, comment lire ce qu'une synchronisation a modifié, et quoi faire — dans l'ordre — lorsque l'état local semble incohérent.
## Quelle commande, quand
<Note>
Pour l'itération locale au quotidien, vous voudrez presque toujours `yarn twenty dev`. Le déploiement et la publication servent à livrer des versions, **pas** pour la boucle locale.
</Note>
| Vous souhaitez… | Commande | Notes |
| ------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Itérer localement avec la synchronisation en direct | `yarn twenty dev` | Surveille vos fichiers et synchronise à chaque modification. |
| Synchroniser une fois puis quitter (CI, scripts, hooks) | `yarn twenty apply` | Effectue une compilation + synchronisation, puis quitte. Ajoutez `--force` pour ignorer la confirmation des changements destructifs. |
| Prévisualiser les changements **sans les appliquer** | `yarn twenty plan` | Calcule et affiche le diff ; n'écrit rien. |
| Retirer l'application de l'espace de travail | `yarn twenty app:uninstall` | Ajoutez `--yes` pour ignorer la confirmation. |
| Envoyer une archive tarball vers un serveur | `yarn twenty app:publish --private` | Nécessite une version de `package.json` **strictement supérieure** — voir [Publication](/l/fr/developers/extend/apps/operations/publishing). |
| Publier sur la place de marché (npm) | `yarn twenty app:publish` | — |
| Installer / mettre à niveau une version déployée | `yarn twenty app:install` | Installe la version actuellement déployée. |
| Effacer le serveur local et repartir de zéro | `yarn twenty docker:reset` | Supprime **toutes** les données locales — en dernier recours. |
<Note>
`yarn twenty dev --once` et `yarn twenty dev --once --dry-run` fonctionnent toujours comme alias obsolètes de `yarn twenty apply` et `yarn twenty plan`.
</Note>
### La synchronisation locale n'a pas besoin d'un incrément de version
La règle de `version` strictement croissante (`VERSION_ALREADY_EXISTS` lors du déploiement, `APP_ALREADY_INSTALLED` / `CANNOT_DOWNGRADE_APPLICATION` lors de l'installation) s'applique à **`app:publish` / `app:install`** — le chemin de mise en production. `yarn twenty dev` synchronise votre manifeste sur place et ne nécessite jamais de changement de version, vous n'avez donc pas besoin de toucher à `package.json` pour itérer. Si vous vous surprenez à incrémenter la version pour tester un changement local, c'est que vous utilisez le chemin de mise en production alors que vous voulez la boucle de développement.
## Lire la sortie de synchronisation
Chaque synchronisation affiche les changements de métadonnées qu'elle a appliqués (ou qu'elle appliquerait, avec `plan`), à la manière de Terraform — un bloc par entité avec ses attributs, puis une ligne récapitulative :
```text filename="Terminal"
# objectMetadata "rocket" will be created
+ icon = "IconRocket"
+ labelSingular = "Rocket"
+ ...
# fieldMetadata "launchedAt" will be updated
~ isNullable = false -> true
Plan: 2 to add, 1 to change, 1 to destroy.
✓ Synced My App (4 files)
```
C'est votre premier diagnostic : il vous indique exactement quels objets, champs et mises en page ont changé, afin que vous puissiez confirmer qu'une synchronisation a fait ce que vous attendiez avant de vérifier l'interface utilisateur.
Les changements destructifs (`to destroy`) sont listés avec ce qu'ils suppriment (par ex. `objectMetadata "auditNote" — drops the table and all its rows`) et nécessitent une confirmation interactive, ou `--force` dans les scripts.
Lorsqu'une synchronisation échoue sur une seule entité, l'erreur nomme l'entité en cause et son `universalIdentifier`, par exemple :
```text
Migration action 'create' for 'fieldMetadata' (universalIdentifier: 2020...4337) failed
```
Utilisez cet identifiant pour trouver l'entité dans votre manifeste (et, si nécessaire, dans l'espace de travail) plutôt que de deviner laquelle est en conflit.
## Prévisualiser les changements (plan)
`yarn twenty plan` construit votre manifeste, demande au serveur le plan de migration et l'affiche — **sans rien appliquer**. C'est le moyen sûr de répondre « que changerait cette synchronisation ? » avant de s'y engager.
```bash filename="Terminal"
yarn twenty plan
```
```text filename="Terminal"
Building manifest...
Computing metadata plan (read-only, nothing will be applied)...
# fieldMetadata "crewCapacity" will be created
+ ...
Plan: 1 to add, 1 to change, 0 to destroy.
✓ Plan complete for My App — no changes were applied
```
Un plan :
* **N'écrit rien** — aucune migration de métadonnées, aucune mise à jour de l'enregistrement d'application, aucun changement de rôle/onglet par défaut, et aucune génération de client d'API.
* Renvoie le **même diff** qu'une synchronisation réelle appliquerait, afin que vous puissiez examiner à l'avance les entités créées/mises à jour/supprimées.
* Est utile avant un changement risqué, lors de la révision d'un changement généré par une IA, ou dans un script qui doit échouer si un changement inattendu est sur le point d'être appliqué.
<Note>
Un plan ne prévisualise que les changements de **métadonnées**, et il nécessite que l'application ait été synchronisée au moins une fois (pour que l'espace de travail la connaisse). Si vous l'exécutez sur une application qui n'a jamais été synchronisée, le serveur indique que l'application n'est pas installée — exécutez d'abord une fois `yarn twenty dev`.
</Note>
## Échelle de récupération
Lorsque les métadonnées locales semblent incorrectes, augmentez le niveau de manière progressive dans cet ordre et arrêtez-vous dès que vous êtes débloqué. Chaque étape est plus perturbatrice que la précédente.
1. **Resynchroniser.** Exécutez à nouveau `yarn twenty apply`. Les synchronisations sont idempotentes — réexécuter un manifeste propre est sûr et résout souvent un incident passager.
2. **Prévisualiser le plan.** Exécutez `yarn twenty plan` pour voir exactement ce que la prochaine synchronisation compte changer, sans l'appliquer.
3. **Lire l'erreur nommée.** Si une synchronisation échoue, relevez le type de métadonnées et l'`universalIdentifier` dans le message (voir ci-dessus) et localisez cette entité dans votre manifeste. Un conflit pointe généralement vers un identifiant dupliqué ou réutilisé.
4. **Désinstaller et réinstaller.** `yarn twenty app:uninstall`, puis synchronisez à nouveau (`yarn twenty dev`). Cette opération reconstruit les métadonnées de l'application à partir d'une base saine tout en gardant le reste de votre espace de travail intact.
5. **Réinitialisation complète (en dernier recours).** `yarn twenty docker:reset`, puis réinjectez des données et resynchronisez.
<Warning>
`yarn twenty docker:reset` supprime **toutes** les données de votre instance locale — chaque espace de travail, enregistrement et application. Ne l'utilisez que lorsque les étapes précédentes ont échoué.
</Warning>
<Note>
Vous avez rencontré une erreur de métadonnées ? Veuillez [ouvrir un ticket](https://github.com/twentyhq/twenty/issues/new/choose) et inclure le message d'échec de migration (avec son type de métadonnées et son `universalIdentifier`), la sortie `Metadata changes` de la synchronisation, ainsi que les commandes que vous avez exécutées.
</Note>
## Éviter les synchronisations concurrentes sur un même espace de travail
La synchronisation applique des migrations de métadonnées. Exécuter plusieurs opérations de synchronisation, de déploiement ou d'installation contre le **même espace de travail au même moment** — par exemple, plusieurs terminaux ou agents IA qui itèrent en parallèle — peut entrelacer ces migrations et laisser les métadonnées dans un état partiellement appliqué.
Le serveur sérialise les synchronisations par espace de travail pour éviter cela, mais vous devriez tout de même faire transiter les opérations sensibles sur les métadonnées par un **processus unique** plutôt que de les lancer en concurrence. Si vous orchestrez le développement avec plusieurs agents, faites passer leurs appels de synchronisation/déploiement/installation par une file unique afin qu'un seul s'exécute à la fois.
## Distinguer les types d'échecs
Lorsque quelque chose se passe mal, le diff de métadonnées et les erreurs nommées vous permettent de localiser l'échec :
* **Erreur de construction du manifeste** — le CLI échoue avant la synchronisation (`MANIFEST_BUILD_FAILED`, `TYPECHECK_FAILED`) ; corrigez le code source de votre application.
* **Erreur de synchronisation / migration** — la construction réussit mais l'application du diff échoue, en nommant l'entité et son `universalIdentifier` ; corrigez les métadonnées en conflit.
* **Erreur de taille des dépendances** — la synchronisation ou l’installation échoue parce que les `dependencies` de production de l’application sont trop volumineuses pour être installées en tant que couche d’exécution (`LOGIC_FUNCTION_DEPENDENCIES_SIZE_EXCEEDED`) ; déplacez vers `devDependencies` les packages que vos fonctions logiques n’importent pas au moment de l’exécution (bibliothèques d’interface utilisateur, outils de développement).
* **Erreur d’exécution du code de l’application** — la synchronisation réussit, mais vos fonctions logiques ou composants se comportent mal à l’exécution ; consultez les [journaux de fonctions](/l/fr/developers/extend/apps/operations/cli).
* **État local de l’instance** — aucun des cas ci-dessus et l’espace de travail semble toujours incorrect ; descendez l’échelle de récupération.

View File

@@ -0,0 +1,264 @@
---
title: Tests
description: Configuration de Vitest, tests d’intégration sur un serveur Twenty réel, vérification des types et CI avec GitHub Actions.
icon: flask
---
Le SDK fournit des API programmatiques qui vous permettent de construire, déployer, installer et désinstaller votre application depuis le code de test. Combiné avec [Vitest](https://vitest.dev/) et les clients d'API typés, vous pouvez écrire des tests d'intégration qui vérifient que votre application fonctionne de bout en bout sur un serveur Twenty réel.
## Utilisation de packages npm
Vous pouvez installer et utiliser n'importe quel package npm dans votre application. Les fonctions logiques et les composants frontaux sont tous deux empaquetés avec [esbuild](https://esbuild.github.io/), qui intègre leurs dépendances dans la sortie — aucun `node_modules` n'est nécessaire à l'exécution.
### Installation d'un package
```bash filename="Terminal"
yarn add axios
```
Puis importez-le dans votre code :
```ts src/logic-functions/fetch-data.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import axios from 'axios';
const handler = async (): Promise<any> => {
const { data } = await axios.get('https://api.example.com/data');
return { data };
};
export default defineLogicFunction({
universalIdentifier: '...',
name: 'fetch-data',
description: 'Fetches data from an external API',
timeoutSeconds: 10,
handler,
});
```
Il en va de même pour les composants frontaux :
```tsx src/front-components/chart.tsx
import { defineFrontComponent } from 'twenty-sdk/define';
import { format } from 'date-fns';
const DateWidget = () => {
return <p>Today is {format(new Date(), 'MMMM do, yyyy')}</p>;
};
export default defineFrontComponent({
universalIdentifier: '...',
name: 'date-widget',
component: DateWidget,
});
```
### Comment fonctionne le bundling
L'étape de build utilise esbuild pour produire un seul fichier autonome par fonction logique et par composant frontal. Les paquets importés sont intégrés dans le bundle, à l’exception de ceux listés ci-dessous.
**Les fonctions logiques** s'exécutent dans un environnement Node.js. Les modules intégrés de Node (`fs`, `path`, `crypto`, `http`, etc.) sont disponibles et n'ont pas besoin d'être installés.
**Les composants frontaux** s'exécutent dans un Web Worker. Les modules intégrés de Node ne sont **pas** disponibles — seuls les packages npm qui fonctionnent dans un environnement navigateur sont pris en charge. Notez que le bac à sable implémente un DOM *partiel*, de sorte qu’un package peut être compilé sans erreur tout en échouant à l’exécution ; voir [Limitations actuelles](/l/fr/developers/extend/apps/layout/front-components#current-limitations).
Les deux environnements disposent de `twenty-client-sdk/core` et `twenty-client-sdk/metadata` en tant que modules pré-fournis — ils ne sont pas intégrés au bundle mais résolus à l'exécution par le serveur.
Les composants frontaux peuvent également partager des dépendances via un [bundle de dépendances partagées](/l/fr/developers/extend/apps/layout/front-components#sharing-dependencies-across-front-components). Les paquets listés dans le champ `frontComponentSharedDependencies` du fichier package.json de l'application sont construits une fois dans un fichier séparé et chargés à partir de celui-ci à l'exécution au lieu d'être intégrés à chaque composant, de sorte qu'un composant qui n'importe que des paquets partagés n'embarque quasiment aucun code de dépendance propre.
## Installation
L'application générée inclut déjà Vitest. Si vous le configurez manuellement, installez les dépendances :
```bash filename="Terminal"
yarn add -D vitest vite-tsconfig-paths
```
Créez un `vitest.config.ts` à la racine de votre application :
```ts vitest.config.ts
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vitest/config';
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
const TWENTY_API_KEY = process.env.TWENTY_API_KEY ?? '<the pre-seeded local dev key>';
// Make env vars available to globalSetup (test.env only applies to workers)
process.env.TWENTY_API_URL = TWENTY_API_URL;
process.env.TWENTY_API_KEY = TWENTY_API_KEY;
export default defineConfig({
plugins: [
tsconfigPaths({
projects: ['tsconfig.spec.json'],
ignoreConfigErrors: true,
}),
],
test: {
testTimeout: 120_000,
hookTimeout: 120_000,
fileParallelism: false,
include: ['src/**/*.integration-test.ts'],
globalSetup: ['src/__tests__/global-setup.ts'],
env: {
TWENTY_API_URL,
TWENTY_API_KEY,
},
},
});
```
Créez un fichier de configuration global qui vérifie que le serveur est joignable, écrit une configuration de test pour le SDK (`~/.twenty/config.test.json`) et synchronise l’application avant l’exécution des tests :
```ts src/__tests__/global-setup.ts
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { appDevOnce, appUninstall } from 'twenty-sdk/cli';
const APP_PATH = process.cwd();
const CONFIG_DIR = path.join(os.homedir(), '.twenty');
export async function setup() {
const apiUrl = process.env.TWENTY_API_URL!;
const apiKey = process.env.TWENTY_API_KEY!;
// Verify the server is running
const response = await fetch(`${apiUrl}/healthz`);
if (!response.ok) {
throw new Error(`Twenty server is not reachable at ${apiUrl}.`);
}
// Write the SDK's test config (the CLI reads config.test.json when NODE_ENV=test)
fs.mkdirSync(CONFIG_DIR, { recursive: true });
fs.writeFileSync(
path.join(CONFIG_DIR, 'config.test.json'),
JSON.stringify({
remotes: { local: { apiUrl, apiKey } },
defaultRemote: 'local',
}, null, 2),
);
// Start from a clean slate, then sync the app
await appUninstall({ appPath: APP_PATH }).catch(() => {});
const result = await appDevOnce({ appPath: APP_PATH });
if (!result.success) {
throw new Error(`Dev sync failed: ${result.error?.message}`);
}
}
export async function teardown() {
await appUninstall({ appPath: APP_PATH });
}
```
## APIs programmatiques du SDK
Le sous-chemin `twenty-sdk/cli` exporte des fonctions que vous pouvez appeler directement depuis le code de test :
| Fonction | Description |
| -------------- | ----------------------------------------------------------------------------------- |
| `appBuild` | Construire l'application et éventuellement créer une archive tarball |
| `appDeploy` | Téléverser une archive tarball vers le serveur |
| `appDevOnce` | Construire et synchroniser l’application une fois (identique à `yarn twenty apply`) |
| `appInstall` | Installer l'application sur l'espace de travail actif |
| `appUninstall` | Désinstaller l'application de l'espace de travail actif |
Chaque fonction retourne un objet résultat avec `success: boolean` et soit `data` soit `error`.
## Écrire un test d'intégration
Voici un exemple complet qui construit, déploie et installe l'application, puis vérifie qu'elle apparaît dans l'espace de travail :
```ts src/__tests__/app-install.integration-test.ts
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application-config';
import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli';
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
const APP_PATH = process.cwd();
describe('App installation', () => {
beforeAll(async () => {
const buildResult = await appBuild({
appPath: APP_PATH,
tarball: true,
onProgress: (message: string) => console.log(`[build] ${message}`),
});
if (!buildResult.success) {
throw new Error(`Build failed: ${buildResult.error?.message}`);
}
const deployResult = await appDeploy({
tarballPath: buildResult.data.tarballPath!,
onProgress: (message: string) => console.log(`[deploy] ${message}`),
});
if (!deployResult.success) {
throw new Error(`Deploy failed: ${deployResult.error?.message}`);
}
const installResult = await appInstall({ appPath: APP_PATH });
if (!installResult.success) {
throw new Error(`Install failed: ${installResult.error?.message}`);
}
});
afterAll(async () => {
await appUninstall({ appPath: APP_PATH });
});
it('should find the installed app in the workspace', async () => {
const metadataClient = new MetadataApiClient();
const result = await metadataClient.query({
findManyApplications: {
id: true,
name: true,
universalIdentifier: true,
},
});
const installedApp = result.findManyApplications.find(
(app: { universalIdentifier: string }) =>
app.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
);
expect(installedApp).toBeDefined();
});
});
```
## Exécuter les tests
Assurez-vous que votre serveur Twenty local est en cours d'exécution, puis :
```bash filename="Terminal"
yarn test
```
Ou en mode surveillance (watch) pendant le développement :
```bash filename="Terminal"
yarn test:watch
```
## Vérification des types
Vous pouvez également exécuter une vérification des types sur votre application sans exécuter les tests :
```bash filename="Terminal"
yarn twenty dev:typecheck
```
Cela exécute `tsc --noEmit` sur le `tsconfig.json` de votre application et signale toute erreur de type. Les applications générées contiennent également un script `yarn typecheck` qui couvre aussi les fichiers de test (`tsconfig.spec.json`).
## CI avec GitHub Actions
Le générateur crée un workflow prêt à l’emploi dans `.github/workflows/ci.yml`. À chaque push sur `main` et à chaque pull request, il lance un serveur Twenty éphémère dans le runner (via l’action `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test`), puis exécute `yarn lint`, `yarn typecheck`, `yarn test:unit` et `yarn test` avec `TWENTY_API_URL` / `TWENTY_API_KEY` pointant vers ce serveur. Aucun secret n’est requis, et vous pouvez fixer la version du serveur via la variable d’environnement `TWENTY_VERSION` en haut du workflow.
Voir [Publication → CI/CD automatisé](/l/fr/developers/extend/apps/operations/publishing#automated-cicd-scaffolded-workflows) pour un guide complet des trois workflows générés (`ci.yml`, le pipeline de déploiement `cd.yml` et `publish.yml` pour la publication sur npm).

View File

@@ -0,0 +1,143 @@
---
title: Traductions
description: Publiez votre application en plusieurs langues — traduisez les libellés du manifeste et les chaînes d’interface utilisateur via un seul catalogue de locales.
icon: language
---
Les applications Twenty sont rédigées en **anglais** : les chaînes de vos sources et de votre manifeste
sont le texte source en anglais, `en` est la locale source à partir de laquelle vous traduisez, et
toute locale laissée non traduite revient à celle-ci par défaut.
Votre application comporte deux types de textes traduisibles, et tous deux transitent par le même
catalogue `locales/` :
* **Libellés du manifeste** — noms d’objets et de champs, titres de vues, éléments de menu et
autres chaînes déclarées dans les métadonnées de votre application.
* **Chaînes de front-component** — le texte d’interface utilisateur que vos composants React front affichent.
Vous marquez les chaînes traduisibles, les extrayez dans des catalogues par locale,
traduisez ces catalogues, et le build sert la bonne langue pour
l’utilisateur actuel — sans configuration supplémentaire.
## Marquer les chaînes de front-component
Importez les helpers de traduction depuis `twenty-sdk/front-component` :
```tsx
import { Trans, t, msg, useTranslate } from 'twenty-sdk/front-component';
const STATUSES = [
{ id: 'draft', label: msg('Draft') },
{ id: 'sent', label: msg('Sent') },
];
const Card = ({ count, name }: { count: number; name: string }) => {
const { t } = useTranslate();
return (
<section>
{/* Static text — reactive to the user's locale */}
<Trans>Loading postcard…</Trans>
{/* Disambiguate identical sources with a context */}
<Trans context="card-title">Untitled</Trans>
{/* Interpolation: pass values explicitly */}
<p>{t('Hi {name}', { name })}</p>
<p>{t('Saved {count} cards', { count })}</p>
{/* Resolve a lazily-declared descriptor */}
<ul>{STATUSES.map((s) => <li key={s.id}>{t(s.label)}</li>)}</ul>
</section>
);
};
```
### Quand utiliser quoi
* **`Trans`** — texte statique dans JSX. Utilisez les props `message` et `values` pour
l’interpolation, comme dans `Trans message="Hi {name}" values={{ name }}`;
l’interpolation directement dans les enfants n’est pas extractible statiquement.
* **`useTranslate().t`** — chaînes dynamiques à l’intérieur d’un composant. Se réaffiche lorsque
l’utilisateur change de langue. À privilégier à l’intérieur du rendu.
* **`t(...)`** (importé directement) — traduction immédiate utilisable **partout**,
y compris dans les gestionnaires d’événements, helpers et dans la portée du module — pas seulement dans le rendu.
* **`msg(...)`** — un descripteur paresseux pour les chaînes déclarées comme données (constantes,
configuration). Résolvez-le plus tard avec `t(descriptor)`.
### Contexte
Passez `context` pour lever l’ambiguïté entre des chaînes source identiques qui se traduisent
différemment :
```tsx
t({ message: 'Open', context: 'door' });
t({ message: 'Open', context: 'window' });
<Trans context="card-title">Untitled</Trans>
```
Les chaînes contextuelles apparaissent dans les catalogues de paramètres régionaux comme un groupe indexé par leur
contexte : `"\<context>": { "\<message>": "\<translation>" }`. Les libellés de manifeste sont
contextuels par construction — chacun porte le rôle de métadonnée qu’il joue
(`objectMetadata.labelSingular`, `fieldMetadata.label`, `view.name`, …), de sorte que
le même mot peut être traduit différemment en tant que nom d’objet et en tant que nom de vue.
## Extraction et traduction
Exécutez la commande d’extraction depuis le répertoire de votre application :
```bash
twenty dev:translations-extract # collect strings into locales/en.json
twenty dev:translations-extract --locale fr-FR # also scaffold a target locale
```
L’extraction collecte à la fois les libellés de votre manifeste et les chaînes `t()`/`msg()`/`Trans`
provenant de votre source front-component dans `locales/\<locale>.json`, indexées par
chaîne source. Renseignez les traductions :
```json
// locales/fr-FR.json
{
"Loading postcard…": "Chargement de la carte…",
"Hi {name}": "Bonjour {name}",
"Saved {count} cards": "{count} cartes enregistrées",
"door": {
"Open": "Ouvrir"
},
"objectMetadata.labelSingular": {
"Postcard": "Carte postale"
}
}
```
Les chaînes sans contexte sont des entrées plates ; les chaînes contextuelles — y compris chaque libellé de manifeste — sont imbriquées sous leur clé de contexte.
Les espaces réservés comme `{name}` sont substitués à l’exécution — conservez-les dans la
traduction. Toute chaîne laissée vide revient au texte source.
## Comment ça marche
`twenty dev:build` compile les catalogues et sert la bonne langue pour
l’utilisateur actuel : les libellés du manifeste sont résolus côté serveur, et les catalogues
front-component sont intégrés à chaque bundle de composant. À l’exécution, un composant lit la
locale depuis son contexte d’exécution (la langue actuelle de l’hôte) et résout
chaque chaîne à partir de son catalogue, en revenant à la source lorsqu’une traduction
manque. Changer la langue dans l’hôte réaffiche en direct les chaînes `Trans` et
`useTranslate().t`.
Les libellés du manifeste sont compilés à chaque synchronisation — `twenty dev:build`, `twenty apply`
et la surveillance continue de `twenty dev` —, donc modifier un fichier de paramètres régionaux et
le synchroniser suffit pour voir le nouveau texte. Les catalogues de composants front-end sont intégrés à
chaque bundle de composants lors de la compilation, donc modifier l'un d'eux implique toujours
de relancer `twenty dev:build` (et de redéployer).
Les enfants textuels de `Trans` peuvent s’étendre sur plusieurs lignes — les espaces sont réduits
de la même façon que JSX les réduit, donc ces deux exemples sont extraits avec la clé `Welcome back` :
```tsx
<Trans>Welcome back</Trans>
<Trans>
Welcome
back
</Trans>
```