@menapo/vi18n 0.0.0-stage → 0.1.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.
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-BIKEuu6B.js +201 -0
  6. package/dist/check-HsmmpJZg.js +1 -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-BaDh0cHG.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-C2ENBRJe.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-C9Sy6UWv.js +103 -0
  25. package/dist/extract-C3S8btx0.js +298 -0
  26. package/dist/formats-9unqj_fZ.js +781 -0
  27. package/dist/i18next-9HAoxwUI.js +1 -0
  28. package/dist/i18next-BEJgv_S8.js +1596 -0
  29. package/dist/import-nANvQutw.js +225 -0
  30. package/dist/index.d.ts +156 -0
  31. package/dist/index.js +239 -0
  32. package/dist/init-C2ScuW6a.js +792 -0
  33. package/dist/library-D5CWvTQs.js +1882 -0
  34. package/dist/lingui-zUiCl9Um.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-RMMMc88P.js +31 -0
  41. package/dist/match-BGr8EXB3.js +89 -0
  42. package/dist/mcp-CHVwBoRP.js +28 -0
  43. package/dist/merge-driver-BTX87aVm.js +422 -0
  44. package/dist/messages-BfjIExyB.js +166 -0
  45. package/dist/migrate-IpLDMXmq.js +1484 -0
  46. package/dist/migrate-rCQuOGsf.js +1 -0
  47. package/dist/openai-CTaMDcl-.js +346 -0
  48. package/dist/output-DWE3SIUA.js +164 -0
  49. package/dist/parse.d.ts +62 -0
  50. package/dist/parse.js +156 -0
  51. package/dist/pipeline-C9Dbotkh.js +2031 -0
  52. package/dist/pipeline-DbX6rlo5.js +1 -0
  53. package/dist/project-Bw9UPIdx.js +1046 -0
  54. package/dist/project-C4GpaN-n.js +381 -0
  55. package/dist/pseudo-DRv30iN5.js +145 -0
  56. package/dist/raw-C4Y6vyGY.js +4708 -0
  57. package/dist/react-intl-BP0u-D5m.js +519 -0
  58. package/dist/restore-CiYv-jxS.js +175 -0
  59. package/dist/rewrite-EsIw_lsq.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-BEcnBbu-.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-Da1Ot9IN.js +10485 -0
  68. package/dist/server-deBOq2vq.js +11823 -0
  69. package/dist/server.d.ts +169 -0
  70. package/dist/server.js +1234 -0
  71. package/dist/sitemap-DJXzKoza.js +159 -0
  72. package/dist/sources-D19czDSA.js +2242 -0
  73. package/dist/status-zr4jY59Y.js +149 -0
  74. package/dist/stdio-CVaJfxA7.js +29 -0
  75. package/dist/stdio-FPOKQAgu.js +95 -0
  76. package/dist/sync-B9V2KFwb.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-CQnJfLjO.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-Byqi2guX.js +28 -0
  93. package/dist/vite-scan-CT_vsp4g.js +242 -0
  94. package/dist/vite.d.ts +34 -0
  95. package/dist/vite.js +7558 -0
  96. package/dist/vue-i18n-g0iGy6CZ.js +651 -0
  97. package/dist/which-BOemZ5Q8.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,225 @@
1
+ import { m as updateCatalogFile } from "./library-D5CWvTQs.js";
2
+ import { t as VERSION } from "./version-Byqi2guX.js";
3
+ import { c as sourceIndexOf } from "./units-CQ5Q99RC.js";
4
+ import { i as rootRelative, r as plural } from "./output-DWE3SIUA.js";
5
+ import { t as EXIT } from "./types-wSh9fCBY.js";
6
+ import { a as loadCatalogs, o as loadProject, t as CliExit, u as readErrors } from "./project-C4GpaN-n.js";
7
+ import { t as readImport } from "./formats-9unqj_fZ.js";
8
+ import { t as applyImport } from "./apply-Bre-lY9J.js";
9
+ import { basename, extname, resolve } from "node:path";
10
+ import { readFile } from "node:fs/promises";
11
+ //#region src/cli/commands/import.ts
12
+ /**
13
+ * `vi18n import [--format f] [--locale l] [--dry-run] <file>…` (PLAN §4.4,
14
+ * §5.19, INTERNALS §2.6.9): translations from exchange files into the
15
+ * catalogs. A row is taken only for the exact source it was made for (D10),
16
+ * and only into an entry the catalog already has, so an import never adds
17
+ * messages or touches the source locale; everything left out is reported
18
+ * with its reason. Writes go through the compare-and-swap writer, so a dev
19
+ * server or another command writing meanwhile loses nothing.
20
+ */
21
+ /** Skipped rows of these reasons are listed one by one; the rest are counted. */
22
+ const LISTED = /* @__PURE__ */ new Set([
23
+ "source-changed",
24
+ "no-source",
25
+ "unsupported",
26
+ "duplicate"
27
+ ]);
28
+ /** Per reason and file, so one stale export does not flood the terminal. */
29
+ const LIST_LIMIT = 20;
30
+ const WHY = {
31
+ unknown: "no entry has this key; run vi18n extract, or the message is gone",
32
+ "source-changed": "translated for other source text than the code has now",
33
+ "no-source": "nothing says which source text it was made for",
34
+ empty: "empty",
35
+ draft: "marked as needing work",
36
+ invalid: "not a valid translation of its source",
37
+ unsupported: "uses markup vi18n cannot read back",
38
+ duplicate: "a second row for the same key with another translation"
39
+ };
40
+ const UTF8 = new TextDecoder("utf-8", { fatal: true });
41
+ async function importCatalogs(ctx, flags) {
42
+ const project = await loadProject(ctx);
43
+ const { config, codec, layout } = project;
44
+ const loaded = await loadCatalogs(project);
45
+ const unreadable = readErrors(loaded.diagnostics);
46
+ if (unreadable.length > 0) throw new CliExit(EXIT.failure, unreadable);
47
+ const context = {
48
+ layout,
49
+ codec,
50
+ sourceIndex: sourceIndexOf(loaded.set.get(config.sourceLocale)?.catalog ?? null, layout, codec)
51
+ };
52
+ const data = {
53
+ dryRun: flags.dryRun,
54
+ files: [],
55
+ changed: [],
56
+ skipped: []
57
+ };
58
+ let failed = false;
59
+ for (const name of flags.files) {
60
+ const path = resolve(ctx.global.cwd, name);
61
+ const shown = rootRelative(config.root, path);
62
+ const problem = (message, line = 0) => {
63
+ failed = true;
64
+ const diagnostic = {
65
+ code: "import-parse",
66
+ severity: "error",
67
+ message,
68
+ file: path
69
+ };
70
+ if (line > 0) diagnostic.line = line;
71
+ ctx.out.report([diagnostic]);
72
+ };
73
+ let text;
74
+ try {
75
+ text = UTF8.decode(await readFile(path));
76
+ } catch (error) {
77
+ const code = error.code;
78
+ problem(code === "ENOENT" ? "no such file" : error instanceof TypeError ? "the file is not valid UTF-8; export it as UTF-8" : `cannot read it: ${error instanceof Error ? error.message : String(error)}`);
79
+ continue;
80
+ }
81
+ const format = flags.format ?? inferFormat(path, text);
82
+ if (format === null) {
83
+ problem(`cannot tell the format from the extension ${JSON.stringify(extname(path))}; pass --format`);
84
+ continue;
85
+ }
86
+ const read = readImport(format, text, { msgid: config.catalogs.msgid });
87
+ if (read.error !== null) {
88
+ problem(`not a ${format} file vi18n can read: ${read.error.message}`, read.error.line);
89
+ continue;
90
+ }
91
+ if (read.srcLang != null && read.srcLang !== config.sourceLocale) {
92
+ problem(`its source language is ${read.srcLang}, but sourceLocale is ${config.sourceLocale}`);
93
+ continue;
94
+ }
95
+ const fromName = basename(path, extname(path));
96
+ const named = read.locale ?? (config.locales.includes(fromName) ? fromName : null);
97
+ if (flags.locale !== null && named !== null && read.locale !== null && flags.locale !== named) {
98
+ problem(`the file is for ${named}, not --locale ${flags.locale}`);
99
+ continue;
100
+ }
101
+ const locale = flags.locale ?? named;
102
+ if (locale === null) {
103
+ problem("the file does not name its locale; pass --locale");
104
+ continue;
105
+ }
106
+ if (locale === config.sourceLocale) {
107
+ problem(`${locale} is the source locale, which is compiled from code and takes no translations`);
108
+ continue;
109
+ }
110
+ if (!config.locales.includes(locale)) {
111
+ problem(`${locale} is not in locales (${config.locales.join(", ")})`);
112
+ continue;
113
+ }
114
+ const target = loaded.set.get(locale);
115
+ const apply = (catalog) => applyImport({
116
+ catalog,
117
+ records: read.records,
118
+ context,
119
+ locale
120
+ });
121
+ let outcome = null;
122
+ if (target === void 0 || target.catalog === null) {
123
+ problem(`${locale} has no catalog yet; run vi18n extract first`);
124
+ continue;
125
+ }
126
+ if (flags.dryRun) outcome = apply(target.catalog);
127
+ else await updateCatalogFile(target.path, target.hash, (current) => {
128
+ if (current === null) return null;
129
+ outcome = apply(current);
130
+ return outcome.catalog === current ? null : outcome.catalog;
131
+ }, {
132
+ locale,
133
+ layout,
134
+ isSourceLocale: false,
135
+ version: VERSION
136
+ });
137
+ if (outcome === null) {
138
+ problem(`${locale}'s catalog disappeared while importing; run vi18n extract`);
139
+ continue;
140
+ }
141
+ report(ctx, data, {
142
+ file: shown,
143
+ format,
144
+ locale,
145
+ outcome,
146
+ path
147
+ });
148
+ }
149
+ return {
150
+ exitCode: failed ? EXIT.failure : EXIT.ok,
151
+ data
152
+ };
153
+ }
154
+ function report(ctx, data, input) {
155
+ const { file, format, locale, outcome, path } = input;
156
+ const counts = {};
157
+ const listed = {};
158
+ const warnings = [];
159
+ for (const row of outcome.skipped) {
160
+ counts[row.reason] = (counts[row.reason] ?? 0) + 1;
161
+ data.skipped.push({
162
+ file,
163
+ locale,
164
+ line: row.line,
165
+ ref: row.ref,
166
+ id: row.id,
167
+ reason: row.reason
168
+ });
169
+ if (!LISTED.has(row.reason)) continue;
170
+ if ((listed[row.reason] = (listed[row.reason] ?? 0) + 1) > LIST_LIMIT) continue;
171
+ const diagnostic = {
172
+ code: "import-skipped",
173
+ severity: "warning",
174
+ message: `${row.ref}: ${WHY[row.reason]}; not imported`,
175
+ file: path,
176
+ locale
177
+ };
178
+ if (row.line > 0) diagnostic.line = row.line;
179
+ if (row.id !== null) diagnostic.id = row.id;
180
+ warnings.push(diagnostic);
181
+ }
182
+ ctx.out.report(warnings);
183
+ ctx.out.report(outcome.diagnostics.map((diagnostic) => ({
184
+ ...diagnostic,
185
+ file: path
186
+ })));
187
+ for (const change of outcome.changed) data.changed.push({
188
+ file,
189
+ locale,
190
+ ...change
191
+ });
192
+ data.files.push({
193
+ file,
194
+ format,
195
+ locale,
196
+ changed: outcome.changed.length,
197
+ unchanged: outcome.unchanged,
198
+ skipped: counts
199
+ });
200
+ const parts = Object.entries(counts).map(([reason, count]) => `${count} ${reason}`);
201
+ ctx.out.result(`${file} → ${locale}: ${outcome.changed.length} ${data.dryRun ? "to change" : "changed"}, ${outcome.unchanged} unchanged` + (parts.length === 0 ? "" : `, ${plural(outcome.skipped.length, "skipped row")} (${parts.join(", ")})`));
202
+ }
203
+ /**
204
+ * The format from the extension. `.json` is vi18n's catalog format when the
205
+ * file has a `messages` object (a flat file's values are all strings), else
206
+ * flat JSON.
207
+ */
208
+ function inferFormat(path, text) {
209
+ switch (extname(path).toLowerCase()) {
210
+ case ".po": return "po";
211
+ case ".xlf":
212
+ case ".xliff": return "xliff2";
213
+ case ".arb": return "arb";
214
+ case ".csv": return "csv";
215
+ case ".json": try {
216
+ const messages = JSON.parse(text.charCodeAt(0) === 65279 ? text.slice(1) : text)?.messages;
217
+ return typeof messages === "object" && messages !== null ? "json" : "flat";
218
+ } catch {
219
+ return "flat";
220
+ }
221
+ default: return null;
222
+ }
223
+ }
224
+ //#endregion
225
+ export { importCatalogs };
@@ -0,0 +1,156 @@
1
+ import { C as Locale, D as ValuesOf, E as RichValuesOf, S as LibraryMessages, T as RichPartsValuesOf, _ as TagHandler, a as Message, b as Values, c as MissingHandler, d as RichHtmlFunction, f as RichPart, g as TFunction, i as HtmlTagHandler, l as MissingInfo, n as Descriptor, o as MessageKey, p as RichPartsFunction, r as Fmt, s as MessageRef, t as DateInput, u as RichFunction, v as TemporalInput, w as Register, x as DefaultTags, y as Translator } from "./types-DsdWBG0b.js";
2
+ //#region src/runtime/t.d.ts
3
+ export declare const t: TFunction;
4
+ /**
5
+ * Declares a message without rendering it; the build turns the call into its
6
+ * id. `msg({ id })` alone names a message an opted-in package declares, typed
7
+ * from its text (`vi18n.gen.ts`).
8
+ */
9
+ export declare function msg<const M extends string>(message: M): MessageRef<ValuesOf<M>>;
10
+ export declare function msg<const D extends Descriptor>(descriptor: D): MessageRef<ValuesOf<D["message"]>>;
11
+ export declare function msg<const K extends Extract<keyof LibraryMessages, string>>(descriptor: {
12
+ readonly id: K;
13
+ }): MessageRef<ValuesOf<LibraryMessages[K]>>;
14
+ //#endregion
15
+ //#region src/runtime/rich.d.ts
16
+ /**
17
+ * Tag handlers come from `values` and receive `(children, key)`; React and
18
+ * Preact glue keys their results, and nodes passed as values, through
19
+ * `State.richKey`. A tag without a handler renders its children.
20
+ */
21
+ export declare const rich: RichFunction;
22
+ export declare const richHtml: RichHtmlFunction;
23
+ export declare const richParts: RichPartsFunction;
24
+ //#endregion
25
+ //#region src/runtime/macro.d.ts
26
+ /**
27
+ * The JSX `<T>` macro's runtime face (PLAN §4.1, INTERNALS §6 D215): the
28
+ * plugin's `vi18n:macro` pass replaces every `<T>…</T>` with a `rich()` call
29
+ * before React, Preact or Solid compile the JSX, so this function exists only
30
+ * to give the import a type and a value. Rendering it means no pass ran.
31
+ */
32
+ /** What `<T>` takes: its children are the message; the rest feed extraction. */
33
+ interface TProps {
34
+ children?: unknown;
35
+ /** Values for the arguments of an ICU string child, `{"{n, plural, …}"}`. */
36
+ values?: {
37
+ readonly [name: string]: unknown;
38
+ };
39
+ /** A manual id, as in `rich({ id, message })`. */
40
+ id?: string;
41
+ /** Context for translators. */
42
+ context?: string;
43
+ /** Length limit for translations. */
44
+ maxLength?: number;
45
+ }
46
+ export declare function T(props: TProps): never;
47
+ declare namespace fmt_d_exports {
48
+ export { collator, compact, compare, currency, currencyMinor, date, dateRange, displayName, duration, list, number, percent, relative, segment, time, unit };
49
+ }
50
+ declare const number: Fmt["number"];
51
+ declare const currency: Fmt["currency"];
52
+ declare const currencyMinor: Fmt["currencyMinor"];
53
+ declare const unit: Fmt["unit"];
54
+ declare const compact: Fmt["compact"];
55
+ declare const percent: Fmt["percent"];
56
+ declare const date: Fmt["date"];
57
+ declare const time: Fmt["time"];
58
+ declare const dateRange: Fmt["dateRange"];
59
+ declare const relative: Fmt["relative"];
60
+ declare const list: Fmt["list"];
61
+ declare const displayName: Fmt["displayName"];
62
+ declare const duration: Fmt["duration"];
63
+ declare const compare: Fmt["compare"];
64
+ declare const collator: Fmt["collator"];
65
+ declare const segment: Fmt["segment"];
66
+ //#endregion
67
+ //#region src/runtime/name.d.ts
68
+ /**
69
+ * `localeName(locale)` (PLAN §4.1, §4.16): what a locale picker shows for a
70
+ * locale, its language's own name, and the `lang` of the text it shows, so
71
+ * screen readers read "Deutsch" in German inside an English page. It reads
72
+ * no state: an own-language name never depends on the current locale (the
73
+ * name in the current locale is `fmt.displayName`).
74
+ */
75
+ /** `localeName()`'s result. */
76
+ interface LocaleName {
77
+ /** The language's own name, first letter upper-cased as menus show it: "Deutsch", "Français". */
78
+ name: string;
79
+ /**
80
+ * The language `name` is in, for the element's `lang`: `locale` itself, the
81
+ * engine's default locale when it has no data for that language (the name
82
+ * is then in that language), or `""` (unknown) when the name is the code.
83
+ */
84
+ lang: string;
85
+ }
86
+ type LocaleNameOptions = Pick<Intl.DisplayNamesOptions, "style" | "languageDisplay">;
87
+ export declare function localeName(locale: string, options?: LocaleNameOptions): LocaleName;
88
+ //#endregion
89
+ //#region src/runtime/zod.d.ts
90
+ /**
91
+ * `vi18nZod()` (PLAN §4.1, INTERNALS §6 D206): a zod 4 `customError` that
92
+ * words issues through vi18n messages in the current locale, so
93
+ * `z.config({ customError: vi18nZod() })` localises every schema without a
94
+ * message of its own. It imports nothing from zod: the issue is typed
95
+ * structurally and zod only ever calls the function.
96
+ *
97
+ * The texts are not here. The extractor treats a `vi18nZod()` call as the
98
+ * `msg()` of each text in `src/core/extract/zod.ts` (catalog references
99
+ * point at the call) and the transform passes them in that order, as ids in
100
+ * builds and descriptors in dev, so they ship in the bundle of the module
101
+ * that calls it. Called unprocessed, it has none and zod keeps its own.
102
+ */
103
+ /** The issue fields the bridge reads (zod 4's `$ZodRawIssue`, structurally). */
104
+ interface ZodIssueLike {
105
+ readonly code?: string;
106
+ readonly input?: unknown;
107
+ readonly expected?: string;
108
+ readonly origin?: string;
109
+ readonly format?: string;
110
+ readonly minimum?: number | bigint;
111
+ readonly maximum?: number | bigint;
112
+ readonly inclusive?: boolean;
113
+ readonly exact?: boolean;
114
+ readonly keys?: readonly string[];
115
+ }
116
+ /** What `vi18nZod()` returns: zod 4's error-map shape. */
117
+ type ZodErrorMap = (issue: ZodIssueLike) => string | undefined;
118
+ export declare const vi18nZod: () => ZodErrorMap;
119
+ //#endregion
120
+ //#region src/runtime/locale.d.ts
121
+ /** The active scope's locale: the request's on the server, the page's in the browser. */
122
+ export declare const getLocale: () => Locale;
123
+ /** Switches the page in place (or by document navigation, §2.11.7). Client only. */
124
+ export declare const setLocale: (locale: Locale) => Promise<void>;
125
+ /** Called with the new locale after every switch; returns an unsubscribe. */
126
+ export declare const subscribe: (listener: (locale: Locale) => void) => (() => void);
127
+ /** The app router's navigate function, for URL strategies (`setNavigator((href) => router.navigate(…))`). */
128
+ export declare const setNavigator: (navigate: ((href: string) => unknown) | null) => void;
129
+ /** Configured (and active pseudo-) locales, filled at registration; the same array forever. */
130
+ export declare const locales: readonly Locale[];
131
+ /** `"rtl"` or `"ltr"`; defaults to the current locale. */
132
+ export declare const dir: (locale?: string) => "ltr" | "rtl";
133
+ /** Settles once the page locale's boot and pending loads have settled. */
134
+ export declare const ready: () => Promise<void>;
135
+ /**
136
+ * For router intent hooks: loads the route's message bundles. The build fills
137
+ * `keys` from the `import()` inside `load`, which is never called: routers own
138
+ * code prefetching (§6 D45).
139
+ */
140
+ export declare const preload: (_load: () => Promise<unknown>, keys?: readonly string[]) => Promise<void>;
141
+ /** Missing-message reports, once per (key, locale); returns an unsubscribe. */
142
+ export declare const onMissing: (handler: MissingHandler) => (() => void);
143
+ /** A copy of `url` with its path in `locale` (default: the current one). */
144
+ export declare const localizeUrl: (url: URL | string, locale?: Locale) => URL;
145
+ /** A copy of `url` without its locale segment (router `rewrite`/`reroute` input). */
146
+ export declare const delocalizeUrl: (url: URL | string) => URL;
147
+ /**
148
+ * `href` in `locale` (default: the current one). Path-absolute and
149
+ * same-origin absolute hrefs are localized (with domains, hrefs on a listed
150
+ * host too, and a locale served by another listed host gives an absolute
151
+ * URL there); relative (`./x`, `x`, `?q`, `#h`) and cross-origin ones are
152
+ * returned unchanged.
153
+ */
154
+ export declare function localizeHref(href: string, locale?: Locale): string;
155
+ //#endregion
156
+ export { type DateInput, type DefaultTags, type Descriptor, type Fmt, type HtmlTagHandler, type Locale, type LocaleName, type LocaleNameOptions, type Message, type MessageKey, type MessageRef, type MissingHandler, type MissingInfo, type Register, type RichPart, type RichPartsValuesOf, type RichValuesOf, type TFunction, type TProps, type TagHandler, type TemporalInput, type Translator, type Values, type ValuesOf, type ZodErrorMap, type ZodIssueLike, fmt_d_exports as fmt };
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { b as trim, d as resolved, n as S, t as textDirection } from "./dir-zw6bGMKQ.js";
3
+ import { a as hostLocale, d as splitLocalePath, i as awayHref, n as atHome, r as atHost, s as localizePath, t as ROUTES } from "./url-CsBkRaJy.js";
4
+ import { C as fTime, S as fSegment, _ as fDuration, b as fPercent, d as fCompare, f as fCurrency, g as fDisplayName, h as fDateRange, l as fCollator, m as fDate, n as msg, p as fCurrencyMinor, r as t, u as fCompact, v as fList, w as fUnit, x as fRelative, y as fNumber } from "./t-DC-c9zE5.js";
5
+ import { i as richParts, n as richHtml, t as rich } from "./rich-DCUKl5HM.js";
6
+ //#region src/runtime/macro.ts
7
+ function T(props) {
8
+ throw new Error("vi18n: <T> is a compile-time macro and was not compiled: add vi18n() to the plugins of this Vite or Vitest config");
9
+ }
10
+ //#endregion
11
+ //#region src/runtime/fmt.ts
12
+ /**
13
+ * The `fmt` namespace (PLAN §5.17): exactly the members of `Fmt`, each in the
14
+ * active scope's locale, zone and `now`. Separate exports, so unused members
15
+ * tree-shake out of `fmt.*` imports.
16
+ */
17
+ var fmt_exports = /* @__PURE__ */ __exportAll({
18
+ collator: () => collator,
19
+ compact: () => compact,
20
+ compare: () => compare,
21
+ currency: () => currency,
22
+ currencyMinor: () => currencyMinor,
23
+ date: () => date,
24
+ dateRange: () => dateRange,
25
+ displayName: () => displayName,
26
+ duration: () => duration,
27
+ list: () => list,
28
+ number: () => number,
29
+ percent: () => percent,
30
+ relative: () => relative,
31
+ segment: () => segment,
32
+ time: () => time,
33
+ unit: () => unit
34
+ });
35
+ const scope = () => {
36
+ const s = S.resolve();
37
+ S.track();
38
+ return s;
39
+ };
40
+ const number = (v, o) => fNumber(scope(), v, o);
41
+ const currency = (v, c, o) => fCurrency(scope(), v, c, o);
42
+ const currencyMinor = (v, c, o) => fCurrencyMinor(scope(), v, c, o);
43
+ const unit = (v, u, o) => fUnit(scope(), v, u, o);
44
+ const compact = (v, o) => fCompact(scope(), v, o);
45
+ const percent = (v, o) => fPercent(scope(), v, o);
46
+ const date = (v, o) => fDate(scope(), v, o);
47
+ const time = (v, o) => fTime(scope(), v, o);
48
+ const dateRange = (a, b, o) => fDateRange(scope(), a, b, o);
49
+ const relative = (v, o) => fRelative(scope(), v, o);
50
+ const list = (items, o) => fList(scope(), items, o);
51
+ const displayName = (code, o) => fDisplayName(scope(), code, o);
52
+ const duration = (d, o) => fDuration(scope(), d, o);
53
+ const compare = (a, b, o) => fCompare(scope(), a, b, o);
54
+ const collator = (o) => fCollator(scope(), o);
55
+ const segment = (text, o) => fSegment(scope(), text, o);
56
+ //#endregion
57
+ //#region src/runtime/name.ts
58
+ /**
59
+ * `localeName(locale)` (PLAN §4.1, §4.16): what a locale picker shows for a
60
+ * locale, its language's own name, and the `lang` of the text it shows, so
61
+ * screen readers read "Deutsch" in German inside an English page. It reads
62
+ * no state: an own-language name never depends on the current locale (the
63
+ * name in the current locale is `fmt.displayName`).
64
+ */
65
+ const names = /* @__PURE__ */ new Map();
66
+ function localeName(locale, options) {
67
+ const key = locale + JSON.stringify(options);
68
+ let n = names.get(key);
69
+ if (!n) {
70
+ try {
71
+ const d = new Intl.DisplayNames(locale, {
72
+ ...options,
73
+ type: "language",
74
+ fallback: "none"
75
+ });
76
+ const lang = d.resolvedOptions().locale;
77
+ const name = d.of(locale);
78
+ n = {
79
+ name: name[0].toLocaleUpperCase(lang) + name.slice(1),
80
+ lang
81
+ };
82
+ } catch {
83
+ n = {
84
+ name: locale,
85
+ lang: ""
86
+ };
87
+ }
88
+ trim(names, 99);
89
+ names.set(key, n);
90
+ }
91
+ return n;
92
+ }
93
+ //#endregion
94
+ //#region src/runtime/zod.ts
95
+ /**
96
+ * `vi18nZod()` (PLAN §4.1, INTERNALS §6 D206): a zod 4 `customError` that
97
+ * words issues through vi18n messages in the current locale, so
98
+ * `z.config({ customError: vi18nZod() })` localises every schema without a
99
+ * message of its own. It imports nothing from zod: the issue is typed
100
+ * structurally and zod only ever calls the function.
101
+ *
102
+ * The texts are not here. The extractor treats a `vi18nZod()` call as the
103
+ * `msg()` of each text in `src/core/extract/zod.ts` (catalog references
104
+ * point at the call) and the transform passes them in that order, as ids in
105
+ * builds and descriptors in dev, so they ship in the bundle of the module
106
+ * that calls it. Called unprocessed, it has none and zod keeps its own.
107
+ */
108
+ const SIZES = {
109
+ string: 2,
110
+ array: 5,
111
+ set: 5,
112
+ map: 5,
113
+ file: 8
114
+ };
115
+ const FORMATS = [
116
+ "email",
117
+ "url",
118
+ "starts_with",
119
+ "ends_with",
120
+ "includes"
121
+ ];
122
+ const vi18nZod = ((...m) => (issue) => {
123
+ if (!m.length) return;
124
+ const { code, origin = "", inclusive } = issue;
125
+ let i = 28;
126
+ let values = issue;
127
+ if (code === "invalid_type") i = issue.input == null ? 0 : 1;
128
+ else if (code === "too_small" || code === "too_big") {
129
+ const big = +(code === "too_big");
130
+ const n = big ? issue.maximum : issue.minimum;
131
+ const size = SIZES[origin];
132
+ if (size) {
133
+ i = size + (issue.exact ? 2 : big);
134
+ values = { count: inclusive === false ? Number(n) + 1 - 2 * big : n };
135
+ } else i = (origin === "date" ? 15 : 11) + 2 * big + +(inclusive === false);
136
+ } else if (code === "not_multiple_of") i = 19;
137
+ else if (code === "invalid_format") {
138
+ const f = FORMATS.indexOf(issue.format);
139
+ i = f < 0 ? 25 : 20 + f;
140
+ } else if (code === "invalid_value") i = 26;
141
+ else if (code === "unrecognized_keys") {
142
+ i = 27;
143
+ values = {
144
+ count: issue.keys.length,
145
+ keys: issue.keys.join(", ")
146
+ };
147
+ }
148
+ return t(m[i], values) || void 0;
149
+ });
150
+ //#endregion
151
+ //#region src/runtime/locale.ts
152
+ /**
153
+ * The public locale API (PLAN §5.12, §5.14, §5.15). Every function goes
154
+ * through the global state, so a duplicate runtime copy acts on the same page.
155
+ */
156
+ /** The active scope's locale: the request's on the server, the page's in the browser. */
157
+ const getLocale = () => S.resolve().locale;
158
+ /** Switches the page in place (or by document navigation, §2.11.7). Client only. */
159
+ const setLocale = (locale) => S.setLocale(locale);
160
+ /** Called with the new locale after every switch; returns an unsubscribe. */
161
+ const subscribe = (listener) => S.subscribe(listener);
162
+ /** The app router's navigate function, for URL strategies (`setNavigator((href) => router.navigate(…))`). */
163
+ const setNavigator = (navigate) => S.setNavigator(navigate);
164
+ const localesOf = (s) => s.locales;
165
+ /** Configured (and active pseudo-) locales, filled at registration; the same array forever. */
166
+ const locales = /* #__PURE__ */ localesOf(S);
167
+ /** `"rtl"` or `"ltr"`; defaults to the current locale. */
168
+ const dir = (locale) => textDirection(locale ?? getLocale());
169
+ /** Settles once the page locale's boot and pending loads have settled. */
170
+ const ready = () => S.ready();
171
+ /**
172
+ * For router intent hooks: loads the route's message bundles. The build fills
173
+ * `keys` from the `import()` inside `load`, which is never called: routers own
174
+ * code prefetching (§6 D45).
175
+ */
176
+ const preload = (_load, keys) => Array.isArray(keys) ? S.need(keys) : resolved;
177
+ /** Missing-message reports, once per (key, locale); returns an unsubscribe. */
178
+ const onMissing = (handler) => S.onMissing(handler);
179
+ const origin = () => globalThis.location?.origin;
180
+ /**
181
+ * A copy of `url` (resolved against the page) with its pathname edited, once
182
+ * registered; with domains, as the codec reads it on the URL's host.
183
+ */
184
+ function edit(url, f) {
185
+ const u = new URL(url, origin());
186
+ const config = S.registration?.config;
187
+ if (config) u.pathname = f(u.pathname, ROUTES ? atHost(config, u.host) : config);
188
+ return u;
189
+ }
190
+ /**
191
+ * `localizeUrl` where localized paths or domains may be configured: a locale
192
+ * served by another listed host moves the URL there (INTERNALS §6 D135).
193
+ */
194
+ function routedUrl(url, l) {
195
+ let away = null;
196
+ const u = edit(url, (p, c) => (away = awayHref(splitLocalePath(p, c).path, l, c)) ?? localizePath(p, l, c));
197
+ if (away === null) return u;
198
+ const to = new URL(away);
199
+ to.search = u.search;
200
+ to.hash = u.hash;
201
+ return to;
202
+ }
203
+ /** A copy of `url` with its path in `locale` (default: the current one). */
204
+ const localizeUrl = (url, locale) => ROUTES ? routedUrl(url, locale ?? getLocale()) : edit(url, (p, c) => localizePath(p, locale ?? getLocale(), c));
205
+ /**
206
+ * A path-absolute href's path in `l` from the current page (whose host's
207
+ * locale the client config carries) or request (`Scope.home`, servers):
208
+ * absolute when `l` lives on another listed host.
209
+ */
210
+ function routedPath(path, l, config) {
211
+ const c = atHome(config, S.serverResolver?.()?.home ?? config.routing.home);
212
+ return awayHref(splitLocalePath(path, c).path, l, c) ?? localizePath(path, l, c);
213
+ }
214
+ /** A copy of `url` without its locale segment (router `rewrite`/`reroute` input). */
215
+ const delocalizeUrl = (url) => edit(url, (p, c) => splitLocalePath(p, c).path);
216
+ /**
217
+ * `href` in `locale` (default: the current one). Path-absolute and
218
+ * same-origin absolute hrefs are localized (with domains, hrefs on a listed
219
+ * host too, and a locale served by another listed host gives an absolute
220
+ * URL there); relative (`./x`, `x`, `?q`, `#h`) and cross-origin ones are
221
+ * returned unchanged.
222
+ */
223
+ function localizeHref(href, locale) {
224
+ const config = S.registration?.config;
225
+ if (!config) return href;
226
+ if (href[0] === "/" && href[1] !== "/") {
227
+ const i = href.search(/[?#]/) >>> 0;
228
+ if (ROUTES) return routedPath(href.slice(0, i), locale ?? getLocale(), config) + href.slice(i);
229
+ return localizePath(href.slice(0, i), locale ?? getLocale(), config) + href.slice(i);
230
+ }
231
+ const base = globalThis.location?.href;
232
+ if (base && /^[\x00-\x20]*(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(href)) try {
233
+ const u = new URL(href, base);
234
+ if (u.origin === origin() || ROUTES && hostLocale(u.host, config) !== void 0) return localizeUrl(u, locale).href;
235
+ } catch {}
236
+ return href;
237
+ }
238
+ //#endregion
239
+ export { T, delocalizeUrl, dir, fmt_exports as fmt, getLocale, localeName, locales, localizeHref, localizeUrl, msg, onMissing, preload, ready, rich, richHtml, richParts, setLocale, setNavigator, subscribe, t, vi18nZod };