---
title: "Lancer des traductions"
description: "translate, watch et les points d'entrée autour d'une exécution, plus les pseudo-locales et les catalogues typés, le tout appelable depuis tes scripts Node.js."
type: "reference"
---
# Lancer des traductions

translate, watch et les points d'entrée autour d'une exécution, plus les pseudo-locales et les catalogues typés, le tout appelable depuis tes scripts Node.js.

## Traduire et surveiller [#lancer-des-traductions]

### translate [#translate]

Le flux en une passe : lire la source, comparer chaque locale cible à la ligne de base du verrou, envoyer les clés manquantes et modifiées au fournisseur, exécuter les contrôles d'intégrité, écrire les fichiers de locale et mettre à jour le verrou. Utilise-le pour les scripts, les étapes de build et les jobs CI.

```ts title="Signature"
function translate(
  input: TranslateInput,
  deps?: TranslateDeps,
): Promise<RunSummary>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `cwd` | `string` | no | Directory the `files.pattern` is resolved against, and where the lock-file, the translation memory, and the run-status file live. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `locales` | `readonly string[]` | no | Restrict the run to a subset of the configured target locales, which is how you translate one locale at a time against a rate-limited provider. Defaults to every configured target. The result keeps the configured order whatever order the subset is given in, and any locale named here that is not a configured target fails the whole run with `UNKNOWN_LOCALE` before anything is read or spent. An explicit empty array selects no locale at all rather than every locale. Locales left out are untouched: their files, their lock entries, and their translation-memory entries all stay as they were. The run-status file always describes the most recent run alone, so a subset run narrows it to that subset. |
| `dryRun` | `boolean` | no | Compute the whole run but write nothing and call no provider. The returned RunSummary reports what would have happened, which makes this safe to run in CI to preview work without spending anything. Defaults to false. In human-only mode (provider `none`) it reads the translation memory, so the plan matches a live run. |
| `estimate` | `boolean` | no | Compute a pre-run cost estimate and return it on RunSummary.estimate. Implies `dryRun`: an estimate constructs no provider, reads no API key, makes no network call, and writes no file, so it is safe to run anywhere. Defaults to false. The figure bounds the plan rather than the invoice: every provider call a live run schedules is counted, plural generation included, and the prompt is measured from the request payload that would be sent. Provider-side retries, a repair round, and a language that expands past the allowance can each push a live run above it; EstimateCaveatCode names them all. It carries a currency amount only when the config supplies a `rates` block covering the configured provider and model; otherwise it reports the quantity and says why the money is missing. See RunEstimate. |
| `prune` | `boolean` | no | Remove keys that no longer exist in the source. Defaults to the config's `prune`, then to false, so orphaned keys are reported but kept unless removal is asked for explicitly. |
| `generatePlurals` | `boolean` | no | Generate the plural categories a target language requires rather than translating each category separately. Defaults to the config's `generatePlurals`, then to false. Takes effect only for the `i18next-json` format with an LLM provider; any other format, a machine-translation provider, and provider `none` generate nothing. |
| `onLockWait` | `LockWaitListener` | no | Called while waiting on another process's write lock, so a CLI can explain a stall instead of appearing to hang. Never called for a lock this process holds itself, such as the lock-file guard a sibling locale holds on a concurrent run. Fires first once a wait has lasted a second. The SDK writes no output itself. |
| `onProgress` | `ProgressListener` | no | Called as locales and sub-batches start and finish, for progress reporting. The SDK writes no output itself. |
| `lockAcquireTimeoutMs` | `number` | no | How long, in milliseconds, to wait for a locale's write lock before that locale fails with `LOCK_CONTENDED`, and for the lock-file guard before a locale whose respelled state could not be moved fails with `LOCALE_STATE_NOT_CARRIED_OVER`. Both waits happen before any provider call. Defaults to ten minutes. It does not bound the lock-file guard a locale takes to record its result once its target file is written: that wait always allows the ten-minute default, so a written file is not left unrecorded. Not used on a dry run, which takes no lock. |
| `concurrency` | `number` | no | How many locales to run at once. Must be an integer of at least 1; defaults to 1. On a live run it cannot be combined with a token budget, configured or passed as `maxTokens`: the ceiling would still hold, but which locale loses its remaining work would depend on the order the locales interleave, so the run would not be reproducible. A whole-run error raised once locales are running starts no further locale, and the locales in flight finish and release their write locks before `translate` rejects, so the rejection arrives after the slowest one. |
| `cache` | `boolean` | no | Consult and update the translation memory, fuzzy reuse included. Defaults to true. Turning it off forces every key through the provider, which is what to do when you want to re-pay for a fresh translation. A dry run never reads the memory, whatever this says, except in human-only mode (provider `none`), where the memory is all a live run would use. The memory is the local CACHE_FILE_NAME file; `false` is the CLI's `--no-cache`. |
| `humanEdits` | `"overwrite" \| "protect" \| "suggest"` | no | Overrides the config's `humanEdits` for this run only (see HumanEditsPolicy). Set `overwrite` to retranslate stale keys a person wrote, as the CLI's `--include-human` flag does. Keys matching the config's `pinnedKeys` stay protected whatever this says. A dry run reads the provenance file too, unless this resolves to `overwrite`. |
| `maxTokens` | `number` | no | A token ceiling for this run alone, as the CLI's `--max-tokens` flag sets it. It is always a hard stop: a provider request that would pass it is withheld rather than sent, whatever the config's `budgetBehavior` says, and its keys are listed in LocaleSummary.budgetWithheld. When the config also sets `maxTokens`, the lower of the two applies, so this can tighten the configured budget but never loosen it. Must be a whole number of at least 1. Defaults to the config's `maxTokens` and `budgetBehavior` alone. |
| `signal` | `AbortSignal` | no | Cancels the run when aborted. No further locale starts, and a wait for a write lock stops. The locales running at the time send no further request, and an in-flight request is abandoned rather than counted as a provider failure, unless the provider reported a failure of its own. What already arrived is still written and recorded, the keys left over get no lock-file entry and stay pending for the next run, the run status is recorded, and every lock is released. The call then resolves rather than rejects: the result carries RunSummary.cancelled, each locale kept from starting is `failed` with the `RUN_CANCELLED` error code, and locales stopped while running carry a `RUN_CANCELLED` notice and are `partial`, or `failed` when no key landed and others were withheld. A dry run only stops early. Defaults to none. |

**Renvoie :** [`RunSummary`](https://verbatra.kreitz-webdev.de/fr/docs/sdk/run-summary.md)

**Lève :** [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#unknown_locale), [`LOCALE_UNSUPPORTED_BY_PROVIDER`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_unsupported_by_provider), [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#unknown_format), [`CONCURRENCY_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#concurrency_invalid), [`CONCURRENCY_BUDGET_CONFLICT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#concurrency_budget_conflict), [`MAX_TOKENS_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#max_tokens_invalid), [`LOCK_TIMEOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#lock_timeout_invalid), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_path_collision), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_invalid), [`PROVIDER_CONSTRUCTION_FAILED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provider_construction_failed), [`NETWORK_POLICY_VIOLATION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#network_policy_violation), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#config_invalid), [`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#lock_file_invalid), [`PROVENANCE_FILE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provenance_file_invalid)

**Exemple :** [Traduis et lis le résumé](https://verbatra.kreitz-webdev.de/fr/docs/sdk-quickstart.md#traduis-et-lis-le-résumé)

Ce que le tableau ne couvre pas :

- `cache` est le [cache de mémoire de traduction](https://verbatra.kreitz-webdev.de/fr/docs/the-cache.md) local (`verbatra.cache.json`, exporté aussi comme `CACHE_FILE_NAME`).
- `humanEdits` (à partir de 0.12.0) : par défaut, les clés obsolètes dont la valeur a été écrite,
  importée ou modifiée hors de verbatra par une personne sont gardées et listées dans
  `LocaleSummary.protected`. Voir [Protéger les traductions humaines](https://verbatra.kreitz-webdev.de/fr/docs/protecting-human-translations.md).
- `onProgress` reçoit les [événements de progression](#événements-de-progression) décrits plus bas.
- `maxBatchSize` et `budgetBehavior` sont réservés à la config ; il n'y a pas de surcharge par
  exécution.

Les problèmes globaux lèvent une `SdkError` ; l'échec d'une seule locale ne lève jamais rien et se
retrouve en `status: "failed"` sur l'entrée de cette locale pendant que l'exécution continue. Voir
[l'anatomie du `RunSummary`](https://verbatra.kreitz-webdev.de/fr/docs/sdk/run-summary.md#anatomie-du-runsummary).

### Événements de progression [#événements-de-progression]

<AvailableFrom version="0.12.0" />

`onProgress` reçoit un `ProgressEvent`, une union discriminée par `type`. Une version mineure peut ajouter des types, donc ignore un `type` que tu ne reconnais pas.

| `type` | Quand | Champs |
| --- | --- | --- |
| `locale-started` | le travail sur une locale commence | `locale`, `localeIndex`, `totalLocales` |
| `locale-planned` | après consultation de la mémoire de traduction et avant l'envoi du premier lot ; seulement quand un fournisseur est appelé | `locale`, `keys`, `batches`, `cacheHits` |
| `sub-batch` | juste avant la tentative de chaque lot de traduction | `locale`, `batchIndex`, `totalBatches` |
| `provider-retry` | un fournisseur intégré réessaie une requête qui a échoué avec un statut réessayable | `attempt`, `delayMs?`, `status?` |
| `repair` | un fournisseur LLM redemande les clés que sa première réponse a omises | `locale`, `keys` |
| `split-retry` | un lot dont la sortie a été coupée est réessayé en deux moitiés | `locale`, `keys` |
| `batch-finished` | un lot est terminé, qu'il ait réussi ou non | `locale`, `batchIndex`, `totalBatches`, `durationMs`, `usage?` |
| `writing` | juste avant l'écriture du fichier d'une locale | `locale` |
| `locale-finished` | le travail sur une locale se termine | `locale`, `status`, `translated`, `localeIndex`, `totalLocales` |
| `run-finished` | toutes les locales sont terminées | `localesCompleted`, `localesFailed` |
| `change-detected` | `watch` uniquement : une modification du fichier source s'est stabilisée | `paths` |
| `idle` | `watch` uniquement : une exécution est terminée et aucune n'attend | aucun |

`provider-retry` ne nomme aucune locale, car un seul fournisseur sert toute l'exécution. Gemini indique le délai et le statut, Anthropic, OpenAI, OpenCode et openai-compatible indiquent la tentative quand leur client la lance, et DeepL, Google Cloud Translation et LibreTranslate n'indiquent rien. Un dry run et une estimation n'émettent que `locale-started`, `locale-finished` et `run-finished`. Les enregistrements de progression `--json` de la CLI s'en tiennent aux quatre types d'origine : `locale-started`, `sub-batch`, `locale-finished` et `run-finished`.

`extract`, `diff` avec `unused` et `doctor` avec `literals` acceptent leur propre `onProgress`. Il reçoit un `ScanProgressEvent`, `{ type: "files-scanned", scanned, total }`, une fois après chaque fichier source de l'application que l'analyse lit.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | `"files-scanned"` | yes | Discriminant, reserved so later scan events can join a union. |
| `scanned` | `number` | yes | How many files have been scanned so far. |
| `total` | `number` | yes | How many files the scan will read in total. |

Un `CreateProvider` personnalisé reçoit un troisième argument, `CreateProviderHooks`, dès qu'une exécution signale sa progression. Appelle son `onRetry` avec `{ attempt, delayMs?, status? }` et les nouvelles tentatives de ton fournisseur apparaissent comme événements `provider-retry`.

### resolveDryRun [#resolvedryrun]

<AvailableFrom version="0.11.0" />

Indique si un ensemble d'options d'exécution se résout en un dry run. La fonction prend le `dryRun`
et l'`estimate` que tu t'apprêtes à passer à `translate` et dit si cette exécution construira un
fournisseur, écrira un fichier ou dépensera quoi que ce soit. C'est le seul endroit où la règle
voulant qu'`estimate` implique `dryRun` est décidée : utilise-la dès que quelque chose autour d'une
exécution doit le savoir à l'avance, plutôt que de redire l'implication et de t'en écarter.

```ts title="Signature"
function resolveDryRun(input: {
  readonly dryRun?: boolean | undefined;
  readonly estimate?: boolean | undefined;
}): boolean;
```

**Renvoie :** `boolean`

```ts title="Exemple"
import { resolveDryRun, translate, type VerbatraConfig } from "@verbatra/sdk";

declare const config: VerbatraConfig;

const options = { dryRun: false, estimate: true };
resolveDryRun(options); // true

const summary = await translate({ config, ...options });
```

### watch [#watch]

Surveille le fichier de la locale source et relance `translate` à chaque changement temporisé. Il déclenche une exécution initiale immédiatement au démarrage, puis une exécution par changement stabilisé. Les exécutions sont sérialisées : les changements survenus pendant une exécution se regroupent en une seule exécution de suivi.

```ts title="Signature"
function watch(
  input: WatchInput,
  deps?: WatchDeps,
): Promise<WatchController>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `cwd` | `string` | no | Directory the `files.pattern` is resolved against, and where each run's lock-file, translation memory, and run-status file live. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `locales` | `readonly string[]` | no | Restrict every run of the session to a subset of the configured target locales. Validated once when watching starts, so an unconfigured locale throws `UNKNOWN_LOCALE` before any watching begins rather than failing on each run. An explicit empty array selects no locale at all. |
| `debounceMs` | `number` | no | How long to coalesce rapid source changes before running. Defaults to 300 milliseconds. |
| `onRun` | `(result: WatchRunResult) => void` | yes | Called after every run with its outcome. This is the only way to observe a watch session, since watch itself resolves as soon as watching starts. |
| `onReady` | `(() => void)` | no | Called once when the session's startup checks have passed and the watcher is attached, right before the initial run starts, so a caller can announce the session ahead of that run's output. |
| `onLockWait` | `LockWaitListener` | no | Called while waiting on another process's write lock, never for one this process holds. |
| `onProgress` | `ProgressListener` | no | Called as each run plans, sends and writes its locales, and as the watcher detects a change or goes idle, for progress reporting. |
| `lockAcquireTimeoutMs` | `number` | no | How long, in milliseconds, to wait for a locale's write lock, before any provider call, before that locale fails with `LOCK_CONTENDED` on the run's summary. Defaults to ten minutes. The lock-file guard a locale takes to record its result after writing its target file always allows the ten-minute default instead. |
| `concurrency` | `number` | no | How many locales to run at once. Defaults to 1. Validated once when watching starts, and applied to every run. |
| `cache` | `boolean` | no | Consult and update the translation memory, fuzzy reuse included. Defaults to true. |

**Renvoie :** `WatchController`

**Lève :** [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#unknown_locale), [`LOCALE_UNSUPPORTED_BY_PROVIDER`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_unsupported_by_provider), [`CONCURRENCY_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#concurrency_invalid), [`LOCK_TIMEOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#lock_timeout_invalid), [`CONCURRENCY_BUDGET_CONFLICT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#concurrency_budget_conflict), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_path_collision), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_unreadable), [`NETWORK_POLICY_VIOLATION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#network_policy_violation), [`PROVIDER_CONSTRUCTION_FAILED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provider_construction_failed), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#config_invalid)

**Exemple :** [Surveiller dans un processus de longue durée](https://verbatra.kreitz-webdev.de/fr/docs/programmatic-api.md#surveiller-dans-un-processus-de-longue-durée)

`debounceMs` vaut 300 par défaut. `onRun` est appelé une fois par exécution avec un `WatchRunResult` : `{ status: "succeeded", summary }` ou `{ status: "failed", error: { code, message, causeCode?, hint? } }`, où `causeCode` nomme l'erreur codée que l'échec enveloppe et `hint` est l'étape suivante que donne `errorHint`. `onReady` est appelé une fois, quand les vérifications de démarrage passent et juste avant l'exécution initiale, pour que tu puisses annoncer la session avant la sortie de cette exécution. Si `onReady` lève une erreur, la surveillance est fermée et `watch` rejette avec cette erreur avant le début de toute exécution. Le SDK n'écrit aucun log ; `onRun` est la seule sortie. `concurrency`, `cache`, `onProgress`, `onLockWait` et `lockAcquireTimeoutMs` sont transmis à chaque exécution et se comportent exactement comme sur `translate`. `locales` restreint chaque exécution de la session à ce sous-ensemble et est validé une seule fois au démarrage, pas à chaque cycle.

Renvoie un `WatchController` avec une seule méthode, `stop()`, qui ferme la surveillance et attend l'exécution en cours. Chaque code de la ligne **Lève** est refusé au démarrage, avant que la surveillance n'existe, donc `watch` lui-même rejette au lieu de renvoyer un contrôleur. Deux d'entre eux pèsent plus sur une session que sur une seule exécution : un `concurrency` supérieur à 1 face à une config qui fixe `maxTokens` lève toujours `CONCURRENCY_BUDGET_CONFLICT`, car il n'existe pas de watch en dry run, et, depuis 0.12.0, un fournisseur impossible à construire, par exemple parce que sa variable de clé d'API manque, lève `PROVIDER_CONSTRUCTION_FAILED` une seule fois au lieu de faire échouer chaque exécution. Tout échec après le démarrage remonte via `onRun` et la surveillance continue.

### releaseHeldLocks [#releaseheldlocks]

<AvailableFrom version="0.12.0" />

Supprime tous les verrous d'écriture que détient le processus courant, pour un processus sur le
point de se terminer sans laisser finir ses exécutions en cours : la CLI l'appelle quand une
interruption arrête `translate` ou `import`, et quand une seconde interruption force l'arrêt de
`watch`. Les exécutions qui ont pris ces verrous perdent leur protection, appelle-le donc seulement
juste avant la fin du processus. Il ne prend aucun argument et ne rejette, avec une `AggregateError`
qui nomme les chemins des verrous, que si un verrou détenu n'a pas pu être supprimé, après avoir
tenté chaque verrou. Un verrou qu'une opération encore en cours prend, ou tente de prendre, pendant
son exécution est refusé avec `RUN_CANCELLED` et ne laisse aucun fichier ; il attend au plus trois
secondes une telle acquisition.

```ts title="Signature"
function releaseHeldLocks(): Promise<void>;
```

**Renvoie :** `void`

Un verrou resté en place malgré tout, parce qu'un processus a été tué net, n'en a pas besoin : une
exécution en attente sur la même machine voit que le processus enregistré n'existe plus et reprend
le verrou elle-même. Voir [le verrou d'écriture](https://verbatra.kreitz-webdev.de/fr/docs/the-lock-file.md#le-verrou-décriture).

## Pseudo-localisation [#pseudo-localisation]

### pseudolocalize [#pseudolocalize]

<AvailableFrom version="0.11.0" />

Construit une locale factice à partir des seules chaînes source, si bien que les troncatures de
mise en page et les chaînes qui n'ont jamais été extraites pour la traduction apparaissent avant
même qu'une clé d'API existe. Chaque valeur est accentuée, allongée d'environ un tiers de sa
longueur traduisible et entourée des marqueurs de délimitation `[` et `]`, tandis que les
placeholders restent intacts dans toutes les syntaxes que reconnaissent les adaptateurs, y compris
les branches `plural` et `select` d'ICU, les balises de balisage et les séquences d'échappement.
Il ne construit aucun fournisseur, ne lit aucune clé d'API et ne fait aucune requête réseau.

```ts title="Signature"
function pseudolocalize(
  input: PseudolocalizeInput,
  deps?: PseudolocalizeDeps,
): Promise<PseudolocalizeResult>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `cwd` | `string` | no | Directory the `files.pattern` is resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `mode` | `"accented" \| "bidi"` | no | The transform to apply. Defaults to `accented`. `bidi` wraps every word of translatable text in a right-to-left mark and override (`U+200F U+202E` before, `U+202C U+200F` after), so it renders right to left while the stored letters keep their order; placeholders, ICU syntax, markup, digits and punctuation stay outside the override, and nothing is accented or padded. |
| `locale` | `string` | no | The pseudolocale's BCP-47 code. Defaults to `en-XA` in `accented` mode and to `ar-XB` in `bidi` mode, a code that resolves to right-to-left text direction, so an application that derives its layout direction from the locale flips without further setup. In `bidi` mode an `i18next-json` plural keyed by suffix also gets every CLDR category the pseudolocale's language needs and the source lacks (for `ar-XB`, `_zero`, `_two`, `_few` and `_many`), filled from the source's `other` form, so no count falls back to another language. It must not be the source locale or any configured target locale, compared case-insensitively, so a pseudolocale can never stand in for a real translation. |
| `out` | `string` | no | Directory the pseudolocale file is written under, relative to `cwd`. Defaults to `.verbatra-local/pseudo`, which `verbatra init` already adds to `.gitignore`. The configured `files.pattern` is expanded inside it, so the file keeps the layout the application expects. It must name a directory inside `cwd`: an absolute path, one that climbs out with `..`, and `cwd` itself are all refused, as is a directory under which the expanded pattern would place the pseudolocale file beside a configured locale file, so a generated pseudolocale never lands outside the project or beside the real translations where nothing ignores it. The same holds after symbolic links are resolved, so a linked directory cannot carry the file outside `cwd` or into the directory of a configured locale file. |

**Renvoie :** `PseudolocalizeResult`

**Lève :** [`PSEUDO_OUTPUT_CONFLICT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#pseudo_output_conflict), [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#unknown_format), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_path_collision), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_invalid), [`TARGET_UNWRITABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#target_unwritable)

**Exemple :** [Construire une pseudo-locale](https://verbatra.kreitz-webdev.de/fr/docs/programmatic-api.md#construire-une-pseudo-locale)

Chaque valeur générée est tenue à la même barrière d'intégrité qu'une traduction de fournisseur doit
franchir. Une valeur qui ne la franchirait pas est copiée telle quelle depuis la source et nommée
dans `copied` plutôt qu'écrite sous une forme cassée, l'entrée reste donc présente et continue de
s'afficher.

<AvailableFrom version="0.12.0" />

`mode` choisit la transformation dans `PSEUDO_MODES` : `accented`, celle par défaut, ou `bidi`, qui
entoure plutôt chaque mot de texte traduisible d'une marque et d'un forçage de droite à gauche et
laisse dehors les placeholders, la syntaxe ICU, le balisage, les chiffres et la ponctuation, sans
rien accentuer. En mode `bidi`, `locale` vaut `ar-XB` par défaut, un code résolu de droite à
gauche ; voir [`verbatra pseudo`](https://verbatra.kreitz-webdev.de/fr/docs/cli/pseudo.md) pour la rencontre entre ses règles de pluriel
de l'arabe et les formes de pluriel de ta source.

`locale` vaut `en-XA` par défaut et `out`
`.verbatra-local/pseudo`, que `verbatra init` ajoute déjà à `.gitignore` ; le `files.pattern`
configuré y est développé, le fichier garde donc la disposition qu'attend l'application. Une
pseudo-locale qui nomme une locale configurée, ou qui se poserait sur un fichier de locale
configuré, est refusée avec `PSEUDO_OUTPUT_CONFLICT` avant que quoi que ce soit ne soit lu ou
écrit, elle ne peut donc ni écraser une vraie traduction ni en tenir lieu ; il en va de même d'un
`out` absolu, qui sort de `cwd` ou qui nomme `cwd` lui-même, comme `.`, et, quand `deps.fs` implémente `realpath` comme la valeur par défaut, d'un `out` qui y aboutit, dans le dossier d'un fichier de locale configuré ou sur un autre fichier dont le projet dépend, une fois les liens symboliques résolus. Comme le fichier vit en dehors de `files.pattern`, `translate`
ne dépense jamais pour lui et `check` et `diff` ne le signalent jamais comme désynchronisé.

Renvoie un `PseudolocalizeResult` : la `locale`, le `mode`, le `path` absolu, combien d'`entries` ont été
traitées, combien ont été `transformed`, les clés qui ont été `copied`, et si quelque chose a été
`written`. La transformation est déterministe, une seconde exécution sur une source inchangée ne
réécrit donc rien et signale `written` à false. Pour `xliff` et `apple-xcstrings`, dont l'écriture
se contente de retoucher un document qui existe déjà, la sortie est recopiée depuis la source à
chaque écriture, si bien qu'une clé ajoutée à la source après la première exécution parvient quand
même à la pseudo-locale, et un XLIFF copié voit son `target-language` réécrit vers la
pseudo-locale.

## Catalogues typés [#catalogues-typés]

### generateTypes [#generatetypes]

<AvailableFrom version="0.11.0" />

Déclare le catalogue source d'un projet en TypeScript : une union de toutes les clés qu'il contient
et, par clé, les arguments que son message interpole. Type une fonction de traduction sur le
résultat et une clé mal orthographiée ou un argument d'interpolation manquant devient une erreur de
compilation au lieu d'un échec de recherche à l'exécution. Il ne dépense rien : aucun fournisseur
n'est construit, aucune variable d'environnement contenant une clé d'API n'est lue et aucune requête
réseau n'est faite.

```ts title="Signature"
function generateTypes(
  input: GenerateTypesInput,
  deps?: GenerateTypesDeps,
): Promise<GenerateTypesResult>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `cwd` | `string` | no | Directory the `files.pattern` and the output path are resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `out` | `string` | no | Where to write the declaration, relative to `cwd`. Defaults to DEFAULT_TYPES_PATH. Refused with `TYPES_OUTPUT_CONFLICT`, before anything is read or written, when it names no file, is absolute, climbs out of `cwd`, does not end in `.ts`, `.mts` or `.cts`, or names a configured locale file, the lock file, the provenance file, the translation-memory cache, a file verbatra searches for its configuration, the GenerateTypesInput.configPath file, or the GenerateTypesInput.glossaryPath file. When the file-system port implements `realpath`, the same checks run again after symbolic links are resolved. Names are compared case-insensitively. A generating run also refuses to replace an existing file there unless that file begins with the header line verbatra writes, after any leading byte order mark and blank lines, and refuses one too large to verify. |
| `configPath` | `string` | no | The configuration file `config` was loaded from, absolute or relative to `cwd`. It is refused as the output path even when its name is not one verbatra searches for. |
| `glossaryPath` | `string` | no | The glossary file the config names, absolute or relative to `cwd`, normally the `path` of a file-backed LoadedConfig.glossary. It is refused as the output path. |
| `check` | `boolean` | no | Compare instead of writing. The run reports whether the file on disk matches what a fresh generation would produce and leaves every file untouched. |

**Renvoie :** `GenerateTypesResult`

**Lève :** [`TYPES_OUTPUT_CONFLICT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#types_output_conflict), [`TYPES_UNWRITABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#types_unwritable), [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#unknown_format), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_path_collision), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#source_invalid)

**Exemple :** [Générer un catalogue typé](https://verbatra.kreitz-webdev.de/fr/docs/programmatic-api.md#générer-un-catalogue-typé)

Un fichier est lu (le catalogue de la locale source) et un fichier est écrit (la déclaration) ; un
fichier de locale cible n'est jamais touché. Les clés sont exactement ce que l'adaptateur de format
avait déjà produit, dans l'ordre du document, si bien que deux exécutions sur un catalogue inchangé
écrivent des octets identiques. Les arguments viennent des jetons de placeholder que l'adaptateur a
extraits, sauf dans les formats de messages ICU (`next-intl-json` et `arb`), où chaque message est
lu avec le même parseur ICU que celui de l'adaptateur. Chaque clé est émise comme un littéral de
chaîne entre guillemets : une clé portant un point, un mot réservé, un chiffre en tête, un
guillemet, ou même la clé vide, est donc déclarée telle quelle plutôt qu'abandonnée ou redécoupée,
et une clé que l'adaptateur a signalée dans `excludedLeafPaths` n'est pas déclarée du tout.

Ce qu'il refuse d'affirmer compte autant que ce qu'il déclare. Un message sans placeholder reçoit
une forme qui fait de tout argument passé une erreur de type ; un message dont les placeholders
nomment leurs arguments reçoit une forme d'objet ; un message aux placeholders numérotés ou anonymes
reçoit un tuple readonly. Un argument ICU que seules certaines branches `select` ou `plural`
utilisent est déclaré comme membre optionnel. Les types d'arguments viennent uniquement de ce que le
catalogue enregistre : `number` pour un argument ICU `number`, `plural` ou `selectordinal` et pour
un formateur ou une conversion numériques, `Date | number` pour un argument ICU `date` ou `time` et
un formateur i18next `datetime`, `string` pour un argument ICU `select` et une conversion printf de
chaîne, et un alias de `string | number` partout ailleurs, jamais un `any` permissif. Une
interpolation i18next non échappée (`{{- name}}`) est déclarée sous le nom qui suit son préfixe. Un
message que l'adaptateur a signalé comme invalide, un message qui semble à la fois nommer et
numéroter ses arguments, et un message dont l'index d'un placeholder est hors limites sont déclarés
avec leurs arguments signalés dans `unresolved` plutôt que déclarés en silence comme n'en prenant
aucun. Les clés plurielles sœurs ne sont jamais fusionnées : chacune est déclarée à part, et celles
que l'adaptateur a marquées au pluriel sont listées.

`out` vaut par défaut
`DEFAULT_TYPES_PATH` (`verbatra-types.d.ts`). Avant toute lecture ou écriture,
`TYPES_OUTPUT_CONFLICT` refuse un `out` qui ne nomme aucun fichier (y compris un `out` terminé par
un séparateur de chemin), est absolu, sort de `cwd` avec `..`, nomme `cwd` lui-même (`.`) ou ne se termine
pas par `.ts`, `.mts` ou `.cts`, ainsi qu'un `out` qui nomme un fichier de locale configuré, le fichier de verrouillage,
le cache de mémoire de traduction, un fichier où verbatra cherche sa configuration, `configPath`, le
fichier de configuration d'où `config` a été chargée, ou `glossaryPath`, le fichier de glossaire
qu'elle désigne ; les noms sont comparés sans tenir compte de la casse, et quand `deps.fs`
implémente `realpath`, comme le fait la valeur par défaut, les mêmes vérifications sont refaites sur
l'endroit où le chemin aboutit une fois les liens symboliques résolus. Une exécution qui génère
refuse aussi, avec le même code, de remplacer un fichier existant qui ne commence pas par la ligne
d'en-tête qu'écrit verbatra, et laisse ce fichier intact. La liste complète se trouve sur la page de
[`verbatra types`](https://verbatra.kreitz-webdev.de/fr/docs/cli/types.md). Avec `check`, rien n'est écrit du tout, rien n'est refusé à
cause de son contenu, et l'exécution signale seulement si le fichier commité correspond toujours, ce
qui est exactement la forme qu'attend un garde-fou de CI.

Renvoie un `GenerateTypesResult` : le `path` absolu, le `sourcePath` dont il a été construit,
combien de `keys` ont été déclarées et combien d'entre elles prennent au moins un argument que
verbatra a pu déterminer (`withArguments`, qui ne compte jamais une clé de `unresolved`), les clés
`unresolved` ainsi que les `excluded` et `plural`, si quelque chose a été `written`, si le fichier
sur disque était `stale` au démarrage de l'exécution, s'il manquait tout à fait (`missing`, un fichier
manquant est aussi `stale`), et s'il s'agissait d'une exécution `check`.
