@justanarthur/payload-plugin-translator 3.1.0 → 3.2.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.
- package/README.md +7 -1
- package/dist/client.css +0 -184
- package/dist/client.d.ts +17 -7
- package/dist/client.js +128 -20
- package/dist/index.d.ts +10 -1
- package/dist/index.js +42 -5
- package/dist/jobs.js +5 -4
- package/dist/rsc.js +371 -139
- package/dist/shared/{chunk-15n5q7wd.js → chunk-4ftfmxgs.js} +110 -24
- package/dist/shared/{chunk-9d433kmv.js → chunk-d0n3f8ad.js} +36 -4
- package/dist/shared/{chunk-p03jz82h.js → chunk-hkx0bzb6.js} +26 -13
- package/dist/types.d.ts +6 -1
- package/package.json +1 -1
|
@@ -1,33 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
samePlaceholders,
|
|
3
|
-
|
|
3
|
+
plainText,
|
|
4
|
+
looksUntranslated,
|
|
5
|
+
TRANSLATE_WORKFLOW_SLUG2,
|
|
4
6
|
collectTranslatableFields,
|
|
5
7
|
entityKey,
|
|
6
8
|
sourceHash
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-d0n3f8ad.js";
|
|
8
10
|
import {
|
|
9
11
|
TRANSLATION_STATUS_SLUG2
|
|
10
12
|
} from "./chunk-31qgv1zk.js";
|
|
11
13
|
|
|
12
|
-
// src/review/plainText.ts
|
|
13
|
-
var plainText = (value) => {
|
|
14
|
-
if (typeof value === "string")
|
|
15
|
-
return value;
|
|
16
|
-
if (!value || typeof value !== "object")
|
|
17
|
-
return "";
|
|
18
|
-
if (Array.isArray(value))
|
|
19
|
-
return value.map(plainText).filter(Boolean).join(" ");
|
|
20
|
-
const node = value;
|
|
21
|
-
if (typeof node.text === "string")
|
|
22
|
-
return node.text;
|
|
23
|
-
if ("root" in node)
|
|
24
|
-
return plainText(node.root);
|
|
25
|
-
if (Array.isArray(node.children))
|
|
26
|
-
return node.children.map(plainText).filter(Boolean).join(node.type === "root" ? `
|
|
27
|
-
` : "");
|
|
28
|
-
return "";
|
|
29
|
-
};
|
|
30
|
-
|
|
31
14
|
// src/review/computeStatus.ts
|
|
32
15
|
var normalize = (text) => text.replace(/\s+/g, " ").trim();
|
|
33
16
|
var classify = (field, sourceText, targetText) => {
|
|
@@ -35,8 +18,7 @@ var classify = (field, sourceText, targetText) => {
|
|
|
35
18
|
return "missing";
|
|
36
19
|
if (field.type === "json" && !samePlaceholders(sourceText, targetText))
|
|
37
20
|
return "placeholders";
|
|
38
|
-
|
|
39
|
-
if (same && field.type !== "slug" && normalize(sourceText).length > 3 && !isOpaqueText(sourceText) && /\s/.test(normalize(sourceText)))
|
|
21
|
+
if (field.type !== "slug" && looksUntranslated(sourceText, targetText))
|
|
40
22
|
return "identical";
|
|
41
23
|
return "ok";
|
|
42
24
|
};
|
|
@@ -250,4 +232,108 @@ var loadLastJob = async (req, { collectionSlug, globalSlug, id }, locale) => {
|
|
|
250
232
|
}
|
|
251
233
|
};
|
|
252
234
|
|
|
253
|
-
|
|
235
|
+
// src/review/bulk.ts
|
|
236
|
+
var JOBS_SLUG = "payload-jobs";
|
|
237
|
+
var pendingWhere = {
|
|
238
|
+
and: [
|
|
239
|
+
{ workflowSlug: { equals: TRANSLATE_WORKFLOW_SLUG2 } },
|
|
240
|
+
{ completedAt: { exists: false } },
|
|
241
|
+
{ hasError: { not_equals: true } }
|
|
242
|
+
]
|
|
243
|
+
};
|
|
244
|
+
var hasTranslateWorkflow = (req) => Boolean(req.payload.config.jobs?.workflows?.some((workflow) => workflow.slug === TRANSLATE_WORKFLOW_SLUG2)) && Boolean(req.payload.collections[JOBS_SLUG]);
|
|
245
|
+
var loadJobsProgress = async (req) => {
|
|
246
|
+
if (!hasTranslateWorkflow(req))
|
|
247
|
+
return null;
|
|
248
|
+
const count = (where) => req.payload.count({ collection: JOBS_SLUG, where, overrideAccess: true, req }).then(({ totalDocs }) => totalDocs);
|
|
249
|
+
const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
250
|
+
const [pending, running, failed] = await Promise.all([
|
|
251
|
+
count(pendingWhere),
|
|
252
|
+
count({ and: [...pendingWhere.and ?? [], { processing: { equals: true } }] }),
|
|
253
|
+
count({ and: [{ workflowSlug: { equals: TRANSLATE_WORKFLOW_SLUG2 } }, { hasError: { equals: true } }, { updatedAt: { greater_than: dayAgo } }] })
|
|
254
|
+
]);
|
|
255
|
+
return { pending, running, failed };
|
|
256
|
+
};
|
|
257
|
+
var loadPendingPairs = async (req) => {
|
|
258
|
+
const { docs } = await req.payload.find({
|
|
259
|
+
collection: JOBS_SLUG,
|
|
260
|
+
where: pendingWhere,
|
|
261
|
+
pagination: false,
|
|
262
|
+
depth: 0,
|
|
263
|
+
overrideAccess: true,
|
|
264
|
+
req
|
|
265
|
+
});
|
|
266
|
+
const pairs = new Set;
|
|
267
|
+
for (const { input } of docs) {
|
|
268
|
+
if (!input)
|
|
269
|
+
continue;
|
|
270
|
+
const key = entityKey({ collectionSlug: input.collection, globalSlug: input.global, id: input.id });
|
|
271
|
+
for (const locale of input.toLocales ?? (input.toLocale ? [input.toLocale] : []))
|
|
272
|
+
pairs.add(`${key}|${locale}`);
|
|
273
|
+
}
|
|
274
|
+
return pairs;
|
|
275
|
+
};
|
|
276
|
+
var incompleteLocales = (entity, locales) => locales.filter((locale) => {
|
|
277
|
+
const review = entity.locales[locale];
|
|
278
|
+
return review && (review.summary.coverage < 100 || review.summary.slugMissing);
|
|
279
|
+
});
|
|
280
|
+
var queueBulkTranslation = async ({ req, tab, locale, mode }) => {
|
|
281
|
+
const pluginConfig = req.payload.config.custom?.translator;
|
|
282
|
+
const { defaultLocale, targetLocales } = readLocales(req);
|
|
283
|
+
const locales = locale ? [locale] : targetLocales;
|
|
284
|
+
const resolver = pluginConfig.resolvers[0]?.key;
|
|
285
|
+
const pending = await loadPendingPairs(req);
|
|
286
|
+
let queuedDocuments = 0;
|
|
287
|
+
let queuedLocales = 0;
|
|
288
|
+
let skippedPending = 0;
|
|
289
|
+
const queue = async (entity) => {
|
|
290
|
+
const toLocales = incompleteLocales(entity, locales).filter((each) => {
|
|
291
|
+
const already = pending.has(`${entity.key}|${each}`);
|
|
292
|
+
if (already)
|
|
293
|
+
skippedPending++;
|
|
294
|
+
return !already;
|
|
295
|
+
});
|
|
296
|
+
if (!toLocales.length)
|
|
297
|
+
return;
|
|
298
|
+
await req.payload.jobs.queue({
|
|
299
|
+
req,
|
|
300
|
+
workflow: TRANSLATE_WORKFLOW_SLUG2,
|
|
301
|
+
input: {
|
|
302
|
+
id: entity.id,
|
|
303
|
+
collection: entity.collectionSlug,
|
|
304
|
+
global: entity.globalSlug,
|
|
305
|
+
updatedAt: new Date().toISOString(),
|
|
306
|
+
fromLocale: defaultLocale,
|
|
307
|
+
toLocales,
|
|
308
|
+
resolver,
|
|
309
|
+
mode
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
queuedDocuments++;
|
|
313
|
+
queuedLocales += toLocales.length;
|
|
314
|
+
};
|
|
315
|
+
if (tab === "globals") {
|
|
316
|
+
const { entities } = await loadGlobalsReview({ req, globalSlugs: pluginConfig.globals });
|
|
317
|
+
for (const entity of entities)
|
|
318
|
+
await queue(entity);
|
|
319
|
+
} else {
|
|
320
|
+
for (let page = 1;; page++) {
|
|
321
|
+
const review = await loadCollectionReview({ req, collectionSlug: tab, page, limit: 50 });
|
|
322
|
+
for (const entity of review.entities)
|
|
323
|
+
await queue(entity);
|
|
324
|
+
if (page >= review.totalPages)
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return { queuedDocuments, queuedLocales, skippedPending };
|
|
329
|
+
};
|
|
330
|
+
var runQueuedTranslations = async (req, limit = 3) => {
|
|
331
|
+
await req.payload.jobs.run({
|
|
332
|
+
limit,
|
|
333
|
+
where: { workflowSlug: { equals: TRANSLATE_WORKFLOW_SLUG2 } },
|
|
334
|
+
req
|
|
335
|
+
});
|
|
336
|
+
return loadJobsProgress(req);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export { readLocales, loadCollectionReview, loadGlobalsReview, parseEntityKey, loadEntityLocaleReview, hasTranslateWorkflow, loadJobsProgress, queueBulkTranslation, runQueuedTranslations };
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// src/jobs/constants.ts
|
|
2
|
+
var TRANSLATE_TASK_SLUG2 = "translateEntityToLocale";
|
|
3
|
+
var TRANSLATE_WORKFLOW_SLUG2 = "translateEntityToLocales";
|
|
4
|
+
|
|
1
5
|
// src/utils/placeholders.ts
|
|
2
6
|
var placeholdersOf = (value) => (value.match(/\{\s*[\w.]+\s*(?:,[^{}]*)?\}/g) ?? []).map((each) => each.replace(/\s+/g, "")).sort();
|
|
3
7
|
var samePlaceholders = (source, translated) => placeholdersOf(source).join("|") === placeholdersOf(translated).join("|");
|
|
@@ -46,6 +50,32 @@ var isOpaqueText = (value) => {
|
|
|
46
50
|
return /^([a-z][a-z0-9+.-]*:|\/\/|\/|#|www\.)/i.test(text) || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(text) || !/\p{L}/u.test(text);
|
|
47
51
|
};
|
|
48
52
|
|
|
53
|
+
// src/utils/plainText.ts
|
|
54
|
+
var plainText = (value) => {
|
|
55
|
+
if (typeof value === "string")
|
|
56
|
+
return value;
|
|
57
|
+
if (!value || typeof value !== "object")
|
|
58
|
+
return "";
|
|
59
|
+
if (Array.isArray(value))
|
|
60
|
+
return value.map(plainText).filter(Boolean).join(" ");
|
|
61
|
+
const node = value;
|
|
62
|
+
if (typeof node.text === "string")
|
|
63
|
+
return node.text;
|
|
64
|
+
if ("root" in node)
|
|
65
|
+
return plainText(node.root);
|
|
66
|
+
if (Array.isArray(node.children))
|
|
67
|
+
return node.children.map(plainText).filter(Boolean).join(node.type === "root" ? `
|
|
68
|
+
` : "");
|
|
69
|
+
return "";
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/utils/looksUntranslated.ts
|
|
73
|
+
var normalize = (text) => text.replace(/\s+/g, " ").trim();
|
|
74
|
+
var looksUntranslated = (source, target) => {
|
|
75
|
+
const sourceText = normalize(plainText(source));
|
|
76
|
+
return sourceText.length > 3 && /\s/.test(sourceText) && !isOpaqueText(sourceText) && sourceText === normalize(plainText(target));
|
|
77
|
+
};
|
|
78
|
+
|
|
49
79
|
// src/utils/sanitizeSlug.ts
|
|
50
80
|
var sanitizeSlug = (text) => text.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
51
81
|
|
|
@@ -95,6 +125,7 @@ var traverseFields = (args) => {
|
|
|
95
125
|
const {
|
|
96
126
|
dataFrom,
|
|
97
127
|
emptyOnly,
|
|
128
|
+
retranslateIdentical,
|
|
98
129
|
fields,
|
|
99
130
|
localizedParent,
|
|
100
131
|
path,
|
|
@@ -106,6 +137,7 @@ var traverseFields = (args) => {
|
|
|
106
137
|
const { additionalTraverseRichText } = _options ?? {};
|
|
107
138
|
const siblingDataFrom = args.siblingDataFrom ?? dataFrom;
|
|
108
139
|
const siblingDataTranslated = args.siblingDataTranslated ?? translatedData;
|
|
140
|
+
const keepsTarget = (source, target) => Boolean(emptyOnly) && hasText(target) && !(retranslateIdentical && looksUntranslated(source, target));
|
|
109
141
|
const recurse = (overrides) => traverseFields({ ...args, siblingDataFrom, siblingDataTranslated, ...overrides });
|
|
110
142
|
for (const field of fields) {
|
|
111
143
|
switch (field.type) {
|
|
@@ -226,7 +258,7 @@ var traverseFields = (args) => {
|
|
|
226
258
|
onField?.({ path: keyPath, type: "json", source: value, target: previous });
|
|
227
259
|
if (!value.trim())
|
|
228
260
|
continue;
|
|
229
|
-
if (
|
|
261
|
+
if (keepsTarget(value, previous))
|
|
230
262
|
continue;
|
|
231
263
|
target[key] = value;
|
|
232
264
|
if (isOpaqueText(value))
|
|
@@ -266,7 +298,7 @@ var traverseFields = (args) => {
|
|
|
266
298
|
if (typeof value !== "string" || !value.trim())
|
|
267
299
|
break;
|
|
268
300
|
const hasCurrent = typeof current === "string" && current.trim().length > 0;
|
|
269
|
-
if (hasCurrent
|
|
301
|
+
if (isSlug ? hasCurrent : keepsTarget(value, current))
|
|
270
302
|
break;
|
|
271
303
|
if (isOpaqueText(value)) {
|
|
272
304
|
siblingDataTranslated[field.name] = value;
|
|
@@ -304,7 +336,7 @@ var traverseFields = (args) => {
|
|
|
304
336
|
onField?.({ path: richTextPath, type: "richText", source: richTextDataFrom, target: current });
|
|
305
337
|
if (!richTextDataFrom || !hasText(richTextDataFrom))
|
|
306
338
|
break;
|
|
307
|
-
if (
|
|
339
|
+
if (keepsTarget(richTextDataFrom, current))
|
|
308
340
|
break;
|
|
309
341
|
const isSlate = Array.isArray(richTextDataFrom);
|
|
310
342
|
const isLexical = typeof richTextDataFrom === "object" && "root" in richTextDataFrom;
|
|
@@ -356,4 +388,4 @@ var entityKey = ({ collectionSlug, globalSlug, id }) => globalSlug ? `global:${g
|
|
|
356
388
|
import { createHash } from "node:crypto";
|
|
357
389
|
var sourceHash = (fields) => createHash("sha1").update(JSON.stringify(fields.map(({ path, source }) => [path, source]))).digest("hex");
|
|
358
390
|
|
|
359
|
-
export { samePlaceholders,
|
|
391
|
+
export { samePlaceholders, plainText, looksUntranslated, traverseFields, TRANSLATE_TASK_SLUG2, TRANSLATE_WORKFLOW_SLUG2, collectTranslatableFields, entityKey, sourceHash };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
samePlaceholders,
|
|
3
3
|
traverseFields,
|
|
4
|
+
TRANSLATE_WORKFLOW_SLUG2,
|
|
4
5
|
collectTranslatableFields,
|
|
5
6
|
entityKey,
|
|
6
7
|
sourceHash
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-d0n3f8ad.js";
|
|
8
9
|
import {
|
|
9
10
|
TRANSLATION_STATUS_SLUG2
|
|
10
11
|
} from "./chunk-31qgv1zk.js";
|
|
@@ -127,6 +128,7 @@ var translateOperation2 = async (args) => {
|
|
|
127
128
|
traverseFields({
|
|
128
129
|
dataFrom,
|
|
129
130
|
emptyOnly: args.emptyOnly,
|
|
131
|
+
retranslateIdentical: args.retranslateIdentical,
|
|
130
132
|
fields: config.fields,
|
|
131
133
|
translatedData,
|
|
132
134
|
valuesToTranslate,
|
|
@@ -178,7 +180,7 @@ ${valuesToTranslate.map((v) => ` ${v.path ?? "(unknown)"}: ${preview(v.value)}`
|
|
|
178
180
|
${summary.join(`
|
|
179
181
|
`)}` : "")
|
|
180
182
|
});
|
|
181
|
-
if (args.update) {
|
|
183
|
+
if (args.update && valuesToTranslate.length > 0) {
|
|
182
184
|
const { _locale, _parent_id, createdAt, updatedAt, ...data } = translatedData;
|
|
183
185
|
await updateEntity({
|
|
184
186
|
collectionSlug,
|
|
@@ -194,16 +196,13 @@ ${summary.join(`
|
|
|
194
196
|
result = {
|
|
195
197
|
success: true,
|
|
196
198
|
translatedData,
|
|
199
|
+
translatedCount: valuesToTranslate.length,
|
|
197
200
|
dataFrom
|
|
198
201
|
};
|
|
199
202
|
}
|
|
200
203
|
return result;
|
|
201
204
|
};
|
|
202
205
|
|
|
203
|
-
// src/jobs/constants.ts
|
|
204
|
-
var TRANSLATE_TASK_SLUG2 = "translateEntityToLocale";
|
|
205
|
-
var TRANSLATE_WORKFLOW_SLUG2 = "translateEntityToLocales";
|
|
206
|
-
|
|
207
206
|
// src/jobs/createAutoTranslateCollectionHook.ts
|
|
208
207
|
function createAutoTranslateCollectionHook2(options) {
|
|
209
208
|
const {
|
|
@@ -432,6 +431,13 @@ var recordTranslationStatus = async ({ req, collectionSlug, globalSlug, id, loca
|
|
|
432
431
|
await upsertTranslationStatus(req, entityKey({ collectionSlug, globalSlug, id }), locale, reviewedBy ? { reviewedHash: hash, reviewedAt: now, reviewedBy } : { sourceHash: hash, translatedAt: now });
|
|
433
432
|
};
|
|
434
433
|
|
|
434
|
+
// src/utils/translateMode.ts
|
|
435
|
+
var translateModeArgs = (mode) => ({
|
|
436
|
+
emptyOnly: mode !== "all",
|
|
437
|
+
retranslateIdentical: mode === "untranslated"
|
|
438
|
+
});
|
|
439
|
+
var isTranslateMode = (value) => value === "all" || value === "missing" || value === "untranslated";
|
|
440
|
+
|
|
435
441
|
// src/jobs/createTranslateTask.ts
|
|
436
442
|
function createTranslateTask2(options = {}) {
|
|
437
443
|
const { slug = "translateEntityToLocale" } = options;
|
|
@@ -451,7 +457,7 @@ function createTranslateTask2(options = {}) {
|
|
|
451
457
|
handler: async (args) => {
|
|
452
458
|
const { input, job, req } = args;
|
|
453
459
|
const { id, collection, global, fromLocale, toLocale, resolver: inputResolver } = input;
|
|
454
|
-
const mode = input.mode
|
|
460
|
+
const mode = isTranslateMode(input.mode) ? input.mode : readAutoTranslateMode(req);
|
|
455
461
|
if (!collection && !global) {
|
|
456
462
|
throw new Error("translateTask: either `collection` or `global` must be provided");
|
|
457
463
|
}
|
|
@@ -470,7 +476,7 @@ function createTranslateTask2(options = {}) {
|
|
|
470
476
|
req,
|
|
471
477
|
collectionSlug: collection,
|
|
472
478
|
globalSlug: global,
|
|
473
|
-
|
|
479
|
+
...translateModeArgs(mode),
|
|
474
480
|
id,
|
|
475
481
|
locale: toLocale,
|
|
476
482
|
localeFrom: fromLocale,
|
|
@@ -507,6 +513,10 @@ function createTranslateTask2(options = {}) {
|
|
|
507
513
|
});
|
|
508
514
|
return { output: { success: true } };
|
|
509
515
|
}
|
|
516
|
+
if (result.translatedCount === 0) {
|
|
517
|
+
req.payload.logger.info({ jobId: job.id, msg: `[translate] ${entityLabel}#${id ?? global} → ${toLocale}: nothing to translate` });
|
|
518
|
+
return { output: { success: true } };
|
|
519
|
+
}
|
|
510
520
|
const translated = result.translatedData ?? {};
|
|
511
521
|
const { _locale: _dropLocale, _parent_id: _dropParent, updatedAt: _dropUpdatedAt, createdAt: _dropCreatedAt, ...data } = translated;
|
|
512
522
|
req.payload.logger.info({
|
|
@@ -558,7 +568,8 @@ function readFirstResolverKey3(req) {
|
|
|
558
568
|
return typeof first?.key === "string" ? first.key : "";
|
|
559
569
|
}
|
|
560
570
|
function readAutoTranslateMode(req) {
|
|
561
|
-
|
|
571
|
+
const mode = req.payload.config.custom?.translator?.autoTranslateMode;
|
|
572
|
+
return isTranslateMode(mode) ? mode : "missing";
|
|
562
573
|
}
|
|
563
574
|
|
|
564
575
|
// src/jobs/createTranslateWorkflow.ts
|
|
@@ -574,11 +585,12 @@ function createTranslateWorkflow2(options = {}) {
|
|
|
574
585
|
{ name: "fromLocale", type: "text", required: true },
|
|
575
586
|
{ name: "toLocales", type: "json", required: false },
|
|
576
587
|
{ name: "toLocale", type: "text", required: false },
|
|
577
|
-
{ name: "resolver", type: "text", required: false }
|
|
588
|
+
{ name: "resolver", type: "text", required: false },
|
|
589
|
+
{ name: "mode", type: "text", required: false }
|
|
578
590
|
],
|
|
579
591
|
handler: async (args) => {
|
|
580
592
|
const { job, req, tasks } = args;
|
|
581
|
-
const { id, collection, global, fromLocale, toLocales, toLocale, updatedAt, resolver } = job.input;
|
|
593
|
+
const { id, collection, global, fromLocale, toLocales, toLocale, updatedAt, resolver, mode } = job.input;
|
|
582
594
|
if (!collection && !global) {
|
|
583
595
|
throw new Error("translateWorkflow: either `collection` or `global` must be provided");
|
|
584
596
|
}
|
|
@@ -612,7 +624,8 @@ function createTranslateWorkflow2(options = {}) {
|
|
|
612
624
|
global,
|
|
613
625
|
fromLocale,
|
|
614
626
|
toLocale: target,
|
|
615
|
-
resolver
|
|
627
|
+
resolver,
|
|
628
|
+
mode
|
|
616
629
|
}
|
|
617
630
|
});
|
|
618
631
|
}
|
|
@@ -620,4 +633,4 @@ function createTranslateWorkflow2(options = {}) {
|
|
|
620
633
|
};
|
|
621
634
|
}
|
|
622
635
|
|
|
623
|
-
export { findEntityWithConfig, translateOperation2,
|
|
636
|
+
export { findEntityWithConfig, translateOperation2, createAutoTranslateCollectionHook2, createAutoTranslateGlobalHook2, recordTranslationStatus, translateModeArgs, isTranslateMode, createTranslateTask2, createTranslateWorkflow2 };
|
package/dist/types.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ type TranslateResolver = {
|
|
|
16
16
|
key: string;
|
|
17
17
|
resolve: (args: TranslateResolverArgs) => Promise<TranslateResolverResponse> | TranslateResolverResponse;
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* `missing` fills empty fields, `untranslated` also replaces fields that still hold the
|
|
21
|
+
* source copy, `all` re-translates everything.
|
|
22
|
+
*/
|
|
23
|
+
type TranslateMode = "all" | "missing" | "untranslated";
|
|
19
24
|
type TranslatorConfig = {
|
|
20
25
|
collections: CollectionSlug[];
|
|
21
26
|
disabled?: boolean;
|
|
@@ -27,7 +32,7 @@ type TranslatorConfig = {
|
|
|
27
32
|
* `missing` (default) fills empty fields and keeps existing translations and slugs;
|
|
28
33
|
* `all` re-translates every field.
|
|
29
34
|
*/
|
|
30
|
-
autoTranslateMode?:
|
|
35
|
+
autoTranslateMode?: TranslateMode;
|
|
31
36
|
/** adds the /admin/translations review view, its endpoints and the status collection (default true) */
|
|
32
37
|
review?: boolean;
|
|
33
38
|
_options?: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justanarthur/payload-plugin-translator",
|
|
3
3
|
"description": "Translator plugin for Payload CMS — automatic localization via Google, OpenAI, LibreTranslate, or custom resolvers.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"files": [
|