Référence SDK

Chaque point d'entrée de @verbatra/sdk, groupé par tâche, avec le modèle d'erreur et l'anatomie du RunSummary.

Page traduite automatiquement

Cette page a été traduite automatiquement, elle peut donc contenir des erreurs ou sonner un peu bizarrement. La version anglaise est la référence. Lire l'original en anglais.

@verbatra/sdk est le moteur sur lequel tourne la commande verbatra. La CLI est une surcouche légère, donc tout ce que la ligne de commande fait, tu peux le faire en code. Cette page catalogue toute la surface publique, groupée par la tâche de chaque point d'entrée. Pour des exemples de bout en bout, voir Recettes SDK.

Installation

npm install --save-dev @verbatra/sdk
# pnpm
pnpm add -D @verbatra/sdk
# yarn
yarn add -D @verbatra/sdk

Requiert Node.js >=22.14.0.

La ligne pnpm installe correctement mais sort en 1 avec ERR_PNPM_IGNORED_BUILDS : pnpm bloque les scripts d'installation du SDK Gemini embarqué et de son protobufjs, et laisse un pnpm-workspace.yaml sans réponse qui fait échouer de la même façon toutes les commandes pnpm suivantes du projet. Lance pnpm approve-builds une fois sans approuver aucune des deux entrées, ou consulte le Dépannage pour la solution non interactive. Il n'y a pas de raccourci npx ici comme pour la CLI, puisque tu importes une bibliothèque au lieu de lancer un binaire.

Clés d'API et environnement

Le SDK ne lit, ne détient ni n'accepte jamais de clé d'API. Le fournisseur lit sa clé depuis l'environnement (par exemple ANTHROPIC_API_KEY) au moment de sa construction. Contrairement à la CLI, le SDK ne charge pas les fichiers .env : dans ton propre script, définis la variable toi-même, par exemple avec node --env-file=.env script.js.

Chaque point d'entrée prend un objet d'entrée dont le premier champ est la config validée (issue de loadConfig), sauf mention contraire. La plupart acceptent aussi un second argument optionnel deps qui injecte un registre, un constructeur de fournisseur ou un système de fichiers ; tu peux l'ignorer en usage normal. Voir Le point d'injection de dépendances pour ce que deps.fs atteint.

Lancer des traductions

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 vérifications 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.

Entrée : { config, cwd?, locales?, dryRun?, prune?, generatePlurals?, concurrency?, cache?, onProgress?, onLockWait?, lockAcquireTimeoutMs? }.

  • locales restreint l'exécution à un sous-ensemble des locales cibles configurées, exactement comme sur check et diff. Une locale non configurée lève UNKNOWN_LOCALE avant toute lecture et toute dépense. Omets-le pour couvrir toutes les locales cibles.
  • dryRun lit, compare et rapporte sans construire ni appeler le fournisseur et sans rien écrire.
  • prune supprime les clés orphelines (clés cibles absentes de la source) du fichier écrit et du verrou. generatePlurals synthétise les formes plurielles CLDR manquantes (i18next-JSON avec un fournisseur LLM uniquement). Les deux sont désactivés par défaut ; quand ils sont définis, chacun remplace l'option de config correspondante pour cette exécution.
  • concurrency traduit jusqu'à ce nombre de locales cibles à la fois (par défaut 1, strictement en série). Une valeur inférieure à 1 lève CONCURRENCY_INVALID ; sur une exécution réelle, une valeur supérieure à 1 avec maxTokens configuré lève CONCURRENCY_BUDGET_CONFLICT (un dry-run est exempté). Une erreur globale levée alors que des locales tournent déjà empêche toute autre locale d'être démarrée, et les locales en cours terminent et libèrent leurs verrous d'écriture avant que translate ne rejette, donc le rejet arrive après la plus lente plutôt qu'instantanément.
  • cache est activé par défaut et réutilise le cache de mémoire de traduction local (verbatra.cache.json, exporté aussi comme CACHE_FILE_NAME) ; mets-le à false pour contourner le cache le temps de l'exécution (le --no-cache de la CLI).
  • onProgress est appelé à mesure que l'exécution avance (au démarrage et à la fin de chaque locale, et par sous-lot du fournisseur), et onLockWait se déclenche pendant qu'un verrou d'écriture de locale est disputé. Les deux sont des callbacks de notification ; le SDK n'écrit rien de lui-même. lockAcquireTimeoutMs remplace la durée pendant laquelle un verrou d'écriture disputé réessaie avant d'échouer avec LOCK_CONTENDED.
  • maxBatchSize, maxTokens et budgetBehavior sont réservés à la config ; il n'y a pas de surcharge par exécution.

Renvoie un RunSummary (voir son anatomie plus bas). Les problèmes globaux lèvent une SdkError ; une locale seule qui échoue ne lève jamais et atterrit comme status: "failed" sur l'entrée de cette locale pendant que l'exécution continue.

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.

Entrée : { config, cwd?, locales?, debounceMs?, onRun, concurrency?, cache?, onProgress?, onLockWait?, lockAcquireTimeoutMs? }. 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 } }. 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. Trois problèmes sont refusés au démarrage, avant que la surveillance n'existe, donc watch lui-même rejette au lieu de renvoyer un contrôleur : un concurrency qui n'est pas un entier d'au moins 1 lève CONCURRENCY_INVALID, un concurrency supérieur à 1 face à une config qui fixe maxTokens lève CONCURRENCY_BUDGET_CONFLICT (il n'existe pas de watch en dry-run, donc le conflit de budget s'applique toujours), et un fichier source manquant lève SOURCE_UNREADABLE. Tout échec après le démarrage remonte via onRun et la surveillance continue.

Inspecter l'état sans écrire

Aucune de ces fonctions n'appelle de fournisseur, n'écrit de fichier ni ne modifie le verrou.

doctor

Disponible à partir de 0.9.0

Ceci nécessite verbatra 0.9.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

Valide la configuration du projet et ne dépense rien : il ne construit aucun fournisseur, ne fait aucune requête réseau et ne lit jamais la valeur d'une clé d'API. Cinq vérifications s'exécutent, chacune avec son propre verdict pass, fail ou skipped : la config se charge et se valide, le format configuré se résout en un adaptateur, l'ID de fournisseur configuré se résout en une fabrique, la variable d'environnement dans laquelle ce fournisseur lit sa clé est définie, et le fichier de locale source peut être lu. Chaque vérification s'exécute même si une précédente a échoué : un seul appel signale donc tous les problèmes indépendants. La clé d'API est vérifiée par son nom uniquement. La vérification du fichier source le lit et le parse au lieu de seulement sonder son existence : un répertoire à sa place, un fichier vide et un contenu malformé sont donc tous signalés ici.

Entrée : { cwd?, configPath? }. Aucune config déjà chargée n'est nécessaire : doctor la charge lui-même, donc un projet sans aucune config obtient quand même un rapport plutôt qu'une erreur levée. Renvoie un DoctorResult dont ok est vrai exactement quand aucune vérification n'a échoué. Il lève CONFIG_NOT_FOUND uniquement pour un configPath explicite qui n'existe pas.

check

Rapporte la dérive par locale sous forme de comptes : missing (dans la source, absent de la cible), stale (source modifiée depuis la dernière traduction) et upToDate. Utilise-le comme contrôle CI.

Entrée : { config, cwd?, locales? }. Renvoie un CheckSummary dont inSync est vrai exactement quand chaque locale vérifiée n'a rien de manquant ni d'obsolète.

diff

Le frère détaillé de check : le même calcul, mais il renvoie les listes de clés par locale (missing, changed, orphaned) au lieu de comptes. Les clés orphelines sont rapportées seulement et ne font jamais basculer hasPendingChanges, puisqu'une exécution par défaut ne les supprime pas.

Entrée : { config, cwd?, locales? }. Renvoie un DiffSummary.

keyIntegrity

Rapporte, pour les clés modifiées de chaque locale, si la valeur cible actuelle correspond toujours aux placeholders de la source et si elle est de l'ICU valide. Chaque entrée porte key, hasPlaceholders, matches, les jetons de placeholder missing et extra en cas de discordance, et icuValid. Les entrées ne portent jamais de valeur de chaîne source ou cible. C'est le rapport d'intégrité par clé que Studio affiche.

Entrée : { config, cwd?, locales?, keys? }. keys restreint la vérification ; seules les clés "modifiées" pour une locale sont vérifiées. Renvoie un LocaleKeyIntegrity par locale vérifiée.

lockState

Rapporte l'existence du fichier de verrouillage, sa version et la dérive par locale (nombre de clés de la ligne de base, plus les comptes manquants, obsolètes et à jour). exists vient d'une sonde explicite, donc "pas encore de fichier de verrouillage" et "un fichier de verrouillage présent mais vide" restent distinguables. Quand le fichier est absent, le résultat est { exists: false } et rien d'autre n'est lu.

Entrée : { config, cwd?, locales? }. Renvoie un LockStateResult.

loadLockFile

Lit le fichier de verrouillage lui-même (verbatra.lock.json, aussi exporté sous LOCK_FILE_NAME) et renvoie sa forme parsée : { version, locales }, où chaque locale associe les clés au hash du contenu source depuis lequel elles ont été traduites pour la dernière fois. Un fichier manquant se dégrade en verrou vide, le même comportement de première exécution sur lequel translate s'appuie ; utilise lockState quand tu dois distinguer l'absence.

Entrée : { cwd? }. Aucune config requise. Renvoie un LockFile.

runStatus

Lit l'instantané des signalements de révision et de la consommation de tokens que la dernière exécution translate ou watch hors dry run a persisté dans .verbatra-local/run-status.json. Ne lève jamais : un fichier manquant, corrompu ou non reconnu se dégrade en { available: false }. Ce fichier est de la télémétrie au mieux, pas une source de vérité.

Entrée : { cwd? }. Aucune config requise. Renvoie { available: false } ou { available: true, version, generatedAt, usage?, budget?, locales }.

Opérations sur une seule clé

Ce sont les interfaces que Verbatra Studio pilote ; utilise-les pour construire ton propre outillage de révision. Toutes les trois résolvent locale et key à neuf à chaque appel et lèvent UNKNOWN_LOCALE ou UNKNOWN_KEY quand l'un des deux n'existe pas.

keyValue

Lit la valeur source actuelle d'une clé et, quand elle existe, sa valeur cible actuelle pour une locale. En lecture seule.

Entrée : { config, cwd?, locale, key }. Renvoie { source, target? } ; target est absent exactement quand la clé n'existe pas encore dans cette locale.

editEntry

Écrit une correction saisie par un humain pour une clé et une locale. La valeur candidate passe la même barrière d'intégrité qu'une traduction de fournisseur avant que quoi que ce soit n'atteigne le disque ; à l'acceptation, le fichier de locale et l'entrée de verrou de cette clé sont mis à jour sous le verrou d'écriture de la locale. N'appelle jamais de fournisseur.

Entrée : { config, cwd?, locale, key, value }. Renvoie un résultat à deux branches : { accepted: true, value }, ou { accepted: false, reason: "placeholder" | "icu" | "degenerate" | "empty", value } sans rien écrire. "empty" couvre une valeur vide ou uniquement composée d'espaces pour une source qui a du texte : une modification ne peut pas exprimer l'effacement d'une clé, alors utilise pour ça la sentinelle [[CLEAR]] du classeur.

retranslateEntry

Relance le fournisseur pour exactement une clé et une locale : un appel à entrée unique via le même chemin de fournisseur que translate, passé par les mêmes vérifications d'intégrité. À l'acceptation, il écrit le fichier de locale et l'entrée de verrou pour cette clé seulement.

Entrée : { config, cwd?, locale, key }. Renvoie { accepted: true, value, reviewReasons } (les codes de raison de révision, s'il y en a, qui s'appliquent à la nouvelle valeur) ou { accepted: false, reason: "placeholder" | "icu" | "degenerate" | "empty", value }. Contrairement à translate, un échec de fournisseur lève ici : une ProviderError de @verbatra/ai-providers avec un code stable comme RATE_LIMITED ou AUTH_FAILED.

Lectures de contenu en masse

Disponible à partir de 0.10.0

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

localeValues

Lit le texte source et cible actuel de chaque clé, sur chaque locale cible demandée, en un seul passage sur les fichiers déjà présents sur le disque. C'est le pendant en masse de keyValue : utilise-la quand tu as besoin de contenu de traduction en masse, par exemple pour chercher ou parcourir des valeurs plutôt que de simples noms de clé, puisque keyValue ne répond que pour une clé à la fois. En lecture seule.

Entrée : { config, cwd?, locales? } ; un locales omis couvre chaque locale cible configurée. Renvoie un tableau de { locale, values }, une entrée par locale, où values associe chaque clé à { source?, target? }. Un target absent signifie que la clé n'a pas encore été traduite dans cette locale ; une source absente signifie que la clé est orpheline, présente dans la locale cible mais plus dans la source.

Instantanés de fichiers de locale

Les briques d'un observateur à rafraîchissement en direct comme celui de Studio : capture l'état d'un fichier de locale, puis compte ce qui a changé depuis.

readLocaleFileSnapshot

Lit un fichier de locale (la locale source ou n'importe quelle locale cible) et le réduit à un hash de contenu par clé. Un fichier qui n'existe pas encore se lit comme un instantané vide plutôt que de lever.

Entrée : { config, locale, cwd? }. Renvoie { locale, hashes }.

diffLocaleSnapshots

Compare deux instantanés du même fichier, pris à des moments différents, et compte les clés ajoutées, modifiées et supprimées entre les deux. Une fonction synchrone ordinaire : diffLocaleSnapshots(previous, current) renvoie { added, changed, removed }. Des comptes seulement, jamais de noms de clés.

Chemins de locale

createLocalePathResolver

Résout la correspondance entre locales et chemins du projet dans les deux sens, à partir de files.pattern, des locales configurées et de files.localeStyle. createLocalePathResolver(cwd, config) renvoie { pathFor, localeFor } : pathFor(locale) est le chemin absolu du fichier d'une locale, et localeFor(path) est la locale à laquelle appartient un chemin, ou undefined pour un chemin qui n'appartient pas à ce projet. Tous les points d'entrée du SDK résolvent les chemins par lui, donc un watcher ou un tableau de bord bâti sur le SDK voit exactement les chemins qu'une exécution écrit.

Toutes les vérifications ont lieu à la création du resolver, avant toute lecture de fichier : un pattern et un style incompatibles, ou une locale pour laquelle le style n'a pas d'écriture correcte, lèvent LOCALE_LAYOUT_INVALID, et deux locales qui résolvent vers le même chemin lèvent LOCALE_PATH_COLLISION.

La paire classeur

La passation pour les traducteurs humains, sous forme de classeur Excel ou de texte délimité ; voir Traduction humaine.

exportWorkbook

Écrit les chaînes encore à traduire (clés manquantes et modifiées par locale ; ajoute les inchangées avec includeUnchanged) dans un classeur .xlsx stylisé. Les lignes portent le même signal de révision qu'une exécution translate calcule. Aucun appel de fournisseur, aucune écriture du verrou.

Entrée : { config, cwd?, out?, locales?, includeUnchanged?, format? }. format vaut xlsx par défaut ; csv et tsv écrivent à la place un <locale>.csv ou <locale>.tsv par locale, donc out désigne pour eux un répertoire (créé s'il manque) et un chemin de fichier pour xlsx. out vaut par défaut DEFAULT_WORKBOOK_PATH (verbatra-translations.xlsx) ou DEFAULT_DELIMITED_PATH (verbatra-translations), tous deux exportés comme constantes. Les valeurs acceptées sont exportées comme EXCHANGE_FORMATS et la valeur par défaut comme DEFAULT_EXCHANGE_FORMAT, pour qu'un outil qui enveloppe le SDK puisse valider un argument de format sans coder la liste en dur. Renvoie { path, locales } : le chemin absolu écrit et un compte de lignes par locale.

importWorkbook

Relit un classeur rempli dans les fichiers de locale, en exécutant les mêmes vérifications de dérive de source et d'intégrité que translate. Seules les lignes acceptées font avancer leur ligne de base du verrou ; une ligne vide ou rejetée continue de se réexporter jusqu'à sa vraie résolution.

Entrée : { config, workbook, cwd?, dryRun?, format? }. Avec csv ou tsv, workbook est soit un seul fichier de remise, soit le répertoire qui en contient un par locale, et la locale vient du nom du fichier. Renvoie la même forme RunSummary que translate (avec needsReview toujours vide, puisqu'aucun fournisseur n'intervient). Une feuille pour une locale qui n'est pas une cible configurée fait échouer cette locale avec CONFIG_INVALID comme donnée sur le résumé, pas comme exception.

Config

loadConfig

Trouve, charge et valide la config du projet, en renvoyant une VerbatraConfig. Options : { cwd?, configPath?, configOverride? }, avec la précédence configOverride (valider un objet en mémoire) sur configPath (charger un fichier explicite) sur la recherche. La recherche démarre à cwd et couvre verbatra.config.ts (aussi .js/.cjs), la famille .verbatrarc (.json, .yaml, .yml, .js, .cjs, .ts) et une propriété "verbatra" dans package.json. Un glossary donné comme chemin de fichier est lu et validé ici, donc le code en aval voit toujours un simple enregistrement.

Lève CONFIG_NOT_FOUND quand rien n'est trouvé, CONFIG_INVALID quand une config est trouvée mais invalide. Voir Le fichier de configuration pour le schéma.

loadConfigWithMeta

Le même chargement, plus la provenance : renvoie { config, source, glossary }, où source dit si la config vient d'une recherche, d'un chemin explicite ou d'une surcharge en mémoire (avec le filepath absolu quand il y en a un), et glossary note si le glossaire était absent, inline ou résolu depuis un fichier. Utilise-le quand tu dois afficher d'où vient la config.

readGlossaryFile

Disponible à partir de 0.9.0

Ceci nécessite verbatra 0.9.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

Lit un glossaire stocké dans un fichier directement depuis le disque et le renvoie sous forme de table plate de termes. Prend { glossary }, la GlossaryProvenance renvoyée par loadConfigWithMeta, si bien que le fichier lu est toujours celui que la config nomme ; il n'y a aucun argument de chemin. Utilise-le dans un outil de longue durée qui doit montrer le glossaire tel qu'il est maintenant, et non tel qu'il était au chargement de la config.

Lève GLOSSARY_NOT_FILE_BACKED quand le glossaire est inline ou absent, et CONFIG_INVALID quand le fichier est manquant, trop volumineux, non UTF-8, invalide en JSON ou n'est pas une table plate de chaînes.

updateGlossaryTerm

Disponible à partir de 0.9.0

Ceci nécessite verbatra 0.9.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

Ajoute, remplace ou supprime exactement un terme d'un glossaire stocké dans un fichier et renvoie le glossaire tel qu'il est désormais. Prend { glossary, cwd?, term, translation }, où translation est le nouveau texte ou null pour supprimer le terme. Le reste du fichier garde son ordre de clés et son indentation, l'écriture est atomique, et tout le cycle lecture, modification, écriture se déroule sous un verrou de glossaire valable pour le projet entier : deux modifications simultanées sont donc sérialisées plutôt qu'entrelacées.

Un glossaire inline est refusé avec GLOSSARY_NOT_FILE_BACKED plutôt que converti : il vit dans un module de config exécutable. Un terme ou une traduction vide, ainsi qu'une modification dont le résultat dépasserait la limite de 1 Mio du glossaire, sont refusés avec CONFIG_INVALID ; une écriture en échec donne GLOSSARY_UNWRITABLE.

defineConfig

Un assistant identité pour écrire un verbatra.config.ts typé : il renvoie son argument inchangé et n'existe que pour l'inférence de types et l'autocomplétion de l'éditeur, y compris la complétion des IDs de modèles connus du fournisseur sélectionné. La restriction de modèle ne vaut qu'à l'écriture ; à l'exécution, toute chaîne non vide passe la validation.

verbatraConfigSchema

Le schéma zod avec lequel loadConfig valide, exporté pour que ton propre outillage puisse valider un objet de config de la même façon que le SDK. Les clés de premier niveau inconnues sont rejetées, donc un secret égaré ne peut pas se cacher dans la config. La seule exception est $schema, une chaîne optionnelle acceptée pour qu'une config JSON ou YAML puisse pointer un éditeur vers le document JSON Schema que le paquet livre sous @verbatra/sdk/config-schema.json. Elle est ignorée à l'exécution.

scaffoldingMetadata

Métadonnées en lecture seule dont la commande init de la CLI dérive ses questions : providerEnv (id de fournisseur vers la variable d'environnement où sa clé est lue), scaffoldModels (un modèle d'échafaudage par défaut par fournisseur LLM), providerTokenLimitKeys (la clé d'option sous laquelle chaque fournisseur LLM reçoit sa limite de tokens de sortie) et supportedFormats (l'ensemble fermé des ids de format). Lis la clé de limite de tokens dans providerTokenLimitKeys plutôt que d'en supposer une : Anthropic l'appelle maxTokens et les autres maxOutputTokens, le schéma valide strictement les options de chaque fournisseur, et DeepL n'a pas d'entrée car il ne prend aucune limite de tokens. Le type ScaffoldableProviderId couvre les quatre fournisseurs hébergés ; openai-compatible en est exclu parce qu'il n'a pas de variable d'environnement unique requise.

Expurgation des secrets

Disponible à partir de 0.10.0

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

redact

Retire d'une chaîne les formes de clé API de fournisseur et la valeur exacte actuelle de toute variable d'environnement de fournisseur configurée, en remplaçant chaque correspondance par [REDACTED]. @verbatra/studio et @verbatra/mcp l'appliquent tous deux à chaque valeur qu'ils renvoient à un appelant qu'ils n'ont pas eux-mêmes générée, comme un terme de glossaire, un chemin de fichier ou un message d'erreur d'un système en amont, afin qu'une clé déjà présente dans ton environnement ou écrite dans un fichier du projet ne puisse jamais atteindre un onglet de navigateur, un agent ou une ligne de log.

Le point d'injection de dépendances

Disponible à partir de 0.9.0

Ceci nécessite verbatra 0.9.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

deps.fs remplace le port de système de fichiers par lequel passe l'I/O propre au SDK, typé SdkFs. Le point d'injection est complet : le fichier d'état d'exécution, le fichier de verrouillage, le glossaire de la config, l'I/O de classeur et d'échange, ainsi que les fichiers de locale eux-mêmes y passent tous, car les adaptateurs de format lisent et écrivent via un port construit à partir du même objet. Une exécution entière peut donc être tenue en mémoire : c'est ainsi que les tests du SDK évitent de toucher au disque, et qu'une application hôte peut adosser une partie d'un projet à autre chose qu'un disque local.

import { translate, type SdkFs } from "@verbatra/sdk";

const summary = await translate({ config }, { fs: inMemoryFs satisfies SdkFs });

Une implémentation doit respecter deux points du contrat. Les lectures sont bornées en taille : readFileBounded et readBytesBounded prennent une limite d'octets et rapportent missing ou too-large comme un état plutôt que de lever, ce qui empêche un fichier hostile ou accidentellement énorme d'épuiser la mémoire. Les écritures doivent être atomiques, pour qu'un crash en cours d'écriture ne laisse jamais un fichier à moitié écrit, et createExclusive doit être atomique face aux autres processus, car c'est la primitive derrière le verrou d'écriture par locale. La création de répertoires revient à l'appelant.

La seule chose que deps.fs n'atteint pas est un deps.adapterRegistry fourni par l'appelant. Ces adaptateurs ont été construits par l'appelant, donc leur accès aux fichiers est celui que l'appelant y a câblé. Fournir les deux signifie que l'appelant possède ce câblage.

Anatomie du RunSummary

translate, importWorkbook et chaque exécution watch réussie se résolvent en un RunSummary :

interface RunSummary {
  dryRun: boolean;          // true when nothing was written and no provider was called
  locales: LocaleSummary[]; // one entry per target locale, in config order
  succeeded: string[];      // locales whose run succeeded
  partial: string[];        // locales written with keys still missing; the CLI exits 1 on these
  failed: string[];         // locales whose run failed
  usage?: UsageSummary;     // summed input/output tokens; absent when no call reported usage
  budget?: RunBudget;       // present only when maxTokens is configured
}

interface LocaleSummary {
  locale: string;
  status: "succeeded" | "partial" | "failed";
  translated: string[];          // keys translated this run (in dry-run, keys that would be)
  cacheHits: string[];           // keys served from the translation-memory cache this run
  unchanged: string[];           // keys already up to date
  orphaned: string[];            // target keys with no matching source key (always reported)
  pruned: string[];              // orphaned keys removed this run; empty unless pruning is on
  invalidIcuSource: string[];    // source keys skipped for invalid ICU
  integrityMismatches: string[]; // translations withheld for a placeholder mismatch
  providerFailures: string[];    // keys withheld because nothing was translated for them
  budgetWithheld: string[];      // keys never sent because a "stop" budget already tripped
  generated: string[];           // CLDR plural forms synthesized this run
  unfilled: string[];            // import only: blank rows whose key still needs a translation
  malformedRows: { row: number; line?: number; column: string }[]; // import only: rows the reader could not parse
  duplicateKeys: { key: string; row: number; line?: number }[];    // import only: later rows for a duplicated key
  notices: LocaleNotice[];       // provider notices and SDK notices for this locale
  needsReview: { key: string; reasons: string[] }[]; // accepted keys flagged for a second look
  usage?: UsageSummary;          // this locale's summed tokens; absent if nothing reported usage
  error?: { code: string; message: string }; // present only when status is "failed"
}

Les parties à connaître :

  • needsReview liste les clés acceptées et écrites que les heuristiques de révision ont signalées, chacune avec ses codes de raison : LENGTH_RATIO_OUTLIER, EQUALS_SOURCE, GLOSSARY_TERM_MISSED, INTEGRITY_REORDERED et PROVIDER_DEGRADED. Un signalement de révision est consultatif et ne retient jamais une clé, donc une clé n'apparaît jamais à la fois dans needsReview et integrityMismatches. Voir Sûreté de la traduction pour la signification de chaque code et Réviser les traductions dans Studio pour traiter la file.
  • notices vivent par locale, jamais au premier niveau. Ils couvrent les avis de fournisseur (par exemple une dégradation DeepL) et les avis du SDK avec les codes PLURAL_CATEGORIES_INCOMPLETE, SUB_BATCH_FAILED, BLANK_ROW_BASELINE_RETAINED, BUDGET_TOKENS_EXCEEDED et CACHE_VERSION_UNRECOGNIZED. L'avis de cache concerne toute l'exécution (un seul fichier, partagé par chaque locale), il est donc attaché à chaque locale de l'exécution.
  • usage est undefined, jamais un zéro fabriqué, dès que rien dans ce périmètre n'a rapporté d'usage : un dry run n'appelle jamais de fournisseur, et DeepL ne rapporte jamais de tokens. RunSummary.usage est la somme sur les locales.
  • budget n'apparaît que quand maxTokens est configuré : { maxTokens, behavior, supported, tokensUsed, exceeded }. Face à un fournisseur sans tokens ou à un dry run, il est quand même présent avec supported: false, donc le garde-fou est visiblement inerte plutôt que faussement déclenché.
  • error.code sur une locale échouée est une chaîne préservée (le code du fournisseur ou de l'adaptateur sous-jacent, avec LOCALE_FAILED seulement en dernier recours), donc ne le traite pas comme un ensemble fermé.
  • cacheHits liste les clés servies depuis le cache de mémoire de traduction plutôt que par le fournisseur. unfilled, malformedRows et duplicateKeys ne sont remplis que par importWorkbook (une exécution translate les laisse vides) : une ligne vide dont la clé demande toujours une traduction au moment de l'import (qu'elle ait été exportée comme new ou comme changed), une ligne du classeur que le lecteur n'a pas pu analyser, et une clé en double dont la première occurrence a gagné. Le line optionnel des deux derniers est la ligne du fichier où commence l'enregistrement, présent uniquement pour un import délimité (csv ou tsv).

Le modèle d'erreur

Les échecs globaux lèvent une SdkError : une seule classe, un code stable et un message sans secret. Branche-toi sur le code, pas sur le message. Les échecs par locale, les avis de fournisseur et les constats d'intégrité remontent comme données sur le RunSummary, jamais comme exceptions.

CodeQuand
CONFIG_NOT_FOUNDaucune config trouvée par la recherche, ou un configPath explicite n'existe pas (levé par loadConfig)
CONFIG_INVALIDune config a été trouvée mais est imparsable ou échoue la validation, ou son fichier de glossaire n'a pas pu être résolu
UNKNOWN_FORMATaucun adaptateur n'est enregistré pour le format configuré ; levé avant toute lecture de fichier
UNKNOWN_LOCALEune locale demandée n'est pas parmi les locales cibles configurées
UNKNOWN_KEYune clé demandée n'est pas dans la ressource source (keyValue, editEntry, retranslateEntry)
PROVIDER_CONSTRUCTION_FAILEDle fournisseur n'a pas pu être construit ; enveloppe l'erreur du fournisseur lui-même, y compris une clé d'API manquante
SOURCE_UNREADABLEle fichier de la locale source n'existe pas
SOURCE_INVALIDle fichier de la locale source n'a pas pu être lu ou parsé ; enveloppe l'erreur de lecture de l'adaptateur
LOCK_FILE_INVALIDle fichier de verrouillage est présent mais corrompu, trop volumineux ou à une version non prise en charge
LOCK_CONTENDEDle verrou d'écriture d'une locale n'a pas pu être acquis avant son délai ; le message nomme le chemin du fichier de verrou
GLOSSARY_NOT_FILE_BACKEDle glossaire de la config est inline ou absent : il n'y a donc aucun fichier de glossaire à lire ou à réécrire (readGlossaryFile, updateGlossaryTerm)
GLOSSARY_UNWRITABLEle fichier de glossaire n'a pas pu être écrit (updateGlossaryTerm)
LOCALE_LAYOUT_INVALIDfiles.pattern et files.localeStyle ne peuvent pas être combinés, ou le style n'a pas d'écriture de chemin valide pour une locale configurée
LOCALE_PATH_COLLISIONdeux locales configurées résolvent vers le même chemin absolu
CONCURRENCY_INVALIDconcurrency a été défini mais n'est pas un entier d'au moins 1 ; levé avant l'exécution de toute locale
CONCURRENCY_BUDGET_CONFLICTune exécution réelle a défini concurrency au-dessus de 1 alors que maxTokens est configuré ; levé avant tout appel au fournisseur (un dry-run est exempté)
TARGET_UNWRITABLEun fichier de locale cible n'a pas pu être écrit (son répertoire n'est pas inscriptible, n'existe pas, est en lecture seule ou est plein) ; le message nomme le fichier cible et le code du système de fichiers, jamais le fichier temporaire interne qu'utilise l'écriture atomique
LOCALE_FAILEDjamais levé : le code de repli enregistré sur l'error d'une locale échouée

Deux exceptions à la règle de la classe d'erreur unique : retranslateEntry relance la ProviderError du fournisseur quand l'appel unique échoue, et runStatus ne lève jamais. Pour la correspondance entre ces codes et les codes de sortie de la CLI, voir CI et codes de sortie ; pour de l'aide par symptôme, voir Dépannage.

Edit on GitHub