---
title: "Le fichier de verrouillage et la provenance"
description: "Ce que verbatra.lock.json et verbatra.provenance.json enregistrent, comment la dérive est détectée et pourquoi tu commites les deux fichiers."
type: "concept"
---
# Le fichier de verrouillage et la provenance

Ce que verbatra.lock.json et verbatra.provenance.json enregistrent, comment la dérive est détectée et pourquoi tu commites les deux fichiers.

`verbatra.lock.json` est la référence avec laquelle chaque exécution compare, pour qu'une exécution
saute ce qui est à jour et retraduise ce qui a dérivé. À côté,
[`verbatra.provenance.json`](#la-provenance-de-chaque-valeur) enregistre qui ou quoi a écrit chaque
valeur.

## Ce qu'il enregistre [#ce-quil-enregistre]

Pour chaque locale cible, un hash par clé traduite de l'entrée source derrière la traduction
actuelle, plus un champ `version` : aucune traduction, aucun secret. Le hash couvre la valeur source
avec sa description, son sens, son indicateur de pluriel et ses placeholders, donc une description
modifiée rend aussi la clé obsolète. Il normalise l'Unicode en NFC et les fins de ligne en LF, donc
réenregistrer un fichier source en CRLF ne change rien.

## Comment la dérive est détectée [#comment-la-dérive-est-détectée]

Une clé source que la cible n'a pas est manquante. Pour une clé présente, le hash source actuel est
comparé à celui enregistré : une différence signifie que la source a changé et la clé est
retraduite ; une correspondance signifie qu'elle n'est jamais envoyée, donc une seconde exécution
sans modification de la source ne coûte rien. Le pipeline complet est sur
[Comment se déroule une exécution](https://verbatra.kreitz-webdev.de/fr/docs/how-it-works.md).

### Clés protégées [#clés-protégées]

<AvailableFrom version="0.12.0" />

L'exception est une clé modifiée dont une personne a écrit ou importé la valeur : par défaut elle
est [protégée](https://verbatra.kreitz-webdev.de/fr/docs/protecting-human-translations.md) et reste obsolète au lieu d'être retraduite.

## Adopter un projet existant [#adopter-un-projet-existant]

Des fichiers de locale qui contiennent déjà des traductions relues ne sont pas retraduits. À la
première exécution il n'y a pas de fichier de verrouillage, donc rien ne peut être périmé : une clé
que la cible possède garde sa valeur, seules les clés manquantes sont traduites, et l'exécution
enregistre chaque hash source comme référence, sans coût fournisseur.

L'adoption se décide par la présence d'une clé, jamais par sa valeur, ce qui a deux conséquences :

- **Une valeur vide ou non traduite compte comme traduite.** Supprime la clé (la vider ne suffit
  pas) et l'exécution suivante la traduit.
- **Une traduction déjà périmée est enregistrée comme à jour.** Corrige-la ou supprime-la avant la
  première exécution.

La même règle garde les formes plurielles écrites à la main, donc `generatePlurals` est sans risque
pendant l'adoption. Pour voir tout cela à l'avance, lance [`verbatra diff`](https://verbatra.kreitz-webdev.de/fr/docs/cli/diff.md) ou
`verbatra translate --dry-run`.

## Comment il est mis à jour [#comment-il-est-mis-à-jour]

- Une exécution complète (`translate`, `watch`, ou un import) remplace les entrées d'une locale par
  le résultat de l'exécution.
- Une action sur une seule clé, comme une retraduction depuis Studio, ne fusionne que l'entrée de
  cette clé.

Dans les deux cas, une clé retenue pendant cette exécution (une vérification d'intégrité ou un appel
fournisseur échoué, une source ICU invalide) garde son hash précédent, donc l'exécution suivante la
retente. Les clés orphelines n'ont pas d'entrée, et des clés triées gardent les diffs petits.

## Le verrou d'écriture [#le-verrou-décriture]

Deux exécutions qui touchent la même locale en même temps pourraient toutes deux comparer avec une
référence périmée et payer deux fois, donc chaque écriture prend un verrou inter-processus propre à
cette locale sous `.verbatra-local/`. Un second écrivain attend, puis compare avec une référence qui
contient le résultat du premier. Des locales différentes ne se bloquent jamais.

Ce que le verrou garantit :

- **Un délai dépassé ne coûte rien.** `--lock-timeout` ne borne que l'attente avant tout appel
  fournisseur, donc une locale qui abandonne n'a rien dépensé ni rien écrit ; enregistrer un fichier
  déjà écrit attend les dix minutes par défaut.
- **Les verrous abandonnés ne te bloquent pas.** Un verrou dont le processus a disparu de cette
  machine est récupéré tout de suite, et un verrou non rafraîchi depuis 30 secondes (les détenteurs
  rafraîchissent toutes les 10) compte comme abandonné.
- **Une interruption libère les verrous.** Ctrl-C ou SIGTERM pendant `translate` ou `import`, et la
  seconde interruption qui force l'arrêt de `watch`, libèrent tous les verrous avant la fin du
  processus.
- **Un verrou perdu arrête l'écriture.** Chaque verrou porte un jeton aléatoire, vérifié avant
  chaque écriture ; quand une autre exécution a repris le verrou, l'écriture s'arrête
  avec [`LOCK_CONTENDED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#lock_contended) et rien n'est écrit.

Ce qu'il ne couvre pas :

- **Un verrou d'une autre machine** (un lecteur réseau partagé) ou d'un verbatra antérieur à 0.12.0
  n'est jamais récupéré automatiquement ; [Dépannage](https://verbatra.kreitz-webdev.de/fr/docs/troubleshooting.md) donne les étapes pour
  le retirer.
- **Une longue pause entre vérification et écriture.** Une exécution mise en pause juste après la
  vérification du jeton (une machine en veille, un processus arrêté) peut encore écrire une fois à
  sa reprise.
- **Des hôtes qui partagent un nom.** Hors Linux, le nom d'hôte est la seule identité de machine,
  donc deux conteneurs au même nom d'hôte qui partagent `.verbatra-local/` peuvent prendre le verrou
  vivant de l'autre pour un verrou abandonné. Donne à chacun son propre nom d'hôte
  ou sa propre copie de travail.

## Un code de locale réécrit [#un-code-de-locale-réécrit]

<AvailableFrom version="0.12.0" />

Le fichier de verrouillage, le cache et le fichier de provenance rangent leur état sous le code de
locale de ta configuration. Quand tu en réécris un, par exemple `pt_BR` en `pt-BR`, la prochaine
exécution de `translate` ou `watch` reporte l'ancien état une fois et signale
[`LOCALE_STATE_CARRIED_OVER`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_state_carried_over). Une modification de la
source faite avant le renommage est toujours retraduite, et les traductions en cache sont toujours
réutilisées.

Le report n'a lieu que sans ambiguïté : `pt-BR` n'a pas d'état à lui, et le fichier
contient un état sous exactement une graphie avec tiret bas (ou sa graphie gettext, comme
`sr@latin` pour `sr-Latn`), comparée sans tenir compte de la casse. Un état que `pt-BR` a déjà n'est
jamais écrasé. Si le report ne peut pas être écrit, cette locale ne tourne pas et échoue avec
[`LOCALE_STATE_NOT_CARRIED_OVER`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#locale_state_not_carried_over), pour que
l'exécution suivante réessaie ; les autres locales tournent normalement.

D'ici là, chaque lecture traite l'ancien état comme celui de `pt-BR` sans écrire, donc une clé périmée est signalée comme périmée. Une écriture sur une seule clé
(une modification, une retraduction, une décision de relecture) et `verbatra import` déplacent
d'abord l'état, de la même façon. Le contrôle `locale-state` de
[`verbatra doctor`](https://verbatra.kreitz-webdev.de/fr/docs/cli/doctor.md) nomme tout état resté en arrière.

## Absent ou corrompu [#absent-ou-corrompu]

Un fichier de verrouillage absent est une [première exécution](#adopter-un-projet-existant), pas une
erreur. Un fichier illisible, mal structuré, trop gros ou dans une version non prise
en charge fait échouer l'exécution avec [`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#lock_file_invalid)
au lieu d'être écrasé, pour que tu puisses le restaurer plutôt que perdre la référence.

## La provenance de chaque valeur [#la-provenance-de-chaque-valeur]

<AvailableFrom version="0.12.0" />

`verbatra.provenance.json` enregistre quel chemin d'écriture a produit chaque valeur présente dans
le fichier de locale, et si quelqu'un l'a relue. Un verbatra plus ancien, par exemple épinglé dans
la CI, l'ignore.

| Origine | Écrite par |
| --- | --- |
| `machine` | une réponse de fournisseur dans `translate`, `watch` ou une retraduction d'une seule clé, avec l'`id` du fournisseur et, quand il est connu, le modèle |
| `memory` | un succès exact du cache, y compris chaque valeur que remplit une exécution sans traduction automatique (fournisseur `none`) |
| `fuzzy` | un succès du [cache approximatif](https://verbatra.kreitz-webdev.de/fr/docs/the-cache.md#réutilisation-approximative) |
| `human` | la modification d'une personne via `editEntry` du SDK, comme la fait la boîte d'édition de Studio |
| `agent` | la modification d'un agent IA via `editEntry` avec `actor: "agent"` |
| `import` | une ligne acceptée par `verbatra import` |
| `unknown` | une décision de relecture sur une valeur sans enregistrement, ou une origine que cette version ne connaît pas |

Deux autres sont déduites à la lecture : `unrecorded` est une valeur sans enregistrement, comme
chaque clé après une mise à jour ; `external` ne correspond plus au hash de son enregistrement parce
que quelque chose hors de verbatra l'a changée, comme la pull request d'un traducteur, un verbatra plus ancien ou une fusion.
Les champs
que renvoie chaque lecture sont dans la
[référence du SDK](https://verbatra.kreitz-webdev.de/fr/docs/sdk/inspect.md#loadprovenance).

Ce que le fichier garantit :

- **Des diffs stables.** Aucun texte traduit ni horodatage, un enregistrement trié par ligne, donc
  une exécution qui ne change rien laisse le fichier inchangé. En cas de conflit de fusion, prends le
  côté qui correspond au fichier de locale que tu gardes : un enregistrement qui ne correspond pas se
  lit comme `external`, ce qui protège la valeur d'une nouvelle traduction.
- **Des enregistrements neufs pour les nouvelles valeurs.** Une écriture qui change une valeur
  remplace son enregistrement par un nouveau, non relu ; une écriture qui laisse valeur et source
  inchangées le garde.
- **Pas d'écrasement silencieux.** Un fichier corrompu arrête chaque écriture avec
  [`PROVENANCE_FILE_INVALID`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provenance_file_invalid) avant qu'un fichier de
  locale ne change ; les rapports omettent plutôt leurs champs de provenance. Un fichier écrit par
  un verbatra plus récent est laissé intact, et un fichier trop gros pour être relu n'est pas écrit
  ([`PROVENANCE_FILE_TOO_LARGE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provenance_file_too_large)).

Il n'est pas infalsifiable ; pour en faire un rapport, voir
[Consigner les preuves de traduction automatique](https://verbatra.kreitz-webdev.de/fr/docs/provenance-evidence.md).

### Décisions de relecture [#décisions-de-relecture]

<AvailableFrom version="0.12.0" />

Un enregistrement peut porter une décision de relecture, `approved` ou `rejected`, avec un nom de
relecteur `reviewer` facultatif. La [page Review de Studio](https://verbatra.kreitz-webdev.de/fr/docs/review-in-studio.md), les
[fonctions de revue du SDK](https://verbatra.kreitz-webdev.de/fr/docs/sdk/review.md) et les [outils MCP de relecture](https://verbatra.kreitz-webdev.de/fr/docs/cli/mcp.md) les
écrivent ; les outils MCP relaient la décision d'une personne et exigent son nom. Une décision
s'applique à la valeur exacte que le relecteur a vue et est refusée si elle a changé.

- **Une approbation** ne change que le fichier de provenance, et se relit comme non relue dès que le
  texte source change.
- **Un rejet** retire la valeur et son entrée de verrouillage, donc la clé se lit comme manquante
  jusqu'à la prochaine exécution de `translate` ou jusqu'à ce qu'une personne écrive une nouvelle
  valeur. L'enregistrement garde un hash du texte retiré et l'entrée du cache est supprimée, pour qu'une exécution ne remette pas le même texte. XLIFF ne
  peut pas retirer une seule traduction, donc un rejet y est refusé avec
  [`REVIEW_REJECT_UNSUPPORTED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#review_reject_unsupported).

Seules les valeurs de classe machine entrent dans la file de relecture et dans la porte `--require-reviewed`. Les comptes `byReviewState` de `check` et de `lock.state` couvrent chaque valeur selon sa décision enregistrée, quelle que soit son origine : une valeur écrite ou importée par une personne sans décision y compte comme `unreviewed` sans figurer dans la file ; lis-les avec `byOrigin`.

Les décisions vivent dans ce fichier commité, donc la file de relecture et
[`verbatra check --require-reviewed`](https://verbatra.kreitz-webdev.de/fr/docs/cli/check.md#exiger-des-traductions-relues) voient le même
état partout, et le nom `reviewer` est public ; verbatra ne le remplit jamais.

## Commite-le [#commite-le]

Commite `verbatra.lock.json` et `verbatra.provenance.json` avec tes fichiers de locale, et ne les
modifie jamais à la main : ils sont la référence avec laquelle ton équipe et ta CI comparent, et ce que restaure un [retour arrière](https://verbatra.kreitz-webdev.de/fr/docs/recovery-and-rollback.md).
