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: Comandi di `yarn twenty` per eseguire funzioni, eseguire lo streaming dei log, gestire le installazioni delle app e passare da un remoto all'altro.
icon: terminal
---
La CLI `yarn twenty` è la tua interfaccia per tutto ciò che riguarda le app. Elenco completo dei comandi:
| Comando | Cosa fa | Documentato in |
| ----------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `dev` | Monitora i file sorgente e sincronizza in tempo reale le modifiche | [Guida rapida](/l/it/developers/extend/apps/getting-started/quick-start) |
| `piano` | Visualizza in anteprima le modifiche ai metadati senza applicarle | [Sincronizzazione e ripristino](/l/it/developers/extend/apps/operations/sync-and-recovery#previewing-changes-plan) |
| `applica` | Applica le modifiche ai metadati dopo aver mostrato il piano | [Sincronizzazione e ripristino](/l/it/developers/extend/apps/operations/sync-and-recovery) |
| `dev:build` | Compila l'app e genera il client API (`--tarball` per creare un `.tgz`) | [Pubblicazione](/l/it/developers/extend/apps/operations/publishing) |
| `dev:typecheck` | Esegui il controllo dei tipi TypeScript | [Test](/l/it/developers/extend/apps/operations/testing) |
| `dev:add` | Genera lo scaffold per una nuova entità | [Scaffolding](/l/it/developers/extend/apps/getting-started/scaffolding) |
| `dev:generate-client` | Rigenera il client API tipizzato | questa pagina |
| `dev:function:exec` / `dev:function:logs` | Esegui le funzioni e trasmetti in streaming i relativi log | questa pagina |
| `dev:translations-extract` | Estrai le stringhe traducibili nei cataloghi in `locales/` | [Traduzioni](/l/it/developers/extend/apps/operations/translations) |
| `dev:catalog-sync` | Attiva la sincronizzazione del catalogo del marketplace | [Pubblicazione](/l/it/developers/extend/apps/operations/publishing#how-marketplace-discovery-works) |
| `app:publish` / `app:install` / `app:uninstall` | Ciclo di vita delle release | [Pubblicazione](/l/it/developers/extend/apps/operations/publishing) e questa pagina |
| `docker:*` | Gestisci il container del server Twenty locale | [Server locale](/l/it/developers/extend/apps/getting-started/local-server) |
| `remote:*` | Gestisci le connessioni al server | questa pagina |
Ogni comando accetta `-r, --remote \<name>` per puntare a un remoto specifico anziché a quello predefinito.
## Esecuzione delle funzioni (`yarn twenty dev:function:exec`)
Esegui manualmente una funzione logica senza attivarla tramite HTTP, cron o evento del database:
```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
```
## Visualizzazione dei log delle funzioni (`yarn twenty dev:function:logs`)
Esegui lo streaming dei log di esecuzione per le funzioni logiche della tua app:
```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>
Questo è diverso da `yarn twenty docker:logs`, che mostra i log del container Docker. `yarn twenty dev:function:logs` mostra i log di esecuzione delle funzioni della tua app dal server Twenty.
</Note>
## Generare il client tipizzato (`yarn twenty dev:generate-client`)
Rigenera il client API tipizzato (`twenty-client-sdk`) dallo schema del remoto attivo, senza eseguire la build né sincronizzare un'app. Usalo per ottenere un client tipizzato in qualsiasi progetto — ad esempio un servizio backend che vive in un repository separato — che comunica con la tua istanza 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
```
Quindi importa il client nel tuo codice:
```typescript
import { CoreApiClient } from 'twenty-client-sdk/core';
```
Esegui nuovamente il comando ogni volta che il tuo modello di dati cambia, per aggiornare i tipi generati.
<Note>
Il client viene generato all'interno di `node_modules`, quindi non viene inserito nel commit insieme al tuo codice. Esegui `yarn twenty dev:generate-client` dopo ogni installazione (ad esempio in uno script `postinstall` o nella CI).
</Note>
## Disinstallazione di un'app (`yarn twenty app:uninstall`)
Rimuovi la tua app dallo spazio di lavoro attivo:
```bash filename="Terminal"
yarn twenty app:uninstall
# Skip the confirmation prompt
yarn twenty app:uninstall --yes
```
## Gestione dei remoti
Un **remoto** è un server Twenty a cui la tua app si connette. Durante la configurazione, lo strumento di scaffolding ne crea uno automaticamente per te. Puoi aggiungere altri remoti o passare da uno all'altro in qualsiasi momento.
```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>
```
Le tue credenziali sono archiviate in `~/.twenty/config.json`.

View File

@@ -0,0 +1,32 @@
---
title: Panoramica
description: Crea, testa e distribuisci la tua app — comandi CLI, test di integrazione, CI e pubblicazione su un server o su npm.
icon: rocket
---
Il **livello operativo** è tutto ciò che fai *alla* tua app piuttosto che *con* essa: eseguire comandi CLI, eseguire test di integrazione contro un server Twenty reale, configurare la CI e distribuire le release — sia come tarball distribuito su un singolo server, sia come pacchetto npm elencato nel marketplace.
```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)
```
## In questa sezione
<CardGroup cols={2}>
<Card title="CLI" icon="terminal" href="/l/it/developers/extend/apps/operations/cli">
Riferimento a `yarn twenty` — exec, logs, uninstall, remotes.
</Card>
<Card title="Sincronizzazione e ripristino" icon="compass" href="/l/it/developers/extend/apps/operations/sync-and-recovery">
Quale comando usare e quando, lettura del diff di sincronizzazione e una scaletta di ripristino.
</Card>
<Card title="Testing" icon="flask" href="/l/it/developers/extend/apps/operations/testing">
Configurazione di Vitest, test di integrazione, controllo dei tipi, workflow di CI.
</Card>
<Card title="Pubblicazione" icon="upload" href="/l/it/developers/extend/apps/operations/publishing">
Crea, distribuisci un tarball, pubblica su npm, installa.
</Card>
</CardGroup>

View File

@@ -0,0 +1,293 @@
---
title: Pubblicazione
icon: upload
description: Distribuisci la tua app Twenty nel marketplace oppure distribuiscila internamente.
---
## Panoramica
Una volta che la tua app è stata [compilata e testata localmente](/l/it/developers/extend/apps/getting-started/concepts), hai due modalità per distribuirla:
* **Distribuisci un tarball** — carica la tua app direttamente su un server Twenty specifico per uso interno o privato.
* **Pubblica su npm** — elenca la tua app nel marketplace di Twenty affinché qualsiasi spazio di lavoro possa scoprirla e installarla.
Entrambi i percorsi partono dalla stessa fase di **build**.
## Compilazione della tua app
Esegui il comando di build per compilare la tua app e generare un `manifest.json` pronto per la distribuzione:
```bash filename="Terminal"
yarn twenty dev:build
```
Questo compila i sorgenti TypeScript, transpila le funzioni di logica e i componenti front-end e scrive tutto in `.twenty/output/`. Aggiungi `--tarball` per produrre anche un pacchetto `.tgz` per la distribuzione manuale o per il comando di publish.
## Distribuzione su un server (tarball)
Per le app che non vuoi rendere pubbliche — strumenti proprietari, integrazioni solo aziendali o build sperimentali — puoi distribuire un tarball direttamente su un server Twenty.
### Prerequisiti
Prima della distribuzione, ti serve un remote configurato che punti al server di destinazione. I remote memorizzano localmente l'URL del server e le credenziali di autenticazione in `~/.twenty/config.json`.
Aggiungi un remote:
```bash filename="Terminal"
yarn twenty remote:add --url https://your-twenty-server.com --as production
```
### Distribuzione
Compila e carica la tua app sul server in un solo passaggio:
```bash filename="Terminal"
yarn twenty app:publish --private
# To deploy to a specific remote:
# yarn twenty app:publish --private --remote production
```
### Condivisione di un'app distribuita
Le app in formato tarball non sono elencate nel marketplace pubblico, quindi altri spazi di lavoro sullo stesso server non le troveranno navigando. Per condividere un'app distribuita:
1. Vai su **Impostazioni > Applicazioni > Registrazioni** e apri la tua app
2. Nella scheda **Distribuzione**, fai clic su **Copia link di condivisione**
3. Condividi questo link con utenti su altri spazi di lavoro — li porterà direttamente alla pagina di installazione dell'app
Il link di condivisione utilizza l'URL di base del server (senza alcun sottodominio dello spazio di lavoro) così funziona per qualsiasi spazio di lavoro sul server.
### Gestione delle versioni
Quando si aggiorna un'app in formato tarball già distribuita, il server richiede che la `version` in `package.json` sia **strettamente superiore** (per l'ordinamento [semver](https://semver.org)) rispetto alla versione attualmente distribuita. Eseguire nuovamente il deploy della stessa versione, o pubblicarne una inferiore, viene rifiutato prima che il tarball venga archiviato — vedrai un errore `VERSION_ALREADY_EXISTS` nella CLI.
Per rilasciare un aggiornamento:
1. Incrementa il campo `version` nel tuo `package.json` (ad es. `1.2.3` → `1.2.4`, `1.3.0` o `2.0.0`).
2. Esegui `yarn twenty app:publish --private` (oppure `yarn twenty app:publish --private --remote production`)
3. Gli spazi di lavoro che hanno installato l'app e abilitato l'aggiornamento automatico (nella scheda Impostazioni dell'app) vengono aggiornati automaticamente in secondo piano; gli altri vedranno l'aggiornamento disponibile nelle loro impostazioni
<Note>
I tag di pre-release funzionano come previsto: incrementare `1.0.0-rc.1` → `1.0.0-rc.2` è consentito e una release finale come `1.0.0` viene correttamente riconosciuta come superiore a `1.0.0-rc.5`. La versione in `package.json` deve essere essa stessa una stringa semver valida.
</Note>
{/* TODO: add screenshot of the Upgrade button */}
### Compatibilità della versione del server
Se la tua app utilizza una funzionalità introdotta in una specifica versione del server Twenty (ad esempio, i provider OAuth aggiunti nella v2.3.0), dovresti dichiarare la versione minima del server richiesta dalla tua app utilizzando il campo `engines.twenty` in `package.json`:
```json filename="package.json"
{
"name": "twenty-my-app",
"version": "1.0.0",
"engines": {
"node": "^24.5.0",
"twenty": ">=2.3.0"
}
}
```
Il valore è un [intervallo semver](https://github.com/npm/node-semver#ranges) standard. Modelli comuni:
| Intervallo | Significato |
| ---------------------------------- | -------------------------------------------------------------- |
| `>=2.3.0` | Qualsiasi server a partire dalla 2.3.0 |
| `>=2.3.0 \<3.0.0` | 2.3.0 o successive, ma precedenti alla prossima versione major |
| `^2.3.0` | Equivale a `>=2.3.0 \<3.0.0` |
**Cosa succede durante il deploy e l'installazione:**
* Se `engines.twenty` è impostato e la versione del server di destinazione non soddisfa l'intervallo, il deploy (caricamento del tarball) o l'installazione vengono rifiutati con un errore `SERVER_VERSION_INCOMPATIBLE` e un messaggio che indica sia l'intervallo richiesto sia la versione effettiva del server.
* Se `engines.twenty` **non è impostato**, l'app è accettata su qualsiasi versione del server (retrocompatibile con le app esistenti).
* Se sul server non è configurata `APP_VERSION`, il controllo viene ignorato.
<Note>
Il server è l'autorità di controllo — convalida `engines.twenty` sia durante il caricamento del tarball sia durante l'installazione nello spazio di lavoro. Se distribuisci un tarball out-of-band o installi dal marketplace, il server continua comunque a imporre la compatibilità.
</Note>
## CI/CD automatizzati (workflow preconfigurati)
Le app generate con `create-twenty-app` includono tre workflow di GitHub Actions pronti all'uso, nella cartella `.github/workflows/`. L'esecuzione della CI non richiede alcuna configurazione, la CD richiede un solo secret e la pubblicazione su npm richiede una configurazione una tantum di npm trusted-publisher.
### CI — `ci.yml`
Esegue automaticamente i test di integrazione a ogni push su `main` e sulle pull request.
**Cosa fa:**
1. Esegue il checkout del codice sorgente della tua app.
2. Avvia un'istanza di test isolata di Twenty utilizzando l'azione composita `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main` (l'equivalente per la CI di `yarn twenty docker:start --test`).
3. Abilita Corepack, configura Node.js dal tuo `.nvmrc` e installa le dipendenze con `yarn install --immutable`.
4. Esegue `yarn test`, passando `TWENTY_API_URL` e `TWENTY_API_KEY` dall'istanza avviata affinché i tuoi test possano comunicare con un server reale.
**Opzioni di configurazione:**
* `TWENTY_VERSION` (variabile di ambiente, predefinito `latest`) — fissa la versione del server Twenty usata nella CI modificando questo valore in `ci.yml`.
* La concorrenza è raggruppata per `github.ref` e annulla le esecuzioni in corso in caso di nuovi push.
Non sono necessari Secrets — l'istanza di test è effimera ed esiste solo per la durata del job.
### CD — `cd.yml`
Esegue il deploy della tua app su un server Twenty configurato a ogni push su `main` e, facoltativamente, da una pull request quando viene applicata l'etichetta `deploy`.
**Cosa fa:**
1. Esegue il checkout della testa della PR (per le PR etichettate) oppure del commit inviato.
2. Esegue `twentyhq/twenty/.github/actions/deploy-twenty-app@main` — l'equivalente per la CI di `yarn twenty app:publish --private`.
3. Esegue `twentyhq/twenty/.github/actions/install-twenty-app@main` in modo che la versione appena distribuita venga installata nello spazio di lavoro di destinazione.
**Configurazione richiesta:**
| Impostazione | Dove | Scopo |
| ----------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `TWENTY_DEPLOY_URL` | `env` in `cd.yml` (predefinito `http://localhost:3000`) | Il server Twenty su cui effettuare il deploy. Modificalo con l'URL reale del tuo server prima del primo utilizzo. |
| `TWENTY_DEPLOY_API_KEY` | Repository GitHub **Settings → Secrets and variables → Actions** | Chiave API con autorizzazione di deploy sul server di destinazione. |
<Note>
Il valore predefinito di `TWENTY_DEPLOY_URL`, `http://localhost:3000`, è un segnaposto — non raggiungerà alcuna risorsa da un runner ospitato su GitHub. Aggiornalo all'URL pubblico del tuo server (oppure usa un runner self-hosted con accesso di rete) prima di abilitare il CD.
</Note>
**Attivare un deploy di anteprima da una PR:**
Aggiungi l'etichetta `deploy` a una pull request. La condizione `if:` in `cd.yml` eseguirà il job per quella PR utilizzando il commit di testa della PR, permettendoti di convalidare una modifica sul server di destinazione prima del merge.
### Pubblica — `publish.yml`
Pubblica la tua app su npm con attestazione di provenienza quando esegui il push di un tag di versione (ad es. `v1.0.0`), oppure quando esegui manualmente il workflow dalla scheda Actions.
**Cosa fa:**
1. Clona la tua app, configura Node.js e aggiorna npm (la pubblicazione attendibile richiede npm 11.5.1 o versioni successive).
2. Esegue `yarn twenty app:publish`, che crea la build dell'app e pubblica `.twenty/output` su npm. In CI aggiunge automaticamente `--provenance` e `--access public`, quindi non sono necessari flag nel workflow.
**Impostazione una tantum:**
Su npmjs.com apri il tuo pacchetto > **Settings → Trusted Publisher** e registra questo repository con il workflow `publish.yml` (consulta la [documentazione su npm trusted publishing](https://docs.npmjs.com/trusted-publishers)). La pubblicazione con provenance certifica quale repository GitHub ha creato il pacchetto ed è anche il modo in cui dichiari la proprietà della tua app in un marketplace Twenty.
<Note>
npm accetta la provenienza solo da repository di origine **pubblici**. Se esegui la pubblicazione da un repository privato, npm rifiuta il bundle di provenienza OIDC con un `E422 ... Errore "Unsupported GitHub Actions source repository visibility: \"private\"`." Per pubblicare da un repository privato, escludi la provenienza impostando `TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'` nella `env` dello step di pubblicazione (nel `publish.yml` generato è incluso un suggerimento commentato):
```yaml filename=".github/workflows/publish.yml"
- name: Publish to npm
env:
TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'
run: yarn twenty app:publish
```
</Note>
### Bloccare le azioni riutilizzabili
I workflow `ci.yml` e `cd.yml` fanno riferimento ad azioni riutilizzabili a `@main`, quindi gli aggiornamenti delle azioni nel repository `twentyhq/twenty` vengono recepiti automaticamente. Se desideri build deterministiche, sostituisci `@main` con uno SHA di commit o un tag di release in ciascuna riga `uses:`.
## Pubblicazione su npm
La pubblicazione su npm rende la tua app scopribile nel marketplace di Twenty. Qualsiasi spazio di lavoro Twenty può sfogliare, installare e aggiornare le app del marketplace direttamente dall'interfaccia utente.
### Requisiti
* Un account [npm](https://www.npmjs.com)
* La parola chiave `twenty-app` nell'array `keywords` del tuo `package.json` (aggiungila manualmente — non è inclusa per impostazione predefinita nel template `create-twenty-app`)
```json filename="package.json"
{
"name": "twenty-app-postcard-sender",
"version": "1.0.0",
"keywords": ["twenty-app"]
}
```
### Metadati del marketplace
La configurazione `defineApplication()` supporta campi opzionali che controllano come la tua app appare nel marketplace. Usa `logo` e `galleryImages` per fare riferimento alle immagini nella cartella `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',
],
});
```
Vedi l'[accordion defineApplication](/l/it/developers/extend/apps/config/application#marketplace-metadata) nella pagina Building Apps per l'elenco completo dei campi del marketplace (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, ecc.).
#### Dimensioni consigliate delle immagini della galleria
Il marketplace visualizza le `galleryImages` in un contenitore `8:5` fisso (ad esempio, `1600×1000 px`).
<Note>
Le immagini della galleria di qualsiasi rapporto d'aspetto vengono visualizzate per intero e non vengono mai ritagliate, ma tutto ciò che è significativamente più alto o più stretto di `8:5` mostrerà bande vuote ai lati.
</Note>
#### Limite dimensione immagine
Il file `logo` e ciascun file di `galleryImages` non devono superare **10 MB**. I file più grandi vengono ignorati quando il marketplace ripubblica le tue risorse pubblicate, quindi non verranno visualizzati.
### Pubblica
```bash filename="Terminal"
yarn twenty app:publish
```
Per pubblicare con un dist-tag specifico (ad es. `beta` o `next`):
```bash filename="Terminal"
yarn twenty app:publish --tag beta
```
### Come funziona l'individuazione nel marketplace
Il server Twenty sincronizza il proprio catalogo del marketplace dal registro npm **ogni ora**.
Puoi attivare la sincronizzazione immediatamente invece di aspettare:
```bash filename="Terminal"
yarn twenty dev:catalog-sync
# To target a specific remote:
# yarn twenty dev:catalog-sync --remote production
```
I metadati mostrati nel marketplace provengono dalla configurazione di `defineApplication()` — vedi [Metadati del marketplace](#marketplace-metadata) sopra.
<Note>
Se la tua app non definisce un `aboutDescription` in `defineApplication()`, il marketplace userà automaticamente il `README.md` del tuo pacchetto su npm come contenuto della pagina Informazioni. Questo significa che puoi mantenere un unico README sia per npm sia per il marketplace di Twenty. Se desideri una descrizione diversa nel marketplace, imposta esplicitamente `aboutDescription`.
</Note>
### Pubblicazione con CI
Il workflow `publish.yml` generato dallo scaffold descritto sopra pubblica automaticamente su npm sui tag di versione, con provenance. Poiché `yarn twenty app:publish` aggiunge `--provenance` e `--access public` per te quando viene eseguito in CI, il workflow non ha bisogno di flag npm — serve solo l'impostazione una tantum del trusted publisher.
Per altri sistemi CI (GitLab CI, CircleCI, ecc.), esegui `yarn install` e poi `yarn twenty app:publish`. La provenance viene emessa quando l'ambiente può generare un token OIDC e, in caso contrario, viene saltata automaticamente.
<Note>
La **npm provenance** aggiunge un badge di attendibilità alla tua scheda npm, consentendo agli utenti di verificare che il pacchetto sia stato creato a partire da uno specifico commit in una pipeline CI pubblica. È anche ciò che ti permette di dichiarare la proprietà della tua app in un marketplace Twenty. Consulta la [documentazione su npm provenance](https://docs.npmjs.com/generating-provenance-statements) per maggiori dettagli.
</Note>
## Installazione delle app
Una volta che un'app è stata pubblicata (npm) o distribuita (tarball), gli spazi di lavoro possono installarla tramite l'interfaccia utente.
Vai alla pagina **Impostazioni > Applicazioni** in Twenty, dove è possibile sfogliare e installare sia le app del marketplace sia quelle distribuite tramite tarball.
{/* TODO: add screenshot of the UI when the app is registered */}
Puoi anche installare le app dalla riga di comando:
```bash filename="Terminal"
yarn twenty app:install
```
<Note>
Il server applica il versioning semver durante l’installazione, rispecchiando le regole del deploy:
* L’installazione della stessa versione già installata nel tuo spazio di lavoro viene rifiutata con un errore `APP_ALREADY_INSTALLED`.
* L’installazione di una versione inferiore rispetto a quella attualmente installata viene rifiutata con un errore `CANNOT_DOWNGRADE_APPLICATION`.
Per installare una versione più recente, effettua prima il deploy o la pubblicazione, quindi riesegui `yarn twenty app:install`.
</Note>

View File

@@ -0,0 +1,126 @@
---
title: Sincronizzazione e ripristino
description: Quale comando usare e quando, come leggere l'output della sincronizzazione e una scala di ripristino per quando i metadati locali divergono — prima di arrivare a un ripristino completo.
icon: compass
---
Lo sviluppo di app in locale ruota attorno alla **sincronizzazione**: la CLI ricostruisce il tuo manifest e il server applica solo la differenza tra questo e i metadati già presenti nel tuo spazio di lavoro. Questa pagina spiega quale comando usare, come leggere ciò che una sincronizzazione ha modificato e cosa fare — in ordine — quando lo stato locale sembra incoerente.
## Quale comando, quando
<Note>
Per l’iterazione locale quotidiana vuoi quasi sempre `yarn twenty dev`. Il deploy e la pubblicazione servono a distribuire le release, **non** per il ciclo locale.
</Note>
| Vuoi… | Comando | Note |
| ----------------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Iterare in locale con sincronizzazione in tempo reale | `yarn twenty dev` | Monitora i file e sincronizza a ogni modifica. |
| Sincronizzare una volta e uscire (CI, script, hook) | `yarn twenty apply` | Esegue una build + sincronizzazione, poi termina. Aggiungi `--force` per saltare la conferma delle modifiche distruttive. |
| Visualizzare in anteprima le modifiche **senza applicarle** | `yarn twenty plan` | Calcola e stampa il diff; non scrive nulla. |
| Rimuovere l'app dallo spazio di lavoro | `yarn twenty app:uninstall` | Aggiungi `--yes` per saltare il prompt. |
| Inviare un tarball a un server | `yarn twenty app:publish --private` | Richiede una versione di `package.json` **strettamente superiore** — vedi [Publishing](/l/it/developers/extend/apps/operations/publishing). |
| Pubblicare nel marketplace (npm) | `yarn twenty app:publish` | — |
| Installare / aggiornare una versione distribuita | `yarn twenty app:install` | Installa la versione attualmente distribuita. |
| Pulire il server locale e ripartire da zero | `yarn twenty docker:reset` | Elimina **tutti** i dati locali — ultima risorsa. |
<Note>
`yarn twenty dev --once` e `yarn twenty dev --once --dry-run` funzionano ancora come alias deprecati per `yarn twenty apply` e `yarn twenty plan`.
</Note>
### La sincronizzazione locale non richiede un incremento di versione
La regola della `version` strettamente crescente (`VERSION_ALREADY_EXISTS` in fase di deploy, `APP_ALREADY_INSTALLED` / `CANNOT_DOWNGRADE_APPLICATION` in fase di installazione) si applica a **`app:publish` / `app:install`** — il percorso di release. `yarn twenty dev` sincronizza il tuo manifest in-place e non richiede mai una modifica di versione, quindi non devi toccare `package.json` per iterare. Se ti ritrovi ad aumentare la versione per testare una modifica locale, stai usando il percorso di release quando invece vuoi il ciclo di sviluppo.
## Lettura dell'output di sincronizzazione
Ogni sincronizzazione stampa le modifiche ai metadati che ha applicato (o che applicherebbe, con `plan`), in stile Terraform — un blocco per entità con i relativi attributi, quindi una riga di riepilogo:
```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)
```
Questo è il tuo primo strumento diagnostico: ti dice esattamente quali oggetti, campi e layout sono cambiati, così puoi confermare che una sincronizzazione ha fatto ciò che ti aspettavi prima di controllare l'interfaccia utente (UI).
Le modifiche distruttive (`to destroy`) sono elencate con ciò che eliminano (ad es. `objectMetadata "auditNote" — drops the table and all its rows`) e richiedono una conferma interattiva, oppure `--force` negli script.
Quando una sincronizzazione fallisce su una singola entità, l'errore indica l'entità in questione e il suo `universalIdentifier`, per esempio:
```text
Migration action 'create' for 'fieldMetadata' (universalIdentifier: 2020...4337) failed
```
Usa quell'identificatore per trovare l'entità nel tuo manifest (e, se necessario, nello spazio di lavoro) invece di indovinare quale sia in conflitto.
## Anteprima delle modifiche (plan)
`yarn twenty plan` crea il tuo manifest, chiede al server il piano di migrazione e lo stampa — **senza applicare nulla**. È il modo sicuro per rispondere a "cosa cambierebbe questa sincronizzazione?" prima di impegnarti ad applicarla.
```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 piano:
* **Non scrive nulla** — nessuna migrazione dei metadati, nessun aggiornamento del record dell'applicazione, nessuna modifica ai ruoli/schede predefiniti e nessuna generazione del client API.
* Restituisce lo **stesso diff** che una sincronizzazione reale applicherebbe, così puoi esaminare in anticipo le entità create/aggiornate/eliminate.
* È utile prima di una modifica rischiosa, quando si rivede una modifica generata da un'IA o in uno script che deve fallire se sta per essere applicata una modifica imprevista.
<Note>
Un piano mostra in anteprima solo le modifiche ai **metadati** e richiede che l'app sia stata sincronizzata almeno una volta (così lo spazio di lavoro la conosce). Se lo esegui su un'app che non è mai stata sincronizzata, il server segnala che l'app non è installata — esegui prima `yarn twenty dev` una volta.
</Note>
## Scala di ripristino
Quando i metadati locali sembrano errati, procedi in quest'ordine e fermati non appena ti sblocchi. Ogni passaggio è più invasivo del precedente.
1. **Nuova sincronizzazione.** Esegui di nuovo `yarn twenty apply`. Le sincronizzazioni sono idempotenti — rieseguire un manifest pulito è sicuro e spesso risolve un problema temporaneo.
2. **Visualizza in anteprima il piano.** Esegui `yarn twenty plan` per vedere esattamente cosa intende cambiare la prossima sincronizzazione, senza applicarlo.
3. **Leggi l'errore nominale.** Se una sincronizzazione fallisce, annota il tipo di metadato e lo `universalIdentifier` nel messaggio (vedi sopra) e individua quell'entità nel tuo manifest. Un conflitto di solito indica un identificatore duplicato o riutilizzato.
4. **Disinstalla e reinstalla.** `yarn twenty app:uninstall`, poi sincronizza di nuovo (`yarn twenty dev`). Questo ricostruisce i metadati dell'app partendo da zero, lasciando intatto il resto del tuo spazio di lavoro.
5. **Ripristino completo (ultima risorsa).** `yarn twenty docker:reset`, poi esegui di nuovo il seeding e la sincronizzazione.
<Warning>
`yarn twenty docker:reset` elimina **tutti** i dati nella tua istanza locale — ogni workspace, record e app. Usalo solo quando i passaggi precedenti hanno fallito.
</Warning>
<Note>
Hai riscontrato un errore di metadati? Per favore [apri una issue](https://github.com/twentyhq/twenty/issues/new/choose) e includi il messaggio di migrazione non riuscita (con il tipo di metadato e lo `universalIdentifier`), l'output `Metadata changes` della sincronizzazione e i comandi che hai eseguito.
</Note>
## Evitare sincronizzazioni concorrenti sullo stesso spazio di lavoro
La sincronizzazione applica le migrazioni dei metadati. Eseguire diverse operazioni di sincronizzazione, deploy o installazione sullo **stesso spazio di lavoro nello stesso momento** — per esempio, più terminali o agenti di IA che iterano in parallelo — può intrecciare queste migrazioni e lasciare i metadati in uno stato parzialmente applicato.
Il server serializza le sincronizzazioni per spazio di lavoro per evitare questo, ma dovresti comunque convogliare le operazioni sensibili sui metadati attraverso un **unico** processo invece di eseguirle in parallelo. Se orchestri lo sviluppo con più agenti, instrada le loro chiamate di sync/deploy/install attraverso una coda unica in modo che ne venga eseguita solo una alla volta.
## Distinguere i tipi di errore
Quando qualcosa va storto, il diff dei metadati e gli errori nominali ti permettono di localizzare il problema:
* **Errore di build del manifest** — la CLI fallisce prima della sincronizzazione (`MANIFEST_BUILD_FAILED`, `TYPECHECK_FAILED`); correggi il sorgente della tua app.
* **Errore di sincronizzazione / migrazione** — la build riesce ma l'applicazione del diff fallisce, indicando l'entità e lo `universalIdentifier`; correggi i metadati in conflitto.
* **Errore dimensione delle dipendenze** — la sincronizzazione o l'installazione non riesce perché le `dependencies` di produzione dell'app sono troppo grandi per essere installate come layer di runtime (`LOGIC_FUNCTION_DEPENDENCIES_SIZE_EXCEEDED`); sposta nei `devDependencies` i pacchetti che le tue funzioni logiche non importano a runtime (librerie UI, strumenti di sviluppo).
* **Errore di runtime del codice dell'app** — la sincronizzazione va a buon fine ma le tue funzioni di logica o i componenti si comportano in modo anomalo in fase di esecuzione; controlla i [log delle funzioni](/l/it/developers/extend/apps/operations/cli).
* **Stato locale dell'istanza** — nessuno dei casi precedenti e lo spazio di lavoro continua a sembrare errato; procedi lungo la scala di ripristino.

View File

@@ -0,0 +1,264 @@
---
title: Testing
description: Configurazione di Vitest, test di integrazione contro un server Twenty reale, controllo dei tipi e CI con GitHub Actions.
icon: flask
---
L'SDK fornisce API programmatiche che ti consentono di compilare, distribuire, installare e disinstallare la tua app dal codice di test. In combinazione con [Vitest](https://vitest.dev/) e i client API tipizzati, puoi scrivere test di integrazione che verificano che la tua app funzioni end-to-end contro un server Twenty reale.
## Uso dei pacchetti npm
Puoi installare e usare qualsiasi pacchetto npm nella tua app. Sia le funzioni logiche sia i componenti front-end vengono impacchettati con [esbuild](https://esbuild.github.io/), che incorpora le loro dipendenze nell'output — non sono necessari i `node_modules` a runtime.
### Installazione di un pacchetto
```bash filename="Terminal"
yarn add axios
```
Quindi importalo nel tuo codice:
```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,
});
```
Lo stesso vale per i componenti front-end:
```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,
});
```
### Come funziona il bundling
La fase di build usa esbuild per produrre un singolo file autonomo per ogni funzione logica e per ogni componente front-end. I pacchetti importati vengono incorporati nel bundle, ad eccezione di quelli elencati di seguito.
**Le funzioni logiche** vengono eseguite in un ambiente Node.js. I moduli integrati di Node (`fs`, `path`, `crypto`, `http`, ecc.) sono disponibili e non necessitano di essere installati.
**I componenti front-end** vengono eseguiti in un Web Worker. I moduli integrati di Node **non** sono disponibili — solo i pacchetti npm che funzionano in un ambiente browser. Nota che la sandbox implementa un DOM *parziale*, quindi un pacchetto può compilarsi correttamente e comunque fallire in fase di esecuzione; vedi [Limitazioni attuali](/l/it/developers/extend/apps/layout/front-components#current-limitations).
Entrambi gli ambienti hanno `twenty-client-sdk/core` e `twenty-client-sdk/metadata` disponibili come moduli preforniti — questi non vengono inclusi nel bundle ma vengono risolti a runtime dal server.
I componenti front-end possono anche condividere dipendenze tramite un [bundle di dipendenze condivise](/l/it/developers/extend/apps/layout/front-components#sharing-dependencies-across-front-components). I pacchetti elencati nel campo `frontComponentSharedDependencies` del package.json dell'app vengono compilati una sola volta in un file separato e caricati da lì a runtime invece di essere incorporati in ogni componente, quindi un componente che importa solo pacchetti condivisi contiene quasi nessun codice di dipendenza proprio.
## Impostazione
L'app generata tramite scaffolding include già Vitest. Se la configuri manualmente, installa le dipendenze:
```bash filename="Terminal"
yarn add -D vitest vite-tsconfig-paths
```
Crea un `vitest.config.ts` alla radice della tua app:
```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,
},
},
});
```
Crea un file di configurazione globale che verifichi che il server sia raggiungibile, scriva una configurazione di test per l'SDK (`~/.twenty/config.test.json`) e sincronizzi l'app prima dell'esecuzione dei test:
```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 });
}
```
## API programmatiche dell'SDK
Il sottopercorso `twenty-sdk/cli` esporta funzioni che puoi chiamare direttamente dal codice di test:
| Funzione | Descrizione |
| -------------- | ---------------------------------------------------------------- |
| `appBuild` | Compila l'app e, opzionalmente, crea un tarball |
| `appDeploy` | Carica un tarball sul server |
| `appDevOnce` | Compila e sincronizza l'app una volta (come `yarn twenty apply`) |
| `appInstall` | Installa l'app nello spazio di lavoro attivo |
| `appUninstall` | Disinstalla l'app dallo spazio di lavoro attivo |
Ogni funzione restituisce un oggetto risultato con `success: boolean` e `data` oppure `error`.
## Scrivere un test di integrazione
Ecco un esempio completo che compila, distribuisce e installa l'app, quindi verifica che compaia nello spazio di lavoro:
```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();
});
});
```
## Esecuzione dei test
Assicurati che il tuo server Twenty locale sia in esecuzione, quindi:
```bash filename="Terminal"
yarn test
```
Oppure in modalità watch durante lo sviluppo:
```bash filename="Terminal"
yarn test:watch
```
## Controllo dei tipi
Puoi anche eseguire il controllo dei tipi sulla tua app senza eseguire i test:
```bash filename="Terminal"
yarn twenty dev:typecheck
```
Questo esegue `tsc --noEmit` sul file `tsconfig.json` della tua app e riporta eventuali errori di tipo. Le app generate dallo scaffolder includono anche uno script `yarn typecheck` che copre anche i file di test (`tsconfig.spec.json`).
## CI con GitHub Actions
Lo strumento di scaffolding genera un workflow pronto all'uso in `.github/workflows/ci.yml`. A ogni push su `main` e a ogni pull request, avvia un server Twenty effimero nel runner (tramite l'azione `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test`), quindi esegue `yarn lint`, `yarn typecheck`, `yarn test:unit` e `yarn test` con `TWENTY_API_URL` / `TWENTY_API_KEY` che puntano a quel server. Non sono necessari segreti e puoi fissare la versione del server tramite la variabile di ambiente `TWENTY_VERSION` all'inizio del workflow.
Vedi [Pubblicazione → CI/CD automatizzato](/l/it/developers/extend/apps/operations/publishing#automated-cicd-scaffolded-workflows) per una spiegazione completa dei tre workflow generati dallo scaffolder (`ci.yml`, la pipeline di deploy `cd.yml` e `publish.yml` per la pubblicazione su npm).

View File

@@ -0,0 +1,144 @@
---
title: Traduzioni
description: Distribuisci la tua app in più lingue — traduci le etichette del manifest e le stringhe dell'interfaccia utente tramite un unico catalogo delle localizzazioni.
icon: language
---
Le app di Twenty sono scritte in **inglese**: le stringhe nel tuo sorgente e nel manifest
sono il testo sorgente in inglese, `en` è la locale di origine da cui traduci e
qualsiasi locale lasciato non tradotto usa quella come fallback.
La tua app ha due tipi di testo traducibile, e entrambi passano attraverso lo stesso
catalogo `locales/`:
* **Etichette del manifest** — nomi di oggetti e campi, titoli delle viste, voci di menu e
altre stringhe dichiarate nei metadati della tua app.
* **String dei front-component** — il testo dell’interfaccia utente renderizzato dai tuoi front component React.
Contrassegni le stringhe traducibili, le estrai in cataloghi per locale,
traduci tali cataloghi e la build serve la lingua corretta per l’utente
corrente — senza cablaggi aggiuntivi.
## Contrassegnare le stringhe dei front-component
Importa gli helper di traduzione da `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>
);
};
```
### Quando usare cosa
* **`Trans`** — testo statico in JSX. Usa le prop `message` e `values` per
l'interpolazione, come in `Trans message="Hi {name}" values={{ name }}`;
l'interpolazione direttamente nei figli non è estraibile staticamente.
* **`useTranslate().t`** — stringhe dinamiche all’interno di un componente. Esegue il re-render quando
l’utente cambia lingua. Preferiscilo all’interno del render.
* **`t(...)`** (importato direttamente) — traduzione eager utilizzabile **ovunque**,
inclusi gestori di eventi, helper e nello scope del modulo — non solo all’interno del render.
* **`msg(...)`** — un descrittore lazy per stringhe dichiarate come dati (costanti,
configurazione). Risolvilo in un secondo momento con `t(descriptor)`.
### Contesto
Passa `context` per distinguere stringhe sorgente identiche che si traducono
in modo diverso:
```tsx
t({ message: 'Open', context: 'door' });
t({ message: 'Open', context: 'window' });
<Trans context="card-title">Untitled</Trans>
```
Le stringhe contestuali compaiono nei cataloghi delle impostazioni locali come un gruppo indicizzato dal loro
contesto: `"\<context>": { "\<message>": "\<translation>" }`. Le etichette del manifest sono
contestuali per costruzione — ognuna porta con sé il ruolo di metadato che svolge
(`objectMetadata.labelSingular`, `fieldMetadata.label`, `view.name`, …), quindi
la stessa parola può essere tradotta in modo diverso come nome di oggetto e come nome di vista.
## Estrazione e traduzione
Esegui il comando di estrazione dalla directory della tua app:
```bash
twenty dev:translations-extract # collect strings into locales/en.json
twenty dev:translations-extract --locale fr-FR # also scaffold a target locale
```
L'estrazione raccoglie sia le etichette del manifest sia le stringhe `t()`/`msg()`/`Trans`
dal tuo sorgente front-component in `locales/\<locale>.json`, indicizzate per
stringa sorgente. Compila le traduzioni:
```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"
}
}
```
Le stringhe prive di contesto sono voci piatte; le stringhe contestuali — inclusa ogni
etichetta del manifest — sono annidate sotto la loro chiave di contesto.
I segnaposto come `{name}` vengono sostituiti a runtime — mantienili nella
traduzione. Qualsiasi stringa lasciata vuota fa fallback al testo sorgente.
## Come viene eseguito
`twenty dev:build` compila i cataloghi e serve la lingua corretta per l’utente
corrente: le etichette del manifest vengono risolte lato server e i cataloghi dei
front-component vengono inclusi in ogni bundle di componente. A runtime un componente legge la
locale dal proprio contesto di esecuzione (la lingua corrente dell’host) e risolve
ogni stringa rispetto al proprio catalogo, facendo fallback alla sorgente quando
una traduzione manca. Cambiare lingua nell'host esegue nuovamente il render delle stringhe `Trans` e
`useTranslate().t` in tempo reale.
Le etichette del manifest vengono compilate a ogni sincronizzazione — `twenty dev:build`, `twenty apply`
e anche il monitoraggio continuo di `twenty dev` — quindi è sufficiente modificare un file di lingua e
sincronizzare per vedere il nuovo testo. I cataloghi dei componenti Front vengono incorporati in
ogni bundle di componenti al momento della build, quindi modificarne uno significa comunque
rieseguire `twenty dev:build` (e ridistribuire).
I figli di testo di `Trans` possono estendersi su più righe — gli spazi bianchi vengono compressi
nello stesso modo in cui JSX li comprime, quindi entrambe queste varianti vengono estratte con la chiave `Welcome back`:
```tsx
<Trans>Welcome back</Trans>
<Trans>
Welcome
back
</Trans>
```