---
title: "Sûreté de la traduction"
description: "Le modèle de sûreté : chaînes non fiables, barrière d'intégrité, signalements de relecture, budget de tokens, et erreurs qui ne fuient jamais."
type: "concept"
---
# Sûreté de la traduction

Le modèle de sûreté : chaînes non fiables, barrière d'intégrité, signalements de relecture, budget de tokens, et erreurs qui ne fuient jamais.

verbatra ne fait confiance ni aux chaînes qu'il traduit ni à ce qu'un fournisseur renvoie.

| Couche | Protège contre | En cas d'échec |
| --- | --- | --- |
| Frontière contre l'injection de prompt | une chaîne qui ressemble à une instruction | rien à faire échouer : les chaînes ne sont jamais que des données |
| Barrière d'intégrité | placeholders, ICU ou balisage cassés, valeurs vides ou dégénérées | la clé est retenue et retentée à l'exécution suivante |
| Signalements de relecture | une valeur valide mais suspecte | la clé est écrite et mise en file pour une personne |
| Budget de tokens | une dépense au-delà d'un plafond que tu fixes | le reste de l'exécution est retenu, ou signalé |
| Erreurs structurées | une clé ou un en-tête qui fuit dans un message | un code stable avec un message fixe |

## Chaînes non fiables et frontière contre l'injection de prompt [#chaînes-non-fiables-et-frontière-contre-linjection-de-prompt]

Une chaîne traduisible peut contenir un texte qui ressemble à une instruction (« ignore your
instructions »), donc verbatra traite chaque chaîne comme une entrée non fiable. Les règles système
envoyées à un fournisseur LLM sont des constantes fixées à la compilation. Tout ce qui varie (les
entrées, ton glossaire et ton ton, les noms de langue, les catégories cibles d'un pluriel) voyage
uniquement dans la charge JSON du tour utilisateur, jamais dans le canal d'instructions. La réponse
doit correspondre à un schéma fixe ; une réponse avec une clé jamais demandée fait échouer tout son
sous-lot.

### Noms de langue, d'écriture et de région [#noms-de-langue-décriture-et-de-région]

<AvailableFrom version="0.12.0" />

Un code de locale seul ne suffit pas toujours : `sr-Latn` revient souvent en cyrillique, et `pt-BR`
et `pt-PT` se confondent. Un fournisseur LLM reçoit donc aussi le nom anglais, l'écriture et la
région de chaque langue, tirés de Node.js pour la locale de ta configuration, même quand `localeMap`
envoie un autre code. Ils voyagent comme des données, une règle système fixe demande au modèle
d'écrire dans l'écriture et la variante nommées, et ils ne font pas partie de l'empreinte du
[cache](https://verbatra.kreitz-webdev.de/fr/docs/the-cache.md). Un code que Node.js ne sait pas
nommer, comme le code à usage privé `qaa`, est envoyé sans nom.

## La barrière d'intégrité [#la-barrière-dintégrité]

Une traduction valide selon le schéma peut quand même être cassée, donc une barrière décide à
partir de la valeur candidate elle-même s'il faut l'accepter ; le rapport du fournisseur n'est
jamais pris pour argent comptant. La même barrière s'applique à chaque chemin d'écriture : une
réponse de fournisseur, un succès du cache, une ligne importée d'un classeur, et une modification
tapée dans Studio. Une valeur partagée par plusieurs clés au même texte source est vérifiée clé par
clé, contre la source propre à chaque clé.

| Vérification | Une candidate est refusée quand |
| --- | --- |
| Placeholders | ses placeholders diffèrent de ceux de la source, comparés comme un multiensemble (le nombre compte, l'ordre non). Ce qui compte comme placeholder est défini par [format](https://verbatra.kreitz-webdev.de/fr/docs/formats.md). |
| ICU | pour next-intl et ARB, elle ne s'analyse plus comme un message ICU, ou ses branches plurielles ne conviennent pas à la langue cible (voir plus bas). La comparaison tient compte des branches, donc un placeholder inventé dans une seule branche plurielle est repéré. |
| Jetons inventés | pour i18next, ngx-translate et YAML, elle ajoute un jeton de forme `{name}` que la source n'a jamais eu. En supprimer un est permis, car les accolades simples y sont du texte littéral. |
| Balisage en ligne | ses balises HTML ou XML diffèrent de celles de la source, ou sont déséquilibrées (voir plus bas). |
| Dégénérescence | c'est une boucle de répétition, ou sa longueur s'est emballée par rapport à la source. |
| Vide | elle est vide ou ne contient que des espaces pour une source non vide. Vider une traduction est un acte délibéré : c'est le rôle du marqueur `[[CLEAR]]` du classeur ([Confier avec Excel ou CSV](https://verbatra.kreitz-webdev.de/fr/docs/manual-translation.md)). |

Une candidate qui enfreint plusieurs vérifications est refusée avec un seul motif, le premier qui
s'applique dans cet ordre : `empty`, `icu` (ne s'analyse pas), `placeholder`, `markup`, `icu`
(branches), `degenerate`. Chaque motif, et les détails que verbatra affiche avec, figure sous
[Motifs de refus d'intégrité](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#integrity-refusal-reasons).

Ce que la barrière garantit : une valeur refusée n'est jamais écrite. Elle apparaît dans le résumé
de l'exécution comme incohérence d'intégrité, garde son hash précédent dans
[le fichier de verrouillage](https://verbatra.kreitz-webdev.de/fr/docs/the-lock-file.md), et est retentée à l'exécution suivante. Une clé
qui n'a reçu aucune traduction (l'appel fournisseur a échoué, ou la clé manquait encore après une
requête de réparation) est signalée comme échec du fournisseur, et est retentée de la même façon.
Côté source, une clé dont la propre valeur est un ICU invalide est mise de côté avant la traduction.

Ce qu'elle ne garantit pas : que la traduction soit juste. Elle prouve la structure, pas le sens.

### Branches plurielles par langue cible [#branches-plurielles-par-langue-cible]

<AvailableFrom version="0.12.0" />

Un pluriel ICU a une branche par catégorie plurielle CLDR de sa langue
([exemples](https://verbatra.kreitz-webdev.de/fr/docs/language-support.md#pluriels)). Pour next-intl et ARB, verbatra lit les catégories
de la langue cible dans les données CLDR intégrées à Node.js :

- Un fournisseur LLM reçoit la demande d'exactement ces branches (cardinales pour `plural`,
  ordinales pour `selectordinal`). Les catégories voyagent comme des données, donc la frontière
  contre l'injection ne change pas.
- La barrière refuse un `plural` ou un `selectordinal` à qui manque une branche requise ou qui en
  garde une que la langue n'a pas, sur chaque chemin d'écriture, et nomme chaque branche fautive.
- Les branches à valeur exacte comme `=0` doivent toutes survivre, et une traduction peut en
  ajouter. Les branches `select` sont les clés de ton code, donc une traduction garde exactement
  celles de la source.
- Pour une locale dont Node.js n'a pas les règles de pluriel, seule `other` est requise.

Une valeur écrite avant cette vérification, comme un pluriel français sans `many`, reste jusqu'à ce
que sa source change ; [`verbatra check --qa`](https://verbatra.kreitz-webdev.de/fr/docs/cli/check.md#contrôle-qualité) la trouve dès
maintenant.

### Parité du balisage en ligne [#parité-du-balisage-en-ligne]

<AvailableFrom version="0.11.0" />

Une balise en ligne perdue ou cassée (un `<b>` dans un bloc `Trans` d'i18next, un `&lt;b&gt;`
échappé dans un `<string>` Android, un `<a href>` dans gettext) casse le rendu, donc la barrière
compare les noms de balise et d'attribut comme un multiensemble :

- **Refusé** : une balise supprimée, inventée ou renommée ; un ensemble de noms d'attribut modifié
  (ajout de `dir` compris) ; un balisage déséquilibré ou mal imbriqué ; deux balises fusionnées en
  une.
- **Accepté** : les mêmes balises dans un autre ordre ; une valeur d'attribut traduite comme `title`
  ou `alt` ; `<br>` écrit `<br/>`.
- **Valeurs protégées** : un attribut d'URL doit garder son schéma et son hôte (`/docs` peut
  devenir `/de/docs`, jamais `https://evil.example/docs`), une URL `javascript:` est refusée, et des
  valeurs comme `style`, les gestionnaires d'événements ou un `<meta content>` doivent rester
  exactement comme dans la source.
- **Non traduit** : le contenu de `script`, `style` et d'éléments semblables doit revenir inchangé.
  Échappe une telle balise dans la prose (`&lt;script&gt;`) pour traduire le texte autour.

Un balisage inventé dans une chaîne qui n'en avait pas est refusé aussi, tandis qu'un simple mot
entre chevrons comme `<Enter>` est lu comme du texte. Les balises que le format signale déjà comme
placeholders sont laissées à la vérification des placeholders. Commentaires, texte brut et sources
mal formées : voir [`markup`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#markup).

## Signalements de relecture [#signalements-de-relecture]

Une seconde couche, consultative, signale les résultats suspects à une personne. Un signalement ne
retient jamais une clé : la valeur est écrite, verrouillée, et mise dans la file de relecture.

| Motif | Signale une traduction qui |
| --- | --- |
| [`LENGTH_RATIO_OUTLIER`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#length_ratio_outlier) | est bien plus courte ou plus longue que sa source, pondérée selon l'écriture |
| [`MAX_LENGTH_EXCEEDED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#max_length_exceeded) | est plus longue que le budget [`maxLength`](https://verbatra.kreitz-webdev.de/fr/docs/config-file.md#maxlength) de la clé <AvailableFrom version="0.11.0" /> |
| [`EQUALS_SOURCE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#equals_source) | est identique à son texte source |
| [`GLOSSARY_TERM_MISSED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#glossary_term_missed) | manque la traduction d'un terme du glossaire, ou altère un terme à ne pas traduire |
| [`GLOSSARY_FORBIDDEN_TERM`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#glossary_forbidden_term) | utilise une forme que le glossaire interdit <AvailableFrom version="0.12.0" /> |
| [`INTEGRITY_REORDERED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#integrity_reordered) | garde chaque placeholder mais dans un autre ordre |
| [`PROVIDER_DEGRADED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provider_degraded) | vient d'un lot que le fournisseur a dégradé, comme une formalité abandonnée |
| [`FUZZY_CACHE_REUSE`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#fuzzy_cache_reuse) | a été [réutilisée depuis une source proche et modifiée](https://verbatra.kreitz-webdev.de/fr/docs/the-cache.md#réutilisation-approximative) <AvailableFrom version="0.11.0" /> |
| [`FOREIGN_PLACEHOLDER_CHANGED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#foreign_placeholder_changed) | perd ou modifie un jeton en forme de placeholder que son [format](https://verbatra.kreitz-webdev.de/fr/docs/formats.md) n'interpole pas, comme `{name}` dans i18next <AvailableFrom version="0.12.0" /> |
| [`BIDI_CONTROLS_CHANGED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#bidi_controls_changed) | laisse un contrôle de direction ouvert, ou ajoute un forçage qui inverse le texte <AvailableFrom version="0.12.0" /> |

DeepL, Google et LibreTranslate reçoivent ce jeton masqué et retiennent une valeur qu'ils ne peuvent
ni masquer ni restaurer ([`PLACEHOLDER_UNSUPPORTED`](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#placeholder_unsupported)) ; le signalement couvre les LLM et les personnes.

Les succès du cache et les valeurs partagées sont signalés comme les traductions fraîches. Les clés
signalées apparaissent sous `needsReview` dans le résumé de l'exécution, dans les colonnes de
relecture du classeur, et sur la [page Review de Studio](https://verbatra.kreitz-webdev.de/fr/docs/review-in-studio.md), jusqu'à ce qu'une
personne approuve, rejette ou réécrive la valeur
([Décisions de relecture](https://verbatra.kreitz-webdev.de/fr/docs/the-lock-file.md#décisions-de-relecture)).

## Le budget de tokens [#le-budget-de-tokens]

`maxTokens` compte les tokens d'une exécution sur tous les appels et toutes les locales ;
`budgetBehavior: "stop"` retient le reste de l'exécution dès que le plafond serait dépassé, à
retenter à l'exécution suivante ([règles](https://verbatra.kreitz-webdev.de/fr/docs/config-file.md#maxtokens-et-budgetbehavior)).

Ce que le budget garantit : le travail fait avant le plafond reste écrit et verrouillé, et rien
n'est laissé à moitié écrit. Ce qu'il ne garantit pas : une requête en vol peut coûter plus que
prévu, le plafond borne une exécution (pas une session `watch`), et les retraductions depuis Studio
ou par un agent ne sont pas couvertes.

## Les erreurs ne fuient jamais [#les-erreurs-ne-fuient-jamais]

Quand un appel fournisseur échoue, l'erreur brute du SDK (qui peut contenir des en-têtes de requête
ou des identifiants) est jetée, jamais journalisée ni relancée. verbatra lève à la place une erreur
structurée avec un [code](https://verbatra.kreitz-webdev.de/fr/docs/error-codes.md#provider-error-codes) stable et un message fixe sans
secret. Le masquage des clés est sur [Traitement des données](https://verbatra.kreitz-webdev.de/fr/docs/data-handling.md#clés-dapi).

## Où tu vois tout ça [#où-tu-vois-tout-ça]

Tout ce qui précède est une donnée du [résumé de l'exécution](https://verbatra.kreitz-webdev.de/fr/docs/sdk/run-summary.md), par locale,
et l'échec d'une locale n'arrête jamais les autres.

### Valeurs déjà versionnées [#valeurs-déjà-versionnées]

<AvailableFrom version="0.12.0" />

[`verbatra check --qa`](https://verbatra.kreitz-webdev.de/fr/docs/cli/check.md#contrôle-qualité) applique la barrière et les signalements
de relecture aux valeurs commitées, sans appel fournisseur.

## Voir aussi [#voir-aussi]

- [Comment se déroule une exécution](https://verbatra.kreitz-webdev.de/fr/docs/how-it-works.md) : où se place chaque vérification dans le pipeline.
- [Traitement des données et confidentialité](https://verbatra.kreitz-webdev.de/fr/docs/data-handling.md) : ce qui quitte ta machine.
