generaltranslation 9.4.3 → 9.5.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 (154) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +2 -1
  3. package/dist/{ApiError-BcjcnTAr.cjs → ApiError-BCjEo_CM.cjs} +1 -1
  4. package/dist/{ApiError-BcjcnTAr.cjs.map → ApiError-BCjEo_CM.cjs.map} +1 -1
  5. package/dist/{ApiError-CUKcz3YS.mjs → ApiError-DxWKM0Xt.mjs} +1 -1
  6. package/dist/{ApiError-CUKcz3YS.mjs.map → ApiError-DxWKM0Xt.mjs.map} +1 -1
  7. package/dist/adapter/createGtApi.d.ts +196 -27
  8. package/dist/adapter/createGtApi.js +561 -117
  9. package/dist/adapter/modelProvider.d.ts +4 -0
  10. package/dist/adapter/modelProvider.js +6 -0
  11. package/dist/derive-BVRyqmWc.mjs +657 -0
  12. package/dist/derive-BVRyqmWc.mjs.map +1 -0
  13. package/dist/{derive-DBCCXTmL.d.cts → derive-J2NQLqZm.d.cts} +1 -1
  14. package/dist/derive-sRw1yaMu.cjs +734 -0
  15. package/dist/derive-sRw1yaMu.cjs.map +1 -0
  16. package/dist/diagnostics-CqAHg_Vc.d.cts +34 -0
  17. package/dist/diagnostics-DKA2SkZB.mjs +45 -0
  18. package/dist/diagnostics-DKA2SkZB.mjs.map +1 -0
  19. package/dist/{unwrapApiResult-BzGfPw75.mjs → diagnostics-DKtiPUvo.cjs} +12 -31
  20. package/dist/diagnostics-DKtiPUvo.cjs.map +1 -0
  21. package/dist/diagnostics-DYtVjOm5.d.mts +34 -0
  22. package/dist/diagnostics.cjs +4 -0
  23. package/dist/diagnostics.d.cts +2 -0
  24. package/dist/diagnostics.d.mts +2 -0
  25. package/dist/diagnostics.d.ts +1 -0
  26. package/dist/diagnostics.js +1 -0
  27. package/dist/diagnostics.mjs +2 -0
  28. package/dist/errors.cjs +1 -1
  29. package/dist/errors.mjs +1 -1
  30. package/dist/file-B37WkCqM.cjs.map +1 -1
  31. package/dist/file-Dga6cyM8.mjs.map +1 -1
  32. package/dist/{id-X2zyx5Jk.mjs → id-B2wA7-S-.mjs} +19 -3
  33. package/dist/id-B2wA7-S-.mjs.map +1 -0
  34. package/dist/{id-pdr3R1xs.cjs → id-DJ_59q21.cjs} +25 -3
  35. package/dist/id-DJ_59q21.cjs.map +1 -0
  36. package/dist/id.cjs +1 -1
  37. package/dist/id.d.cts +1 -1
  38. package/dist/id.d.mts +1 -1
  39. package/dist/id.mjs +1 -1
  40. package/dist/index.cjs +94 -753
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +14 -33
  43. package/dist/index.d.mts +13 -32
  44. package/dist/index.d.ts +20 -16
  45. package/dist/index.js +110 -98
  46. package/dist/index.mjs +88 -746
  47. package/dist/index.mjs.map +1 -1
  48. package/dist/internal.cjs +16 -186
  49. package/dist/internal.cjs.map +1 -1
  50. package/dist/internal.d.cts +200 -62
  51. package/dist/internal.d.mts +199 -61
  52. package/dist/internal.d.ts +3 -1
  53. package/dist/internal.js +2 -1
  54. package/dist/internal.mjs +6 -178
  55. package/dist/internal.mjs.map +1 -1
  56. package/dist/logging/errors.d.ts +0 -1
  57. package/dist/logging/errors.js +0 -6
  58. package/dist/logging/logger.js +6 -4
  59. package/dist/openapi.json +12 -6
  60. package/dist/runtime.cjs +580 -2
  61. package/dist/runtime.cjs.map +1 -0
  62. package/dist/runtime.d.cts +12 -6
  63. package/dist/runtime.d.mts +12 -6
  64. package/dist/runtime.d.ts +10 -4
  65. package/dist/runtime.js +10 -65
  66. package/dist/runtime.mjs +579 -1
  67. package/dist/runtime.mjs.map +1 -0
  68. package/dist/runtimeTranslate-CVw143pQ.mjs +506 -0
  69. package/dist/runtimeTranslate-CVw143pQ.mjs.map +1 -0
  70. package/dist/runtimeTranslate-DJioRjb6.cjs +601 -0
  71. package/dist/runtimeTranslate-DJioRjb6.cjs.map +1 -0
  72. package/dist/translate/awaitJobs.d.ts +2 -2
  73. package/dist/translate/awaitJobs.js +1 -156
  74. package/dist/translate/checkJobStatus.d.ts +2 -1
  75. package/dist/translate/checkJobStatus.js +1 -55
  76. package/dist/translate/createBranch.d.ts +2 -6
  77. package/dist/translate/createBranch.js +1 -53
  78. package/dist/translate/enqueueFiles.js +1 -95
  79. package/dist/translate/getProjectInfo.d.ts +2 -6
  80. package/dist/translate/getProjectInfo.js +1 -54
  81. package/dist/translate/processFileMoves.d.ts +3 -13
  82. package/dist/translate/processFileMoves.js +1 -90
  83. package/dist/translate/publishFiles.d.ts +3 -15
  84. package/dist/translate/publishFiles.js +1 -56
  85. package/dist/translate/queryBranchData.js +1 -53
  86. package/dist/translate/queryFileData.d.ts +3 -41
  87. package/dist/translate/queryFileData.js +1 -71
  88. package/dist/translate/runtimeTranslate.d.ts +6 -0
  89. package/dist/translate/runtimeTranslate.js +297 -0
  90. package/dist/translate/setupProject.d.ts +2 -6
  91. package/dist/translate/setupProject.js +1 -63
  92. package/dist/translate/submitUserEditDiffs.js +1 -68
  93. package/dist/translate/utils/fetchWithTimeout.js +19 -12
  94. package/dist/{types-bCr8pV1Z.d.cts → types-Si4UstLL.d.mts} +41 -165
  95. package/dist/types-dir/__tests__/runtimeTranslate.type-test.js +18 -0
  96. package/dist/types-dir/api/branch.d.ts +3 -9
  97. package/dist/types-dir/api/checkFileTranslations.d.ts +2 -22
  98. package/dist/types-dir/api/downloadFileBatch.d.ts +2 -7
  99. package/dist/types-dir/api/entry.d.ts +3 -8
  100. package/dist/types-dir/api/file.d.ts +2 -1
  101. package/dist/types-dir/api/json.d.ts +1 -4
  102. package/dist/types-dir/api/project.d.ts +2 -7
  103. package/dist/types-dir/api/uploadAssets.d.ts +3 -10
  104. package/dist/types-dir/api/uploadAssets.js +0 -4
  105. package/dist/types-dir/config.d.ts +1 -0
  106. package/dist/{types-Dp1drjxq.d.mts → types-yByDbKnV.d.cts} +41 -165
  107. package/dist/types.d.cts +2 -2
  108. package/dist/types.d.mts +2 -2
  109. package/dist/types.d.ts +26 -7
  110. package/dist/utils/isSupportedFileFormatTransform.js +1 -0
  111. package/package.json +15 -2
  112. package/dist/derive-2CDqwrvS.cjs +0 -303
  113. package/dist/derive-2CDqwrvS.cjs.map +0 -1
  114. package/dist/derive-CTzR56T_.mjs +0 -233
  115. package/dist/derive-CTzR56T_.mjs.map +0 -1
  116. package/dist/id-X2zyx5Jk.mjs.map +0 -1
  117. package/dist/id-pdr3R1xs.cjs.map +0 -1
  118. package/dist/isVariable-8-Wy5FnX.mjs +0 -20
  119. package/dist/isVariable-8-Wy5FnX.mjs.map +0 -1
  120. package/dist/isVariable-I3nllgeI.cjs +0 -25
  121. package/dist/isVariable-I3nllgeI.cjs.map +0 -1
  122. package/dist/projects/getProjectData.js +0 -87
  123. package/dist/runtime-Bcp4F2ME.mjs +0 -974
  124. package/dist/runtime-Bcp4F2ME.mjs.map +0 -1
  125. package/dist/runtime-C25lwh9m.cjs +0 -1027
  126. package/dist/runtime-C25lwh9m.cjs.map +0 -1
  127. package/dist/translate/api.d.ts +0 -4
  128. package/dist/translate/api.js +0 -4
  129. package/dist/translate/createTag.d.ts +0 -19
  130. package/dist/translate/createTag.js +0 -67
  131. package/dist/translate/downloadFileBatch.d.ts +0 -1
  132. package/dist/translate/downloadFileBatch.js +0 -80
  133. package/dist/translate/getOrphanedFiles.d.ts +0 -8
  134. package/dist/translate/getOrphanedFiles.js +0 -97
  135. package/dist/translate/querySourceFile.d.ts +0 -1
  136. package/dist/translate/querySourceFile.js +0 -67
  137. package/dist/translate/translateMany.d.ts +0 -1
  138. package/dist/translate/translateMany.js +0 -124
  139. package/dist/translate/uploadFonts.d.ts +0 -1
  140. package/dist/translate/uploadFonts.js +0 -74
  141. package/dist/translate/uploadSourceFiles.d.ts +0 -1
  142. package/dist/translate/uploadSourceFiles.js +0 -90
  143. package/dist/translate/uploadTranslations.d.ts +0 -1
  144. package/dist/translate/uploadTranslations.js +0 -106
  145. package/dist/translate/utils/apiRequest.d.ts +0 -1
  146. package/dist/translate/utils/apiRequest.js +0 -167
  147. package/dist/translate/utils/generateRequestHeaders.d.ts +0 -2
  148. package/dist/translate/utils/generateRequestHeaders.js +0 -21
  149. package/dist/translate/utils/handleFetchError.d.ts +0 -1
  150. package/dist/translate/utils/handleFetchError.js +0 -12
  151. package/dist/unwrapApiResult-BzGfPw75.mjs.map +0 -1
  152. package/dist/unwrapApiResult-Dv6Mfw_K.cjs +0 -134
  153. package/dist/unwrapApiResult-Dv6Mfw_K.cjs.map +0 -1
  154. /package/dist/{projects/getProjectData.d.ts → types-dir/__tests__/runtimeTranslate.type-test.d.ts} +0 -0
@@ -0,0 +1,4 @@
1
+ import { ModelProvider } from '@generaltranslation/api';
2
+ export type { ModelProvider };
3
+ export declare const supportedModelProviders: ("ANTHROPIC" | "OPENAI" | "XAI" | "GOOGLE")[];
4
+ export declare function isModelProvider(value: unknown): value is ModelProvider;
@@ -0,0 +1,6 @@
1
+ import { ModelProvider } from '@generaltranslation/api';
2
+ export var supportedModelProviders =
3
+ /* @__PURE__ */ Object.values(ModelProvider);
4
+ export function isModelProvider(value) {
5
+ return supportedModelProviders.includes(value);
6
+ }
@@ -0,0 +1,657 @@
1
+ import { a as unwrapApiResult, n as translateMany, o as isModelProvider, s as supportedModelProviders, t as translate$1 } from "./runtimeTranslate-CVw143pQ.mjs";
2
+ import { t as createDiagnosticMessage } from "./diagnostics-DKA2SkZB.mjs";
3
+ import { n as isBinaryFileFormat } from "./file-Dga6cyM8.mjs";
4
+ import { DEFAULT_BATCH_SIZE, createApiClient, createBranch, createProject, createProjectApiKey, createTag, downloadFiles, enqueueFileTranslations, generateProjectContext, getBranchInfo, getFileInfo, getOrphanedFiles, getProjectInfo, getTranslationJobInfo, getTranslationStatus, listOrgs, listProjects, pollJobs, processBatches, processFileMoves, publishFiles, submitUserEditDiffs, uploadAssets, uploadSourceFiles, uploadTranslations } from "@generaltranslation/api";
5
+ import { resolveAliasLocale, resolveCanonicalLocale, standardizeLocale } from "@generaltranslation/format";
6
+ import { TYPE, parse } from "@generaltranslation/icu";
7
+ //#region src/utils/base64.ts
8
+ function encode(data) {
9
+ if (typeof Buffer !== "undefined") return Buffer.from(data, "utf8").toString("base64");
10
+ const bytes = new TextEncoder().encode(data);
11
+ let binary = "";
12
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
13
+ return btoa(binary);
14
+ }
15
+ function decode(base64) {
16
+ if (typeof Buffer !== "undefined") return Buffer.from(base64, "base64").toString("utf8");
17
+ const binary = atob(base64);
18
+ const bytes = new Uint8Array(binary.length);
19
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
20
+ return new TextDecoder().decode(bytes);
21
+ }
22
+ function encodeFileContent(content, fileFormat) {
23
+ return isBinaryFileFormat(fileFormat) ? content : encode(content);
24
+ }
25
+ function decodeFileContent(content, fileFormat) {
26
+ return isBinaryFileFormat(fileFormat) ? content : decode(content);
27
+ }
28
+ //#endregion
29
+ //#region src/utils/isSupportedFileFormatTransform.ts
30
+ const SUPPORTED_TRANSFORMATIONS = {
31
+ GTJSON: ["GTJSON"],
32
+ JSON: ["JSON"],
33
+ PO: ["PO"],
34
+ POT: ["POT", "PO"],
35
+ YAML: ["YAML"],
36
+ MDX: ["MDX"],
37
+ MD: ["MD"],
38
+ TS: ["TS"],
39
+ JS: ["JS"],
40
+ HTML: ["HTML"],
41
+ TXT: ["TXT"],
42
+ TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"],
43
+ LOTTIE: ["LOTTIE"],
44
+ SVG: ["SVG"],
45
+ DOT_STRINGS: ["DOT_STRINGS"],
46
+ DOT_STRINGSDICT: ["DOT_STRINGSDICT"],
47
+ ANDROID_STRINGS: ["ANDROID_STRINGS"],
48
+ SRT: ["SRT"],
49
+ XCSTRINGS: ["XCSTRINGS"]
50
+ };
51
+ /**
52
+ * This function checks if a file format transformation is supported during translation
53
+ * @param from - The source file format.
54
+ * @param to - The target file format.
55
+ * @returns True if the transformation is supported, false otherwise
56
+ */
57
+ function isSupportedFileFormatTransform(from, to) {
58
+ return SUPPORTED_TRANSFORMATIONS[from]?.includes(to) ?? false;
59
+ }
60
+ //#endregion
61
+ //#region src/translate/utils/validateFileFormatTransform.ts
62
+ /**
63
+ * Returns a user-facing validation error when a requested file format transform
64
+ * is missing source format context or is not currently supported.
65
+ */
66
+ function getFileFormatTransformError(file) {
67
+ if (!file.transformFormat) return void 0;
68
+ const fileLabel = file.fileName ?? file.fileId ?? "unknown file";
69
+ if (!file.fileFormat) return `fileFormat is required when transformFormat is provided for ${fileLabel}`;
70
+ if (!isSupportedFileFormatTransform(file.fileFormat, file.transformFormat)) return `Unsupported file format transform: ${file.fileFormat} -> ${file.transformFormat}`;
71
+ }
72
+ /**
73
+ * Validates file format transforms before sending upload/enqueue requests.
74
+ */
75
+ function validateFileFormatTransforms(files) {
76
+ for (const file of files) {
77
+ const error = getFileFormatTransformError(file);
78
+ if (error) throw new Error(error);
79
+ }
80
+ }
81
+ //#endregion
82
+ //#region src/adapter/createGtApi.ts
83
+ async function collectPages(loadPage) {
84
+ const items = [];
85
+ let cursor;
86
+ do {
87
+ const page = await loadPage(cursor);
88
+ items.push(...page.items);
89
+ cursor = page.nextCursor ?? void 0;
90
+ } while (cursor);
91
+ return items;
92
+ }
93
+ function normalizeJobStatus(job) {
94
+ return {
95
+ jobId: job.jobId,
96
+ status: job.status,
97
+ ...job.status === "failed" ? { error: { message: job.error.message ?? "" } } : {}
98
+ };
99
+ }
100
+ function createGtApiAdapter(defaultConfig) {
101
+ let client;
102
+ let config;
103
+ function resolveServiceLocale(locale) {
104
+ return standardizeLocale(resolveCanonicalLocale(locale, config?.customMapping));
105
+ }
106
+ function aliasUploadedFileLocale(file) {
107
+ return file.locale ? {
108
+ ...file,
109
+ locale: resolveAliasLocale(file.locale, config?.customMapping)
110
+ } : file;
111
+ }
112
+ function getConfig() {
113
+ if (!config) throw new Error("API client not configured — call configureApiClient first");
114
+ return config;
115
+ }
116
+ function getClient(timeoutMs) {
117
+ if (timeoutMs === void 0 && client) return client;
118
+ return createApiClient({
119
+ ...getConfig(),
120
+ timeoutMs
121
+ });
122
+ }
123
+ function configure(nextConfig) {
124
+ client = createApiClient(nextConfig);
125
+ config = { ...nextConfig };
126
+ }
127
+ async function translate(source, options, timeoutMs) {
128
+ return translate$1(source, options, {
129
+ ...getConfig(),
130
+ ...timeoutMs !== void 0 && { timeoutMs }
131
+ });
132
+ }
133
+ async function translateMany$1(sources, options, timeoutMs) {
134
+ return translateMany(sources, options, {
135
+ ...getConfig(),
136
+ ...timeoutMs !== void 0 && { timeoutMs }
137
+ });
138
+ }
139
+ if (defaultConfig) configure(defaultConfig);
140
+ async function loadJobStatuses(jobIds, options = {}) {
141
+ return unwrapApiResult(await getTranslationJobInfo({
142
+ body: { jobIds: [...jobIds] },
143
+ client: getClient(options.timeoutMs),
144
+ signal: options.signal
145
+ }));
146
+ }
147
+ async function loadProjectInfo(projectId, timeoutMs) {
148
+ const resolvedProjectId = projectId ?? getConfig().projectId;
149
+ if (!resolvedProjectId) throw new Error("Project ID is required to fetch project information");
150
+ return unwrapApiResult(await getProjectInfo({
151
+ client: getClient(timeoutMs),
152
+ path: { projectId: resolvedProjectId }
153
+ }));
154
+ }
155
+ return {
156
+ configure,
157
+ getClient,
158
+ resolveAliasLocale(locale) {
159
+ return resolveAliasLocale(locale, config?.customMapping);
160
+ },
161
+ resolveCanonicalLocale(locale) {
162
+ return resolveServiceLocale(locale);
163
+ },
164
+ translate,
165
+ translateMany: translateMany$1,
166
+ async queryBranchData(body) {
167
+ return unwrapApiResult(await getBranchInfo({
168
+ body,
169
+ client: getClient()
170
+ }));
171
+ },
172
+ async createBranch(body) {
173
+ return unwrapApiResult(await createBranch({
174
+ body,
175
+ client: getClient()
176
+ }));
177
+ },
178
+ async processFileMoves(moves, options = {}) {
179
+ const results = await processBatches(moves, async (batch) => {
180
+ return unwrapApiResult(await processFileMoves({
181
+ body: {
182
+ branchId: options.branchId,
183
+ moves: batch
184
+ },
185
+ client: getClient(options.timeout)
186
+ })).results;
187
+ });
188
+ const succeeded = results.filter(({ success }) => success).length;
189
+ return {
190
+ results,
191
+ summary: {
192
+ total: moves.length,
193
+ succeeded,
194
+ failed: results.length - succeeded
195
+ }
196
+ };
197
+ },
198
+ async getOrphanedFiles(branchId, fileIds, options = {}) {
199
+ const request = async (batch) => unwrapApiResult(await getOrphanedFiles({
200
+ body: {
201
+ branchId,
202
+ fileIds: batch
203
+ },
204
+ client: getClient(options.timeout)
205
+ }));
206
+ if (fileIds.length === 0) return request([]);
207
+ const results = await processBatches(fileIds, async (batch) => [await request(batch)]);
208
+ const orphanedFiles = new Map(results[0].orphanedFiles.map((file) => [file.fileId, file]));
209
+ for (const result of results.slice(1)) {
210
+ const batchFileIds = new Set(result.orphanedFiles.map((file) => file.fileId));
211
+ for (const fileId of Array.from(orphanedFiles.keys())) if (!batchFileIds.has(fileId)) orphanedFiles.delete(fileId);
212
+ }
213
+ return { orphanedFiles: Array.from(orphanedFiles.values()) };
214
+ },
215
+ async setupProject(files, options = {}) {
216
+ return unwrapApiResult(await generateProjectContext({
217
+ body: {
218
+ files: files.map(({ branchId, fileId, versionId }) => ({
219
+ branchId,
220
+ fileId,
221
+ versionId
222
+ })),
223
+ locales: options.locales?.map((locale) => resolveServiceLocale(locale)),
224
+ force: options.force
225
+ },
226
+ client: getClient(options.timeoutMs)
227
+ }));
228
+ },
229
+ loadJobStatuses,
230
+ async checkJobStatus(jobIds, timeoutMs) {
231
+ return (await loadJobStatuses(jobIds, { timeoutMs })).map(normalizeJobStatus);
232
+ },
233
+ async awaitJobs(jobIds, options) {
234
+ const result = await pollJobs(jobIds, (pendingJobIds, signal) => loadJobStatuses(pendingJobIds, { signal }), options);
235
+ return {
236
+ ...result,
237
+ jobs: result.jobs.map(normalizeJobStatus)
238
+ };
239
+ },
240
+ async enqueueFiles(files, options) {
241
+ validateFileFormatTransforms(files);
242
+ const modelProvider = options.modelProvider;
243
+ if (modelProvider !== void 0 && !isModelProvider(modelProvider)) throw new Error(createDiagnosticMessage({
244
+ source: "generaltranslation",
245
+ severity: "Error",
246
+ whatHappened: `Unsupported model provider \`${modelProvider}\``,
247
+ fix: `Use one of: ${supportedModelProviders.join(", ")}`
248
+ }));
249
+ const targetLocales = options.targetLocales.map((locale) => resolveServiceLocale(locale));
250
+ const result = await processBatches(files, async (batch) => {
251
+ const response = unwrapApiResult(await enqueueFileTranslations({
252
+ body: {
253
+ files: batch.map(({ branchId, fileId, versionId, fileName, transformFormat }) => ({
254
+ branchId,
255
+ fileId,
256
+ versionId,
257
+ fileName,
258
+ transformFormat
259
+ })),
260
+ targetLocales,
261
+ sourceLocale: options.sourceLocale ? resolveServiceLocale(options.sourceLocale) : void 0,
262
+ modelProvider,
263
+ force: options.force
264
+ },
265
+ client: getClient(options.timeout)
266
+ }));
267
+ const jobData = "jobData" in response ? response.jobData : response.data;
268
+ return Object.entries(jobData);
269
+ });
270
+ return {
271
+ jobData: Object.fromEntries(result),
272
+ locales: targetLocales,
273
+ message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`
274
+ };
275
+ },
276
+ async createTag(body) {
277
+ return unwrapApiResult(await createTag({
278
+ body,
279
+ client: getClient()
280
+ }));
281
+ },
282
+ async publishFiles(files) {
283
+ return unwrapApiResult(await publishFiles({
284
+ body: { files: files.map(({ fileId, versionId, branchId, publish }) => ({
285
+ fileId,
286
+ versionId,
287
+ branchId,
288
+ publish
289
+ })) },
290
+ client: getClient()
291
+ }));
292
+ },
293
+ async submitUserEditDiffs(body, options = {}) {
294
+ return processBatches(body.diffs, async (diffs) => [unwrapApiResult(await submitUserEditDiffs({
295
+ body: {
296
+ projectId: body.projectId,
297
+ diffs: diffs.map(({ diff, branchId, versionId, fileId, localContent, locale }) => ({
298
+ diff,
299
+ branchId,
300
+ versionId,
301
+ fileId,
302
+ localContent,
303
+ locale: resolveServiceLocale(locale)
304
+ }))
305
+ },
306
+ client: getClient(options.timeout)
307
+ }))]);
308
+ },
309
+ async createProject(orgId, body) {
310
+ return unwrapApiResult(await createProject({
311
+ path: { orgId },
312
+ body: {
313
+ ...body,
314
+ defaultLocale: resolveServiceLocale(body.defaultLocale)
315
+ },
316
+ client: getClient()
317
+ }));
318
+ },
319
+ /** Every project the configured credentials can read. */
320
+ async listProjects() {
321
+ return collectPages(async (cursor) => {
322
+ const { projects, nextCursor } = unwrapApiResult(await listProjects({
323
+ query: cursor ? { cursor } : void 0,
324
+ client: getClient()
325
+ }));
326
+ return {
327
+ items: projects,
328
+ nextCursor
329
+ };
330
+ });
331
+ },
332
+ /** Organizations where the signed-in user can create projects; user tokens only. */
333
+ async listOrgs() {
334
+ return collectPages(async (cursor) => {
335
+ const { orgs, nextCursor } = unwrapApiResult(await listOrgs({
336
+ query: cursor ? { cursor } : void 0,
337
+ client: getClient()
338
+ }));
339
+ return {
340
+ items: orgs,
341
+ nextCursor
342
+ };
343
+ });
344
+ },
345
+ async createProjectApiKey(projectId, body) {
346
+ return unwrapApiResult(await createProjectApiKey({
347
+ path: { projectId },
348
+ body,
349
+ client: getClient()
350
+ }));
351
+ },
352
+ loadProjectInfo,
353
+ async getProjectInfo(projectId, timeoutMs) {
354
+ const result = await loadProjectInfo(projectId, timeoutMs);
355
+ return {
356
+ ...result,
357
+ defaultLocale: resolveAliasLocale(result.defaultLocale, config?.customMapping),
358
+ currentLocales: result.currentLocales.map((locale) => resolveAliasLocale(locale, config?.customMapping))
359
+ };
360
+ },
361
+ async queryFileData(body, timeoutMs) {
362
+ const result = unwrapApiResult(await getFileInfo({
363
+ body: {
364
+ ...body,
365
+ translatedFiles: body.translatedFiles?.map((file) => ({
366
+ ...file,
367
+ locale: resolveServiceLocale(file.locale)
368
+ }))
369
+ },
370
+ client: getClient(timeoutMs)
371
+ }));
372
+ return {
373
+ ...result,
374
+ translatedFiles: result.translatedFiles.map((file) => ({
375
+ ...file,
376
+ locale: resolveAliasLocale(file.locale, config?.customMapping)
377
+ })),
378
+ sourceFiles: result.sourceFiles.map((file) => ({
379
+ ...file,
380
+ sourceLocale: resolveAliasLocale(file.sourceLocale, config?.customMapping),
381
+ locales: file.locales.map((locale) => resolveAliasLocale(locale, config?.customMapping))
382
+ }))
383
+ };
384
+ },
385
+ async querySourceFile(path, query = {}, timeoutMs) {
386
+ const result = unwrapApiResult(await getTranslationStatus({
387
+ path,
388
+ query,
389
+ client: getClient(timeoutMs)
390
+ }));
391
+ return {
392
+ ...result,
393
+ translations: result.translations.map((translation) => ({
394
+ ...translation,
395
+ locale: resolveAliasLocale(translation.locale, config?.customMapping)
396
+ })),
397
+ sourceFile: {
398
+ ...result.sourceFile,
399
+ sourceLocale: resolveAliasLocale(result.sourceFile.sourceLocale, config?.customMapping),
400
+ locales: result.sourceFile.locales.map((locale) => resolveAliasLocale(locale, config?.customMapping))
401
+ }
402
+ };
403
+ },
404
+ async downloadFileBatch(files, options = {}) {
405
+ const request = async (batch) => unwrapApiResult(await downloadFiles({
406
+ body: batch.map((file) => ({
407
+ ...file,
408
+ locale: file.locale ? resolveServiceLocale(file.locale) : void 0
409
+ })),
410
+ client: getClient(options.timeout)
411
+ }));
412
+ const responses = await processBatches(files, async (batch) => [await request(batch)]);
413
+ return {
414
+ files: responses.flatMap((response) => response.files.map((file) => ({
415
+ ...file,
416
+ ...file.locale && { locale: resolveAliasLocale(file.locale, config?.customMapping) },
417
+ data: decodeFileContent(file.data, file.fileFormat),
418
+ metadata: file.metadata
419
+ }))),
420
+ count: responses.reduce((count, response) => count + response.count, 0),
421
+ pending: responses.flatMap((response) => (response.pending ?? []).map((file) => ({
422
+ ...file,
423
+ locale: resolveAliasLocale(file.locale, config?.customMapping)
424
+ })))
425
+ };
426
+ },
427
+ async uploadSourceFiles(files, options) {
428
+ const sourceLocale = resolveServiceLocale(options.sourceLocale);
429
+ return { uploadedFiles: await processBatches(files, async (batch) => {
430
+ return unwrapApiResult(await uploadSourceFiles({
431
+ body: {
432
+ data: batch.map(({ source }) => ({ source: {
433
+ ...source,
434
+ content: encodeFileContent(source.content, source.fileFormat),
435
+ locale: resolveServiceLocale(source.locale)
436
+ } })),
437
+ sourceLocale
438
+ },
439
+ client: getClient(options.timeout)
440
+ })).uploadedFiles.map(aliasUploadedFileLocale);
441
+ }) };
442
+ },
443
+ async uploadFonts(fonts, options = {}) {
444
+ const assets = await processBatches(fonts, async (batch) => {
445
+ return unwrapApiResult(await uploadAssets({
446
+ body: { assets: batch },
447
+ client: getClient(options.timeout)
448
+ })).assets;
449
+ }, { batchSize: 50 });
450
+ return {
451
+ assets,
452
+ count: assets.length
453
+ };
454
+ },
455
+ async uploadTranslations(files, options) {
456
+ validateFileFormatTransforms(files.map(({ source }) => source));
457
+ return { uploadedFiles: await processBatches(files, async (batch) => {
458
+ return unwrapApiResult(await uploadTranslations({
459
+ body: {
460
+ data: batch.map(({ source, translations }) => ({
461
+ source: {
462
+ ...source,
463
+ content: encodeFileContent(source.content, source.fileFormat),
464
+ locale: resolveServiceLocale(source.locale)
465
+ },
466
+ translations: translations.map((translation) => ({
467
+ ...translation,
468
+ locale: resolveServiceLocale(translation.locale),
469
+ content: encodeFileContent(translation.content, translation.fileFormat)
470
+ }))
471
+ })),
472
+ sourceLocale: resolveServiceLocale(options.sourceLocale)
473
+ },
474
+ client: getClient(options.timeout)
475
+ })).uploadedFiles.map(aliasUploadedFileLocale);
476
+ }) };
477
+ }
478
+ };
479
+ }
480
+ //#endregion
481
+ //#region src/derive/utils/traverseIcu.ts
482
+ /**
483
+ * Given an ICU string, traverse the AST and call the visitor function for each element that matches the type T
484
+ * @param icu - The ICU string to traverse
485
+ * @param shouldVisit - A function that returns true if the element should be visited
486
+ * @param visitor - A function that is called for each element that matches the type T
487
+ * @returns The modified AST of the ICU string.
488
+ *
489
+ * @note This function is a heavy operation, use sparingly
490
+ */
491
+ function traverseIcu({ icuString, shouldVisit, visitor, options: { recurseIntoVisited = true, ...otherOptions } }) {
492
+ const ast = parse(icuString, otherOptions);
493
+ handleChildren(ast);
494
+ return ast;
495
+ function handleChildren(children) {
496
+ children.map(handleChild);
497
+ }
498
+ function handleChild(child) {
499
+ let visited = false;
500
+ if (shouldVisit(child)) {
501
+ visitor(child);
502
+ visited = true;
503
+ }
504
+ if (!visited || recurseIntoVisited) {
505
+ if (child.type === TYPE.select || child.type === TYPE.plural) Object.values(child.options).map((option) => option.value).map(handleChildren);
506
+ else if (child.type === TYPE.tag) handleChildren(child.children);
507
+ }
508
+ }
509
+ }
510
+ //#endregion
511
+ //#region src/derive/utils/constants.ts
512
+ const VAR_IDENTIFIER = "_gt_";
513
+ const VAR_NAME_IDENTIFIER = "_gt_var_name";
514
+ //#endregion
515
+ //#region src/derive/utils/regex.ts
516
+ const GT_INDEXED_IDENTIFIER_REGEX = new RegExp(`^${VAR_IDENTIFIER}\\d+$`);
517
+ const GT_UNINDEXED_IDENTIFIER_REGEX = new RegExp(`^${VAR_IDENTIFIER}$`);
518
+ //#endregion
519
+ //#region src/derive/utils/traverseHelpers.ts
520
+ function isGTIndexedSelectElement(child) {
521
+ return child.type === TYPE.select && GT_INDEXED_IDENTIFIER_REGEX.test(child.value) && !!child.options.other && (child.options.other.value.length === 0 || child.options.other.value.length > 0 && child.options.other.value[0]?.type === TYPE.literal);
522
+ }
523
+ function isGTUnindexedSelectElement(child) {
524
+ return child.type === TYPE.select && GT_UNINDEXED_IDENTIFIER_REGEX.test(child.value) && !!child.options.other && (child.options.other.value.length === 0 || child.options.other.value.length > 0 && child.options.other.value[0]?.type === TYPE.literal);
525
+ }
526
+ //#endregion
527
+ //#region src/derive/decodeVars.ts
528
+ /**
529
+ * Given an encoded ICU string, interpolate only _gt_ variables that have been marked with declareVar()
530
+ * @example
531
+ * const encodedIcu = "Hi" + declareVar("Brian") + ", my name is {name}"
532
+ * // 'Hi {_gt_, select, other {Brian}}, my name is {name}'
533
+ * decodeVars(encodedIcu)
534
+ * // 'Hi Brian, my name is {name}'
535
+ */
536
+ function decodeVars(icuString) {
537
+ if (!icuString.includes("_gt_")) return icuString;
538
+ const variableLocations = [];
539
+ function visitor(child) {
540
+ variableLocations.push({
541
+ start: child.location?.start.offset ?? 0,
542
+ end: child.location?.end.offset ?? 0,
543
+ value: child.options.other.value.length > 0 ? child.options.other.value[0].value : ""
544
+ });
545
+ }
546
+ traverseIcu({
547
+ icuString,
548
+ shouldVisit: isGTUnindexedSelectElement,
549
+ visitor,
550
+ options: {
551
+ recurseIntoVisited: false,
552
+ captureLocation: true
553
+ }
554
+ });
555
+ let previousIndex = 0;
556
+ const outputList = [];
557
+ for (let i = 0; i < variableLocations.length; i++) {
558
+ outputList.push(icuString.slice(previousIndex, variableLocations[i].start));
559
+ outputList.push(variableLocations[i].value);
560
+ previousIndex = variableLocations[i].end;
561
+ }
562
+ if (previousIndex < icuString.length) outputList.push(icuString.slice(previousIndex));
563
+ return outputList.join("");
564
+ }
565
+ //#endregion
566
+ //#region src/derive/utils/sanitizeVar.ts
567
+ /**
568
+ * Sanitizes string by escaping ICU syntax
569
+ *
570
+ * Sanitize arbitrary string so it does not break the following ICU message syntax:
571
+ * {_gt_, select, other {string_here}}
572
+ *
573
+ * Escapes ICU special characters by:
574
+ * 1. Doubling all single quotes (U+0027 ')
575
+ * 2. Adding a single quote before the first special character ({}<>)
576
+ * 3. Adding a single quote after the last special character ({}<>)
577
+ */
578
+ function sanitizeVar(string) {
579
+ let result = string.replace(/'/g, "''");
580
+ const specialChars = /[{}<>]/;
581
+ const firstSpecialIndex = result.search(specialChars);
582
+ if (firstSpecialIndex === -1) return result;
583
+ let lastSpecialIndex = -1;
584
+ for (let i = result.length - 1; i >= 0; i--) if (specialChars.test(result[i])) {
585
+ lastSpecialIndex = i;
586
+ break;
587
+ }
588
+ result = result.slice(0, firstSpecialIndex) + "'" + result.slice(firstSpecialIndex, lastSpecialIndex + 1) + "'" + result.slice(lastSpecialIndex + 1);
589
+ return result;
590
+ }
591
+ //#endregion
592
+ //#region src/derive/declareVar.ts
593
+ /**
594
+ * Mark as a non-translatable string. Use within a derive() call to mark content as not derivable (e.g., not possible to statically analyze).
595
+ *
596
+ * @example
597
+ * function nonDerivableFunction() {
598
+ * return Math.random();
599
+ * }
600
+ *
601
+ * function derivableFunction() {
602
+ * if (condition) {
603
+ * return declareVar(nonDerivableFunction())
604
+ * }
605
+ * return 'John Doe';
606
+ * }
607
+ *
608
+ * const gt = useGT();
609
+ * gt(`My name is ${derive(derivableFunction())}`);
610
+ *
611
+ * @param {string | number | boolean | null | undefined} variable - The variable to sanitize.
612
+ * @param {Object} [options] - The options for the sanitization.
613
+ * @param {string} [options.$name] - The name of the variable.
614
+ * @returns {string} The sanitized value.
615
+ */
616
+ function declareVar(variable, options) {
617
+ const variableSection = ` other {${sanitizeVar(String(variable ?? ""))}}`;
618
+ let nameSection = "";
619
+ if (options?.$name) nameSection = ` ${VAR_NAME_IDENTIFIER} {${sanitizeVar(options.$name)}}`;
620
+ return `{${VAR_IDENTIFIER}, select,${variableSection}${nameSection}}`;
621
+ }
622
+ //#endregion
623
+ //#region src/derive/derive.ts
624
+ /**
625
+ * Marks content as derivable by the GT compiler and CLI.
626
+ *
627
+ * Use `derive()` when a translation string or context needs content that is
628
+ * computed from source code, but should still be discovered during extraction
629
+ * instead of treated as a runtime interpolation variable. The CLI attempts to
630
+ * resolve the derivable expression into every possible static value and
631
+ * includes those values in the source content that gets translated.
632
+ *
633
+ * `derive()` returns its argument unchanged at runtime.
634
+ *
635
+ * Run `gt validate` after adding or changing `derive()` calls to verify that
636
+ * each derivable expression can be resolved by the CLI before translating or
637
+ * building.
638
+ *
639
+ * @example
640
+ * ```jsx
641
+ * function getSubject() {
642
+ * return (Math.random() > 0.5) ? "Alice" : "Brian";
643
+ * }
644
+ * ...
645
+ * gt(`My name is ${derive(getSubject())}`);
646
+ * ```
647
+ *
648
+ * @param {T extends string | boolean | number | null | undefined} content - Content to derive for translation extraction.
649
+ * @returns {T} The same content, unchanged at runtime.
650
+ */
651
+ function derive(content) {
652
+ return content;
653
+ }
654
+ //#endregion
655
+ export { isGTUnindexedSelectElement as a, createGtApiAdapter as c, decodeFileContent as d, encode as f, isGTIndexedSelectElement as i, isSupportedFileFormatTransform as l, declareVar as n, VAR_IDENTIFIER as o, encodeFileContent as p, decodeVars as r, traverseIcu as s, derive as t, decode as u };
656
+
657
+ //# sourceMappingURL=derive-BVRyqmWc.mjs.map