@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,245 @@
1
+ import { i as toRuntimeConfig } from "./runtime-DTMmliT1.js";
2
+ import { a as assetCatalogsModule, i as SERVER_FILES, o as serverCatalogVersion, s as serverCatalogsDir, t as compileLocales } from "./locales-DX4MOBFE.js";
3
+ import { t as findCollisions } from "./collisions-CfpZU8e4.js";
4
+ import { a as table, i as rootRelative, r as plural } from "./output-DWE3SIUA.js";
5
+ import { t as EXIT } from "./types-wSh9fCBY.js";
6
+ import { a as loadCatalogs, f as scan, i as hasErrors, n as compareText, o as loadProject, r as computeDrift, s as occurrencesOf, u as readErrors } from "./project-C4GpaN-n.js";
7
+ import { dirname, join, resolve } from "node:path";
8
+ import { randomBytes } from "node:crypto";
9
+ import { mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
10
+ //#region src/cli/commands/compile.ts
11
+ /**
12
+ * `vi18n compile [--out dir] [--assets dir] [--strict] [--pseudo] [--check]`
13
+ * (INTERNALS §2.12, PLAN §5.3): compiled catalogs for code Vite does not
14
+ * build (a wrangler Worker, e-mail rendering), loaded with
15
+ * `registerCatalogs`. It refuses to run while `extract --check` reports
16
+ * drift, so what ships always matches the code. A committed `--out`
17
+ * directory can still lag behind the catalogs (a translation edited,
18
+ * `extract` run without `compile`): `--check` compares it with what would be
19
+ * written, for CI.
20
+ *
21
+ * `--assets` is the Workers layout of `ssr.catalogs: "assets"` (spike S12):
22
+ * the catalogs go to the static-assets directory under the server message
23
+ * set's version, and `<out>/catalogs.js` reads them through `env.ASSETS`, so
24
+ * the Worker bundles none and only the locales requests use take memory.
25
+ */
26
+ async function compile(ctx, flags) {
27
+ const project = await loadProject(ctx);
28
+ const { config, codec } = project;
29
+ const data = {
30
+ out: null,
31
+ assets: null,
32
+ files: [],
33
+ missing: {},
34
+ drift: []
35
+ };
36
+ const scanned = await scan(project);
37
+ ctx.out.report(scanned.diagnostics.filter((d) => d.severity === "error"));
38
+ const loaded = await loadCatalogs(project);
39
+ const unreadable = readErrors(loaded.diagnostics);
40
+ if (unreadable.length > 0) {
41
+ ctx.out.report(unreadable);
42
+ return {
43
+ exitCode: EXIT.failure,
44
+ data
45
+ };
46
+ }
47
+ const collided = findCollisions(occurrencesOf(scanned), loaded.set, codec, { referenced: new Set(config.extraction.keep) });
48
+ if (hasErrors(collided)) {
49
+ ctx.out.report(collided);
50
+ return {
51
+ exitCode: EXIT.failure,
52
+ data
53
+ };
54
+ }
55
+ const refusals = (await computeDrift(project, scanned.messages, loaded.set)).diagnostics.filter((d) => d.code === "catalog-drift" || d.code === "id-scheme-mismatch");
56
+ if (refusals.length > 0) {
57
+ ctx.out.report(refusals);
58
+ ctx.out.note("vi18n compile: the catalogs do not match the code; run vi18n extract first");
59
+ return {
60
+ exitCode: EXIT.failure,
61
+ data
62
+ };
63
+ }
64
+ const pseudo = flags.pseudo ? config.pseudoLocales : [];
65
+ const locales = [...config.locales, ...pseudo];
66
+ const compiled = compileLocales({
67
+ config,
68
+ codec,
69
+ messages: scanned.messages,
70
+ keep: config.extraction.keep,
71
+ catalogs: loaded.set,
72
+ locales
73
+ });
74
+ let missingTotal = 0;
75
+ for (const locale of config.locales) {
76
+ const result = compiled.get(locale);
77
+ ctx.out.report(result.diagnostics);
78
+ if (locale === config.sourceLocale) continue;
79
+ let count = 0;
80
+ for (const status of result.status.values()) if (status.state === "missing") count++;
81
+ data.missing[locale] = count;
82
+ missingTotal += count;
83
+ }
84
+ if (flags.out !== null) {
85
+ const out = resolve(ctx.global.cwd, flags.out);
86
+ data.out = rootRelative(config.root, out);
87
+ if (!flags.check) await mkdir(out, { recursive: true });
88
+ const files = [];
89
+ const runtime = toRuntimeConfig(config, {
90
+ base: "/",
91
+ pseudo: flags.pseudo
92
+ });
93
+ const assets = flags.assets === null ? null : resolve(ctx.global.cwd, flags.assets);
94
+ let version = null;
95
+ if (assets === null) for (const locale of locales) {
96
+ const messages = compiled.get(locale).messages;
97
+ files.push([join(out, `${locale}.json`), bundleJson(messages)]);
98
+ }
99
+ else {
100
+ data.assets = rootRelative(config.root, assets);
101
+ version = serverCatalogVersion({
102
+ idScheme: codec.idScheme,
103
+ v: null,
104
+ ids: compiled.get(config.sourceLocale).messages.keys(),
105
+ sourceHashOf: (id) => scanned.messages.get(id)?.sourceHash ?? ""
106
+ });
107
+ for (const locale of locales) {
108
+ const messages = compiled.get(locale).messages;
109
+ const path = join(assets, serverCatalogsDir(version), locale, SERVER_FILES.catalog);
110
+ files.push([path, bundleJson(messages)]);
111
+ }
112
+ runtime.ssr.maxLoadedLocales = config.ssr.maxLoadedLocales;
113
+ }
114
+ files.push([join(out, "sources.json"), sourcesJson(scanned.messages)]);
115
+ files.push([join(out, "config.json"), JSON.stringify(runtime) + "\n"]);
116
+ if (version !== null) {
117
+ files.push([join(out, "catalogs.js"), assetCatalogsModule({
118
+ locales,
119
+ dir: serverCatalogsDir(version),
120
+ deploy: `deploy ${flags.assets} (written by vi18n compile --assets) with this Worker`,
121
+ modules: "compile without --assets to bundle the catalogs as modules"
122
+ })]);
123
+ files.push([join(out, "catalogs.d.ts"), CATALOGS_DTS]);
124
+ }
125
+ const fix = `vi18n compile --out ${flags.out}${assets === null ? "" : ` --assets ${flags.assets}`}${flags.pseudo ? " --pseudo" : ""}`;
126
+ for (const [path, content] of files) {
127
+ const file = rootRelative(config.root, path);
128
+ data.files.push(file);
129
+ if (!flags.check) {
130
+ await mkdir(dirname(path), { recursive: true });
131
+ await writeIfChanged(path, content);
132
+ continue;
133
+ }
134
+ const current = await readIfExists(path);
135
+ if (current !== null && current.replace(/\r\n/g, "\n") === content) continue;
136
+ data.drift.push(file);
137
+ ctx.out.report([{
138
+ code: "catalog-drift",
139
+ severity: "error",
140
+ message: current === null ? `${file} does not exist yet; run ${fix}` : `${file} is out of date; run ${fix}`,
141
+ file
142
+ }]);
143
+ }
144
+ if (version !== null && assets !== null && !flags.check) {
145
+ const locales = [...config.locales, ...config.pseudoLocales];
146
+ const removed = await removeOtherVersions(assets, version, locales);
147
+ if (removed > 0) ctx.out.note(`removed ${plural(removed, "earlier catalog version")} from ${ctx.out.display(rootRelative(config.root, join(assets, "vi18n")))}`);
148
+ }
149
+ }
150
+ const where = data.out === null ? "" : ctx.out.display(data.out) + (data.assets === null ? "" : ` and ${ctx.out.display(data.assets)}`);
151
+ const rows = Object.entries(data.missing).map(([locale, count]) => [locale, count]);
152
+ if (rows.length > 0) ctx.out.result(table(["locale", "missing"], rows));
153
+ if (data.out !== null && flags.check) ctx.out.result(data.drift.length > 0 ? `vi18n compile --check: ${data.drift.length} out-of-date file(s) in ${where}` : `vi18n compile --check: ${where} ${data.assets === null ? "is" : "are"} up to date`);
154
+ else if (data.out !== null) ctx.out.result(`wrote ${plural(data.files.length, "file")} to ${where}`);
155
+ const failed = hasErrors(ctx.out.diagnostics) || flags.strict && missingTotal > 0;
156
+ if (flags.strict && missingTotal > 0) ctx.out.note(`vi18n compile --strict: ${plural(missingTotal, "missing translation")}`);
157
+ return {
158
+ exitCode: failed ? EXIT.failure : EXIT.ok,
159
+ data
160
+ };
161
+ }
162
+ /** Types of the generated `catalogs.js` for TypeScript apps (no `allowJs` needed). */
163
+ const CATALOGS_DTS = `// Generated by vi18n compile --assets: catalog loaders for registerCatalogs().
164
+ declare const catalogs: { [locale: string]: () => Promise<{ [id: string]: unknown }> };
165
+ export default catalogs;
166
+ `;
167
+ /** A version directory name (`hash8`): base64url, 8 characters. */
168
+ const VERSION_NAME = /^[\w-]{8}$/;
169
+ /**
170
+ * Removes the versions of `<assets>/vi18n/` other than `version` that this
171
+ * command wrote: directories named like a version holding only
172
+ * `<locale>/catalog.json` for configured locales. Anything else there (a
173
+ * Vite build's stable manifests, the app's own files) is left alone.
174
+ */
175
+ async function removeOtherVersions(assets, version, locales) {
176
+ const root = join(assets, "vi18n");
177
+ let removed = 0;
178
+ for (const entry of await readdir(root, { withFileTypes: true }).catch(() => [])) {
179
+ if (!entry.isDirectory() || entry.name === version || !VERSION_NAME.test(entry.name)) continue;
180
+ const dir = join(root, entry.name);
181
+ if (!await onlyCatalogs(dir, locales)) continue;
182
+ await rm(dir, {
183
+ recursive: true,
184
+ force: true
185
+ });
186
+ removed++;
187
+ }
188
+ return removed;
189
+ }
190
+ async function onlyCatalogs(dir, locales) {
191
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
192
+ if (!entry.isDirectory() || !locales.includes(entry.name)) return false;
193
+ if ((await readdir(join(dir, entry.name), { withFileTypes: true })).some((file) => !file.isFile() || file.name !== SERVER_FILES.catalog)) return false;
194
+ }
195
+ return true;
196
+ }
197
+ /** `BundleData` with keys in code-unit order and no whitespace: byte-stable for diffs and caches. */
198
+ function bundleJson(messages) {
199
+ const ids = [...messages.keys()].sort(compareText);
200
+ const data = Object.create(null);
201
+ for (const id of ids) data[id] = messages.get(id);
202
+ return JSON.stringify(data) + "\n";
203
+ }
204
+ /**
205
+ * Every exact source literal of a generated-id message → its id, so
206
+ * untransformed code (`t("Hello {name}")` in a Worker) finds the compiled
207
+ * message (PLAN §5.3). Manual ids are looked up by id and need no entry.
208
+ */
209
+ function sourcesJson(messages) {
210
+ const pairs = [];
211
+ for (const message of messages.values()) {
212
+ if (message.manual) continue;
213
+ for (const source of message.sources) pairs.push([source, message.id]);
214
+ }
215
+ pairs.sort((a, b) => compareText(a[0], b[0]));
216
+ const data = Object.create(null);
217
+ for (const [source, id] of pairs) data[source] = id;
218
+ return JSON.stringify(data) + "\n";
219
+ }
220
+ async function readIfExists(path) {
221
+ try {
222
+ return await readFile(path, "utf8");
223
+ } catch (error) {
224
+ if (error.code === "ENOENT") return null;
225
+ throw error;
226
+ }
227
+ }
228
+ /** Unchanged files keep their mtime (watchers, incremental deploys); others are replaced atomically. */
229
+ async function writeIfChanged(path, content) {
230
+ try {
231
+ if (await readFile(path, "utf8") === content) return;
232
+ } catch (error) {
233
+ if (error.code !== "ENOENT") throw error;
234
+ }
235
+ const temp = `${path}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
236
+ try {
237
+ await writeFile(temp, content);
238
+ await rename(temp, path);
239
+ } catch (error) {
240
+ await rm(temp, { force: true });
241
+ throw error;
242
+ }
243
+ }
244
+ //#endregion
245
+ export { compile };