@menapo/vi18n 0.0.0-stage → 0.1.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.
Files changed (100) hide show
  1. package/LICENSE +49 -0
  2. package/README.md +110 -2
  3. package/dist/apply-Bre-lY9J.js +228 -0
  4. package/dist/captured-Bj8bO6vd.js +1034 -0
  5. package/dist/check-D34P-S--.js +1 -0
  6. package/dist/check-DyrAbv73.js +201 -0
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.js +41 -0
  9. package/dist/codec-DuvU2VQy.js +207 -0
  10. package/dist/collect-Cx4_SKOe.js +13 -0
  11. package/dist/collisions-CfpZU8e4.js +217 -0
  12. package/dist/compile-B5Mz6WJm.js +245 -0
  13. package/dist/compile-Cc97JaW2.js +2502 -0
  14. package/dist/concurrency-C9UUWuDC.js +96 -0
  15. package/dist/concurrency-DONL7t4V.js +1 -0
  16. package/dist/config.d.ts +21 -0
  17. package/dist/config.js +39 -0
  18. package/dist/dir-zw6bGMKQ.js +290 -0
  19. package/dist/duplicates-yuRljQ6h.js +185 -0
  20. package/dist/engine-B7p40M__.js +531 -0
  21. package/dist/engine.d.ts +43 -0
  22. package/dist/engine.js +1241 -0
  23. package/dist/exclude-Du-Zd_qI.js +26 -0
  24. package/dist/export-DGsMbcTZ.js +103 -0
  25. package/dist/extract-Dujlsgnk.js +298 -0
  26. package/dist/formats-KPIg-08V.js +781 -0
  27. package/dist/i18next-CrUnKFfh.js +1596 -0
  28. package/dist/i18next-Rgo-v9l0.js +1 -0
  29. package/dist/import-Cwdhcywt.js +225 -0
  30. package/dist/index.d.ts +156 -0
  31. package/dist/index.js +239 -0
  32. package/dist/init-BecCTvKi.js +792 -0
  33. package/dist/library-D5CWvTQs.js +1882 -0
  34. package/dist/lingui--PcOOYry.js +833 -0
  35. package/dist/lint.d.ts +105 -0
  36. package/dist/lint.js +971 -0
  37. package/dist/load-CQRz4PpM.js +2950 -0
  38. package/dist/load-gW-oJt1Q.js +747 -0
  39. package/dist/locales-DX4MOBFE.js +827 -0
  40. package/dist/lsp-Cq1Nuu-Q.js +31 -0
  41. package/dist/match-BGr8EXB3.js +89 -0
  42. package/dist/mcp-Cf0T7qPW.js +28 -0
  43. package/dist/merge-driver-CpiiSVIc.js +422 -0
  44. package/dist/messages-Cxa-5tR0.js +166 -0
  45. package/dist/migrate-CntqvrW4.js +1 -0
  46. package/dist/migrate-dPgq9uzy.js +1484 -0
  47. package/dist/openai-CTaMDcl-.js +346 -0
  48. package/dist/output-DsaHKHEt.js +164 -0
  49. package/dist/parse.d.ts +62 -0
  50. package/dist/parse.js +156 -0
  51. package/dist/pipeline-C7g11THL.js +2031 -0
  52. package/dist/pipeline-wxS0SApG.js +1 -0
  53. package/dist/project-Dwx7iPm6.js +381 -0
  54. package/dist/project-pXipT8iG.js +1046 -0
  55. package/dist/pseudo-DRv30iN5.js +145 -0
  56. package/dist/raw-C4Y6vyGY.js +4708 -0
  57. package/dist/react-intl-CaBVwJ9u.js +519 -0
  58. package/dist/restore-Btq66Tid.js +175 -0
  59. package/dist/rewrite-CiTRAICl.js +803 -0
  60. package/dist/rich-DCUKl5HM.js +97 -0
  61. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  62. package/dist/run-DYD_VXKy.js +694 -0
  63. package/dist/runtime-DTMmliT1.js +64 -0
  64. package/dist/scan-worker.d.ts +62 -0
  65. package/dist/scan-worker.js +1 -0
  66. package/dist/scoped-BMYpSthj.js +44 -0
  67. package/dist/server-BDkykMjb.js +11823 -0
  68. package/dist/server-qv3mz70d.js +10485 -0
  69. package/dist/server.d.ts +169 -0
  70. package/dist/server.js +1234 -0
  71. package/dist/sitemap-DV3o8QD7.js +159 -0
  72. package/dist/sources-D19czDSA.js +2242 -0
  73. package/dist/status-DZArW5aE.js +149 -0
  74. package/dist/stdio-CVaJfxA7.js +29 -0
  75. package/dist/stdio-FPOKQAgu.js +95 -0
  76. package/dist/sync-CcVzger_.js +658 -0
  77. package/dist/t-DC-c9zE5.js +454 -0
  78. package/dist/test.d.ts +116 -0
  79. package/dist/test.js +319 -0
  80. package/dist/translate-DZR3MkSA.js +299 -0
  81. package/dist/ts-BaU5yOf0.js +4863 -0
  82. package/dist/types-CgUCkFU1.d.ts +707 -0
  83. package/dist/types-D3QGM8XO.js +146 -0
  84. package/dist/types-DsdWBG0b.d.ts +558 -0
  85. package/dist/types-DtvQ7UdD.js +1948 -0
  86. package/dist/types-wSh9fCBY.js +11 -0
  87. package/dist/units-CQ5Q99RC.js +150 -0
  88. package/dist/url-CRfCOhUI.js +172 -0
  89. package/dist/url-CsBkRaJy.js +225 -0
  90. package/dist/validate-BxpupdAf.js +2615 -0
  91. package/dist/validate-D6DJepZv.js +365 -0
  92. package/dist/version-BlyLGlOa.js +28 -0
  93. package/dist/vite-scan-B_YW4X_a.js +242 -0
  94. package/dist/vite.d.ts +34 -0
  95. package/dist/vite.js +7558 -0
  96. package/dist/vue-i18n-CEMnpv7k.js +651 -0
  97. package/dist/which-C6PFI1Dm.js +116 -0
  98. package/dist/worker-84U6uYB3.js +1656 -0
  99. package/package.json +97 -3
  100. package/schemas/catalog.json +57 -0
@@ -0,0 +1,707 @@
1
+ //#region src/runtime/types.d.ts
2
+ /** Where a locale may come from, in `routing.strategy` order. */
3
+ type LocaleStrategy = "url" | "cookie" | "header" | "localStorage" | "default";
4
+ /** URL codec strategies (Nuxt i18n names); domains are `routing.domains` on top of `prefix_except_default`. */
5
+ type UrlStrategy = "prefix_except_default" | "prefix" | "prefix_and_default" | "no_prefix";
6
+ declare global {
7
+ /**
8
+ * Defined by `vi18n:config` (`true` in `vite dev`, `false` in builds). Runtime
9
+ * code reads it as `typeof __VI18N_DEV__ !== "undefined" && __VI18N_DEV__`, so
10
+ * code bundled without the plugin behaves as production. `var`, not `const`:
11
+ * the two pack configs each inline this file into their own `.d.ts` chunk,
12
+ * and a consumer importing both would hit a block-scoped redeclaration.
13
+ */
14
+ var __VI18N_DEV__: boolean | undefined;
15
+ /**
16
+ * Defined by `vi18n:config`: whether the config has `routing.paths` or
17
+ * `routing.domains`. Code bundled without the plugin keeps the support
18
+ * (`typeof __VI18N_ROUTES__ === "undefined" || __VI18N_ROUTES__`), and a
19
+ * plugin build of a config without either folds it out (PLAN §6).
20
+ */
21
+ var __VI18N_ROUTES__: boolean | undefined;
22
+ /**
23
+ * Defined by `vi18n:config`: whether `ssr.payload` is `"preload"`. Code
24
+ * bundled without the plugin keeps the support (a Nitro-built `/server`
25
+ * copy reads the registration's config), and a plugin build of the default
26
+ * config folds it out of the engine and `/server` (PLAN §6).
27
+ */
28
+ var __VI18N_PRELOAD__: boolean | undefined;
29
+ /**
30
+ * Defined by `vi18n:config`: whether `output.compactIds` is on. Only the
31
+ * plugin's boot module imports the engine, so undefined reads as false.
32
+ */
33
+ var __VI18N_COMPACT__: boolean | undefined;
34
+ /**
35
+ * Defined by `vi18n:config`: whether `output.perLocale` is on. Undefined
36
+ * is false, as for `__VI18N_COMPACT__`.
37
+ */
38
+ var __VI18N_INLINE__: boolean | undefined;
39
+ }
40
+ //#endregion
41
+ //#region src/core/types.d.ts
42
+ type Severity = "error" | "warning" | "info";
43
+ /**
44
+ * Every problem vi18n reports has one of these codes. The CLI prints them in
45
+ * `--json` and as GitHub annotation titles (`vi18n(<code>)`).
46
+ */
47
+ type DiagnosticCode = "icu-syntax" | "icu-missing-other" | "icu-unsupported-type" | "icu-pattern-style" | "icu-pound-nested" | "icu-unknown-skeleton" | "icu-unknown-currency" | "icu-unknown-unit" | "icu-bidi-control" | "icu-unbalanced-isolate" | "icu-argument-mismatch" | "icu-tag-mismatch" | "icu-plural-missing-category" | "icu-plural-unused-category" | "icu-plural-one-literal" | "icu-apostrophe" | "icu-max-length" | "extract-dynamic-message" | "extract-non-literal-option" | "extract-invalid-manual-id" | "extract-module-scope" | "extract-html-sink" | "extract-captured-value" | "extract-wrapper-unused" | "extract-outside-include" | "extract-parse-error" | "extract-missing-compiler" | "extract-empty-root" | "id-collision" | "id-scheme-mismatch" | "catalog-parse" | "catalog-duplicate" | "catalog-wrapped" | "catalog-foreign-context" | "catalog-source-mismatch" | "catalog-fuzzy" | "catalog-invalid-translation" | "catalog-missing-translation" | "catalog-unused-entry" | "catalog-obsolete-dropped" | "catalog-safety-limit" | "catalog-drift" | "catalog-write-conflict" | "keep-missing-entry" | "import-parse" | "import-skipped" | "restore-git" | "merge-conflict" | "config-invalid" | "config-not-found" | "build-guard-skipped" | "build-dead-messages" | "ai-validation-failed" | "ai-identical-output" | "ai-provider-error" | "ai-missing-key" | "ai-cost-limit" | "migrate-dynamic-key" | "migrate-date-placeholder" | "migrate-manual" | "migrate-unconverted";
48
+ interface Diagnostic {
49
+ code: DiagnosticCode;
50
+ severity: Severity;
51
+ /** One sentence, no trailing period, naming what to do when there is a fix. */
52
+ message: string;
53
+ /** Posix path relative to the config root (or absolute outside it). */
54
+ file?: string;
55
+ /** 1-based; 0 or absent when unknown. */
56
+ line?: number;
57
+ column?: number;
58
+ locale?: string;
59
+ /** Message id or manual id concerned. */
60
+ id?: string;
61
+ /** Other places involved, e.g. the second text of a collision. */
62
+ related?: {
63
+ file?: string;
64
+ line?: number;
65
+ column?: number;
66
+ message: string;
67
+ }[];
68
+ /** Offsets in the scanned code; set only under `ScanOptions.ranges` (the `/lint` rules report at them). */
69
+ range?: [number, number];
70
+ }
71
+ /**
72
+ * Errors thrown by core functions (codec, parsers, loaders) carry the
73
+ * diagnostic, so callers in any module can report them without `instanceof`.
74
+ */
75
+ interface DiagnosticError extends Error {
76
+ diagnostic: Diagnostic;
77
+ }
78
+ /** UTF-16 offsets into the parsed string (after NFC and LF normalisation). */
79
+ interface IcuLoc {
80
+ start: number;
81
+ end: number;
82
+ }
83
+ type IcuNode = IcuLiteral | IcuArgument | IcuFormatted | IcuSelect | IcuPlural | IcuPound | IcuTag;
84
+ /** A parsed message: nodes in order; adjacent literals are merged; `[]` is the empty message. */
85
+ type IcuMessage = IcuNode[];
86
+ /** Literal text with quoting removed (`''` → `'`, `'{'` → `{`). Never empty. */
87
+ interface IcuLiteral {
88
+ type: "literal";
89
+ value: string;
90
+ loc?: IcuLoc;
91
+ }
92
+ /** `{name}` */
93
+ interface IcuArgument {
94
+ type: "argument";
95
+ name: string;
96
+ loc?: IcuLoc;
97
+ }
98
+ /** `{name, number|date|time[, style]}` */
99
+ interface IcuFormatted {
100
+ type: "number" | "date" | "time";
101
+ name: string;
102
+ style: IcuStyle | null;
103
+ /**
104
+ * Intl options resolved by the parser (FormatJS `formats` tables for
105
+ * keywords, skeleton conversion for `::…`). Null when Intl defaults apply.
106
+ */
107
+ options: {
108
+ [option: string]: string | number | boolean;
109
+ } | null;
110
+ loc?: IcuLoc;
111
+ }
112
+ /**
113
+ * A style as written, normalised: keywords as-is; skeletons without the
114
+ * leading `::`, tokens separated by exactly one space.
115
+ */
116
+ type IcuStyle = {
117
+ kind: "keyword";
118
+ value: "integer" | "percent" | "short" | "medium" | "long" | "full";
119
+ } | {
120
+ kind: "skeleton";
121
+ value: string;
122
+ };
123
+ /** One branch of a select or plural, in source order. */
124
+ interface IcuOption {
125
+ /** Select value, `=N` normalised to `"=" + String(Number(N))` (`=01` is `=1`), or a CLDR category / `other`. */
126
+ key: string;
127
+ value: IcuMessage;
128
+ loc?: IcuLoc;
129
+ }
130
+ /** `{name, select, …}` */
131
+ interface IcuSelect {
132
+ type: "select";
133
+ name: string;
134
+ options: IcuOption[];
135
+ loc?: IcuLoc;
136
+ }
137
+ /** `{name, plural|selectordinal, [offset:N] …}` */
138
+ interface IcuPlural {
139
+ type: "plural";
140
+ pluralType: "cardinal" | "ordinal";
141
+ name: string;
142
+ /** 0 when absent. */
143
+ offset: number;
144
+ options: IcuOption[];
145
+ loc?: IcuLoc;
146
+ }
147
+ /** `#` in an immediate plural/selectordinal branch (also inside tags there). */
148
+ interface IcuPound {
149
+ type: "pound";
150
+ loc?: IcuLoc;
151
+ }
152
+ /** `<name>…</name>`, or `<name/>` when `children` is null. No attributes. */
153
+ interface IcuTag {
154
+ type: "tag";
155
+ name: string;
156
+ children: IcuMessage | null;
157
+ loc?: IcuLoc;
158
+ }
159
+ /**
160
+ * The one place that turns source text into ids. Built by `createCodec(length)`
161
+ * (`src/core/codec.ts`). Wave-1 modules receive it as a parameter.
162
+ */
163
+ interface MessageCodec {
164
+ /** `ids.length`, 8–16. */
165
+ readonly idLength: number;
166
+ /** `sha256-b64u-<idLength>-v2` (PO `X-Vi18n-Id`, JSON `idScheme`). */
167
+ readonly idScheme: string;
168
+ /** NFC + LF, parse, canonical print. Throws a {@link DiagnosticError} (`icu-*`) on invalid ICU. */
169
+ canonicalize(source: string): string;
170
+ /**
171
+ * Parse after NFC + LF normalisation; memoised, so the same AST object is
172
+ * returned for the same string and must not be mutated. Throws like `canonicalize`.
173
+ */
174
+ parse(source: string): IcuMessage;
175
+ /** `base64url(sha256(utf8(canonical + "\u001F")))`, 43 characters. */
176
+ sourceHash(canonical: string): string;
177
+ /** The first `idLength` characters of `sourceHash`: a generated id, or a manual entry's label. */
178
+ label(canonical: string): string;
179
+ }
180
+ /** How a message argument reached vi18n. */
181
+ type CalleeKind = "t" | "msg" | "rich" | "richHtml" | "richParts" | "alias" | "global" | "translator";
182
+ /** One message at one call site. JSON-serialisable: it is cached and stored in `meta.vi18n`. */
183
+ interface MessageOccurrence {
184
+ /** Generated id (`label`) or the manual id. */
185
+ id: string;
186
+ manual: boolean;
187
+ /** The exact JS string value at the call site (a `sources.json` key). */
188
+ source: string;
189
+ canonical: string;
190
+ /** 43-character hash of `canonical`. */
191
+ sourceHash: string;
192
+ /** Generated id of `canonical`; equals `id` when `manual` is false. */
193
+ label: string;
194
+ /** The `context` note as written (may span lines). */
195
+ context?: string;
196
+ maxLength?: number;
197
+ callee: CalleeKind;
198
+ /** Posix path relative to the config root (a `#:` reference). */
199
+ file: string;
200
+ /** 1-based position in the original file; 0 when not yet located. */
201
+ line: number;
202
+ column: number;
203
+ }
204
+ //#endregion
205
+ //#region src/ai/types.d.ts
206
+ /** Whatever a provider needs to answer one request. One target locale per request. */
207
+ interface ProviderRequest {
208
+ sourceLocale: string;
209
+ targetLocale: string;
210
+ /**
211
+ * Stable system prefix (product description, tone, ICU rules, required plural
212
+ * categories); identical across batches of a locale so implicit caching applies.
213
+ */
214
+ system: string;
215
+ /** Items to translate, deduplicated across routes; 40–80 per request. */
216
+ items: AiItem[];
217
+ /** JSON Schema of the expected answer (Gemini `responseJsonSchema`). */
218
+ responseSchema: JsonSchema;
219
+ }
220
+ /** One item, sent as data. Text is masked: URLs, e-mail addresses and HTML entities become `@@PHn@@`. */
221
+ interface AiItem {
222
+ /** Catalog key: generated id or manual id. Results are mapped back by this. */
223
+ id: string;
224
+ /** Canonical source, masked. */
225
+ source: string;
226
+ /** The developer's `context` notes, joined with "\n" (D3). */
227
+ context?: string;
228
+ /**
229
+ * Route and file context: the config-relative files that use the message
230
+ * (at most 5, sorted). A file-based router's path names the screen.
231
+ */
232
+ files?: string[];
233
+ /** Argument names in the source, in first-use order. */
234
+ placeholders: string[];
235
+ /** Tag names in the source. */
236
+ tags: string[];
237
+ maxLength?: number;
238
+ /** Plural categories the target locale needs, when the message has a plural. */
239
+ pluralCategories?: {
240
+ cardinal: string[];
241
+ ordinal: string[];
242
+ };
243
+ /** Nearest non-`ai` translations in the target locale (masked). Never AI output. */
244
+ examples: {
245
+ source: string;
246
+ translation: string;
247
+ }[];
248
+ /** Retries only: the checks the previous answer failed. */
249
+ failingChecks?: string[];
250
+ }
251
+ /** A provider's answer. `items` may be partial; missing ids count as failures. */
252
+ interface ProviderResponse {
253
+ items: {
254
+ id: string;
255
+ translation: string;
256
+ }[];
257
+ usage?: {
258
+ inputTokens: number;
259
+ outputTokens: number;
260
+ };
261
+ }
262
+ /** What the pipeline passes with each request. */
263
+ interface TranslateOptions {
264
+ signal?: AbortSignal;
265
+ /**
266
+ * Call on every rate limit (HTTP 429, `RESOURCE_EXHAUSTED`) before waiting
267
+ * it out, with the delay the server asked for when it named one: the
268
+ * pipeline halves its concurrency and holds new requests that long.
269
+ */
270
+ onRateLimit?: (retryAfterMs: number | null) => void;
271
+ }
272
+ /** A pluggable translation backend (`ai.provider`). */
273
+ interface TranslationProvider {
274
+ /** `"gemini"`, `"openai-compatible"`, or a custom name. */
275
+ readonly name: string;
276
+ readonly model: string;
277
+ translate(request: ProviderRequest, options?: TranslateOptions): Promise<ProviderResponse>;
278
+ /**
279
+ * `--dry-run` / `--max-cost`: estimated USD for the given token counts, from a
280
+ * pinned price table; `NaN` when the model has no known price.
281
+ */
282
+ estimateCost?(usage: {
283
+ inputTokens: number;
284
+ outputTokens: number;
285
+ }): number;
286
+ /**
287
+ * The environment variable the key is read from, null when no key is sent.
288
+ * The CLI redacts its value from all output.
289
+ */
290
+ readonly apiKeyEnv?: string | null;
291
+ /** The `ai-missing-key` a call would fail with now, or null; asked before the first request. */
292
+ missingKey?(): Diagnostic | null;
293
+ /** The same provider with another model (`--model`). */
294
+ withModel?(model: string): TranslationProvider;
295
+ /**
296
+ * P2 Batch tier (`--tier batch`): answers many requests in asynchronous
297
+ * jobs at a lower price, in request order. A request the job failed is a
298
+ * `DiagnosticError` (`ai-provider-error`) in its place; a failed job throws.
299
+ */
300
+ translateBatch?(requests: readonly ProviderRequest[], options?: BatchOptions): Promise<(ProviderResponse | DiagnosticError)[]>;
301
+ }
302
+ interface BatchOptions {
303
+ signal?: AbortSignal;
304
+ /** Progress while a job runs (its name and state), for the terminal. */
305
+ onProgress?: (progress: {
306
+ job: string;
307
+ state: string;
308
+ requests: number;
309
+ }) => void;
310
+ }
311
+ /** P2 Gemini service tiers (`--tier`); Flex and Batch cost half, Batch answers asynchronously. */
312
+ type Tier = "standard" | "flex" | "batch";
313
+ /** Options shared by provider factories. Keys come only from the environment. */
314
+ interface ProviderOptions {
315
+ model?: string;
316
+ /** Name of the env variable holding the key. */
317
+ apiKeyEnv?: string;
318
+ /** A key is only sent to a host other than the provider's default when `apiKeyEnv` is set explicitly. */
319
+ baseURL?: string;
320
+ /** Gemini only. Default `"standard"`. */
321
+ tier?: Tier;
322
+ /** Injected in tests (recorded fixtures). Defaults to `globalThis.fetch`. */
323
+ fetch?: typeof fetch;
324
+ /** Injected in tests. Defaults to `process.env`. */
325
+ env?: {
326
+ readonly [name: string]: string | undefined;
327
+ };
328
+ }
329
+ /** `openaiCompatible(options)`: any `/chat/completions` API (OpenAI, OpenRouter, Ollama, Gemini's OpenAI endpoint). */
330
+ interface OpenAICompatibleOptions extends Omit<ProviderOptions, "tier"> {
331
+ model: string;
332
+ /** Default `https://api.openai.com/v1`. */
333
+ baseURL?: string;
334
+ /**
335
+ * Env variable holding the key, sent as `Authorization: Bearer`. Default
336
+ * `OPENAI_API_KEY`, and only to the default host: another host gets no key
337
+ * unless this names one (Ollama needs none).
338
+ */
339
+ apiKeyEnv?: string;
340
+ /**
341
+ * How the answer's shape is requested: `json_schema` (structured output,
342
+ * the default), `json_object`, or `text` (the prompt alone). A server that
343
+ * refuses one is asked again with the next.
344
+ */
345
+ responseFormat?: "json_schema" | "json_object" | "text";
346
+ /** USD per 1M input and output tokens, for `--dry-run` and `--max-cost`; without it the cost is unknown. */
347
+ prices?: {
348
+ input: number;
349
+ output: number;
350
+ };
351
+ }
352
+ /** A JSON Schema object (the Gemini `responseJsonSchema` subset). */
353
+ type JsonSchema = {
354
+ [keyword: string]: unknown;
355
+ };
356
+ //#endregion
357
+ //#region src/config/types.d.ts
358
+ /** Severity of a `strict` rule. */
359
+ type Level = "off" | "warn" | "error";
360
+ /** The two generated pseudo-locales (PLAN §4.7, §5.21). */
361
+ type PseudoLocale = "en-XA" | "ar-XB";
362
+ /** `vi18n.config.ts` as written. Every key is optional except where noted. */
363
+ interface Vi18nConfig {
364
+ /** Default `"en"`. Also the default locale of URL strategies and negotiation. */
365
+ sourceLocale?: string;
366
+ /** Default `[sourceLocale]`. Must contain `sourceLocale`. */
367
+ locales?: string[];
368
+ /** Default `[]`. Listed pseudo-locales are active in `vite dev` and in builds whose mode is not `production`. */
369
+ pseudoLocales?: PseudoLocale[];
370
+ /** Appended after the tag-derived chain (`de-CH` → `de`), before `sourceLocale`. */
371
+ fallbacks?: {
372
+ [locale: string]: string[];
373
+ };
374
+ project?: {
375
+ /** Directories or files, relative to the config file. Default `["src"]`. */
376
+ include?: string[];
377
+ extensions?: string[];
378
+ /** gitignore-style: a pattern without `/` matches any path segment; one with `/` (a leading `/` too) is a glob from the config root. */
379
+ exclude?: string[];
380
+ };
381
+ extraction?: {
382
+ /** Appended to the defaults `@menapo/vi18n` and `@menapo/vi18n/server`, which always apply. */
383
+ importSources?: string[];
384
+ /** Other exported names that behave like `t` (matched only when imported from an import source). */
385
+ aliases?: string[];
386
+ /** Import-free template callees such as Vue's `$t` (bare, `_ctx.` and `$setup.` forms). */
387
+ globals?: string[];
388
+ /** Ids that always ship (dynamic keys); `base` in SPAs, `shared` otherwise. */
389
+ keep?: string[];
390
+ /**
391
+ * Published packages (by name) whose code vi18n extracts and rewrites
392
+ * like the app's, and whose catalogs it reads under the app's own
393
+ * (`package.json#vi18n`). Default `[]`.
394
+ */
395
+ dependencies?: string[];
396
+ };
397
+ ids?: {
398
+ /** Base64url characters of every generated id, 8–16. Default 12. Changing it is a re-key. */
399
+ length?: number;
400
+ };
401
+ catalogs?: {
402
+ format?: "po" | "json";
403
+ /** Relative to the config file, with `{locale}`. Default `locales/{locale}.po` (`.json` for JSON). */
404
+ path?: string;
405
+ msgid?: "source" | "id";
406
+ /**
407
+ * PO only: mark every entry `#, icu-message-format`, which turns on
408
+ * Weblate's ICU MessageFormat checks. vi18n owns the flag: `vi18n extract`
409
+ * adds it to every entry, or removes it when false. Default false.
410
+ */
411
+ icuFlag?: boolean;
412
+ };
413
+ output?: OutputOptions;
414
+ routing?: {
415
+ strategy?: LocaleStrategy[];
416
+ routeStrategies?: {
417
+ [pattern: string]: LocaleStrategy[];
418
+ };
419
+ url?: UrlStrategy;
420
+ redirectRoot?: boolean;
421
+ propagate?: "header" | false;
422
+ switch?: "in-place" | "navigate";
423
+ cookie?: {
424
+ name?: string;
425
+ maxAge?: number;
426
+ };
427
+ /**
428
+ * The path the app's pages live under, as the URL codec reads it
429
+ * (`/de/pricing` under `/` names German). Default: Vite's `base`. Set it
430
+ * where Vite's base is an asset prefix instead (Nuxt: `app.baseURL`,
431
+ * while Vite's base is `/_nuxt/` in dev). null is the default.
432
+ */
433
+ base?: string | null;
434
+ /**
435
+ * Localized paths: route path → locale → that locale's path, e.g.
436
+ * `{ "/about": { de: "/ueber-uns" } }` puts the German page at
437
+ * `/de/ueber-uns` while the router still sees `/about`. Paths are
438
+ * base-free; a `*` segment stands for one segment and a final `**` for
439
+ * any number, and each translation keeps them in order
440
+ * (`{ "/blog/*": { de: "/artikel/*" } }`).
441
+ */
442
+ paths?: {
443
+ [path: string]: {
444
+ [locale: string]: string;
445
+ };
446
+ };
447
+ /**
448
+ * Domain routing: host → the locale it serves, e.g.
449
+ * `{ "example.com": "en", "example.de": "de" }`. A key is a host
450
+ * (`https` assumed) or an origin (`http://localhost:5173`); a locale's
451
+ * first host is where links to it go. Every locale needs a host, and
452
+ * `url` stays `prefix_except_default`: on a listed host its locale is
453
+ * unprefixed, on any other host (dev servers, previews) the prefixes
454
+ * apply. The hosts are an allowlist: links and redirects never name
455
+ * another.
456
+ */
457
+ domains?: {
458
+ [host: string]: string;
459
+ };
460
+ };
461
+ ssr?: {
462
+ timeZone?: string;
463
+ timeZoneFrom?: {
464
+ [pattern: string]: "config" | "request";
465
+ };
466
+ /**
467
+ * `"bundles"` (default): the page's client bundles are inlined into its
468
+ * SSR payload. `"preload"`: the payload names them and the page gets one
469
+ * `<link rel="preload" as="fetch" crossorigin>` per bundle instead, which
470
+ * the client runtime's fetch takes over, so bundles cache across pages.
471
+ */
472
+ payload?: "bundles" | "preload";
473
+ /**
474
+ * Where a Vite-built server reads its catalogs. `"modules"`: lazy JSON
475
+ * modules in the server bundle. `"assets"`: files in the client output
476
+ * (`vi18n/<v>/<locale>/`), read through the Workers static-assets binding
477
+ * `env.ASSETS`, at most `maxLoadedLocales` locales loaded. `"auto"`
478
+ * (default): `"assets"` in a server environment that targets workerd
479
+ * (its resolve conditions include `workerd`, as @cloudflare/vite-plugin's
480
+ * do) of a build with a client entry, `"modules"` everywhere else.
481
+ */
482
+ catalogs?: "auto" | "modules" | "assets";
483
+ /**
484
+ * With catalogs read from static assets: how many locales a server
485
+ * instance keeps loaded, the source locale included; the least recently
486
+ * used beyond it is dropped and read again when a request needs it.
487
+ * Default 8.
488
+ */
489
+ maxLoadedLocales?: number;
490
+ normalizeSpaces?: boolean;
491
+ };
492
+ ai?: {
493
+ /** `"gemini"` (default) or a provider object: `openaiCompatible({ … })` or a custom one. */
494
+ provider?: "gemini" | TranslationProvider;
495
+ model?: string;
496
+ /**
497
+ * What AI never translates: configured locales, message ids, and globs
498
+ * (with `/` or `*`) over the config-relative files that use a message.
499
+ */
500
+ exclude?: string[];
501
+ /**
502
+ * Required translations of source terms per locale (a language such as
503
+ * `de` covers `de-CH`): `{ workspace: { de: "Arbeitsbereich" } }`.
504
+ */
505
+ glossary?: {
506
+ [term: string]: {
507
+ [locale: string]: string;
508
+ };
509
+ };
510
+ /** Names copied unchanged into every locale, e.g. `["Tidepool", "Wi-Fi"]`. */
511
+ doNotTranslate?: string[];
512
+ /** Tone and formality per locale, e.g. `{ de: "informal (du)" }`. */
513
+ tone?: {
514
+ [locale: string]: string;
515
+ };
516
+ /** Product description for the stable system prompt prefix. */
517
+ description?: string;
518
+ /** Environment variable holding the key. Default `GEMINI_API_KEY`. */
519
+ apiKeyEnv?: string;
520
+ /** Items per request, 40–80. Default 60. */
521
+ batchSize?: number;
522
+ /** Most requests in flight; halved on rate limits and regained gradually. Default 4. */
523
+ concurrency?: number;
524
+ /**
525
+ * P2: in `vite dev`, translate new messages in the background (debounced,
526
+ * off the transform path) and write them as `ai` entries. Default false.
527
+ */
528
+ dev?: boolean;
529
+ };
530
+ /**
531
+ * Global rich-text tag handlers (PLAN §5.16): the element a message tag
532
+ * renders as when a call passes no handler of its own, in `richHtml()`
533
+ * and, in React, Preact and Vue, in `rich()`.
534
+ */
535
+ defaults?: {
536
+ tags?: {
537
+ [tag: string]: TagDefault;
538
+ };
539
+ };
540
+ /**
541
+ * `vite dev` only: Alt+click on text opens the in-context editor, which
542
+ * writes translations into the catalogs (INTERNALS §2.18). Builds never
543
+ * carry it. Default `false`.
544
+ */
545
+ devtools?: boolean;
546
+ /** `true` sets every rule to `"error"`. */
547
+ strict?: boolean | {
548
+ missing?: Level;
549
+ invalid?: Level;
550
+ moduleScope?: Level;
551
+ };
552
+ }
553
+ /** `output.*`: settings that matter to the build alone, also accepted inline by `vi18n({ output })`. */
554
+ interface OutputOptions {
555
+ split?: {
556
+ shared?: "per-set" | "single";
557
+ /** Source-locale bytes below which a set shared by several roots is duplicated. */
558
+ dupBelow?: number;
559
+ /** `s.*` bundles smaller than this coalesce into `shared`. */
560
+ minBytes?: number;
561
+ /** Cap on `s.*` bundles per root (spike S4); extra sets coalesce into `shared`. Default: no cap. */
562
+ maxBundlesPerRoot?: number | null;
563
+ };
564
+ guard?: "auto" | "always" | "off";
565
+ /** Stable URL outside `assetsDir`, relative to `base`, with `{locale}`. */
566
+ manifestPath?: string;
567
+ /** `"module"` puts the manifest into the runtime chunk (build-time `ssr:false` shells). */
568
+ manifest?: "data" | "module";
569
+ /** Globs on facade module ids that act as `base` entries in SSR builds. */
570
+ baseEntries?: string[];
571
+ /**
572
+ * Bundles as JSON arrays of messages, mapped to ids by position through one
573
+ * `ids.<v>.json` per build version that every locale shares. Default false.
574
+ */
575
+ compactIds?: boolean;
576
+ /**
577
+ * One client build per locale with its translations inlined into the
578
+ * JavaScript (static SPAs): no bundle fetches, and switching locale loads
579
+ * the other locale's build. Default false.
580
+ */
581
+ perLocale?: boolean;
582
+ }
583
+ /**
584
+ * The validated config with every default applied. Paths are absolute;
585
+ * `catalogs.path` keeps its `{locale}` placeholder.
586
+ */
587
+ interface ResolvedConfig {
588
+ /** Directory of `vi18n.config.ts`, or the Vite root / cwd when there is none. */
589
+ root: string;
590
+ /** Absolute path of the config file; null in zero-config mode. */
591
+ configFile: string | null;
592
+ sourceLocale: string;
593
+ locales: string[];
594
+ pseudoLocales: PseudoLocale[];
595
+ fallbacks: {
596
+ [locale: string]: string[];
597
+ };
598
+ project: {
599
+ include: string[];
600
+ extensions: string[];
601
+ exclude: string[];
602
+ };
603
+ extraction: {
604
+ importSources: string[];
605
+ aliases: string[];
606
+ globals: string[];
607
+ keep: string[];
608
+ dependencies: string[];
609
+ };
610
+ ids: {
611
+ length: number;
612
+ };
613
+ catalogs: {
614
+ format: "po" | "json";
615
+ path: string;
616
+ msgid: "source" | "id";
617
+ icuFlag: boolean;
618
+ };
619
+ output: {
620
+ split: {
621
+ shared: "per-set" | "single";
622
+ dupBelow: number;
623
+ minBytes: number;
624
+ maxBundlesPerRoot: number | null;
625
+ };
626
+ guard: "auto" | "always" | "off";
627
+ manifestPath: string;
628
+ manifest: "data" | "module";
629
+ baseEntries: string[];
630
+ compactIds: boolean;
631
+ perLocale: boolean;
632
+ };
633
+ routing: {
634
+ strategy: LocaleStrategy[];
635
+ routeStrategies: {
636
+ [pattern: string]: LocaleStrategy[];
637
+ };
638
+ url: UrlStrategy;
639
+ redirectRoot: boolean;
640
+ propagate: "header" | false;
641
+ switch: "in-place" | "navigate";
642
+ cookie: {
643
+ name: string;
644
+ maxAge: number;
645
+ };
646
+ /** `routing.base`; null: the environment's Vite `base`. */
647
+ base: string | null;
648
+ paths: {
649
+ [path: string]: {
650
+ [locale: string]: string;
651
+ };
652
+ };
653
+ /** Keys in origin form: `https://example.de`, `http://localhost:5173`. */
654
+ domains: {
655
+ [origin: string]: string;
656
+ };
657
+ };
658
+ ssr: {
659
+ timeZone: string;
660
+ timeZoneFrom: {
661
+ [pattern: string]: "config" | "request";
662
+ };
663
+ payload: "bundles" | "preload";
664
+ catalogs: "auto" | "modules" | "assets";
665
+ maxLoadedLocales: number;
666
+ normalizeSpaces: boolean;
667
+ };
668
+ ai: {
669
+ provider: "gemini" | TranslationProvider;
670
+ model: string;
671
+ exclude: string[];
672
+ glossary: {
673
+ [term: string]: {
674
+ [locale: string]: string;
675
+ };
676
+ };
677
+ doNotTranslate: string[];
678
+ tone: {
679
+ [locale: string]: string;
680
+ };
681
+ description: string | null;
682
+ apiKeyEnv: string;
683
+ batchSize: number;
684
+ concurrency: number;
685
+ dev: boolean;
686
+ };
687
+ defaults: {
688
+ tags: {
689
+ [tag: string]: TagDefault;
690
+ };
691
+ };
692
+ devtools: boolean;
693
+ strict: {
694
+ missing: Level;
695
+ invalid: Level;
696
+ moduleScope: Level;
697
+ };
698
+ }
699
+ /** A `defaults.tags` entry: an HTML element name, or the element with fixed attributes. */
700
+ type TagDefault = string | {
701
+ element: string;
702
+ attributes?: {
703
+ [name: string]: string;
704
+ };
705
+ };
706
+ //#endregion
707
+ export { MessageOccurrence as _, Vi18nConfig as a, OpenAICompatibleOptions as c, ProviderResponse as d, Tier as f, MessageCodec as g, Diagnostic as h, ResolvedConfig as i, ProviderOptions as l, TranslationProvider as m, OutputOptions as n, AiItem as o, TranslateOptions as p, PseudoLocale as r, BatchOptions as s, Level as t, ProviderRequest as u, LocaleStrategy as v, UrlStrategy as y };