@gtkx/cli 1.4.0 → 1.5.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 (143) hide show
  1. package/README.md +1 -1
  2. package/dist/builder.d.ts +1 -0
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +2 -2
  5. package/dist/builder.js.map +1 -1
  6. package/dist/codegen/run-codegen.d.ts +2 -0
  7. package/dist/codegen/run-codegen.d.ts.map +1 -1
  8. package/dist/codegen/run-codegen.js +30 -6
  9. package/dist/codegen/run-codegen.js.map +1 -1
  10. package/dist/commands/codegen.js +1 -1
  11. package/dist/commands/codegen.js.map +1 -1
  12. package/dist/deploy/freedesktop/localize.d.ts +6 -0
  13. package/dist/deploy/freedesktop/localize.d.ts.map +1 -0
  14. package/dist/deploy/freedesktop/localize.js +107 -0
  15. package/dist/deploy/freedesktop/localize.js.map +1 -0
  16. package/dist/deploy/install-hints.d.ts.map +1 -1
  17. package/dist/deploy/install-hints.js +5 -0
  18. package/dist/deploy/install-hints.js.map +1 -1
  19. package/dist/deploy/payload/launcher.d.ts.map +1 -1
  20. package/dist/deploy/payload/launcher.js +2 -0
  21. package/dist/deploy/payload/launcher.js.map +1 -1
  22. package/dist/deploy/payload/stage.d.ts +1 -1
  23. package/dist/deploy/payload/stage.d.ts.map +1 -1
  24. package/dist/deploy/payload/stage.js +20 -11
  25. package/dist/deploy/payload/stage.js.map +1 -1
  26. package/dist/deploy/run-deploy.d.ts.map +1 -1
  27. package/dist/deploy/run-deploy.js +87 -15
  28. package/dist/deploy/run-deploy.js.map +1 -1
  29. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  30. package/dist/deploy/targets/flatpak-source.js +21 -10
  31. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  32. package/dist/deploy/tools.d.ts +6 -1
  33. package/dist/deploy/tools.d.ts.map +1 -1
  34. package/dist/deploy/tools.js +26 -1
  35. package/dist/deploy/tools.js.map +1 -1
  36. package/dist/dev/locale-dir.d.ts +3 -0
  37. package/dist/dev/locale-dir.d.ts.map +1 -0
  38. package/dist/dev/locale-dir.js +17 -0
  39. package/dist/dev/locale-dir.js.map +1 -0
  40. package/dist/dev/runner-main.d.ts.map +1 -1
  41. package/dist/dev/runner-main.js +2 -0
  42. package/dist/dev/runner-main.js.map +1 -1
  43. package/dist/dev/runner.d.ts.map +1 -1
  44. package/dist/dev/runner.js +6 -0
  45. package/dist/dev/runner.js.map +1 -1
  46. package/dist/dev/vite-dev-server.d.ts +1 -0
  47. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  48. package/dist/dev/vite-dev-server.js.map +1 -1
  49. package/dist/i18n/binding-extractor.d.ts +30 -0
  50. package/dist/i18n/binding-extractor.d.ts.map +1 -0
  51. package/dist/i18n/binding-extractor.js +1324 -0
  52. package/dist/i18n/binding-extractor.js.map +1 -0
  53. package/dist/i18n/catalog-template.d.ts +3 -0
  54. package/dist/i18n/catalog-template.d.ts.map +1 -0
  55. package/dist/i18n/catalog-template.js +18 -0
  56. package/dist/i18n/catalog-template.js.map +1 -0
  57. package/dist/i18n/catalogs.d.ts +21 -0
  58. package/dist/i18n/catalogs.d.ts.map +1 -0
  59. package/dist/i18n/catalogs.js +139 -0
  60. package/dist/i18n/catalogs.js.map +1 -0
  61. package/dist/i18n/extractor-plugin.d.ts +8 -0
  62. package/dist/i18n/extractor-plugin.d.ts.map +1 -0
  63. package/dist/i18n/extractor-plugin.js +247 -0
  64. package/dist/i18n/extractor-plugin.js.map +1 -0
  65. package/dist/i18n/metadata-templates.d.ts +11 -0
  66. package/dist/i18n/metadata-templates.d.ts.map +1 -0
  67. package/dist/i18n/metadata-templates.js +11 -0
  68. package/dist/i18n/metadata-templates.js.map +1 -0
  69. package/dist/i18n/source-messages.d.ts +23 -0
  70. package/dist/i18n/source-messages.d.ts.map +1 -0
  71. package/dist/i18n/source-messages.js +403 -0
  72. package/dist/i18n/source-messages.js.map +1 -0
  73. package/dist/i18n/types.d.ts +10 -0
  74. package/dist/i18n/types.d.ts.map +1 -0
  75. package/dist/i18n/types.js +108 -0
  76. package/dist/i18n/types.js.map +1 -0
  77. package/dist/internal/source-imports.d.ts +5 -1
  78. package/dist/internal/source-imports.d.ts.map +1 -1
  79. package/dist/internal/source-imports.js +23 -44
  80. package/dist/internal/source-imports.js.map +1 -1
  81. package/dist/mcp/client.d.ts +0 -1
  82. package/dist/mcp/client.d.ts.map +1 -1
  83. package/dist/mcp/client.js +11 -39
  84. package/dist/mcp/client.js.map +1 -1
  85. package/dist/mcp/handlers.d.ts +2 -1
  86. package/dist/mcp/handlers.d.ts.map +1 -1
  87. package/dist/mcp/handlers.js.map +1 -1
  88. package/dist/settings/render.d.ts +4 -1
  89. package/dist/settings/render.d.ts.map +1 -1
  90. package/dist/settings/render.js +11 -2
  91. package/dist/settings/render.js.map +1 -1
  92. package/dist/settings/schema.d.ts.map +1 -1
  93. package/dist/settings/schema.js +3 -1
  94. package/dist/settings/schema.js.map +1 -1
  95. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  96. package/dist/vite-plugins/asset-imports.js +2 -12
  97. package/dist/vite-plugins/asset-imports.js.map +1 -1
  98. package/dist/vite-plugins/i18n.d.ts +5 -0
  99. package/dist/vite-plugins/i18n.d.ts.map +1 -0
  100. package/dist/vite-plugins/i18n.js +88 -0
  101. package/dist/vite-plugins/i18n.js.map +1 -0
  102. package/dist/vite-plugins/index.d.ts +1 -1
  103. package/dist/vite-plugins/index.d.ts.map +1 -1
  104. package/dist/vite-plugins/index.js +3 -1
  105. package/dist/vite-plugins/index.js.map +1 -1
  106. package/dist/vite-plugins/resources.d.ts.map +1 -1
  107. package/dist/vite-plugins/resources.js +10 -55
  108. package/dist/vite-plugins/resources.js.map +1 -1
  109. package/dist/vite-plugins/self-contained.d.ts.map +1 -1
  110. package/dist/vite-plugins/self-contained.js +128 -135
  111. package/dist/vite-plugins/self-contained.js.map +1 -1
  112. package/package.json +10 -9
  113. package/src/builder.ts +3 -2
  114. package/src/codegen/run-codegen.ts +53 -7
  115. package/src/commands/codegen.ts +1 -1
  116. package/src/deploy/freedesktop/localize.ts +144 -0
  117. package/src/deploy/install-hints.ts +5 -0
  118. package/src/deploy/payload/launcher.ts +2 -0
  119. package/src/deploy/payload/stage.ts +35 -10
  120. package/src/deploy/run-deploy.ts +128 -13
  121. package/src/deploy/targets/flatpak-source.ts +33 -10
  122. package/src/deploy/tools.ts +35 -0
  123. package/src/dev/locale-dir.ts +22 -0
  124. package/src/dev/runner-main.ts +2 -0
  125. package/src/dev/runner.ts +8 -0
  126. package/src/dev/vite-dev-server.ts +1 -0
  127. package/src/i18n/binding-extractor.ts +1969 -0
  128. package/src/i18n/catalog-template.ts +24 -0
  129. package/src/i18n/catalogs.ts +216 -0
  130. package/src/i18n/extractor-plugin.ts +413 -0
  131. package/src/i18n/metadata-templates.ts +29 -0
  132. package/src/i18n/source-messages.ts +608 -0
  133. package/src/i18n/types.ts +154 -0
  134. package/src/internal/source-imports.ts +28 -57
  135. package/src/mcp/client.ts +17 -44
  136. package/src/mcp/handlers.ts +7 -6
  137. package/src/settings/render.ts +16 -2
  138. package/src/settings/schema.ts +3 -1
  139. package/src/vite-plugins/asset-imports.ts +3 -15
  140. package/src/vite-plugins/i18n.ts +146 -0
  141. package/src/vite-plugins/index.ts +3 -0
  142. package/src/vite-plugins/resources.ts +10 -72
  143. package/src/vite-plugins/self-contained.ts +150 -169
@@ -0,0 +1,403 @@
1
+ import { findKeys } from "i18next-cli";
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
3
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { runCliTool } from "../internal/run-cli-tool.js";
5
+ import { replaceCatalogTemplate } from "./catalog-template.js";
6
+ import { gtkxExtractorPlugin } from "./extractor-plugin.js";
7
+ import { metadataTemplateFiles } from "./metadata-templates.js";
8
+ const CONTEXT_SEPARATOR = "\u{4}";
9
+ const DEFAULT_NAMESPACE = "translation";
10
+ const POTFILES_FILENAME = "POTFILES.in";
11
+ const SYNTHETIC_FILENAME = "messages.js";
12
+ const quietLogger = () => {
13
+ const reports = [];
14
+ return {
15
+ reports,
16
+ logger: {
17
+ info() {
18
+ return;
19
+ },
20
+ warn(message, more) {
21
+ const detail = more === undefined ? "" : ` ${String(more)}`;
22
+ reports.push(`${message}${detail}`);
23
+ },
24
+ error(message) {
25
+ reports.push(String(message));
26
+ },
27
+ },
28
+ };
29
+ };
30
+ const extractorConfig = (sourceFiles) => {
31
+ const integration = gtkxExtractorPlugin();
32
+ return {
33
+ locales: ["en"],
34
+ plugins: [integration.plugin],
35
+ extract: {
36
+ input: sourceFiles,
37
+ output: "unused/{{language}}/{{namespace}}.json",
38
+ contextSeparator: CONTEXT_SEPARATOR,
39
+ defaultNS: DEFAULT_NAMESPACE,
40
+ disablePlurals: false,
41
+ extractFromComments: false,
42
+ functions: [],
43
+ generateBasePluralForms: false,
44
+ keySeparator: ".",
45
+ nsSeparator: false,
46
+ pluralSeparator: "_",
47
+ transComponents: integration.transComponents,
48
+ useTranslationNames: [],
49
+ warnOnConflicts: "error",
50
+ },
51
+ };
52
+ };
53
+ const splitContext = (key) => {
54
+ const index = key.lastIndexOf(CONTEXT_SEPARATOR);
55
+ if (index === -1) {
56
+ return { context: null, msgid: key };
57
+ }
58
+ return { context: key.slice(index + CONTEXT_SEPARATOR.length), msgid: key.slice(0, index) };
59
+ };
60
+ const namespaceFor = (entry) => typeof entry.ns === "string" ? entry.ns : DEFAULT_NAMESPACE;
61
+ const validateIdentity = (context, msgid) => {
62
+ if (context === "" || msgid.length === 0) {
63
+ throw new Error("Translation keys and contexts cannot be empty");
64
+ }
65
+ };
66
+ const compareLocations = (left, right) => left.file.localeCompare(right.file) ||
67
+ (left.line ?? 0) - (right.line ?? 0) ||
68
+ (left.column ?? 0) - (right.column ?? 0);
69
+ const normalizedLocations = (locations) => {
70
+ const unique = new Map();
71
+ for (const location of locations) {
72
+ const key = `${location.file}\0${String(location.line)}\0${String(location.column)}`;
73
+ unique.set(key, location);
74
+ }
75
+ return unique.values().toArray().toSorted(compareLocations);
76
+ };
77
+ const pointSource = (entry, msgid) => {
78
+ if (entry.explicitDefault !== true || typeof entry.defaultValue !== "string") {
79
+ return msgid;
80
+ }
81
+ return entry.defaultValue;
82
+ };
83
+ const pointMessage = (entry) => {
84
+ const { context, msgid } = splitContext(entry.key);
85
+ validateIdentity(context, msgid);
86
+ const isDefaultExplicit = entry.explicitDefault === true;
87
+ const singular = pointSource(entry, msgid);
88
+ if (singular.length === 0) {
89
+ throw new Error("Translation source strings cannot be empty");
90
+ }
91
+ return {
92
+ context,
93
+ kind: isDefaultExplicit ? "default" : "point",
94
+ locations: normalizedLocations(entry.locations ?? []),
95
+ msgid,
96
+ namespace: namespaceFor(entry),
97
+ plural: null,
98
+ singular,
99
+ };
100
+ };
101
+ const expandedPlural = (entry) => {
102
+ if (entry.isOrdinal === true) {
103
+ throw new Error("GNU gettext catalogs do not support i18next ordinal plurals");
104
+ }
105
+ const suffix = /_(few|many|one|other|two|zero)$/u.exec(entry.key);
106
+ const defaultValue = entry.defaultValue;
107
+ const category = suffix?.[1];
108
+ if (suffix === null || category === undefined || typeof defaultValue !== "string") {
109
+ throw new Error("Unable to recover an i18next plural source pair");
110
+ }
111
+ return {
112
+ baseKey: entry.key.slice(0, -suffix[0].length),
113
+ variant: {
114
+ category,
115
+ defaultValue,
116
+ locations: entry.locations ?? [],
117
+ },
118
+ };
119
+ };
120
+ const groupedPlurals = (entries) => {
121
+ const groups = new Map();
122
+ for (const entry of entries) {
123
+ const { baseKey, variant } = expandedPlural(entry);
124
+ const namespace = namespaceFor(entry);
125
+ const key = `${namespace}\0${baseKey}`;
126
+ const group = groups.get(key) ?? { baseKey, namespace, variants: [] };
127
+ group.variants.push(variant);
128
+ groups.set(key, group);
129
+ }
130
+ return groups.values().toArray();
131
+ };
132
+ const pairedVariants = (variants) => {
133
+ const categories = new Map(variants.map((variant) => [variant.category, variant]));
134
+ if (categories.size !== 2 || !categories.has("one") || !categories.has("other")) {
135
+ throw new Error("GNU gettext requires one singular and one plural source string");
136
+ }
137
+ const one = categories.get("one");
138
+ const other = categories.get("other");
139
+ if (one === undefined || other === undefined) {
140
+ throw new Error("Unable to recover an i18next plural source pair");
141
+ }
142
+ return { one, other };
143
+ };
144
+ const pluralMessage = ({ baseKey, namespace, variants }) => {
145
+ const { one, other } = pairedVariants(variants);
146
+ const { context, msgid } = splitContext(baseKey);
147
+ validateIdentity(context, msgid);
148
+ const hasStableKey = one.defaultValue !== other.defaultValue;
149
+ const singular = hasStableKey ? one.defaultValue : msgid;
150
+ const plural = other.defaultValue;
151
+ if (singular === plural || singular.length === 0 || plural.length === 0) {
152
+ throw new Error("GNU gettext plural source strings must be distinct and non-empty");
153
+ }
154
+ return {
155
+ context,
156
+ kind: hasStableKey ? "pluralDefaults" : "plural",
157
+ locations: normalizedLocations(variants.flatMap((variant) => variant.locations)),
158
+ msgid,
159
+ namespace,
160
+ plural,
161
+ singular,
162
+ };
163
+ };
164
+ const pluralMessages = (entries) => groupedPlurals(entries).map((group) => pluralMessage(group));
165
+ const assertCardinal = (entry) => {
166
+ if (entry.isOrdinal === true) {
167
+ throw new Error("GNU gettext catalogs do not support i18next ordinal plurals");
168
+ }
169
+ };
170
+ const sourceMessages = (entries) => {
171
+ const points = [];
172
+ const plurals = [];
173
+ for (const entry of entries) {
174
+ assertCardinal(entry);
175
+ if (entry.isExpandedPlural === true) {
176
+ plurals.push(entry);
177
+ continue;
178
+ }
179
+ if (entry.hasCount === true) {
180
+ throw new Error("Count-based translations require an explicit plural source string");
181
+ }
182
+ points.push(entry);
183
+ }
184
+ return [...points.map((entry) => pointMessage(entry)), ...pluralMessages(plurals)];
185
+ };
186
+ const compareMessages = (left, right) => left.namespace.localeCompare(right.namespace) ||
187
+ (left.context ?? "").localeCompare(right.context ?? "") ||
188
+ left.msgid.localeCompare(right.msgid) ||
189
+ left.singular.localeCompare(right.singular) ||
190
+ (left.plural ?? "").localeCompare(right.plural ?? "");
191
+ const normalizedSourceFiles = (root, paths) => {
192
+ const files = paths
193
+ .map((path) => resolve(root, path))
194
+ .filter((path) => {
195
+ const projectPath = relative(root, path);
196
+ return projectPath !== ".." && !projectPath.startsWith(`..${sep}`) && !isAbsolute(projectPath);
197
+ });
198
+ return new Set(files).values().toArray().toSorted((left, right) => left.localeCompare(right));
199
+ };
200
+ const findSourceMessages = async (sourceFiles) => {
201
+ if (sourceFiles.length === 0) {
202
+ return [];
203
+ }
204
+ const fileErrors = [];
205
+ const { logger, reports } = quietLogger();
206
+ const { allKeys } = await findKeys(extractorConfig(sourceFiles), logger, fileErrors);
207
+ if (fileErrors.length > 0 || reports.length > 0) {
208
+ throw new Error([...fileErrors, ...reports].join("\n"));
209
+ }
210
+ return sourceMessages(allKeys.values().toArray()).toSorted(compareMessages);
211
+ };
212
+ const projectPath = (root, path) => {
213
+ const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);
214
+ const projectRelative = relative(root, absolute);
215
+ if (projectRelative === "" ||
216
+ projectRelative === ".." ||
217
+ projectRelative.startsWith(`..${sep}`) ||
218
+ isAbsolute(projectRelative)) {
219
+ return null;
220
+ }
221
+ return projectRelative.replaceAll("\\", "/");
222
+ };
223
+ const writePotfiles = (project, sourceFiles) => {
224
+ const paths = sourceFiles
225
+ .map((path) => projectPath(project.root, path))
226
+ .filter((path) => path !== null);
227
+ const sorted = [...new Set(paths)].toSorted((left, right) => left.localeCompare(right));
228
+ const target = resolve(project.poDir, POTFILES_FILENAME);
229
+ writeFileSync(target, sorted.length === 0 ? "" : `${sorted.join("\n")}\n`);
230
+ return target;
231
+ };
232
+ const renderCatalogCall = (message) => {
233
+ const msgid = JSON.stringify(message.singular);
234
+ if (message.plural !== null) {
235
+ const plural = JSON.stringify(message.plural);
236
+ return message.context === null
237
+ ? `ngettext(${msgid}, ${plural}, 0);`
238
+ : `npgettext(${JSON.stringify(message.context)}, ${msgid}, ${plural}, 0);`;
239
+ }
240
+ return message.context === null
241
+ ? `gettext(${msgid});`
242
+ : `pgettext(${JSON.stringify(message.context)}, ${msgid});`;
243
+ };
244
+ const readSources = (sourceFiles) => new Map(sourceFiles.map((path) => [path, readFileSync(path, "utf8")]));
245
+ const locatedOwners = (project, message) => {
246
+ const owners = [];
247
+ for (const location of message.locations) {
248
+ const path = projectPath(project.root, location.file);
249
+ if (path !== null) {
250
+ owners.push({ path, line: location.line });
251
+ }
252
+ }
253
+ const unique = new Map(owners.map((owner) => [`${owner.path}\0${String(owner.line)}`, owner]));
254
+ return unique.values().toArray();
255
+ };
256
+ const inferredOwner = (project, message, sources) => {
257
+ for (const [path, source] of sources) {
258
+ const index = source.indexOf(message.msgid);
259
+ if (index !== -1) {
260
+ return {
261
+ path: projectPath(project.root, path) ?? SYNTHETIC_FILENAME,
262
+ line: source.slice(0, index).split("\n").length,
263
+ };
264
+ }
265
+ }
266
+ return null;
267
+ };
268
+ const sourceOwners = (project, message, sources) => {
269
+ const located = locatedOwners(project, message);
270
+ if (located.length > 0) {
271
+ return located;
272
+ }
273
+ return [inferredOwner(project, message, sources) ?? { path: SYNTHETIC_FILENAME, line: undefined }];
274
+ };
275
+ const syntheticEntries = (project, messages, sourceFiles) => {
276
+ const sources = readSources(sourceFiles);
277
+ const entries = new Map();
278
+ for (const message of messages) {
279
+ for (const owner of sourceOwners(project, message, sources)) {
280
+ const owned = entries.get(owner.path) ?? [];
281
+ owned.push({ call: renderCatalogCall(message), line: owner.line });
282
+ entries.set(owner.path, owned);
283
+ }
284
+ }
285
+ if (entries.size === 0) {
286
+ entries.set(SYNTHETIC_FILENAME, []);
287
+ }
288
+ return entries;
289
+ };
290
+ const compareSyntheticEntries = (left, right) => (left.line ?? Number.MAX_SAFE_INTEGER) - (right.line ?? Number.MAX_SAFE_INTEGER);
291
+ const lastSyntheticLine = (entries) => {
292
+ let line = 0;
293
+ for (const entry of entries) {
294
+ line = Math.max(line, entry.line ?? 0);
295
+ }
296
+ return line;
297
+ };
298
+ const appendSyntheticEntry = (lines, entry, requestedLine) => {
299
+ const index = requestedLine - 1;
300
+ const existing = lines[index];
301
+ if (existing === undefined || existing.length === 0) {
302
+ lines[index] = entry.call;
303
+ return;
304
+ }
305
+ lines[index] = `${existing} ${entry.call}`;
306
+ };
307
+ const renderSyntheticSource = (entries) => {
308
+ const lines = [];
309
+ const sorted = entries.toSorted(compareSyntheticEntries);
310
+ let nextLine = lastSyntheticLine(entries) + 1;
311
+ for (const entry of sorted) {
312
+ const requestedLine = Math.max(1, entry.line ?? nextLine++);
313
+ appendSyntheticEntry(lines, entry, requestedLine);
314
+ }
315
+ return `${lines.join("\n")}\n`;
316
+ };
317
+ const writeSyntheticSources = (workDir, project, messages, sourceFiles) => {
318
+ const entries = syntheticEntries(project, messages, sourceFiles);
319
+ const paths = [];
320
+ for (const [path, owned] of entries) {
321
+ const target = join(workDir, path);
322
+ mkdirSync(dirname(target), { recursive: true });
323
+ writeFileSync(target, renderSyntheticSource(owned));
324
+ paths.push(path);
325
+ }
326
+ const potfiles = join(workDir, POTFILES_FILENAME);
327
+ writeFileSync(potfiles, `${paths.toSorted((left, right) => left.localeCompare(right)).join("\n")}\n`);
328
+ return potfiles;
329
+ };
330
+ const extractSourceMessages = ({ project, messages, sourceFiles, output, workDir }) => {
331
+ const potfilesPath = writeSyntheticSources(workDir, project, messages, sourceFiles);
332
+ runCliTool({
333
+ tool: "xgettext",
334
+ args: [
335
+ "--language=JavaScript",
336
+ "--from-code=UTF-8",
337
+ "--force-po",
338
+ "--keyword=gettext:1",
339
+ "--keyword=ngettext:1,2",
340
+ "--keyword=pgettext:1c,2",
341
+ "--keyword=npgettext:1c,2,3",
342
+ `--directory=${workDir}`,
343
+ `--files-from=${potfilesPath}`,
344
+ `--output=${output}`,
345
+ ],
346
+ target: output,
347
+ });
348
+ };
349
+ const extractMetadataFragment = (project, input, output) => {
350
+ runCliTool({
351
+ tool: "msggrep",
352
+ args: [
353
+ "--force-po",
354
+ `--output-file=${output}`,
355
+ ...metadataTemplateFiles(project).map((file) => `--location=${file.relativePath}`),
356
+ input,
357
+ ],
358
+ target: input,
359
+ });
360
+ };
361
+ const joinMetadataFragment = (output, fragment) => {
362
+ runCliTool({
363
+ tool: "xgettext",
364
+ args: ["--language=PO", "--join-existing", "--force-po", `--output=${output}`, fragment],
365
+ target: output,
366
+ });
367
+ };
368
+ const extractCatalogTemplate = ({ project, messages, sourceFiles, shouldPreserveMetadataMessages, output = resolve(project.poDir, `${project.domain}.pot`), }) => {
369
+ const workDir = mkdtempSync(join(project.poDir, ".gtkx-i18n-"));
370
+ const source = join(workDir, "source.pot");
371
+ const hasPreviousTemplate = existsSync(output);
372
+ try {
373
+ if (shouldPreserveMetadataMessages && hasPreviousTemplate) {
374
+ const fragment = join(workDir, "metadata.pot");
375
+ extractMetadataFragment(project, output, fragment);
376
+ extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });
377
+ joinMetadataFragment(source, fragment);
378
+ }
379
+ else {
380
+ extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });
381
+ }
382
+ replaceCatalogTemplate(source, output);
383
+ }
384
+ finally {
385
+ rmSync(workDir, { recursive: true, force: true });
386
+ }
387
+ };
388
+ const extractSourceCatalogTo = async (project, paths, output) => {
389
+ const sourceFiles = normalizedSourceFiles(project.root, paths);
390
+ const messages = await findSourceMessages(sourceFiles);
391
+ writePotfiles(project, sourceFiles);
392
+ extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages: false, output });
393
+ return { messages, sourceFiles };
394
+ };
395
+ const extractSourceCatalog = async (project, paths, shouldPreserveMetadataMessages = true) => {
396
+ const sourceFiles = normalizedSourceFiles(project.root, paths);
397
+ const messages = await findSourceMessages(sourceFiles);
398
+ writePotfiles(project, sourceFiles);
399
+ extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages });
400
+ return { messages, sourceFiles };
401
+ };
402
+ export { extractSourceCatalog, extractSourceCatalogTo };
403
+ //# sourceMappingURL=source-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-messages.js","sourceRoot":"","sources":["../../src/i18n/source-messages.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtractedKey, I18nextToolkitConfig, Logger } from \"i18next-cli\";\nimport { findKeys } from \"i18next-cli\";\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport type { CatalogProject } from \"./catalogs.js\";\nimport { runCliTool } from \"../internal/run-cli-tool.js\";\nimport { replaceCatalogTemplate } from \"./catalog-template.js\";\nimport { gtkxExtractorPlugin } from \"./extractor-plugin.js\";\nimport { metadataTemplateFiles } from \"./metadata-templates.js\";\n\ntype SourceLocation = {\n file: string;\n line?: number | undefined;\n column?: number | undefined;\n};\n\ntype SourceMessage = {\n context: string | null;\n kind: \"default\" | \"plural\" | \"pluralDefaults\" | \"point\";\n locations: SourceLocation[];\n msgid: string;\n namespace: string;\n plural: string | null;\n singular: string;\n};\n\ntype SourceCatalog = {\n messages: SourceMessage[];\n sourceFiles: string[];\n};\n\ntype SyntheticEntry = {\n call: string;\n line: number | undefined;\n};\n\ntype SourceExtraction = {\n messages: SourceMessage[];\n output: string;\n project: CatalogProject;\n sourceFiles: string[];\n workDir: string;\n};\n\ntype CatalogTemplateExtraction = {\n messages: SourceMessage[];\n output?: string | undefined;\n project: CatalogProject;\n shouldPreserveMetadataMessages: boolean;\n sourceFiles: string[];\n};\n\ntype PluralVariant = {\n category: string;\n defaultValue: string;\n locations: SourceLocation[];\n};\n\ntype PluralGroup = {\n baseKey: string;\n namespace: string;\n variants: PluralVariant[];\n};\n\nconst CONTEXT_SEPARATOR = \"\\u{4}\";\nconst DEFAULT_NAMESPACE = \"translation\";\nconst POTFILES_FILENAME = \"POTFILES.in\";\nconst SYNTHETIC_FILENAME = \"messages.js\";\n\nconst quietLogger = (): { logger: Logger; reports: string[] } => {\n const reports: string[] = [];\n\n return {\n reports,\n logger: {\n info() {\n return;\n },\n warn(message, more) {\n const detail = more === undefined ? \"\" : ` ${String(more)}`;\n reports.push(`${message}${detail}`);\n },\n error(message) {\n reports.push(String(message));\n },\n },\n };\n};\n\nconst extractorConfig = (sourceFiles: string[]): I18nextToolkitConfig => {\n const integration = gtkxExtractorPlugin();\n\n return {\n locales: [\"en\"],\n plugins: [integration.plugin],\n extract: {\n input: sourceFiles,\n output: \"unused/{{language}}/{{namespace}}.json\",\n contextSeparator: CONTEXT_SEPARATOR,\n defaultNS: DEFAULT_NAMESPACE,\n disablePlurals: false,\n extractFromComments: false,\n functions: [],\n generateBasePluralForms: false,\n keySeparator: \".\",\n nsSeparator: false,\n pluralSeparator: \"_\",\n transComponents: integration.transComponents,\n useTranslationNames: [],\n warnOnConflicts: \"error\",\n },\n };\n};\n\nconst splitContext = (key: string): { context: string | null; msgid: string } => {\n const index = key.lastIndexOf(CONTEXT_SEPARATOR);\n\n if (index === -1) {\n return { context: null, msgid: key };\n }\n\n return { context: key.slice(index + CONTEXT_SEPARATOR.length), msgid: key.slice(0, index) };\n};\n\nconst namespaceFor = (entry: ExtractedKey): string =>\n typeof entry.ns === \"string\" ? entry.ns : DEFAULT_NAMESPACE;\n\nconst validateIdentity = (context: string | null, msgid: string): void => {\n if (context === \"\" || msgid.length === 0) {\n throw new Error(\"Translation keys and contexts cannot be empty\");\n }\n};\n\nconst compareLocations = (left: SourceLocation, right: SourceLocation): number =>\n left.file.localeCompare(right.file) ||\n (left.line ?? 0) - (right.line ?? 0) ||\n (left.column ?? 0) - (right.column ?? 0);\n\nconst normalizedLocations = (locations: SourceLocation[]): SourceLocation[] => {\n const unique: Map<string, SourceLocation> = new Map();\n\n for (const location of locations) {\n const key = `${location.file}\\0${String(location.line)}\\0${String(location.column)}`;\n unique.set(key, location);\n }\n\n return unique.values().toArray().toSorted(compareLocations);\n};\n\nconst pointSource = (entry: ExtractedKey, msgid: string): string => {\n if (entry.explicitDefault !== true || typeof entry.defaultValue !== \"string\") {\n return msgid;\n }\n\n return entry.defaultValue;\n};\n\nconst pointMessage = (entry: ExtractedKey): SourceMessage => {\n const { context, msgid } = splitContext(entry.key);\n validateIdentity(context, msgid);\n const isDefaultExplicit = entry.explicitDefault === true;\n const singular = pointSource(entry, msgid);\n\n if (singular.length === 0) {\n throw new Error(\"Translation source strings cannot be empty\");\n }\n\n return {\n context,\n kind: isDefaultExplicit ? \"default\" : \"point\",\n locations: normalizedLocations(entry.locations ?? []),\n msgid,\n namespace: namespaceFor(entry),\n plural: null,\n singular,\n };\n};\n\nconst expandedPlural = (entry: ExtractedKey): { baseKey: string; variant: PluralVariant } => {\n if (entry.isOrdinal === true) {\n throw new Error(\"GNU gettext catalogs do not support i18next ordinal plurals\");\n }\n\n const suffix = /_(few|many|one|other|two|zero)$/u.exec(entry.key);\n const defaultValue = entry.defaultValue;\n const category = suffix?.[1];\n\n if (suffix === null || category === undefined || typeof defaultValue !== \"string\") {\n throw new Error(\"Unable to recover an i18next plural source pair\");\n }\n\n return {\n baseKey: entry.key.slice(0, -suffix[0].length),\n variant: {\n category,\n defaultValue,\n locations: entry.locations ?? [],\n },\n };\n};\n\nconst groupedPlurals = (entries: ExtractedKey[]): PluralGroup[] => {\n const groups: Map<string, PluralGroup> = new Map();\n\n for (const entry of entries) {\n const { baseKey, variant } = expandedPlural(entry);\n const namespace = namespaceFor(entry);\n const key = `${namespace}\\0${baseKey}`;\n const group = groups.get(key) ?? { baseKey, namespace, variants: [] };\n group.variants.push(variant);\n groups.set(key, group);\n }\n\n return groups.values().toArray();\n};\n\nconst pairedVariants = (variants: PluralVariant[]): { one: PluralVariant; other: PluralVariant } => {\n const categories = new Map(variants.map((variant) => [variant.category, variant]));\n\n if (categories.size !== 2 || !categories.has(\"one\") || !categories.has(\"other\")) {\n throw new Error(\"GNU gettext requires one singular and one plural source string\");\n }\n\n const one = categories.get(\"one\");\n const other = categories.get(\"other\");\n\n if (one === undefined || other === undefined) {\n throw new Error(\"Unable to recover an i18next plural source pair\");\n }\n\n return { one, other };\n};\n\nconst pluralMessage = ({ baseKey, namespace, variants }: PluralGroup): SourceMessage => {\n const { one, other } = pairedVariants(variants);\n const { context, msgid } = splitContext(baseKey);\n validateIdentity(context, msgid);\n const hasStableKey = one.defaultValue !== other.defaultValue;\n const singular = hasStableKey ? one.defaultValue : msgid;\n const plural = other.defaultValue;\n\n if (singular === plural || singular.length === 0 || plural.length === 0) {\n throw new Error(\"GNU gettext plural source strings must be distinct and non-empty\");\n }\n\n return {\n context,\n kind: hasStableKey ? \"pluralDefaults\" : \"plural\",\n locations: normalizedLocations(variants.flatMap((variant) => variant.locations)),\n msgid,\n namespace,\n plural,\n singular,\n };\n};\n\nconst pluralMessages = (entries: ExtractedKey[]): SourceMessage[] =>\n groupedPlurals(entries).map((group) => pluralMessage(group));\n\nconst assertCardinal = (entry: ExtractedKey): void => {\n if (entry.isOrdinal === true) {\n throw new Error(\"GNU gettext catalogs do not support i18next ordinal plurals\");\n }\n};\n\nconst sourceMessages = (entries: ExtractedKey[]): SourceMessage[] => {\n const points: ExtractedKey[] = [];\n const plurals: ExtractedKey[] = [];\n\n for (const entry of entries) {\n assertCardinal(entry);\n\n if (entry.isExpandedPlural === true) {\n plurals.push(entry);\n continue;\n }\n\n if (entry.hasCount === true) {\n throw new Error(\"Count-based translations require an explicit plural source string\");\n }\n\n points.push(entry);\n }\n\n return [...points.map((entry) => pointMessage(entry)), ...pluralMessages(plurals)];\n};\n\nconst compareMessages = (left: SourceMessage, right: SourceMessage): number =>\n left.namespace.localeCompare(right.namespace) ||\n (left.context ?? \"\").localeCompare(right.context ?? \"\") ||\n left.msgid.localeCompare(right.msgid) ||\n left.singular.localeCompare(right.singular) ||\n (left.plural ?? \"\").localeCompare(right.plural ?? \"\");\n\nconst normalizedSourceFiles = (root: string, paths: string[]): string[] => {\n const files = paths\n .map((path) => resolve(root, path))\n .filter((path) => {\n const projectPath = relative(root, path);\n\n return projectPath !== \"..\" && !projectPath.startsWith(`..${sep}`) && !isAbsolute(projectPath);\n });\n\n return new Set(files).values().toArray().toSorted((left, right) => left.localeCompare(right));\n};\n\nconst findSourceMessages = async (sourceFiles: string[]): Promise<SourceMessage[]> => {\n if (sourceFiles.length === 0) {\n return [];\n }\n\n const fileErrors: string[] = [];\n const { logger, reports } = quietLogger();\n const { allKeys } = await findKeys(extractorConfig(sourceFiles), logger, fileErrors);\n\n if (fileErrors.length > 0 || reports.length > 0) {\n throw new Error([...fileErrors, ...reports].join(\"\\n\"));\n }\n\n return sourceMessages(allKeys.values().toArray()).toSorted(compareMessages);\n};\n\nconst projectPath = (root: string, path: string): string | null => {\n const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);\n const projectRelative = relative(root, absolute);\n\n if (\n projectRelative === \"\" ||\n projectRelative === \"..\" ||\n projectRelative.startsWith(`..${sep}`) ||\n isAbsolute(projectRelative)\n ) {\n return null;\n }\n\n return projectRelative.replaceAll(\"\\\\\", \"/\");\n};\n\nconst writePotfiles = (project: CatalogProject, sourceFiles: string[]): string => {\n const paths = sourceFiles\n .map((path) => projectPath(project.root, path))\n .filter((path): path is string => path !== null);\n\n const sorted = [...new Set(paths)].toSorted((left, right) => left.localeCompare(right));\n const target = resolve(project.poDir, POTFILES_FILENAME);\n writeFileSync(target, sorted.length === 0 ? \"\" : `${sorted.join(\"\\n\")}\\n`);\n\n return target;\n};\n\nconst renderCatalogCall = (message: SourceMessage): string => {\n const msgid = JSON.stringify(message.singular);\n\n if (message.plural !== null) {\n const plural = JSON.stringify(message.plural);\n\n return message.context === null\n ? `ngettext(${msgid}, ${plural}, 0);`\n : `npgettext(${JSON.stringify(message.context)}, ${msgid}, ${plural}, 0);`;\n }\n\n return message.context === null\n ? `gettext(${msgid});`\n : `pgettext(${JSON.stringify(message.context)}, ${msgid});`;\n};\n\nconst readSources = (sourceFiles: string[]): Map<string, string> =>\n new Map(sourceFiles.map((path) => [path, readFileSync(path, \"utf8\")]));\n\nconst locatedOwners = (\n project: CatalogProject,\n message: SourceMessage,\n): { path: string; line: number | undefined }[] => {\n const owners: { path: string; line: number | undefined }[] = [];\n\n for (const location of message.locations) {\n const path = projectPath(project.root, location.file);\n\n if (path !== null) {\n owners.push({ path, line: location.line });\n }\n }\n\n const unique = new Map(owners.map((owner) => [`${owner.path}\\0${String(owner.line)}`, owner]));\n\n return unique.values().toArray();\n};\n\nconst inferredOwner = (\n project: CatalogProject,\n message: SourceMessage,\n sources: Map<string, string>,\n): { path: string; line: number } | null => {\n for (const [path, source] of sources) {\n const index = source.indexOf(message.msgid);\n\n if (index !== -1) {\n return {\n path: projectPath(project.root, path) ?? SYNTHETIC_FILENAME,\n line: source.slice(0, index).split(\"\\n\").length,\n };\n }\n }\n\n return null;\n};\n\nconst sourceOwners = (\n project: CatalogProject,\n message: SourceMessage,\n sources: Map<string, string>,\n): { path: string; line: number | undefined }[] => {\n const located = locatedOwners(project, message);\n\n if (located.length > 0) {\n return located;\n }\n\n return [inferredOwner(project, message, sources) ?? { path: SYNTHETIC_FILENAME, line: undefined }];\n};\n\nconst syntheticEntries = (\n project: CatalogProject,\n messages: SourceMessage[],\n sourceFiles: string[],\n): Map<string, SyntheticEntry[]> => {\n const sources = readSources(sourceFiles);\n const entries: Map<string, SyntheticEntry[]> = new Map();\n\n for (const message of messages) {\n for (const owner of sourceOwners(project, message, sources)) {\n const owned = entries.get(owner.path) ?? [];\n owned.push({ call: renderCatalogCall(message), line: owner.line });\n entries.set(owner.path, owned);\n }\n }\n\n if (entries.size === 0) {\n entries.set(SYNTHETIC_FILENAME, []);\n }\n\n return entries;\n};\n\nconst compareSyntheticEntries = (left: SyntheticEntry, right: SyntheticEntry): number =>\n (left.line ?? Number.MAX_SAFE_INTEGER) - (right.line ?? Number.MAX_SAFE_INTEGER);\n\nconst lastSyntheticLine = (entries: SyntheticEntry[]): number => {\n let line = 0;\n\n for (const entry of entries) {\n line = Math.max(line, entry.line ?? 0);\n }\n\n return line;\n};\n\nconst appendSyntheticEntry = (lines: string[], entry: SyntheticEntry, requestedLine: number): void => {\n const index = requestedLine - 1;\n const existing = lines[index];\n\n if (existing === undefined || existing.length === 0) {\n lines[index] = entry.call;\n\n return;\n }\n\n lines[index] = `${existing} ${entry.call}`;\n};\n\nconst renderSyntheticSource = (entries: SyntheticEntry[]): string => {\n const lines: string[] = [];\n const sorted = entries.toSorted(compareSyntheticEntries);\n let nextLine = lastSyntheticLine(entries) + 1;\n\n for (const entry of sorted) {\n const requestedLine = Math.max(1, entry.line ?? nextLine++);\n appendSyntheticEntry(lines, entry, requestedLine);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n};\n\nconst writeSyntheticSources = (\n workDir: string,\n project: CatalogProject,\n messages: SourceMessage[],\n sourceFiles: string[],\n): string => {\n const entries = syntheticEntries(project, messages, sourceFiles);\n const paths: string[] = [];\n\n for (const [path, owned] of entries) {\n const target = join(workDir, path);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, renderSyntheticSource(owned));\n paths.push(path);\n }\n\n const potfiles = join(workDir, POTFILES_FILENAME);\n writeFileSync(potfiles, `${paths.toSorted((left, right) => left.localeCompare(right)).join(\"\\n\")}\\n`);\n\n return potfiles;\n};\n\nconst extractSourceMessages = ({ project, messages, sourceFiles, output, workDir }: SourceExtraction): void => {\n const potfilesPath = writeSyntheticSources(workDir, project, messages, sourceFiles);\n\n runCliTool({\n tool: \"xgettext\",\n args: [\n \"--language=JavaScript\",\n \"--from-code=UTF-8\",\n \"--force-po\",\n \"--keyword=gettext:1\",\n \"--keyword=ngettext:1,2\",\n \"--keyword=pgettext:1c,2\",\n \"--keyword=npgettext:1c,2,3\",\n `--directory=${workDir}`,\n `--files-from=${potfilesPath}`,\n `--output=${output}`,\n ],\n target: output,\n });\n};\n\nconst extractMetadataFragment = (project: CatalogProject, input: string, output: string): void => {\n runCliTool({\n tool: \"msggrep\",\n args: [\n \"--force-po\",\n `--output-file=${output}`,\n ...metadataTemplateFiles(project).map((file) => `--location=${file.relativePath}`),\n input,\n ],\n target: input,\n });\n};\n\nconst joinMetadataFragment = (output: string, fragment: string): void => {\n runCliTool({\n tool: \"xgettext\",\n args: [\"--language=PO\", \"--join-existing\", \"--force-po\", `--output=${output}`, fragment],\n target: output,\n });\n};\n\nconst extractCatalogTemplate = ({\n project,\n messages,\n sourceFiles,\n shouldPreserveMetadataMessages,\n output = resolve(project.poDir, `${project.domain}.pot`),\n}: CatalogTemplateExtraction): void => {\n const workDir = mkdtempSync(join(project.poDir, \".gtkx-i18n-\"));\n const source = join(workDir, \"source.pot\");\n const hasPreviousTemplate = existsSync(output);\n\n try {\n if (shouldPreserveMetadataMessages && hasPreviousTemplate) {\n const fragment = join(workDir, \"metadata.pot\");\n extractMetadataFragment(project, output, fragment);\n extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });\n joinMetadataFragment(source, fragment);\n } else {\n extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });\n }\n\n replaceCatalogTemplate(source, output);\n } finally {\n rmSync(workDir, { recursive: true, force: true });\n }\n};\n\nconst extractSourceCatalogTo = async (\n project: CatalogProject,\n paths: string[],\n output: string,\n): Promise<SourceCatalog> => {\n const sourceFiles = normalizedSourceFiles(project.root, paths);\n const messages = await findSourceMessages(sourceFiles);\n writePotfiles(project, sourceFiles);\n extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages: false, output });\n\n return { messages, sourceFiles };\n};\n\nconst extractSourceCatalog = async (\n project: CatalogProject,\n paths: string[],\n shouldPreserveMetadataMessages = true,\n): Promise<SourceCatalog> => {\n const sourceFiles = normalizedSourceFiles(project.root, paths);\n const messages = await findSourceMessages(sourceFiles);\n writePotfiles(project, sourceFiles);\n extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages });\n\n return { messages, sourceFiles };\n};\n\nexport { type SourceMessage, extractSourceCatalog, extractSourceCatalogTo };\n"]}
@@ -0,0 +1,10 @@
1
+ import type { SourceMessage } from "./source-messages.js";
2
+ type I18nTypesResult = {
3
+ isWritten: boolean;
4
+ path: string;
5
+ };
6
+ declare const I18N_TYPES_FILENAME = "i18n.d.ts";
7
+ declare const i18nTypesPath: (root: string) => string;
8
+ declare const emitI18nTypes: (root: string, messages: SourceMessage[], isEnabled?: boolean) => I18nTypesResult;
9
+ export { I18N_TYPES_FILENAME, emitI18nTypes, i18nTypesPath };
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,KAAK,eAAe,GAAG;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,QAAA,MAAM,mBAAmB,cAAc,CAAC;AAwHxC,QAAA,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAkE,CAAC;AAUzG,QAAA,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,UAAU,aAAa,EAAE,EAAE,mBAAgB,KAAG,eAYlF,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ const I18N_TYPES_FILENAME = "i18n.d.ts";
4
+ const INTERPOLATION_PATTERN = /\{\{[^{}]+\}\}/u;
5
+ const stringType = (values) => [...new Set(values)].map((value) => JSON.stringify(value)).join(" | ");
6
+ const contextField = (context) => context === null ? "" : ` context: ${JSON.stringify(context)};`;
7
+ const hasInterpolation = (values) => values.some((value) => INTERPOLATION_PATTERN.test(value));
8
+ const pointVariant = (message) => {
9
+ const isRequired = message.context !== null || hasInterpolation([message.msgid]);
10
+ const isInterpolated = hasInterpolation([message.msgid]);
11
+ return (`{${contextField(message.context)} interpolated: ${String(isInterpolated)}; kind: "point"; ` +
12
+ `required: ${String(isRequired)}; value: ${JSON.stringify(message.msgid)} }`);
13
+ };
14
+ const defaultVariant = (message) => {
15
+ const values = [message.singular];
16
+ const isInterpolated = hasInterpolation(values);
17
+ const isRequired = message.context !== null || isInterpolated;
18
+ return (`{${contextField(message.context)} defaultValue: ${JSON.stringify(message.singular)}; ` +
19
+ `interpolated: ${String(isInterpolated)}; kind: "default"; required: ${String(isRequired)}; ` +
20
+ `value: ${stringType(values)} }`);
21
+ };
22
+ const requirePlural = (message) => {
23
+ if (message.plural === null) {
24
+ throw new Error("Plural translation metadata requires a plural source string");
25
+ }
26
+ return message.plural;
27
+ };
28
+ const pluralVariant = (message) => {
29
+ const plural = requirePlural(message);
30
+ const values = [message.singular, plural];
31
+ const isInterpolated = hasInterpolation(values);
32
+ return (`{${contextField(message.context)} defaultValue: ${JSON.stringify(plural)}; ` +
33
+ `interpolated: ${String(isInterpolated)}; kind: "plural"; required: true; ` +
34
+ `value: ${stringType(values)} }`);
35
+ };
36
+ const pluralDefaultsVariant = (message) => {
37
+ const plural = requirePlural(message);
38
+ const values = [message.singular, plural];
39
+ const isInterpolated = hasInterpolation(values);
40
+ return (`{${contextField(message.context)} defaultValueOne: ${JSON.stringify(message.singular)}; ` +
41
+ `defaultValueOther: ${JSON.stringify(plural)}; interpolated: ${String(isInterpolated)}; ` +
42
+ `kind: "pluralDefaults"; required: true; value: ${stringType(values)} }`);
43
+ };
44
+ const variantsFor = (message) => {
45
+ if (message.kind === "plural") {
46
+ return [pluralVariant(message)];
47
+ }
48
+ if (message.kind === "pluralDefaults") {
49
+ return [pluralDefaultsVariant(message)];
50
+ }
51
+ return message.kind === "default" ? [defaultVariant(message)] : [pointVariant(message)];
52
+ };
53
+ const renderRegistry = (messages) => {
54
+ const entries = new Map();
55
+ for (const message of messages) {
56
+ const variants = entries.get(message.msgid) ?? new Set();
57
+ for (const variant of variantsFor(message)) {
58
+ variants.add(variant);
59
+ }
60
+ entries.set(message.msgid, variants);
61
+ }
62
+ return [...entries]
63
+ .toSorted(([left], [right]) => left.localeCompare(right))
64
+ .map(([msgid, variants]) => ` ${JSON.stringify(msgid)}: ${[...variants].join(" | ")};`);
65
+ };
66
+ const generatedHeader = () => [
67
+ "/**",
68
+ " * Translation declarations generated by GTKX. Regenerated by",
69
+ " * `gtkx codegen`, `gtkx dev`, and `gtkx build`; do not edit.",
70
+ " */",
71
+ ];
72
+ const renderI18nTypes = (messages, isEnabled = true) => {
73
+ if (!isEnabled) {
74
+ return [...generatedHeader(), "export {};", ""].join("\n");
75
+ }
76
+ return [
77
+ ...generatedHeader(),
78
+ 'import "@gtkx/i18n";',
79
+ "",
80
+ 'declare module "@gtkx/i18n" {',
81
+ " interface TranslationRegistry {",
82
+ ...renderRegistry(messages),
83
+ " }",
84
+ "}",
85
+ "",
86
+ ].join("\n");
87
+ };
88
+ const i18nTypesPath = (root) => join(root, "node_modules", ".gtkx", I18N_TYPES_FILENAME);
89
+ const readFileOrNull = (path) => {
90
+ try {
91
+ return readFileSync(path, "utf8");
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ };
97
+ const emitI18nTypes = (root, messages, isEnabled = true) => {
98
+ const path = i18nTypesPath(root);
99
+ const content = renderI18nTypes(messages, isEnabled);
100
+ if (readFileOrNull(path) === content) {
101
+ return { isWritten: false, path };
102
+ }
103
+ mkdirSync(dirname(path), { recursive: true });
104
+ writeFileSync(path, content);
105
+ return { isWritten: true, path };
106
+ };
107
+ export { I18N_TYPES_FILENAME, emitI18nTypes, i18nTypesPath };
108
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { SourceMessage } from \"./source-messages.js\";\n\ntype I18nTypesResult = {\n isWritten: boolean;\n path: string;\n};\n\nconst I18N_TYPES_FILENAME = \"i18n.d.ts\";\nconst INTERPOLATION_PATTERN = /\\{\\{[^{}]+\\}\\}/u;\n\nconst stringType = (values: string[]): string =>\n [...new Set(values)].map((value) => JSON.stringify(value)).join(\" | \");\n\nconst contextField = (context: string | null): string =>\n context === null ? \"\" : ` context: ${JSON.stringify(context)};`;\n\nconst hasInterpolation = (values: string[]): boolean => values.some((value) => INTERPOLATION_PATTERN.test(value));\n\nconst pointVariant = (message: SourceMessage): string => {\n const isRequired = message.context !== null || hasInterpolation([message.msgid]);\n const isInterpolated = hasInterpolation([message.msgid]);\n\n return (\n `{${contextField(message.context)} interpolated: ${String(isInterpolated)}; kind: \"point\"; ` +\n `required: ${String(isRequired)}; value: ${JSON.stringify(message.msgid)} }`\n );\n};\n\nconst defaultVariant = (message: SourceMessage): string => {\n const values = [message.singular];\n const isInterpolated = hasInterpolation(values);\n const isRequired = message.context !== null || isInterpolated;\n\n return (\n `{${contextField(message.context)} defaultValue: ${JSON.stringify(message.singular)}; ` +\n `interpolated: ${String(isInterpolated)}; kind: \"default\"; required: ${String(isRequired)}; ` +\n `value: ${stringType(values)} }`\n );\n};\n\nconst requirePlural = (message: SourceMessage): string => {\n if (message.plural === null) {\n throw new Error(\"Plural translation metadata requires a plural source string\");\n }\n\n return message.plural;\n};\n\nconst pluralVariant = (message: SourceMessage): string => {\n const plural = requirePlural(message);\n const values = [message.singular, plural];\n const isInterpolated = hasInterpolation(values);\n\n return (\n `{${contextField(message.context)} defaultValue: ${JSON.stringify(plural)}; ` +\n `interpolated: ${String(isInterpolated)}; kind: \"plural\"; required: true; ` +\n `value: ${stringType(values)} }`\n );\n};\n\nconst pluralDefaultsVariant = (message: SourceMessage): string => {\n const plural = requirePlural(message);\n const values = [message.singular, plural];\n const isInterpolated = hasInterpolation(values);\n\n return (\n `{${contextField(message.context)} defaultValueOne: ${JSON.stringify(message.singular)}; ` +\n `defaultValueOther: ${JSON.stringify(plural)}; interpolated: ${String(isInterpolated)}; ` +\n `kind: \"pluralDefaults\"; required: true; value: ${stringType(values)} }`\n );\n};\n\nconst variantsFor = (message: SourceMessage): string[] => {\n if (message.kind === \"plural\") {\n return [pluralVariant(message)];\n }\n\n if (message.kind === \"pluralDefaults\") {\n return [pluralDefaultsVariant(message)];\n }\n\n return message.kind === \"default\" ? [defaultVariant(message)] : [pointVariant(message)];\n};\n\nconst renderRegistry = (messages: SourceMessage[]): string[] => {\n const entries: Map<string, Set<string>> = new Map();\n\n for (const message of messages) {\n const variants = entries.get(message.msgid) ?? new Set<string>();\n\n for (const variant of variantsFor(message)) {\n variants.add(variant);\n }\n\n entries.set(message.msgid, variants);\n }\n\n return [...entries]\n .toSorted(([left], [right]) => left.localeCompare(right))\n .map(([msgid, variants]) => ` ${JSON.stringify(msgid)}: ${[...variants].join(\" | \")};`);\n};\n\nconst generatedHeader = (): string[] => [\n \"/**\",\n \" * Translation declarations generated by GTKX. Regenerated by\",\n \" * `gtkx codegen`, `gtkx dev`, and `gtkx build`; do not edit.\",\n \" */\",\n];\n\nconst renderI18nTypes = (messages: SourceMessage[], isEnabled = true): string => {\n if (!isEnabled) {\n return [...generatedHeader(), \"export {};\", \"\"].join(\"\\n\");\n }\n\n return [\n ...generatedHeader(),\n 'import \"@gtkx/i18n\";',\n \"\",\n 'declare module \"@gtkx/i18n\" {',\n \" interface TranslationRegistry {\",\n ...renderRegistry(messages),\n \" }\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n};\n\nconst i18nTypesPath = (root: string): string => join(root, \"node_modules\", \".gtkx\", I18N_TYPES_FILENAME);\n\nconst readFileOrNull = (path: string): string | null => {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n};\n\nconst emitI18nTypes = (root: string, messages: SourceMessage[], isEnabled = true): I18nTypesResult => {\n const path = i18nTypesPath(root);\n const content = renderI18nTypes(messages, isEnabled);\n\n if (readFileOrNull(path) === content) {\n return { isWritten: false, path };\n }\n\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content);\n\n return { isWritten: true, path };\n};\n\nexport { I18N_TYPES_FILENAME, emitI18nTypes, i18nTypesPath };\n"]}
@@ -1,8 +1,12 @@
1
+ import type { ParserOptions } from "vite";
1
2
  type SourceImport = {
2
3
  importer: string;
3
4
  source: string;
4
5
  };
6
+ type SourceLanguage = NonNullable<ParserOptions["lang"]>;
7
+ declare const sourceLanguage: (path: string) => SourceLanguage | undefined;
8
+ declare const discoverSourceFiles: (dir: string) => string[];
5
9
  declare const parseRuntimeImportsIn: (path: string) => SourceImport[] | null;
6
10
  declare const discoverSourceImports: (dir: string) => SourceImport[];
7
- export { discoverSourceImports, parseRuntimeImportsIn, type SourceImport };
11
+ export { discoverSourceFiles, discoverSourceImports, parseRuntimeImportsIn, type SourceImport, sourceLanguage };
8
12
  //# sourceMappingURL=source-imports.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-imports.d.ts","sourceRoot":"","sources":["../../src/internal/source-imports.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAgLF,QAAA,MAAM,qBAAqB,GAAI,MAAM,MAAM,KAAG,YAAY,EAAE,GAAG,IACP,CAAC;AAKzD,QAAA,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,YAAY,EAMxD,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,KAAK,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"source-imports.d.ts","sourceRoot":"","sources":["../../src/internal/source-imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,MAAM,CAAC;AAM/D,KAAK,YAAY,GAAG;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,cAAc,GAAG,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAwBzD,QAAA,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,cAAc,GAAG,SAMvD,CAAC;AAgCF,QAAA,MAAM,mBAAmB,GAAI,KAAK,MAAM,KAAG,MAAM,EAKhD,CAAC;AA+EF,QAAA,MAAM,qBAAqB,GAAI,MAAM,MAAM,KAAG,YAAY,EAAE,GAAG,IACP,CAAC;AAKzD,QAAA,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,YAAY,EAKxD,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,KAAK,YAAY,EAAE,cAAc,EAAE,CAAC"}