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 pour les tests ; tu peux l'ignorer en usage normal.

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?, dryRun?, prune?, generatePlurals?, concurrency?, cache?, onProgress?, onLockWait?, lockAcquireTimeoutMs? }.

  • 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?, 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.

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.

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.

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.

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.

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) et supportedFormats (l'ensemble fermé des ids de format). 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.

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
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