@verbatra/sdk 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -2
- package/dist/index.cjs +714 -238
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +551 -147
- package/dist/index.d.ts +551 -147
- package/dist/index.js +712 -240
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,191 @@
|
|
|
1
|
-
import { AnthropicModel, OpenAiModel, GeminiModel, ProviderNotice, TranslationProvider } from '@verbatra/ai-providers';
|
|
2
1
|
import { z } from 'zod';
|
|
3
|
-
import
|
|
2
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
3
|
+
import { Interactions } from '@google/genai';
|
|
4
|
+
import OpenAI from 'openai';
|
|
4
5
|
|
|
6
|
+
/** Zod schema accepting exactly one of {@link SUPPORTED_FORMATS}. */
|
|
7
|
+
declare const supportedFormatSchema$1: z.ZodEnum<{
|
|
8
|
+
"i18next-json": "i18next-json";
|
|
9
|
+
"vue-i18n-json": "vue-i18n-json";
|
|
10
|
+
"next-intl-json": "next-intl-json";
|
|
11
|
+
"ngx-translate-json": "ngx-translate-json";
|
|
12
|
+
xliff: "xliff";
|
|
13
|
+
yaml: "yaml";
|
|
14
|
+
arb: "arb";
|
|
15
|
+
}>;
|
|
16
|
+
/** One of the supported source formats; a member of {@link SUPPORTED_FORMATS}. */
|
|
17
|
+
type SupportedFormat$1 = z.infer<typeof supportedFormatSchema$1>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A single, format-neutral translation unit. Placeholders are supplied already
|
|
21
|
+
* extracted; core never derives them from the value.
|
|
22
|
+
*/
|
|
23
|
+
declare const translationEntrySchema$1: z.ZodObject<{
|
|
24
|
+
key: z.ZodString;
|
|
25
|
+
namespace: z.ZodString;
|
|
26
|
+
value: z.ZodString;
|
|
27
|
+
description: z.ZodOptional<z.ZodString>;
|
|
28
|
+
meaning: z.ZodOptional<z.ZodString>;
|
|
29
|
+
placeholders: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
30
|
+
isPlural: z.ZodBoolean;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
/** The validated shape of one translation unit; the inferred type of {@link translationEntrySchema}. */
|
|
33
|
+
type TranslationEntry$1 = Readonly<z.infer<typeof translationEntrySchema$1>>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Result of comparing source placeholders against translated-output placeholders as MULTISETS
|
|
37
|
+
* (counts matter). Always returned (never thrown) for an ordinary mismatch.
|
|
38
|
+
*/
|
|
39
|
+
interface PlaceholderIntegrityResult {
|
|
40
|
+
/** True when nothing is missing or extra and order is preserved. */
|
|
41
|
+
readonly matches: boolean;
|
|
42
|
+
/** Occurrences present in source but absent from the translation, one per dropped occurrence. Sorted. */
|
|
43
|
+
readonly missing: readonly string[];
|
|
44
|
+
/** Occurrences present in the translation but absent from source, one per surplus occurrence. Sorted. */
|
|
45
|
+
readonly extra: readonly string[];
|
|
46
|
+
/** Same multiset present in both, but in a different order. */
|
|
47
|
+
readonly reordered: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A provider is either a prompt-driven LLM or a dedicated machine-translation API. */
|
|
51
|
+
type ProviderKind = "llm" | "machine-translation";
|
|
52
|
+
/** Target tone for a translation. Maps to formality for machine-translation providers. */
|
|
53
|
+
type Tone = "formal" | "informal" | "neutral";
|
|
54
|
+
/**
|
|
55
|
+
* Produces the placeholder set of a value for the output integrity check. Supplied
|
|
56
|
+
* by the caller (the SDK) so it matches the entries' format; ai-providers never
|
|
57
|
+
* derives placeholders itself.
|
|
58
|
+
*/
|
|
59
|
+
type PlaceholderExtractor = (value: string) => readonly string[];
|
|
60
|
+
/**
|
|
61
|
+
* A batch translation request. Format- and provider-neutral: it carries no prompt,
|
|
62
|
+
* model, key, or other provider-specific field. The placeholder extractor is
|
|
63
|
+
* mandatory (see validateRequest).
|
|
64
|
+
*/
|
|
65
|
+
interface TranslateRequest {
|
|
66
|
+
/** BCP-47 source locale of the entries (for example, "en"). */
|
|
67
|
+
readonly sourceLocale: string;
|
|
68
|
+
/** BCP-47 target locale to translate into (for example, "de"). */
|
|
69
|
+
readonly targetLocale: string;
|
|
70
|
+
/** The entries to translate; at least one is required. */
|
|
71
|
+
readonly entries: readonly TranslationEntry$1[];
|
|
72
|
+
/** Optional source-term to target-term map applied by glossary-capable providers. */
|
|
73
|
+
readonly glossary?: Readonly<Record<string, string>>;
|
|
74
|
+
/** Optional target tone; machine-translation providers map it to formality. */
|
|
75
|
+
readonly tone?: Tone;
|
|
76
|
+
/** Mandatory placeholder extractor; the output integrity check runs against it. */
|
|
77
|
+
readonly extractPlaceholders: PlaceholderExtractor;
|
|
78
|
+
}
|
|
79
|
+
/** Token usage, when the provider reports it. Absent for providers without tokens (DeepL). */
|
|
80
|
+
interface Usage {
|
|
81
|
+
readonly inputTokens: number;
|
|
82
|
+
readonly outputTokens: number;
|
|
83
|
+
}
|
|
84
|
+
/** Result of a batch translation: per-key values and per-key integrity outcomes. */
|
|
85
|
+
interface TranslateResult {
|
|
86
|
+
/** The translated value for each requested key. */
|
|
87
|
+
readonly values: ReadonlyMap<string, string>;
|
|
88
|
+
/** The placeholder-integrity outcome for each key (source vs translated placeholder sets). */
|
|
89
|
+
readonly integrity: ReadonlyMap<string, PlaceholderIntegrityResult>;
|
|
90
|
+
/** Token usage when the provider reports it; absent for token-less providers. */
|
|
91
|
+
readonly usage?: Usage;
|
|
92
|
+
}
|
|
5
93
|
/**
|
|
6
|
-
* The provider
|
|
7
|
-
*
|
|
8
|
-
*
|
|
94
|
+
* The single contract every provider implements. It is narrow enough that a machine-translation API like
|
|
95
|
+
* DeepL fits it directly, while LLM providers implement it by delegating to {@link runLlmTranslation}.
|
|
96
|
+
* A new provider attaches by implementing this and registering it in a {@link ProviderRegistry}.
|
|
9
97
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
98
|
+
* Implementer invariants:
|
|
99
|
+
* - Translatable strings are UNTRUSTED. They travel only as data to the provider; never splice them into
|
|
100
|
+
* instruction text, and never act on instructions a value appears to contain.
|
|
101
|
+
* - Read the API key ONLY from the environment (inside the SDK client). The request, config, and this
|
|
102
|
+
* interface never carry a key.
|
|
103
|
+
* - Fail with a secret-free {@link ProviderError}: never bind, log, or re-throw raw SDK error text (it can
|
|
104
|
+
* carry a key or request headers). Validate the request at the boundary with `validateRequest` so the
|
|
105
|
+
* integrity check can never be skipped.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* // A machine-translation provider implements translateBatch directly (the DeepL shape).
|
|
110
|
+
* function createMyMtProvider(client: MyClient): TranslationProvider {
|
|
111
|
+
* return {
|
|
112
|
+
* id: "my-mt",
|
|
113
|
+
* kind: "machine-translation",
|
|
114
|
+
* supportsGlossary: false,
|
|
115
|
+
* async translateBatch(request) {
|
|
116
|
+
* const data = validateRequest(request); // throws INVALID_REQUEST on a bad request
|
|
117
|
+
* const texts = data.entries.map((e) => e.value);
|
|
118
|
+
* const out = await client.translate(texts, data.targetLocale); // SDK reads MY_API_KEY from env
|
|
119
|
+
* // map out -> values, run the integrity check, return { values, integrity }
|
|
120
|
+
* return buildResult(data, out, request.extractPlaceholders);
|
|
121
|
+
* },
|
|
122
|
+
* };
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
interface TranslationProvider {
|
|
127
|
+
/** A stable identifier for this provider (for example, "anthropic", "deepl"). */
|
|
128
|
+
readonly id: string;
|
|
129
|
+
/** Whether this provider is a prompt-driven LLM or a dedicated machine-translation API. */
|
|
130
|
+
readonly kind: ProviderKind;
|
|
131
|
+
/** Whether this provider applies a configured glossary. */
|
|
132
|
+
readonly supportsGlossary: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Translate a batch of entries.
|
|
135
|
+
*
|
|
136
|
+
* @param request - The provider-neutral batch request (no prompt, model, or key).
|
|
137
|
+
* @returns The per-key translated values and per-key placeholder-integrity outcomes.
|
|
138
|
+
* @throws {@link ProviderError}, secret-free, with the code for the failure (the concrete codes are
|
|
139
|
+
* the implementation's; see each provider factory).
|
|
140
|
+
*/
|
|
141
|
+
translateBatch(request: TranslateRequest): Promise<TranslateResult>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The Anthropic authoring model type, sourced from the SDK's own model union. It is an
|
|
146
|
+
* open union (known literals plus `string & {}`), so unknown or newly released model IDs
|
|
147
|
+
* are still accepted. This drives editor completions only; the runtime schema validates.
|
|
148
|
+
*/
|
|
149
|
+
type AnthropicModel = Anthropic.Messages.Model;
|
|
150
|
+
/**
|
|
151
|
+
* Stable codes for the DeepL graceful-degradation notices, DeepL only. These are returned DATA on a
|
|
152
|
+
* successful result, NOT thrown:
|
|
153
|
+
*
|
|
154
|
+
* - `FORMALITY_DOWNGRADED`: a requested formality was not applied (the free tier does not support it).
|
|
155
|
+
* - `GLOSSARY_IGNORED`: a supplied generic glossary was not applied.
|
|
156
|
+
*/
|
|
157
|
+
type ProviderNoticeCode = "FORMALITY_DOWNGRADED" | "GLOSSARY_IGNORED";
|
|
158
|
+
/**
|
|
159
|
+
* An observable, structured signal that something was gracefully degraded (not an
|
|
160
|
+
* error). Carries only a stable code and a static message, never a key or content.
|
|
161
|
+
* Surfaced as result data, never thrown; callers inspect it but need not treat it as a failure.
|
|
162
|
+
*/
|
|
163
|
+
interface ProviderNotice {
|
|
164
|
+
/** The stable {@link ProviderNoticeCode} for what was degraded. */
|
|
165
|
+
readonly code: ProviderNoticeCode;
|
|
166
|
+
/** A static, safe description; never a key or translatable content. */
|
|
167
|
+
readonly message: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The Gemini authoring model type, sourced from the installed SDK's own model union so
|
|
172
|
+
* verbatra restates no model IDs. It is an open union, so unknown model IDs are still
|
|
173
|
+
* accepted. Type-only: it informs editor completions and is never validated at runtime,
|
|
174
|
+
* where the schema stays `z.string().min(1)`.
|
|
175
|
+
*/
|
|
176
|
+
type GeminiModel = Interactions.Model;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The OpenAI authoring model type, sourced from the OpenAI SDK's published chat-model
|
|
180
|
+
* union. It drives editor completions only; it is never read at runtime, and the
|
|
181
|
+
* runtime schema stays `z.string().min(1)`.
|
|
182
|
+
*/
|
|
183
|
+
type OpenAiModel = OpenAI.ChatModel;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The provider section of the config: a discriminated union over the provider id, reusing each
|
|
187
|
+
* provider's own config schema. There is no key field anywhere in this union; the provider reads its
|
|
188
|
+
* API key from the environment at construction.
|
|
13
189
|
*/
|
|
14
190
|
declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
15
191
|
id: z.ZodLiteral<"anthropic">;
|
|
@@ -38,6 +214,11 @@ declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
38
214
|
type ProviderConfig = z.infer<typeof providerConfigSchema>;
|
|
39
215
|
type ProviderId = ProviderConfig["id"];
|
|
40
216
|
|
|
217
|
+
/**
|
|
218
|
+
* The verbatra project configuration. It carries no API key (the provider reads its key from the
|
|
219
|
+
* environment), and unknown top-level keys are rejected so a stray secret cannot hide in it. Validated
|
|
220
|
+
* with zod at the boundary regardless of where it was loaded from.
|
|
221
|
+
*/
|
|
41
222
|
declare const verbatraConfigSchema: z.ZodObject<{
|
|
42
223
|
sourceLocale: z.ZodString;
|
|
43
224
|
targetLocales: z.ZodArray<z.ZodString>;
|
|
@@ -46,6 +227,9 @@ declare const verbatraConfigSchema: z.ZodObject<{
|
|
|
46
227
|
"vue-i18n-json": "vue-i18n-json";
|
|
47
228
|
"next-intl-json": "next-intl-json";
|
|
48
229
|
"ngx-translate-json": "ngx-translate-json";
|
|
230
|
+
xliff: "xliff";
|
|
231
|
+
yaml: "yaml";
|
|
232
|
+
arb: "arb";
|
|
49
233
|
}>;
|
|
50
234
|
files: z.ZodObject<{
|
|
51
235
|
pattern: z.ZodString;
|
|
@@ -86,16 +270,6 @@ declare const verbatraConfigSchema: z.ZodObject<{
|
|
|
86
270
|
}, z.core.$strict>;
|
|
87
271
|
type VerbatraConfig = z.infer<typeof verbatraConfigSchema>;
|
|
88
272
|
|
|
89
|
-
/**
|
|
90
|
-
* The closed set of a provider's known model IDs: exactly the string literals its SDK
|
|
91
|
-
* model type ships, with the SDK's own open `string & {}` arm stripped out. Distributing
|
|
92
|
-
* over the union and dropping any arm the wide `string` extends leaves only the literals,
|
|
93
|
-
* so the authoring field offers and ACCEPTS only the selected provider's known models. A
|
|
94
|
-
* foreign or unknown model (for example a Claude model under `id: "gemini"`) is a type
|
|
95
|
-
* error at authoring time. This is a static authoring constraint only; the runtime schema
|
|
96
|
-
* stays `z.string().min(1)` and still accepts any non-empty string, so a brand-new model
|
|
97
|
-
* the installed SDK does not yet list is flagged in the editor but still runs.
|
|
98
|
-
*/
|
|
99
273
|
type KnownModels<M extends string> = M extends string ? (string extends M ? never : M) : never;
|
|
100
274
|
type AuthoringVariant<Id extends ProviderId, M extends string> = Extract<ProviderConfig, {
|
|
101
275
|
id: Id;
|
|
@@ -108,13 +282,6 @@ type AuthoringVariant<Id extends ProviderId, M extends string> = Extract<Provide
|
|
|
108
282
|
model: KnownModels<M>;
|
|
109
283
|
};
|
|
110
284
|
} : never : never;
|
|
111
|
-
/**
|
|
112
|
-
* The authoring view of one provider variant, keyed by id. LLM providers (anthropic,
|
|
113
|
-
* openai, gemini) restrict `options.model` to that provider's known model literals; DeepL
|
|
114
|
-
* has no model field and is carried through unchanged. Keying by id (rather than a flat
|
|
115
|
-
* union) lets {@link AuthoringConfigFor} select exactly one variant for a literal id, so
|
|
116
|
-
* the `options.model` site is one provider's literal set and never a multi-provider union.
|
|
117
|
-
*/
|
|
118
285
|
type AuthoringProviderVariant = {
|
|
119
286
|
anthropic: AuthoringVariant<"anthropic", AnthropicModel>;
|
|
120
287
|
openai: AuthoringVariant<"openai", OpenAiModel>;
|
|
@@ -124,20 +291,10 @@ type AuthoringProviderVariant = {
|
|
|
124
291
|
}>;
|
|
125
292
|
};
|
|
126
293
|
/**
|
|
127
|
-
* The authoring view of the whole config for a
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* `options.model` is that provider's known model literals alone and not a union across
|
|
132
|
-
* providers. `defineConfig` declares one overload per provider parameterized on this type
|
|
133
|
-
* (`AuthoringConfigFor<"openai">` and so on), so overload resolution picks the variant from
|
|
134
|
-
* the `provider.id` literal. That, together with the closed {@link KnownModels} set, makes a
|
|
135
|
-
* foreign model (for example a Claude model under `id: "gemini"`) a type error and aims to
|
|
136
|
-
* keep editors with weaker discriminated-union narrowing (for example the JetBrains/WebStorm
|
|
137
|
-
* completion engine) offering only the selected provider's models, since each overload's
|
|
138
|
-
* parameter is already a single variant with no nested union to narrow. When `TId` defaults
|
|
139
|
-
* to `ProviderId`, `provider` is the full authoring union. Every value assignable here is
|
|
140
|
-
* assignable to {@link VerbatraConfig}, because a model literal is a subtype of `string`.
|
|
294
|
+
* The authoring view of the whole config for a provider id: a {@link VerbatraConfig} whose `provider`
|
|
295
|
+
* is that id's single authoring variant, so `options.model` offers only that provider's models. When
|
|
296
|
+
* `TId` defaults to `ProviderId`, `provider` is the full authoring union. Every value here is assignable
|
|
297
|
+
* to {@link VerbatraConfig}, since a model literal is a subtype of `string`.
|
|
141
298
|
*/
|
|
142
299
|
type AuthoringConfigFor<TId extends ProviderId = ProviderId> = Omit<VerbatraConfig, "provider"> & {
|
|
143
300
|
provider: AuthoringProviderVariant[TId];
|
|
@@ -150,30 +307,16 @@ type AuthoringConfigFor<TId extends ProviderId = ProviderId> = Omit<VerbatraConf
|
|
|
150
307
|
type AuthoringConfig = AuthoringConfigFor;
|
|
151
308
|
|
|
152
309
|
/**
|
|
153
|
-
* Identity helper for authoring a
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* It is declared as one overload per provider id rather than a single generic. Each
|
|
158
|
-
* overload's parameter is the concrete single-provider authoring config
|
|
159
|
-
* ({@link AuthoringConfigFor}), so `provider.options.model` is already that one provider's
|
|
160
|
-
* known model literals, with no union across providers and no generic for an editor to
|
|
161
|
-
* infer. Overload resolution selects the matching overload from the `provider.id` literal,
|
|
162
|
-
* so the editor offers only the selected provider's models and a foreign or unknown model
|
|
163
|
-
* (for example a Claude model under `id: "gemini"`) is a type error. This is deliberately
|
|
164
|
-
* overload-based: a generic whose type parameter is inferred from a nested `provider.id`
|
|
165
|
-
* collapses correctly in tsserver but not in editors with weaker inference (notably the
|
|
166
|
-
* JetBrains/WebStorm completion engine), which then fall back to the full union and offer
|
|
167
|
-
* every provider's models. Concrete per-provider signatures avoid that inference step.
|
|
310
|
+
* Identity helper for authoring a typed `verbatra.config.ts`. It returns its argument unchanged; its
|
|
311
|
+
* only purpose is full type inference and editor autocomplete on the config object, including
|
|
312
|
+
* completion of the selected provider's known model literals.
|
|
168
313
|
*
|
|
169
|
-
* The
|
|
170
|
-
*
|
|
171
|
-
*
|
|
314
|
+
* The model restriction is a static authoring constraint only: `loadConfig` validates `model` as a
|
|
315
|
+
* non-empty string, so a model the installed provider SDK does not yet list is flagged in the editor
|
|
316
|
+
* but still runs.
|
|
172
317
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* `z.string().min(1)`, so a model the installed provider SDK does not yet list is flagged
|
|
176
|
-
* in the editor but still runs.
|
|
318
|
+
* @param config - The verbatra configuration object.
|
|
319
|
+
* @returns The same config, typed as {@link VerbatraConfig}.
|
|
177
320
|
*/
|
|
178
321
|
declare function defineConfig(config: AuthoringConfigFor<"anthropic">): VerbatraConfig;
|
|
179
322
|
declare function defineConfig(config: AuthoringConfigFor<"openai">): VerbatraConfig;
|
|
@@ -190,12 +333,10 @@ interface LoadConfigOptions {
|
|
|
190
333
|
*/
|
|
191
334
|
readonly configOverride?: unknown;
|
|
192
335
|
/**
|
|
193
|
-
* An explicit config file to load instead of searching. A relative path resolves
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* present-but-unparseable/invalid file is CONFIG_INVALID. Precedence: configOverride
|
|
198
|
-
* wins over configPath, which wins over search.
|
|
336
|
+
* An explicit config file to load instead of searching. A relative path resolves against `cwd`; an
|
|
337
|
+
* absolute path is used as given. Parsed and zod-validated exactly like a searched file: a missing
|
|
338
|
+
* file is `CONFIG_NOT_FOUND`, a present but invalid one is `CONFIG_INVALID`. Takes precedence over
|
|
339
|
+
* search, but `configOverride` takes precedence over it.
|
|
199
340
|
*/
|
|
200
341
|
readonly configPath?: string;
|
|
201
342
|
}
|
|
@@ -259,14 +400,313 @@ declare class SdkError extends Error {
|
|
|
259
400
|
constructor(code: SdkErrorCode, message: string);
|
|
260
401
|
}
|
|
261
402
|
|
|
403
|
+
/** Zod schema accepting exactly one of {@link SUPPORTED_FORMATS}. */
|
|
404
|
+
declare const supportedFormatSchema: z.ZodEnum<{
|
|
405
|
+
"i18next-json": "i18next-json";
|
|
406
|
+
"vue-i18n-json": "vue-i18n-json";
|
|
407
|
+
"next-intl-json": "next-intl-json";
|
|
408
|
+
"ngx-translate-json": "ngx-translate-json";
|
|
409
|
+
xliff: "xliff";
|
|
410
|
+
yaml: "yaml";
|
|
411
|
+
arb: "arb";
|
|
412
|
+
}>;
|
|
413
|
+
/** One of the supported source formats; a member of {@link SUPPORTED_FORMATS}. */
|
|
414
|
+
type SupportedFormat = z.infer<typeof supportedFormatSchema>;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* A single, format-neutral translation unit. Placeholders are supplied already
|
|
418
|
+
* extracted; core never derives them from the value.
|
|
419
|
+
*/
|
|
420
|
+
declare const translationEntrySchema: z.ZodObject<{
|
|
421
|
+
key: z.ZodString;
|
|
422
|
+
namespace: z.ZodString;
|
|
423
|
+
value: z.ZodString;
|
|
424
|
+
description: z.ZodOptional<z.ZodString>;
|
|
425
|
+
meaning: z.ZodOptional<z.ZodString>;
|
|
426
|
+
placeholders: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
427
|
+
isPlural: z.ZodBoolean;
|
|
428
|
+
}, z.core.$strip>;
|
|
429
|
+
/** The validated shape of one translation unit; the inferred type of {@link translationEntrySchema}. */
|
|
430
|
+
type TranslationEntry = Readonly<z.infer<typeof translationEntrySchema>>;
|
|
431
|
+
/** All translation entries for one locale and namespace, keyed by entry key. */
|
|
432
|
+
interface LocaleResource {
|
|
433
|
+
/** The locale these entries belong to (for example, "en" or "de"). */
|
|
434
|
+
readonly locale: string;
|
|
435
|
+
/** The namespace these entries belong to. */
|
|
436
|
+
readonly namespace: string;
|
|
437
|
+
/** The source format the resource came from, for round-trip fidelity. */
|
|
438
|
+
readonly format: SupportedFormat;
|
|
439
|
+
/** Entries addressable by key. */
|
|
440
|
+
readonly entries: ReadonlyMap<string, TranslationEntry>;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* The result of reading a file into core's intermediate representation.
|
|
445
|
+
*/
|
|
446
|
+
interface ReadResult {
|
|
447
|
+
/** The parsed locale resource. */
|
|
448
|
+
readonly resource: LocaleResource;
|
|
449
|
+
/** Keys whose values are invalid for the format's message syntax. Empty for non-ICU formats. */
|
|
450
|
+
readonly invalidIcuKeys: readonly string[];
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* The contract every format adapter implements. A new format attaches by implementing this interface
|
|
454
|
+
* and registering it in an {@link AdapterRegistry}.
|
|
455
|
+
*
|
|
456
|
+
* For a JSON-family format, implement via {@link createJsonFileAdapter} rather than from scratch. A
|
|
457
|
+
* non-JSON format implements this interface directly and first needs its format added to core's
|
|
458
|
+
* `SupportedFormat`.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* ```ts
|
|
462
|
+
* const registry = createDefaultRegistry();
|
|
463
|
+
* const resolution = registry.resolve("locales/en.json", { format: "i18next-json" });
|
|
464
|
+
* if (resolution.status === "resolved") {
|
|
465
|
+
* const { resource } = await resolution.adapter.read("locales/en.json", "en");
|
|
466
|
+
* await resolution.adapter.write(resource, "locales/en.json");
|
|
467
|
+
* }
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
interface FormatAdapter {
|
|
471
|
+
/** The single format this adapter handles (a `SupportedFormat` from core). */
|
|
472
|
+
readonly format: SupportedFormat;
|
|
473
|
+
/**
|
|
474
|
+
* Detect whether this adapter can handle a file, by path extension and an optional content sample.
|
|
475
|
+
* Best-effort and side-effect-free; it reads nothing from disk.
|
|
476
|
+
*
|
|
477
|
+
* @param filePath - The path of the file under consideration.
|
|
478
|
+
* @param sample - An optional leading content sample to aid detection.
|
|
479
|
+
* @returns True if this adapter could handle the file. Several adapters may return true for the same
|
|
480
|
+
* file (all JSON adapters claim `.json`); the caller disambiguates by explicit format.
|
|
481
|
+
*/
|
|
482
|
+
canHandle(filePath: string, sample?: string): boolean;
|
|
483
|
+
/**
|
|
484
|
+
* Read a file into a {@link LocaleResource} plus its message-validity result.
|
|
485
|
+
*
|
|
486
|
+
* @param filePath - The file to read.
|
|
487
|
+
* @param locale - The locale to tag the resource with.
|
|
488
|
+
* @returns The parsed resource and the keys whose values are invalid for the format.
|
|
489
|
+
* @throws {@link AdapterError} when the content is malformed, oversized, or structurally invalid
|
|
490
|
+
* (the implementation names the specific codes). A missing or unopenable path instead rejects with
|
|
491
|
+
* the underlying filesystem error.
|
|
492
|
+
*/
|
|
493
|
+
read(filePath: string, locale: string): Promise<ReadResult>;
|
|
494
|
+
/**
|
|
495
|
+
* Write a {@link LocaleResource} back to a file, preserving key order and structure, atomically.
|
|
496
|
+
*
|
|
497
|
+
* @param resource - The resource to serialize.
|
|
498
|
+
* @param filePath - The destination file.
|
|
499
|
+
* @throws {@link AdapterError} if the resource cannot be represented in the format; rejects with the
|
|
500
|
+
* underlying filesystem error on a write failure.
|
|
501
|
+
*/
|
|
502
|
+
write(resource: LocaleResource, filePath: string): Promise<void>;
|
|
503
|
+
/**
|
|
504
|
+
* Extract the format's placeholder tokens from a single value, resolving nothing.
|
|
505
|
+
*
|
|
506
|
+
* @param value - The translatable string to scan.
|
|
507
|
+
* @returns The placeholder tokens found, in document order. Does not throw.
|
|
508
|
+
*/
|
|
509
|
+
extractPlaceholders(value: string): readonly string[];
|
|
510
|
+
/**
|
|
511
|
+
* Validate a single value against the format's message syntax before it is written. Non-ICU formats
|
|
512
|
+
* (i18next, vue-i18n, ngx-translate) treat every value as valid and return true.
|
|
513
|
+
*
|
|
514
|
+
* @param value - The candidate translated value to validate.
|
|
515
|
+
* @returns True when the value is valid for the format's message syntax. Does not throw; an
|
|
516
|
+
* unparseable value returns false.
|
|
517
|
+
*/
|
|
518
|
+
validateMessage(value: string): boolean;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** Outcome of resolving an adapter for a file. Structured; never throws. */
|
|
522
|
+
type AdapterResolution = {
|
|
523
|
+
readonly status: "resolved";
|
|
524
|
+
readonly adapter: FormatAdapter;
|
|
525
|
+
} | {
|
|
526
|
+
readonly status: "no-match";
|
|
527
|
+
readonly filePath: string;
|
|
528
|
+
readonly triedFormats: readonly SupportedFormat[];
|
|
529
|
+
} | {
|
|
530
|
+
readonly status: "ambiguous";
|
|
531
|
+
readonly filePath: string;
|
|
532
|
+
readonly candidates: readonly SupportedFormat[];
|
|
533
|
+
};
|
|
534
|
+
/** Options for {@link AdapterRegistry.resolve}: select a format explicitly, or aid detection. */
|
|
535
|
+
interface ResolveOptions {
|
|
536
|
+
/** A content sample to aid detection. */
|
|
537
|
+
readonly sample?: string;
|
|
538
|
+
/** Bypass detection and select this format explicitly. */
|
|
539
|
+
readonly format?: SupportedFormat;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Holds the registered adapters and resolves one for a file. Open for extension:
|
|
543
|
+
* adapters attach through register without changing resolution logic.
|
|
544
|
+
*/
|
|
545
|
+
declare class AdapterRegistry {
|
|
546
|
+
private readonly adapters;
|
|
547
|
+
/**
|
|
548
|
+
* Register an adapter.
|
|
549
|
+
*
|
|
550
|
+
* @param adapter - The adapter to add.
|
|
551
|
+
* @returns This registry, for chaining.
|
|
552
|
+
*/
|
|
553
|
+
register(adapter: FormatAdapter): this;
|
|
554
|
+
private formats;
|
|
555
|
+
private resolveByFormat;
|
|
556
|
+
private resolveByDetection;
|
|
557
|
+
/**
|
|
558
|
+
* Resolve the adapter for a file, by explicit format when given, otherwise by detection.
|
|
559
|
+
*
|
|
560
|
+
* @param filePath - The file to resolve an adapter for.
|
|
561
|
+
* @param options - `format` selects explicitly and skips detection; `sample` aids detection.
|
|
562
|
+
* @returns A structured {@link AdapterResolution}: `resolved`, `no-match`, or `ambiguous`. Never
|
|
563
|
+
* throws; an unresolvable file is a status, not an exception.
|
|
564
|
+
*/
|
|
565
|
+
resolve(filePath: string, options?: ResolveOptions): AdapterResolution;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Outcome of a bounded read: the content, or why it could not be read in bounds. */
|
|
569
|
+
type BoundedFileRead = {
|
|
570
|
+
readonly kind: "ok";
|
|
571
|
+
readonly content: string;
|
|
572
|
+
} | {
|
|
573
|
+
readonly kind: "missing";
|
|
574
|
+
} | {
|
|
575
|
+
readonly kind: "too-large";
|
|
576
|
+
};
|
|
577
|
+
/** Outcome of a bounded binary read: the bytes, or why they could not be read in bounds. */
|
|
578
|
+
type BoundedBytesRead = {
|
|
579
|
+
readonly kind: "ok";
|
|
580
|
+
readonly bytes: Uint8Array;
|
|
581
|
+
} | {
|
|
582
|
+
readonly kind: "missing";
|
|
583
|
+
} | {
|
|
584
|
+
readonly kind: "too-large";
|
|
585
|
+
};
|
|
586
|
+
/**
|
|
587
|
+
* The minimal file-system surface the SDK needs. Reads are bounded and writes are atomic. Injectable so
|
|
588
|
+
* tests stay deterministic; the format adapters do their own file IO and bypass this seam.
|
|
589
|
+
*/
|
|
590
|
+
interface SdkFs {
|
|
591
|
+
/** Whether a readable file exists at the path. */
|
|
592
|
+
fileExists(path: string): Promise<boolean>;
|
|
593
|
+
/**
|
|
594
|
+
* Read a file as UTF-8 through a single handle, bounded to maxBytes. TOCTOU-safe: the handle is
|
|
595
|
+
* fstat'd and the read never advances past the sized length, so swapping in a larger file cannot
|
|
596
|
+
* bypass the cap. A missing or unreadable path is "missing"; a file over the cap is "too-large".
|
|
597
|
+
*/
|
|
598
|
+
readFileBounded(path: string, maxBytes: number): Promise<BoundedFileRead>;
|
|
599
|
+
/** Read a file as raw bytes with the same TOCTOU-safe, bounded discipline as {@link readFileBounded}. */
|
|
600
|
+
readBytesBounded(path: string, maxBytes: number): Promise<BoundedBytesRead>;
|
|
601
|
+
/** Write atomically: a temp file in the same directory, then rename over the target. */
|
|
602
|
+
writeFile(path: string, data: string): Promise<void>;
|
|
603
|
+
/** Write raw bytes atomically (temp file, then rename over the target). Used for the workbook. */
|
|
604
|
+
writeBytes(path: string, data: Uint8Array): Promise<void>;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/** Per-locale drift status: counts only, no key lists. */
|
|
608
|
+
interface LocaleCheckSummary {
|
|
609
|
+
/** The target locale this entry reports on. */
|
|
610
|
+
readonly locale: string;
|
|
611
|
+
/** Keys present in source but absent from the target. */
|
|
612
|
+
readonly missing: number;
|
|
613
|
+
/** Keys whose source changed since the target was last translated. */
|
|
614
|
+
readonly stale: number;
|
|
615
|
+
/** Keys whose recorded baseline still matches the source. */
|
|
616
|
+
readonly upToDate: number;
|
|
617
|
+
/** True when nothing needs (re)translating for this locale. */
|
|
618
|
+
readonly inSync: boolean;
|
|
619
|
+
}
|
|
620
|
+
/** The aggregate read-only status across all checked target locales. */
|
|
621
|
+
interface CheckSummary {
|
|
622
|
+
/** True only when every checked locale is in sync. */
|
|
623
|
+
readonly inSync: boolean;
|
|
624
|
+
/** One entry per checked target locale, in config order. */
|
|
625
|
+
readonly locales: readonly LocaleCheckSummary[];
|
|
626
|
+
}
|
|
627
|
+
/** Input for {@link check}: the validated config and which locales to check. */
|
|
628
|
+
interface CheckInput {
|
|
629
|
+
/** The validated configuration (typically from {@link loadConfig}). */
|
|
630
|
+
readonly config: VerbatraConfig;
|
|
631
|
+
/** Directory the file pattern and lock-file resolve against; defaults to cwd. */
|
|
632
|
+
readonly cwd?: string;
|
|
633
|
+
/** Subset of target locales to check; defaults to all configured target locales. */
|
|
634
|
+
readonly locales?: readonly string[];
|
|
635
|
+
}
|
|
636
|
+
/** Composition seam for {@link check}: inject a registry and a file system for tests. */
|
|
637
|
+
interface CheckDeps {
|
|
638
|
+
readonly adapterRegistry?: AdapterRegistry;
|
|
639
|
+
readonly fs?: SdkFs;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Report which keys are missing or stale per target locale, without calling a provider, writing any
|
|
643
|
+
* file, or touching the lock. Each locale is reported as counts only (missing, stale, up-to-date);
|
|
644
|
+
* a locale is `inSync` when nothing is missing or stale, and the top-level `inSync` is true only when
|
|
645
|
+
* every checked locale is. Orphaned keys and integrity are not reported, since they concern a write.
|
|
646
|
+
*
|
|
647
|
+
* @param input - The validated config and which locales to check.
|
|
648
|
+
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
649
|
+
* @returns The aggregate and per-locale drift status.
|
|
650
|
+
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
651
|
+
* with the same meanings as in `translate`.
|
|
652
|
+
*/
|
|
653
|
+
declare function check(input: CheckInput, deps?: CheckDeps): Promise<CheckSummary>;
|
|
654
|
+
|
|
655
|
+
/** Per-locale pending change: the key lists, not counts. */
|
|
656
|
+
interface LocaleDiff {
|
|
657
|
+
/** The target locale this entry reports on. */
|
|
658
|
+
readonly locale: string;
|
|
659
|
+
/** Keys present in source but absent from the target; would be added by a run. */
|
|
660
|
+
readonly missing: readonly string[];
|
|
661
|
+
/** Keys whose source changed since last translated; would be re-translated. */
|
|
662
|
+
readonly changed: readonly string[];
|
|
663
|
+
/** Keys present in target but absent from source; report-only, never pending. */
|
|
664
|
+
readonly orphaned: readonly string[];
|
|
665
|
+
/** True when the locale has missing or changed keys; orphaned keys do not count. */
|
|
666
|
+
readonly hasPendingChanges: boolean;
|
|
667
|
+
}
|
|
668
|
+
/** The aggregate read-only diff across all checked target locales. */
|
|
669
|
+
interface DiffSummary {
|
|
670
|
+
/** True when any checked locale has pending changes. */
|
|
671
|
+
readonly hasPendingChanges: boolean;
|
|
672
|
+
/** One entry per checked target locale, in config order. */
|
|
673
|
+
readonly locales: readonly LocaleDiff[];
|
|
674
|
+
}
|
|
675
|
+
/** Input for {@link diff}: the validated config and which locales to diff. */
|
|
676
|
+
interface DiffInput {
|
|
677
|
+
/** The validated configuration (typically from {@link loadConfig}). */
|
|
678
|
+
readonly config: VerbatraConfig;
|
|
679
|
+
/** Directory the file pattern and lock-file resolve against; defaults to cwd. */
|
|
680
|
+
readonly cwd?: string;
|
|
681
|
+
/** Subset of target locales to diff; defaults to all configured target locales. */
|
|
682
|
+
readonly locales?: readonly string[];
|
|
683
|
+
}
|
|
684
|
+
/** Composition seam for {@link diff}: inject a registry and a file system for tests. */
|
|
685
|
+
interface DiffDeps {
|
|
686
|
+
readonly adapterRegistry?: AdapterRegistry;
|
|
687
|
+
readonly fs?: SdkFs;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Report the exact pending change per target locale as three key lists (missing, changed, orphaned),
|
|
691
|
+
* without calling a provider, writing any file, or touching the lock. This is the detailed sibling of
|
|
692
|
+
* {@link check}. A locale's `hasPendingChanges` is driven by missing or changed only; orphaned keys are
|
|
693
|
+
* reported but do not flip it, since a default `translate` run does not prune. The top-level
|
|
694
|
+
* `hasPendingChanges` is true when any checked locale has pending changes.
|
|
695
|
+
*
|
|
696
|
+
* @param input - The validated config and which locales to diff.
|
|
697
|
+
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
698
|
+
* @returns The aggregate and per-locale pending change.
|
|
699
|
+
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
700
|
+
* with the same meanings as in `translate`.
|
|
701
|
+
*/
|
|
702
|
+
declare function diff(input: DiffInput, deps?: DiffDeps): Promise<DiffSummary>;
|
|
703
|
+
|
|
262
704
|
/** A stable code for an SDK-originated notice (not a provider notice). */
|
|
263
705
|
type SdkNoticeCode = "PLURAL_CATEGORIES_INCOMPLETE" | "SUB_BATCH_FAILED";
|
|
264
706
|
/**
|
|
265
707
|
* A notice raised by the SDK itself (not a provider), structurally identical to a {@link ProviderNotice}
|
|
266
708
|
* so both share the {@link LocaleSummary.notices} channel. Carries only a stable code and a static,
|
|
267
|
-
* secret-free message; never a key value or translatable content.
|
|
268
|
-
* the ai-providers `ProviderNoticeCode` union stays free of SDK concerns (the dependency arrow points
|
|
269
|
-
* sdk -> ai-providers, never the reverse).
|
|
709
|
+
* secret-free message; never a key value or translatable content.
|
|
270
710
|
*/
|
|
271
711
|
interface SdkNotice {
|
|
272
712
|
/** The stable {@link SdkNoticeCode} for what the SDK is reporting. */
|
|
@@ -302,10 +742,9 @@ interface LocaleSummary {
|
|
|
302
742
|
/** Translated keys that failed the placeholder-integrity check and were withheld. */
|
|
303
743
|
readonly integrityMismatches: readonly string[];
|
|
304
744
|
/**
|
|
305
|
-
* Plural-category keys verbatra
|
|
306
|
-
* never supplied), kept distinct from {@link translated}
|
|
307
|
-
*
|
|
308
|
-
* was enabled and acted. In a dry-run this is empty (the provider is not called).
|
|
745
|
+
* Plural-category keys verbatra synthesized this run (for example a Polish `items_few` the source
|
|
746
|
+
* never supplied), kept distinct from {@link translated}. Empty unless plural generation was enabled
|
|
747
|
+
* and acted, and empty in a dry-run.
|
|
309
748
|
*/
|
|
310
749
|
readonly generated: readonly string[];
|
|
311
750
|
/**
|
|
@@ -336,54 +775,6 @@ interface RunSummary {
|
|
|
336
775
|
readonly failed: readonly string[];
|
|
337
776
|
}
|
|
338
777
|
|
|
339
|
-
/** Outcome of a bounded read: the content, or why it could not be read in bounds. */
|
|
340
|
-
type BoundedFileRead = {
|
|
341
|
-
readonly kind: "ok";
|
|
342
|
-
readonly content: string;
|
|
343
|
-
} | {
|
|
344
|
-
readonly kind: "missing";
|
|
345
|
-
} | {
|
|
346
|
-
readonly kind: "too-large";
|
|
347
|
-
};
|
|
348
|
-
/** Outcome of a bounded binary read: the bytes, or why they could not be read in bounds. */
|
|
349
|
-
type BoundedBytesRead = {
|
|
350
|
-
readonly kind: "ok";
|
|
351
|
-
readonly bytes: Uint8Array;
|
|
352
|
-
} | {
|
|
353
|
-
readonly kind: "missing";
|
|
354
|
-
} | {
|
|
355
|
-
readonly kind: "too-large";
|
|
356
|
-
};
|
|
357
|
-
/**
|
|
358
|
-
* The minimal file-system surface the SDK needs: existence checks, the lock-file read/write,
|
|
359
|
-
* and the untrusted workbook bytes read/write for the export/import flow. Reads are bounded
|
|
360
|
-
* (see {@link readFileBounded} / {@link readBytesBounded}) and writes are atomic. Injectable so
|
|
361
|
-
* tests stay deterministic; the format adapters do their own file IO and are not routed through
|
|
362
|
-
* this seam.
|
|
363
|
-
*/
|
|
364
|
-
interface SdkFs {
|
|
365
|
-
/** Whether a readable file exists at the path. */
|
|
366
|
-
fileExists(path: string): Promise<boolean>;
|
|
367
|
-
/**
|
|
368
|
-
* Read a file as UTF-8 through a single handle, bounded to maxBytes. TOCTOU-safe: the
|
|
369
|
-
* handle is fstat'd and the read never advances past the sized length, so swapping the
|
|
370
|
-
* path for a larger file after the size check cannot bypass the cap. A missing or
|
|
371
|
-
* unreadable path is "missing" (first-run); a file over the cap is "too-large".
|
|
372
|
-
*/
|
|
373
|
-
readFileBounded(path: string, maxBytes: number): Promise<BoundedFileRead>;
|
|
374
|
-
/**
|
|
375
|
-
* Read a file as raw bytes through a single handle, bounded to maxBytes, with the SAME
|
|
376
|
-
* TOCTOU-safe discipline as {@link readFileBounded}: the handle is fstat'd and the read never
|
|
377
|
-
* advances past the sized length. Used for the untrusted workbook on import; a file over the
|
|
378
|
-
* cap is "too-large", a missing path is "missing".
|
|
379
|
-
*/
|
|
380
|
-
readBytesBounded(path: string, maxBytes: number): Promise<BoundedBytesRead>;
|
|
381
|
-
/** Write atomically: a temp file in the same directory, then rename over the target. */
|
|
382
|
-
writeFile(path: string, data: string): Promise<void>;
|
|
383
|
-
/** Write raw bytes atomically (temp file, then rename over the target). Used for the workbook. */
|
|
384
|
-
writeBytes(path: string, data: Uint8Array): Promise<void>;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
778
|
/** Builds the provider from its config. Injectable so tests stay offline. */
|
|
388
779
|
type CreateProvider = (config: ProviderConfig) => TranslationProvider;
|
|
389
780
|
|
|
@@ -497,11 +888,10 @@ interface ExportWorkbookResult {
|
|
|
497
888
|
}[];
|
|
498
889
|
}
|
|
499
890
|
/**
|
|
500
|
-
* Export the strings needing human translation into a styled `.xlsx` workbook.
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
* writes the bytes through the {@link SdkFs} seam. No provider is called and no lock-file is written.
|
|
891
|
+
* Export the strings needing human translation into a styled `.xlsx` workbook. Each target locale is
|
|
892
|
+
* diffed against the source and lock baseline to pick the rows (missing and changed by default; add
|
|
893
|
+
* unchanged with `includeUnchanged`), and the bytes are written to `out`. No provider is called and no
|
|
894
|
+
* lock-file is written.
|
|
505
895
|
*
|
|
506
896
|
* @param input - The validated config and export options.
|
|
507
897
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
@@ -528,19 +918,16 @@ interface ImportWorkbookDeps {
|
|
|
528
918
|
readonly fs?: SdkFs;
|
|
529
919
|
}
|
|
530
920
|
/**
|
|
531
|
-
* Import a filled workbook back into the locale files.
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
* `validateMessage`), writes the accepted values through the format adapter, and updates the lock
|
|
536
|
-
* through the existing lock logic. Returns a {@link RunSummary} structurally identical to
|
|
537
|
-
* `translate`'s, so the CLI formatter and exit-code rule are shared with no special case.
|
|
921
|
+
* Import a filled workbook back into the locale files. Each target-locale data sheet runs the same
|
|
922
|
+
* source-drift, placeholder, and ICU checks as the translate flow, the accepted values are written
|
|
923
|
+
* through the format adapter, and the lock is updated. Returns a {@link RunSummary} structurally
|
|
924
|
+
* identical to `translate`'s.
|
|
538
925
|
*
|
|
539
926
|
* Whole-run failures (unknown format, unreadable/invalid/oversized workbook, corrupt lock) throw a
|
|
540
927
|
* structured {@link SdkError}. A per-sheet failure (a locale not in config, a broken-round-trip key,
|
|
541
928
|
* a write failure) is isolated as that locale's `status: "failed"`, not a throw; per-row rejections
|
|
542
|
-
* are withheld and reported on the locale
|
|
543
|
-
*
|
|
929
|
+
* are withheld and reported on the locale. Dry-run validates and reports without writing any locale or
|
|
930
|
+
* lock file.
|
|
544
931
|
*
|
|
545
932
|
* @param input - The validated config, the workbook path, and run options.
|
|
546
933
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
@@ -549,6 +936,28 @@ interface ImportWorkbookDeps {
|
|
|
549
936
|
*/
|
|
550
937
|
declare function importWorkbook(input: ImportWorkbookInput, deps?: ImportWorkbookDeps): Promise<RunSummary>;
|
|
551
938
|
|
|
939
|
+
/**
|
|
940
|
+
* Read-only metadata the CLI `init` scaffold derives its tables from, so the CLI never restates the
|
|
941
|
+
* provider, env-var, model, or format truth owned by core and ai-providers.
|
|
942
|
+
*/
|
|
943
|
+
declare const scaffoldingMetadata: {
|
|
944
|
+
/** Provider id -> the environment variable its API key is read from. Owned by ai-providers. */
|
|
945
|
+
readonly providerEnv: {
|
|
946
|
+
readonly anthropic: "ANTHROPIC_API_KEY";
|
|
947
|
+
readonly openai: "OPENAI_API_KEY";
|
|
948
|
+
readonly gemini: "GEMINI_API_KEY";
|
|
949
|
+
readonly deepl: "DEEPL_API_KEY";
|
|
950
|
+
};
|
|
951
|
+
/** LLM provider id -> a cosmetic default scaffold model. Owned by ai-providers. DeepL has none. */
|
|
952
|
+
readonly scaffoldModels: {
|
|
953
|
+
readonly anthropic: "claude-sonnet-4-6";
|
|
954
|
+
readonly openai: "gpt-5.4-mini";
|
|
955
|
+
readonly gemini: "gemini-2.5-flash";
|
|
956
|
+
};
|
|
957
|
+
/** The closed set of source format ids. Owned by core. */
|
|
958
|
+
readonly supportedFormats: readonly ["i18next-json", "vue-i18n-json", "next-intl-json", "ngx-translate-json", "xliff", "yaml", "arb"];
|
|
959
|
+
};
|
|
960
|
+
|
|
552
961
|
/** A minimal source-change event source. Production wraps chokidar; tests inject a stub. */
|
|
553
962
|
interface Watcher {
|
|
554
963
|
/** Register a listener invoked once per coalesced source-change event. */
|
|
@@ -605,16 +1014,11 @@ interface WatchController {
|
|
|
605
1014
|
stop(): Promise<void>;
|
|
606
1015
|
}
|
|
607
1016
|
/**
|
|
608
|
-
* Start watching the source file and re-run the one-shot translate on each debounced change.
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
* watching continues. Returns a controller whose stop() closes the watcher and awaits the in-flight
|
|
614
|
-
* run (the caller wires any signal, e.g. SIGINT, to it).
|
|
615
|
-
*
|
|
616
|
-
* Only the startup source check throws; every run outcome after start is surfaced through `onRun` as a
|
|
617
|
-
* {@link WatchRunResult} (a failed run never rejects the in-flight promise).
|
|
1017
|
+
* Start watching the source file and re-run the one-shot {@link translate} on each debounced change.
|
|
1018
|
+
* Runs are serialized: changes during a run collapse into a single follow-up, so two runs never
|
|
1019
|
+
* overlap. A missing source at startup throws; every run outcome after start is surfaced through
|
|
1020
|
+
* `onRun` as a {@link WatchRunResult} and watching continues. Returns a controller whose `stop()`
|
|
1021
|
+
* closes the watcher and awaits the in-flight run.
|
|
618
1022
|
*
|
|
619
1023
|
* @param input - The config, optional cwd/debounce, and the `onRun` callback that receives each result.
|
|
620
1024
|
* @param deps - Optional composition seams (watcher, run, registry, provider builder, file system) for tests.
|
|
@@ -646,4 +1050,4 @@ interface WatchController {
|
|
|
646
1050
|
*/
|
|
647
1051
|
declare function watch(input: WatchInput, deps?: WatchDeps): Promise<WatchController>;
|
|
648
1052
|
|
|
649
|
-
export { type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleNotice, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, defineConfig, exportWorkbook, importWorkbook, loadConfig, translate, verbatraConfigSchema, watch };
|
|
1053
|
+
export { type CheckDeps, type CheckInput, type CheckSummary, type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type DiffDeps, type DiffInput, type DiffSummary, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleCheckSummary, type LocaleDiff, type LocaleNotice, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type SupportedFormat$1 as SupportedFormat, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, check, defineConfig, diff, exportWorkbook, importWorkbook, loadConfig, scaffoldingMetadata, translate, verbatraConfigSchema, watch };
|