@verbatra/sdk 0.9.1 → 0.10.0

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/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { z } from 'zod';
2
2
  import Anthropic from '@anthropic-ai/sdk';
3
- import { Interactions } from '@google/genai';
4
3
  import OpenAI from 'openai';
5
4
 
6
5
  /**
@@ -236,12 +235,22 @@ interface TranslationProvider {
236
235
  type AnthropicModel = Anthropic.Messages.Model;
237
236
 
238
237
  /**
239
- * The Gemini authoring model type, sourced from the installed SDK's own model union so
240
- * verbatra restates no model IDs. It is an open union, so unknown model IDs are still
241
- * accepted. Type-only: it informs editor completions and is never validated at runtime,
242
- * where the schema stays `z.string().min(1)`.
243
- */
244
- type GeminiModel = Interactions.Model;
238
+ * The Gemini authoring model type. Unlike the sibling Anthropic and OpenAI model types, this
239
+ * union is hand-maintained rather than re-exported from `@google/genai`: every entry point of
240
+ * that package's `.d.ts` carries an unconditional top-level import of
241
+ * `@modelcontextprotocol/sdk/client/index.js`, an optional peer dependency it does not install.
242
+ * Re-exporting any type from that package, including its model union, drags that import into
243
+ * this package's own published types and breaks `tsc --noEmit` with `skipLibCheck: false` for
244
+ * any consumer who has not separately installed the MCP SDK. Keeping this list literal avoids
245
+ * that transitive dependency entirely.
246
+ *
247
+ * It is an open union (`(string & {})` at the end), so unknown or newly released model IDs are
248
+ * still accepted. Type-only: it informs editor completions and is never validated at runtime,
249
+ * where the schema stays `z.string().min(1)`. The list is current as of `@google/genai` 2.17.1
250
+ * and does not update automatically; refresh it by hand when adopting a newer SDK version that
251
+ * adds models worth completing on.
252
+ */
253
+ type GeminiModel = "gemini-2.5-flash" | "gemini-2.5-pro" | "gemma-4-26b-a4b-it" | "gemma-4-31b-it" | "gemini-flash-latest" | "gemini-flash-lite-latest" | "gemini-pro-latest" | "gemini-2.5-flash-lite" | "gemini-2.5-flash-image" | "gemini-3-flash-preview" | "gemini-3.1-pro-preview" | "gemini-3.1-pro-preview-customtools" | "gemini-3.1-flash-lite" | "gemini-3-pro-image" | "nano-banana-pro-preview" | "gemini-3.1-flash-image" | "gemini-3.5-flash" | "gemini-3.6-flash" | "gemini-3.7-flash" | "lyria-3-clip-preview" | "lyria-3-pro-preview" | "gemini-robotics-er-1.6-preview" | "gemini-robotics-er-2-preview" | (string & {});
245
254
 
246
255
  /**
247
256
  * The OpenAI authoring model type, sourced from the OpenAI SDK's published chat-model union
@@ -251,13 +260,18 @@ type GeminiModel = Interactions.Model;
251
260
  type OpenAiModel = OpenAI.ChatModel;
252
261
 
253
262
  /**
254
- * Zod schema accepting exactly one of the eight source formats verbatra can read and write. Each
263
+ * Zod schema accepting exactly one of the twelve source formats verbatra can read and write. Each
255
264
  * member names the ecosystem it round-trips, not just a file extension, because several of them share
256
265
  * one: `i18next-json` is i18next's nested JSON with its plural key suffixes, `vue-i18n-json` is Vue
257
266
  * I18n's JSON with its pipe-separated plural values, `next-intl-json` is next-intl's ICU-message JSON,
258
- * and `ngx-translate-json` is ngx-translate's nested JSON. The remaining four are `xliff` (the XLIFF
259
- * interchange XML), `yaml` (plain nested YAML), `arb` (Flutter's Application Resource Bundle), and
260
- * `properties` (Java and Spring `.properties` files).
267
+ * and `ngx-translate-json` is ngx-translate's nested JSON. The remaining eight are `xliff` (the XLIFF
268
+ * interchange XML), `yaml` (plain nested YAML), `arb` (Flutter's Application Resource Bundle),
269
+ * `properties` (Java and Spring `.properties` files), `apple-strings` (Apple's flat `.strings`
270
+ * localization format for iOS and macOS), `apple-xcstrings` (Apple's Xcode String Catalog, a single
271
+ * JSON document holding every locale of a `.xcstrings` catalogue together), `android-xml` (Android's
272
+ * `res/values/strings.xml` resource format, including `<plurals>` and `translatable="false"` entries),
273
+ * and `gettext-po` (GNU gettext's `.po` and `.pot` catalogs, including `msgctxt` disambiguation and
274
+ * `msgid_plural`/`msgstr[n]` plural forms keyed by the file's own `Plural-Forms` index count).
261
275
  *
262
276
  * The set is closed: a format outside it cannot be represented, so adding one means adding a member
263
277
  * here and an adapter that claims it.
@@ -271,8 +285,12 @@ declare const supportedFormatSchema$1: z.ZodEnum<{
271
285
  yaml: "yaml";
272
286
  arb: "arb";
273
287
  properties: "properties";
288
+ "apple-strings": "apple-strings";
289
+ "apple-xcstrings": "apple-xcstrings";
290
+ "android-xml": "android-xml";
291
+ "gettext-po": "gettext-po";
274
292
  }>;
275
- /** One of the eight supported source formats; the inferred type of {@link supportedFormatSchema}. */
293
+ /** One of the twelve supported source formats; the inferred type of {@link supportedFormatSchema}. */
276
294
  type SupportedFormat$1 = z.infer<typeof supportedFormatSchema$1>;
277
295
 
278
296
  /**
@@ -404,6 +422,11 @@ declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
404
422
  glossaryId: z.ZodOptional<z.ZodString>;
405
423
  requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
406
424
  }, z.core.$strict>;
425
+ }, z.core.$strip>, z.ZodObject<{
426
+ id: z.ZodLiteral<"google-translate">;
427
+ options: z.ZodObject<{
428
+ requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
429
+ }, z.core.$strict>;
407
430
  }, z.core.$strip>, z.ZodObject<{
408
431
  id: z.ZodLiteral<"openai-compatible">;
409
432
  options: z.ZodObject<{
@@ -419,15 +442,16 @@ declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
419
442
  * carries exactly the options it supports and nothing else.
420
443
  *
421
444
  * No variant has a field for an API key. Keys are read from the environment by the provider itself
422
- * (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `DEEPL_API_KEY`), which is what keeps
423
- * them out of config files and out of version control. The `openai-compatible` variant may name a
424
- * different environment variable through `apiKeyEnvVar`, but still never holds the key itself.
445
+ * (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `DEEPL_API_KEY`, or
446
+ * `GOOGLE_TRANSLATE_API_KEY`), which is what keeps them out of config files and out of version
447
+ * control. The `openai-compatible` variant may name a different environment variable through
448
+ * `apiKeyEnvVar`, but still never holds the key itself.
425
449
  */
426
450
  type ProviderConfig = z.infer<typeof providerConfigSchema>;
427
451
  /**
428
- * The identifier of a supported translation provider: `anthropic`, `openai`, `gemini`, `deepl`, or
429
- * `openai-compatible`. The last one targets a local or self-hosted server that speaks the OpenAI
430
- * chat-completions API.
452
+ * The identifier of a supported translation provider: `anthropic`, `openai`, `gemini`, `deepl`,
453
+ * `google-translate`, or `openai-compatible`. The last one targets a local or self-hosted server
454
+ * that speaks the OpenAI chat-completions API.
431
455
  */
432
456
  type ProviderId = ProviderConfig["id"];
433
457
 
@@ -460,6 +484,10 @@ declare const verbatraConfigSchema: z.ZodObject<{
460
484
  yaml: "yaml";
461
485
  arb: "arb";
462
486
  properties: "properties";
487
+ "apple-strings": "apple-strings";
488
+ "apple-xcstrings": "apple-xcstrings";
489
+ "android-xml": "android-xml";
490
+ "gettext-po": "gettext-po";
463
491
  }>;
464
492
  files: z.ZodObject<{
465
493
  pattern: z.ZodString;
@@ -496,6 +524,11 @@ declare const verbatraConfigSchema: z.ZodObject<{
496
524
  glossaryId: z.ZodOptional<z.ZodString>;
497
525
  requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
498
526
  }, z.core.$strict>;
527
+ }, z.core.$strip>, z.ZodObject<{
528
+ id: z.ZodLiteral<"google-translate">;
529
+ options: z.ZodObject<{
530
+ requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
531
+ }, z.core.$strict>;
499
532
  }, z.core.$strip>, z.ZodObject<{
500
533
  id: z.ZodLiteral<"openai-compatible">;
501
534
  options: z.ZodObject<{
@@ -569,9 +602,9 @@ type AuthoringVariant<Id extends ProviderId, M extends string> = Extract<Provide
569
602
  } : never : never;
570
603
  /**
571
604
  * Maps each provider ID to its authoring-time config variant. The three language-model providers
572
- * get narrowed model unions; DeepL has no model to narrow, and `openai-compatible` deliberately
573
- * keeps a free-form model string because the endpoint is a local or self-hosted server whose model
574
- * list the SDK cannot know ahead of time.
605
+ * get narrowed model unions; DeepL and Google Cloud Translation have no model to narrow, and
606
+ * `openai-compatible` deliberately keeps a free-form model string because the endpoint is a local
607
+ * or self-hosted server whose model list the SDK cannot know ahead of time.
575
608
  */
576
609
  type AuthoringProviderVariant = {
577
610
  /** Anthropic, with `model` narrowed to the Claude model IDs. */
@@ -584,6 +617,13 @@ type AuthoringProviderVariant = {
584
617
  deepl: Extract<ProviderConfig, {
585
618
  id: "deepl";
586
619
  }>;
620
+ /**
621
+ * Google Cloud Translation (Basic, v2), which takes no model for the same reason as DeepL: it is
622
+ * a machine-translation API rather than a language model.
623
+ */
624
+ "google-translate": Extract<ProviderConfig, {
625
+ id: "google-translate";
626
+ }>;
587
627
  /** A local or self-hosted OpenAI-compatible endpoint, whose model stays a free-form string. */
588
628
  "openai-compatible": Extract<ProviderConfig, {
589
629
  id: "openai-compatible";
@@ -662,6 +702,14 @@ declare function defineConfig(config: AuthoringConfigFor<"gemini">): VerbatraCon
662
702
  * @returns The same object, typed as {@link VerbatraConfigInput}.
663
703
  */
664
704
  declare function defineConfig(config: AuthoringConfigFor<"deepl">): VerbatraConfigInput;
705
+ /**
706
+ * Types a `verbatra.config.ts` narrowed to the Google Cloud Translation provider. Like DeepL, it is
707
+ * a machine-translation API rather than a language model, so its options carry no model field.
708
+ *
709
+ * @param config - The config object, narrowed to the Google Cloud Translation provider.
710
+ * @returns The same object, typed as {@link VerbatraConfigInput}.
711
+ */
712
+ declare function defineConfig(config: AuthoringConfigFor<"google-translate">): VerbatraConfigInput;
665
713
  /**
666
714
  * Types a `verbatra.config.ts` for any supported provider. This is the fallback overload, and the
667
715
  * one that serves `openai-compatible`, where the model is a free-form string because the endpoint
@@ -795,8 +843,8 @@ interface LoadConfigOptions {
795
843
  */
796
844
  type ConfigSource = {
797
845
  /**
798
- * `search` means cosmiconfig found the file by walking up from the working directory;
799
- * `explicit` means the caller named it through `configPath`.
846
+ * `search` means cosmiconfig found the file by walking up from the working directory, up to
847
+ * the nearest `.git` directory; `explicit` means the caller named it through `configPath`.
800
848
  */
801
849
  readonly kind: "search" | "explicit";
802
850
  /** The absolute path of the config file that was loaded. */
@@ -821,12 +869,26 @@ interface LoadedConfig {
821
869
  *
822
870
  * Resolution order is: an explicit `configOverride`, then an explicit `configPath`, then a
823
871
  * cosmiconfig search upward from `cwd` across `verbatra.config.ts`, the `.verbatrarc` family, and a
824
- * `verbatra` property in `package.json`. A `configPath` that does not exist is an error rather than
825
- * a fallback to searching, so a typo in a path never silently loads a different project's config.
872
+ * `verbatra` property in `package.json`. The upward search stops at the nearest ancestor directory
873
+ * containing a `.git` entry; if none is found, it stops at the user's home directory when that is an
874
+ * ancestor of `cwd`, and otherwise it does not search above `cwd` at all, so a nested workspace
875
+ * package finds a config at its monorepo root without wandering above it, and a project outside the
876
+ * home directory tree (a CI checkout, for instance) never triggers an unbounded walk to the
877
+ * filesystem root. A config file outside that directory chain, including cosmiconfig's own OS-level
878
+ * global config directory, is never used, even though the underlying search strategy checks it; it is
879
+ * treated the same as no config found. A `configPath` that does not exist is an error rather than a
880
+ * fallback to searching, so a typo in a path never silently loads a different project's config.
826
881
  *
827
882
  * A glossary given as a path is read and validated here, so the returned config always carries a
828
883
  * resolved term map.
829
884
  *
885
+ * A `verbatra.config.ts` file is transpiled and loaded through jiti. When it imports `@verbatra/sdk`
886
+ * or `@verbatra/cli`, those bare specifiers are aliased to the package that is actually running this
887
+ * function, so the import resolves to the running version even when a different, conflicting version
888
+ * of either package also happens to be reachable from the config file's own location. A package is
889
+ * only aliased when its own entry point can be resolved from the running code; otherwise the import
890
+ * falls back to jiti's ordinary bare-specifier resolution, unchanged from before this behavior existed.
891
+ *
830
892
  * @param options - Where and how to look for the config.
831
893
  * @returns The validated config with its config-source and glossary provenance.
832
894
  *
@@ -841,8 +903,10 @@ declare function loadConfigWithMeta(options?: LoadConfigOptions): Promise<Loaded
841
903
  * pass the result to {@link translate}, {@link check}, {@link diff}, or any other entry point.
842
904
  *
843
905
  * Resolution order is an explicit `configOverride`, then an explicit `configPath`, then a
844
- * cosmiconfig search upward from `cwd`. A glossary declared as a file path is read and validated
845
- * here, so the returned {@link VerbatraConfig} always carries a resolved term map.
906
+ * cosmiconfig search upward from `cwd`, stopping at the nearest ancestor `.git` directory, or
907
+ * failing that, the user's home directory when it is an ancestor of `cwd`, or failing that, `cwd`
908
+ * itself. A glossary declared as a file path is read and validated here, so the returned
909
+ * {@link VerbatraConfig} always carries a resolved term map.
846
910
  *
847
911
  * Reach for {@link loadConfigWithMeta} when you also need to know which file was loaded.
848
912
  *
@@ -963,13 +1027,18 @@ declare class SdkError extends Error {
963
1027
  }
964
1028
 
965
1029
  /**
966
- * Zod schema accepting exactly one of the eight source formats verbatra can read and write. Each
1030
+ * Zod schema accepting exactly one of the twelve source formats verbatra can read and write. Each
967
1031
  * member names the ecosystem it round-trips, not just a file extension, because several of them share
968
1032
  * one: `i18next-json` is i18next's nested JSON with its plural key suffixes, `vue-i18n-json` is Vue
969
1033
  * I18n's JSON with its pipe-separated plural values, `next-intl-json` is next-intl's ICU-message JSON,
970
- * and `ngx-translate-json` is ngx-translate's nested JSON. The remaining four are `xliff` (the XLIFF
971
- * interchange XML), `yaml` (plain nested YAML), `arb` (Flutter's Application Resource Bundle), and
972
- * `properties` (Java and Spring `.properties` files).
1034
+ * and `ngx-translate-json` is ngx-translate's nested JSON. The remaining eight are `xliff` (the XLIFF
1035
+ * interchange XML), `yaml` (plain nested YAML), `arb` (Flutter's Application Resource Bundle),
1036
+ * `properties` (Java and Spring `.properties` files), `apple-strings` (Apple's flat `.strings`
1037
+ * localization format for iOS and macOS), `apple-xcstrings` (Apple's Xcode String Catalog, a single
1038
+ * JSON document holding every locale of a `.xcstrings` catalogue together), `android-xml` (Android's
1039
+ * `res/values/strings.xml` resource format, including `<plurals>` and `translatable="false"` entries),
1040
+ * and `gettext-po` (GNU gettext's `.po` and `.pot` catalogs, including `msgctxt` disambiguation and
1041
+ * `msgid_plural`/`msgstr[n]` plural forms keyed by the file's own `Plural-Forms` index count).
973
1042
  *
974
1043
  * The set is closed: a format outside it cannot be represented, so adding one means adding a member
975
1044
  * here and an adapter that claims it.
@@ -983,8 +1052,12 @@ declare const supportedFormatSchema: z.ZodEnum<{
983
1052
  yaml: "yaml";
984
1053
  arb: "arb";
985
1054
  properties: "properties";
1055
+ "apple-strings": "apple-strings";
1056
+ "apple-xcstrings": "apple-xcstrings";
1057
+ "android-xml": "android-xml";
1058
+ "gettext-po": "gettext-po";
986
1059
  }>;
987
- /** One of the eight supported source formats; the inferred type of {@link supportedFormatSchema}. */
1060
+ /** One of the twelve supported source formats; the inferred type of {@link supportedFormatSchema}. */
988
1061
  type SupportedFormat = z.infer<typeof supportedFormatSchema>;
989
1062
 
990
1063
  /**
@@ -1062,10 +1135,13 @@ interface ReadResult {
1062
1135
  */
1063
1136
  readonly invalidIcuKeys: readonly string[];
1064
1137
  /**
1065
- * Dotted paths of leaves that were present in the source but excluded because they are not
1066
- * strings (a stray number, boolean, or null). These are never translated, hashed, diffed, or
1067
- * checked for placeholder or ICU integrity, and are not written back if the file is later
1068
- * rewritten. Empty for a file with no such leaves.
1138
+ * Keys or dotted paths that were present in the source but excluded from translation: a stray
1139
+ * non-string leaf (a number, boolean, or null) for a tree-based format, or a key the format's own
1140
+ * metadata marks as not translatable. These are never translated, hashed, diffed, or checked for
1141
+ * placeholder or ICU integrity. Whether one survives a later rewrite of the same file depends on
1142
+ * the adapter: an adapter that reconstructs the whole file from `resource.entries` alone drops it,
1143
+ * while an adapter that patches only the entries it touches into the existing document (for
1144
+ * example `apple-xcstrings`) preserves it verbatim. Empty for a file with no such leaves.
1069
1145
  */
1070
1146
  readonly excludedLeafPaths: readonly string[];
1071
1147
  }
@@ -1785,6 +1861,90 @@ interface LocaleSnapshotDelta {
1785
1861
  */
1786
1862
  declare function diffLocaleSnapshots(previous: LocaleFileSnapshot, current: LocaleFileSnapshot): LocaleSnapshotDelta;
1787
1863
 
1864
+ /** One key's current source and target text within a {@link LocaleValues} map. */
1865
+ interface KeyValuePair {
1866
+ /** The key's text in the source locale, absent when the key exists only in this target (orphaned). */
1867
+ readonly source?: string;
1868
+ /** The key's text in this target locale, absent when the key has not been translated yet. */
1869
+ readonly target?: string;
1870
+ }
1871
+ /** One target locale's current source and target text for every key, as returned by {@link localeValues}. */
1872
+ interface LocaleValues {
1873
+ /** The target locale these values were read for. */
1874
+ readonly locale: string;
1875
+ /**
1876
+ * Source and target text per key, keyed by key name. Covers missing, changed, orphaned, and
1877
+ * in-sync keys alike.
1878
+ */
1879
+ readonly values: Readonly<Record<string, KeyValuePair>>;
1880
+ }
1881
+ /** Input for {@link localeValues}. */
1882
+ interface LocaleValuesInput {
1883
+ /** The resolved project config, normally from {@link loadConfig}. */
1884
+ readonly config: VerbatraConfig;
1885
+ /** Directory the `files.pattern` is resolved against. Defaults to the process working directory. */
1886
+ readonly cwd?: string;
1887
+ /** Restrict the report to these target locales. Defaults to every configured target locale. */
1888
+ readonly locales?: readonly string[];
1889
+ }
1890
+ /** Injectable dependencies for {@link localeValues}. Every field has a working default. */
1891
+ interface LocaleValuesDeps {
1892
+ /** Format-adapter registry to resolve the configured format. Defaults to the built-in registry. */
1893
+ readonly adapterRegistry?: AdapterRegistry;
1894
+ /** File-system port. Defaults to the real file system. */
1895
+ readonly fs?: SdkFs;
1896
+ }
1897
+ /**
1898
+ * Reads every key's current source and target text, across every requested target locale, in one
1899
+ * pass over the files already on disk. It writes nothing and calls no provider.
1900
+ *
1901
+ * This exists to back client-side search over translation content rather than key names alone: a
1902
+ * caller holding the result in memory can match a query against source or target text without a
1903
+ * further round trip per key. {@link keyValue} and {@link diff} answer narrower questions (one key,
1904
+ * or key names only); this is the bulk read a caller would otherwise have to simulate with many
1905
+ * {@link keyValue} calls.
1906
+ *
1907
+ * A key present in the source but not yet translated in a locale reports `target` as absent; a key
1908
+ * present in a locale but no longer in the source (orphaned) reports `source` as absent instead. A
1909
+ * target locale file that does not exist yet is treated as empty rather than as an error, so every
1910
+ * key in a newly added locale reports `target` as absent.
1911
+ *
1912
+ * Note that a malformed target locale file surfaces the adapter's own error and code rather than a
1913
+ * wrapped {@link SdkError}, because only source reads are wrapped. Its message names the offending
1914
+ * locale and the resolved path. A caller that maps SDK codes should be ready for an unrecognized
1915
+ * error from a target file.
1916
+ *
1917
+ * @param input - The config and the optional locale filter.
1918
+ * @param deps - Optional adapter registry and file-system overrides.
1919
+ * @returns Per-locale source and target text, keyed by key name.
1920
+ *
1921
+ * @throws {@link SdkError} `UNKNOWN_FORMAT`: no adapter is registered for the configured format.
1922
+ * @throws {@link SdkError} `LOCALE_LAYOUT_INVALID`: the `files.pattern` and `files.localeStyle`
1923
+ * cannot be combined, or a configured locale has no valid path spelling under that style.
1924
+ * @throws {@link SdkError} `LOCALE_PATH_COLLISION`: two configured locales resolve to the same path.
1925
+ * @throws {@link SdkError} `SOURCE_UNREADABLE`: the source locale file does not exist.
1926
+ * @throws {@link SdkError} `SOURCE_INVALID`: the source locale file could not be parsed.
1927
+ * @throws {@link SdkError} `UNKNOWN_LOCALE`: a requested locale is not a configured target locale.
1928
+ *
1929
+ * @example
1930
+ * ```ts
1931
+ * import { loadConfig, localeValues } from "@verbatra/sdk";
1932
+ *
1933
+ * const config = await loadConfig();
1934
+ * const locales = await localeValues({ config });
1935
+ *
1936
+ * const needle = "welcome";
1937
+ * for (const locale of locales) {
1938
+ * for (const [key, pair] of Object.entries(locale.values)) {
1939
+ * if (pair.target?.toLowerCase().includes(needle)) {
1940
+ * console.log(`${locale.locale} ${key}: ${pair.target}`);
1941
+ * }
1942
+ * }
1943
+ * }
1944
+ * ```
1945
+ */
1946
+ declare function localeValues(input: LocaleValuesInput, deps?: LocaleValuesDeps): Promise<readonly LocaleValues[]>;
1947
+
1788
1948
  /** One locale's lock-file baseline and the drift measured against it. */
1789
1949
  interface LockLocaleState {
1790
1950
  /** The target locale this entry describes. */
@@ -2593,9 +2753,10 @@ interface ExportWorkbookResult {
2593
2753
  * unsupported version.
2594
2754
  * @throws {@link SdkError} `UNKNOWN_LOCALE`: a requested locale is not a configured target locale.
2595
2755
  * @throws The underlying file-system error, unwrapped, when the handoff could not be written: `out`
2596
- * names a directory that does not exist or is not writable, or the device is full. Branch on the
2597
- * Node `code`, such as `ENOENT`, rather than on the message, which can name the internal temporary
2598
- * file the atomic write uses.
2756
+ * resolves to a location the process lacks permission to write, or the device is full. A missing
2757
+ * output directory is created automatically and is not a cause. Branch on the Node `code`, such as
2758
+ * `EACCES` or `ENOSPC`, rather than on the message, which can name the internal temporary file the
2759
+ * atomic write uses.
2599
2760
  */
2600
2761
  declare function exportWorkbook(input: ExportWorkbookInput, deps?: ExportWorkbookDeps): Promise<ExportWorkbookResult>;
2601
2762
 
@@ -2696,6 +2857,12 @@ interface LocalePathResolverConfig {
2696
2857
  readonly sourceLocale: string;
2697
2858
  /** Every target locale. All of them are mapped up front so collisions are caught immediately. */
2698
2859
  readonly targetLocales: readonly string[];
2860
+ /**
2861
+ * The configured format. Every format maps each locale to a distinct path except a
2862
+ * shared-catalogue format (one holding every locale in a single file, such as `apple-xcstrings`),
2863
+ * which maps every locale to the same path.
2864
+ */
2865
+ readonly format: SupportedFormat$1;
2699
2866
  /** The file layout. */
2700
2867
  readonly files: {
2701
2868
  /** The path pattern, which must contain the `{locale}` token. */
@@ -2715,6 +2882,9 @@ interface LocalePathResolver {
2715
2882
  * The configured locale owning an absolute path, or `undefined` when the path belongs to no
2716
2883
  * configured locale. The path is normalized before lookup, so a relative or non-canonical path
2717
2884
  * still resolves.
2885
+ *
2886
+ * Always `undefined` for a shared-catalogue format: every configured locale resolves to the same
2887
+ * path there, so no single locale owns it.
2718
2888
  */
2719
2889
  localeFor(absolutePath: string): string | undefined;
2720
2890
  }
@@ -2730,15 +2900,21 @@ interface LocalePathResolver {
2730
2900
  * path collision is reported here, before any file is read and before any provider is called,
2731
2901
  * rather than partway through a run.
2732
2902
  *
2903
+ * For a shared-catalogue format (such as `apple-xcstrings`), `pathFor` resolves every locale to the
2904
+ * same path (the `{locale}` token is still required in the pattern but substitutes to the empty
2905
+ * string), no locale style is applied, and `localeFor` always returns `undefined` rather than
2906
+ * reporting a collision: every configured locale sharing one path is the expected shape for these
2907
+ * formats, not a configuration mistake.
2908
+ *
2733
2909
  * @param cwd - Directory the pattern is resolved against.
2734
- * @param config - The source locale, target locales, and file layout.
2910
+ * @param config - The source locale, target locales, format, and file layout.
2735
2911
  * @returns A resolver mapping locales to paths and paths back to locales.
2736
2912
  *
2737
2913
  * @throws {@link SdkError} `LOCALE_LAYOUT_INVALID`: the pattern lacks the `{locale}` token, a
2738
2914
  * segment style's token does not stand alone between separators, or a configured locale has no
2739
2915
  * valid single-segment spelling under the declared style.
2740
2916
  * @throws {@link SdkError} `LOCALE_PATH_COLLISION`: two configured locales resolve to the same
2741
- * absolute path.
2917
+ * absolute path, for a format that is not a shared-catalogue format.
2742
2918
  */
2743
2919
  declare function createLocalePathResolver(cwd: string, config: LocalePathResolverConfig): LocalePathResolver;
2744
2920
 
@@ -2793,6 +2969,33 @@ declare function loadLockFile(input?: LoadLockFileInput, deps?: LoadLockFileDeps
2793
2969
  */
2794
2970
  declare const LOCK_FILE_NAME = "verbatra.lock.json";
2795
2971
 
2972
+ /**
2973
+ * Scrubs provider API key shapes and any currently configured provider environment variable value
2974
+ * out of a string, replacing each match with `[REDACTED]`.
2975
+ *
2976
+ * Two independent passes run: a set of shape patterns for the major providers (OpenAI-style `sk-`
2977
+ * keys, Gemini-style `AIza` keys, and hex UUID-shaped keys, with or without a `:fx` suffix), and an
2978
+ * exact-value scrub of whatever `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`,
2979
+ * `DEEPL_API_KEY`, `GOOGLE_TRANSLATE_API_KEY`, or `OPENAI_COMPATIBLE_API_KEY` currently holds in
2980
+ * the process environment. Use this on any text a surface returns to a caller that did not itself
2981
+ * generate that text, such as a file path, a config value, or an upstream error message, so a key
2982
+ * value already present in the environment or written by a user can never reach an agent, a
2983
+ * browser tab, or a log line.
2984
+ *
2985
+ * @param text - The text to scrub.
2986
+ * @returns The same text with every matching key shape and configured key value replaced by
2987
+ * `[REDACTED]`.
2988
+ *
2989
+ * @example
2990
+ * ```ts
2991
+ * import { redact } from "@verbatra/sdk";
2992
+ *
2993
+ * redact("key is sk-abcdEFGH12345678 in the log");
2994
+ * // "key is [REDACTED] in the log"
2995
+ * ```
2996
+ */
2997
+ declare function redact(text: string): string;
2998
+
2796
2999
  /**
2797
3000
  * A provider that project scaffolding can offer out of the box. It excludes `openai-compatible`,
2798
3001
  * which needs a `baseUrl` and a model name that only the user can supply, so there is nothing
@@ -2815,8 +3018,12 @@ declare const scaffoldingMetadata: {
2815
3018
  readonly openai: "OPENAI_API_KEY";
2816
3019
  readonly gemini: "GEMINI_API_KEY";
2817
3020
  readonly deepl: "DEEPL_API_KEY";
3021
+ readonly "google-translate": "GOOGLE_TRANSLATE_API_KEY";
2818
3022
  };
2819
- /** A reasonable default model to prefill per language-model provider. DeepL has none, since it takes no model. */
3023
+ /**
3024
+ * A reasonable default model to prefill per language-model provider. DeepL and Google Cloud
3025
+ * Translation have none, since neither takes a model.
3026
+ */
2820
3027
  readonly scaffoldModels: {
2821
3028
  readonly anthropic: "claude-sonnet-4-6";
2822
3029
  readonly openai: "gpt-5.4-mini";
@@ -2827,7 +3034,7 @@ declare const scaffoldingMetadata: {
2827
3034
  * not agree: Anthropic calls it `maxTokens` and the others `maxOutputTokens`. A generator that
2828
3035
  * prefills a token limit must read the key from here rather than assume one, because
2829
3036
  * {@link verbatraConfigSchema} validates each provider's options strictly and rejects the wrong
2830
- * one. DeepL has no entry, since it takes no token limit.
3037
+ * one. DeepL and Google Cloud Translation have no entry, since neither takes a token limit.
2831
3038
  */
2832
3039
  readonly providerTokenLimitKeys: {
2833
3040
  readonly anthropic: "maxTokens";
@@ -2835,7 +3042,7 @@ declare const scaffoldingMetadata: {
2835
3042
  readonly gemini: "maxOutputTokens";
2836
3043
  };
2837
3044
  /** Every i18n file format the SDK can read and write. */
2838
- readonly supportedFormats: readonly ["i18next-json", "vue-i18n-json", "next-intl-json", "ngx-translate-json", "xliff", "yaml", "arb", "properties"];
3045
+ readonly supportedFormats: readonly ["i18next-json", "vue-i18n-json", "next-intl-json", "ngx-translate-json", "xliff", "yaml", "arb", "properties", "apple-strings", "apple-xcstrings", "android-xml", "gettext-po"];
2839
3046
  };
2840
3047
 
2841
3048
  /**
@@ -2980,4 +3187,4 @@ interface WatchController {
2980
3187
  */
2981
3188
  declare function watch(input: WatchInput, deps?: WatchDeps): Promise<WatchController>;
2982
3189
 
2983
- export { type BudgetBehavior, CACHE_FILE_NAME, type CheckDeps, type CheckInput, type CheckSummary, type ConfigSource, type CreateProvider, type CreateWatcher, DEFAULT_DELIMITED_PATH, DEFAULT_EXCHANGE_FORMAT, DEFAULT_WORKBOOK_PATH, type DiffDeps, type DiffInput, type DiffSummary, type DoctorCheck, type DoctorCheckId, type DoctorCheckStatus, type DoctorDeps, type DoctorInput, type DoctorResult, type DuplicateKeyReport, EXCHANGE_FORMATS, type EditEntryDeps, type EditEntryInput, type EditEntryResult, type ExchangeFormat, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type GlossaryFileDeps, type GlossaryFileInput, type GlossaryProvenance, type ImportWorkbookDeps, type ImportWorkbookInput, type IntegrityGateReason, type KeyIntegrityDeps, type KeyIntegrityEntry, type KeyIntegrityInput, type KeyValueDeps, type KeyValueInput, type KeyValueResult, LOCK_FILE_NAME, type LoadConfigOptions, type LoadLockFileDeps, type LoadLockFileInput, type LoadedConfig, type LocaleCheckSummary, type LocaleDiff, type LocaleFileSnapshot, type LocaleFinishedEvent, type LocaleKeyIntegrity, type LocaleNotice, type LocalePathResolver, type LocalePathResolverConfig, type LocaleSnapshotDelta, type LocaleStartedEvent, type LocaleStyle, type LocaleSummary, type LockFile, type LockHolder, type LockLocaleState, type LockStateDeps, type LockStateInput, type LockStateResult, type LockWaitEvent, type LockWaitListener, type MalformedRowReport, type NeedsReviewEntry, type ProgressEvent, type ProgressListener, type ProviderConfig, type ProviderId, type ReadLocaleFileSnapshotDeps, type ReadLocaleFileSnapshotInput, type RetranslateEntryDeps, type RetranslateEntryInput, type RetranslateEntryResult, type ReviewReasonCode, type RunBudget, type RunFinishedEvent, type RunStatusDeps, type RunStatusFile, type RunStatusInput, type RunStatusLocale, type RunStatusResult, type RunSummary, type RunTranslate, type ScaffoldableProviderId, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type SubBatchProgressEvent, type SupportedFormat$1 as SupportedFormat, type TranslateDeps, type TranslateInput, type TranslationMemory, type UpdateGlossaryTermInput, type UsageSummary, type VerbatraConfig, type VerbatraConfigInput, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, check, createLocalePathResolver, defineConfig, diff, diffLocaleSnapshots, doctor, editEntry, exportWorkbook, importWorkbook, keyIntegrity, keyValue, loadConfig, loadConfigWithMeta, loadLockFile, lockState, readGlossaryFile, readLocaleFileSnapshot, retranslateEntry, runStatus, scaffoldingMetadata, translate, updateGlossaryTerm, verbatraConfigSchema, watch };
3190
+ export { type BudgetBehavior, CACHE_FILE_NAME, type CheckDeps, type CheckInput, type CheckSummary, type ConfigSource, type CreateProvider, type CreateWatcher, DEFAULT_DELIMITED_PATH, DEFAULT_EXCHANGE_FORMAT, DEFAULT_WORKBOOK_PATH, type DiffDeps, type DiffInput, type DiffSummary, type DoctorCheck, type DoctorCheckId, type DoctorCheckStatus, type DoctorDeps, type DoctorInput, type DoctorResult, type DuplicateKeyReport, EXCHANGE_FORMATS, type EditEntryDeps, type EditEntryInput, type EditEntryResult, type ExchangeFormat, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type GlossaryFileDeps, type GlossaryFileInput, type GlossaryProvenance, type ImportWorkbookDeps, type ImportWorkbookInput, type IntegrityGateReason, type KeyIntegrityDeps, type KeyIntegrityEntry, type KeyIntegrityInput, type KeyValueDeps, type KeyValueInput, type KeyValuePair, type KeyValueResult, LOCK_FILE_NAME, type LoadConfigOptions, type LoadLockFileDeps, type LoadLockFileInput, type LoadedConfig, type LocaleCheckSummary, type LocaleDiff, type LocaleFileSnapshot, type LocaleFinishedEvent, type LocaleKeyIntegrity, type LocaleNotice, type LocalePathResolver, type LocalePathResolverConfig, type LocaleSnapshotDelta, type LocaleStartedEvent, type LocaleStyle, type LocaleSummary, type LocaleValues, type LocaleValuesDeps, type LocaleValuesInput, type LockFile, type LockHolder, type LockLocaleState, type LockStateDeps, type LockStateInput, type LockStateResult, type LockWaitEvent, type LockWaitListener, type MalformedRowReport, type NeedsReviewEntry, type ProgressEvent, type ProgressListener, type ProviderConfig, type ProviderId, type ReadLocaleFileSnapshotDeps, type ReadLocaleFileSnapshotInput, type RetranslateEntryDeps, type RetranslateEntryInput, type RetranslateEntryResult, type ReviewReasonCode, type RunBudget, type RunFinishedEvent, type RunStatusDeps, type RunStatusFile, type RunStatusInput, type RunStatusLocale, type RunStatusResult, type RunSummary, type RunTranslate, type ScaffoldableProviderId, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type SubBatchProgressEvent, type SupportedFormat$1 as SupportedFormat, type TranslateDeps, type TranslateInput, type TranslationMemory, type UpdateGlossaryTermInput, type UsageSummary, type VerbatraConfig, type VerbatraConfigInput, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, check, createLocalePathResolver, defineConfig, diff, diffLocaleSnapshots, doctor, editEntry, exportWorkbook, importWorkbook, keyIntegrity, keyValue, loadConfig, loadConfigWithMeta, loadLockFile, localeValues, lockState, readGlossaryFile, readLocaleFileSnapshot, redact, retranslateEntry, runStatus, scaffoldingMetadata, translate, updateGlossaryTerm, verbatraConfigSchema, watch };