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
@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
pnpm add -D @verbatra/sdk
# npm
npm install -D @verbatra/sdk
# yarn
yarn add -D @verbatra/sdkRequiert Node.js >=22.14.0.
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é des placeholders et d'ICU, é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? }.
dryRunlit, compare et rapporte sans construire ni appeler le fournisseur et sans rien écrire.prunesupprime les clés orphelines (clés cibles absentes de la source) du fichier écrit et du verrou.generatePluralssynthé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.concurrencytraduit jusqu'à ce nombre de locales cibles à la fois (par défaut 1, strictement en série). Une valeur inférieure à 1 lèveCONCURRENCY_INVALID; sur une exécution réelle, une valeur supérieure à 1 avecmaxTokensconfiguré lèveCONCURRENCY_BUDGET_CONFLICT(un dry-run est exempté).cacheest activé par défaut et réutilise le cache de mémoire de traduction local ; mets-le à false pour contourner le cache le temps de l'exécution (le--no-cachede la CLI).onProgressest appelé à mesure que l'exécution avance (au démarrage et à la fin de chaque locale, et par sous-lot du fournisseur), etonLockWaitse 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.lockAcquireTimeoutMsremplace la durée pendant laquelle un verrou d'écriture disputé réessaie avant d'échouer avecLOCK_CONTENDED.maxBatchSize,maxTokensetbudgetBehaviorsont 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 (un watch budgété avec concurrency supérieur à 1 échoue à chaque exécution avec CONCURRENCY_BUDGET_CONFLICT).
Renvoie un WatchController avec une seule méthode, stop(), qui ferme la surveillance et attend l'exécution en cours. Un fichier source manquant lève SOURCE_UNREADABLE au démarrage ; tout échec ultérieur 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 le même contrôle de placeholders et d'ICU 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", value } sans rien écrire.
retranslateEntry
Relance le fournisseur pour exactement une clé et une locale : un appel à entrée unique via le même registre de fournisseurs 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", 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.
La paire classeur
La passation Excel pour les traducteurs humains ; 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? }. out vaut par défaut DEFAULT_WORKBOOK_PATH (verbatra-translations.xlsx), exporté comme constante. 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, de placeholders et d'ICU 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? }. 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
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" | "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: changed rows the translator left blank
malformedRows: { row: number; column: string }[]; // import only: rows the reader could not parse
duplicateKeys: { key: string; row: 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_REORDEREDetPROVIDER_DEGRADED. Un signalement de révision est consultatif et ne retient jamais une clé, donc une clé n'apparaît jamais à la fois dansneedsReviewetintegrityMismatches. 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_RETAINEDetBUDGET_TOKENS_EXCEEDED. - 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.usageest la somme sur les locales. - budget n'apparaît que quand
maxTokensest configuré :{ maxTokens, behavior, supported, tokensUsed, exceeded }. Face à un fournisseur sans tokens ou à un dry run, il est quand même présent avecsupported: 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_FAILEDseulement 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écutiontranslateles laisse vides) : une lignechangedvide, 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 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.
| Code | Quand |
|---|---|
CONFIG_NOT_FOUND | aucune config trouvée par la recherche, ou un configPath explicite n'existe pas (levé par loadConfig) |
CONFIG_INVALID | une 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_FORMAT | aucun adaptateur n'est enregistré pour le format configuré ; levé avant toute lecture de fichier |
UNKNOWN_LOCALE | une locale demandée n'est pas parmi les locales cibles configurées |
UNKNOWN_KEY | une clé demandée n'est pas dans la ressource source (keyValue, editEntry, retranslateEntry) |
PROVIDER_CONSTRUCTION_FAILED | le fournisseur n'a pas pu être construit ; enveloppe l'erreur du fournisseur lui-même, y compris une clé d'API manquante |
SOURCE_UNREADABLE | le fichier de la locale source n'existe pas |
SOURCE_INVALID | le fichier de la locale source n'a pas pu être lu ou parsé ; enveloppe l'erreur de lecture de l'adaptateur |
LOCK_FILE_INVALID | le fichier de verrouillage est présent mais corrompu, trop volumineux ou à une version non prise en charge |
LOCK_CONTENDED | le 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 |
CONCURRENCY_INVALID | concurrency a été défini mais n'est pas un entier d'au moins 1 ; levé avant l'exécution de toute locale |
CONCURRENCY_BUDGET_CONFLICT | une 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é) |
LOCALE_FAILED | jamais 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.