@justanarthur/payload-plugin-translator 3.0.3 → 3.1.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 +20 -2
- package/dist/client.css +184 -0
- package/dist/client.d.ts +14 -2
- package/dist/client.js +97 -11
- package/dist/index.d.ts +13 -1
- package/dist/index.js +171 -42
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.js +21 -20
- package/dist/resolvers/copy.d.ts +1 -1
- package/dist/resolvers/copy.js +5 -5
- package/dist/resolvers/google.d.ts +1 -1
- package/dist/resolvers/google.js +5 -6
- package/dist/resolvers/libreTranslate.d.ts +1 -1
- package/dist/resolvers/libreTranslate.js +5 -6
- package/dist/resolvers/openAI.d.ts +4 -2
- package/dist/resolvers/openAI.js +5 -6
- package/dist/resolvers/types.d.ts +1 -1
- package/dist/rsc.d.ts +5 -0
- package/dist/rsc.js +483 -0
- package/dist/shared/chunk-15n5q7wd.js +253 -0
- package/dist/shared/chunk-31qgv1zk.js +5 -0
- package/dist/shared/chunk-9d433kmv.js +359 -0
- package/dist/shared/{chunk-zhrw0jnz.js → chunk-mvqymw6n.js} +3 -3
- package/dist/shared/chunk-nxddacte.js +243 -0
- package/dist/shared/{chunk-q51q8rd2.js → chunk-p03jz82h.js} +280 -512
- package/dist/shared/{chunk-97ktc51q.js → chunk-zenq7s47.js} +2 -2
- package/dist/shared/{chunk-fsveh29m.js → chunk-zs19h344.js} +3 -3
- package/dist/types.d.ts +8 -0
- package/package.json +18 -9
- package/dist/shared/chunk-ecnph6hw.js +0 -205
- /package/dist/shared/{chunk-frnemj69.js → chunk-e6c0qzkt.js} +0 -0
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ export const myResolver: TranslateResolver = {
|
|
|
79
79
|
| `globals` | `GlobalSlug[]` | yes | Globals to auto-translate. |
|
|
80
80
|
| `resolvers` | `TranslateResolver[]` | yes | Tried in order; first to succeed wins per chunk. |
|
|
81
81
|
| `autoTranslate` | `boolean` | no | Default `true`. Set `false` to opt out of the auto-translate afterChange hook — useful when you drive translation manually via the `translateOperation` export. |
|
|
82
|
+
| `autoTranslateMode` | `'missing' \| 'all'` | no | Default `'missing'`: a publish in the default locale fills empty fields in other locales and keeps existing translations and slugs. `'all'` re-translates everything. |
|
|
83
|
+
| `review` | `boolean` | no | Default `true`. Adds the `/admin/translations` review view, its endpoints and the hidden `translation-status` collection (needs a migration on postgres). |
|
|
82
84
|
| `disabled` | `boolean` | no | Skip the plugin entirely (no overrides, no jobs). Useful in tests. |
|
|
83
85
|
| `_options.additionalTraverseRichText` | function | no | Hook to extend rich-text traversal — see below. |
|
|
84
86
|
|
|
@@ -100,8 +102,8 @@ translator({
|
|
|
100
102
|
})
|
|
101
103
|
```
|
|
102
104
|
|
|
103
|
-
The hook receives `onText` which mutates the data tree, plus the
|
|
104
|
-
|
|
105
|
+
The hook receives `onText` which mutates the data tree, plus the current node as `siblingData`.
|
|
106
|
+
It is called for every node without a `text` property, including `block` and `inlineBlock` nodes.
|
|
105
107
|
|
|
106
108
|
## How it works under the hood
|
|
107
109
|
|
|
@@ -113,6 +115,22 @@ richText field before translation begins.
|
|
|
113
115
|
- The plugin de-duplicates via `AUTO_TRANSLATE_MARKER` — re-running it on an already-attached hook
|
|
114
116
|
is a no-op, so it's safe to wrap multiple plugins around the same collection.
|
|
115
117
|
|
|
118
|
+
## Reviewing translations
|
|
119
|
+
|
|
120
|
+
With `review` on, **Translations** appears in the admin nav (`/admin/translations`):
|
|
121
|
+
|
|
122
|
+
- **Overview**: one row per document (paged, newest first) or global, one column per target locale.
|
|
123
|
+
Each cell shows the share of translatable fields that have a translation. `404` means the locale
|
|
124
|
+
has no slug, `↻` means the source changed since the last translation, `✓` means someone reviewed
|
|
125
|
+
that locale against the current source.
|
|
126
|
+
- **Detail** (click a cell): every translatable field with the source and target text side by side,
|
|
127
|
+
marked `missing`, `same as source` (likely never translated) or `placeholders differ`, plus the
|
|
128
|
+
last auto-translate job and its error. Actions: *Translate missing fields*, *Re-translate all*,
|
|
129
|
+
*Mark reviewed*.
|
|
130
|
+
|
|
131
|
+
The view only lists collections and globals the signed-in user can read, and the endpoints behind
|
|
132
|
+
the actions require a user.
|
|
133
|
+
|
|
116
134
|
## Manual translation
|
|
117
135
|
|
|
118
136
|
Two escape hatches when you don't want the auto-hook:
|
package/dist/client.css
CHANGED
|
@@ -39,3 +39,187 @@
|
|
|
39
39
|
flex-wrap: wrap;
|
|
40
40
|
gap: .5rem;
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
/* src/client/components/Review/styles.css */
|
|
44
|
+
.translator-review {
|
|
45
|
+
padding-bottom: calc(var(--base) * 3);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.translator-review__header {
|
|
49
|
+
display: flex;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
align-items: baseline;
|
|
52
|
+
gap: var(--base);
|
|
53
|
+
margin: calc(var(--base) * 1.5) 0;
|
|
54
|
+
flex-wrap: wrap;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.translator-review__header h1 {
|
|
58
|
+
margin: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.translator-review__tabs {
|
|
62
|
+
display: flex;
|
|
63
|
+
gap: calc(var(--base) / 2);
|
|
64
|
+
margin-bottom: var(--base);
|
|
65
|
+
flex-wrap: wrap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.translator-review__tab {
|
|
69
|
+
border: 1px solid var(--theme-elevation-150);
|
|
70
|
+
color: var(--theme-elevation-800);
|
|
71
|
+
text-decoration: none;
|
|
72
|
+
border-radius: 999px;
|
|
73
|
+
padding: 4px 12px;
|
|
74
|
+
font-size: 13px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.translator-review__tab[aria-current="true"] {
|
|
78
|
+
background: var(--theme-elevation-900);
|
|
79
|
+
border-color: var(--theme-elevation-900);
|
|
80
|
+
color: var(--theme-elevation-0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.translator-review__scroll {
|
|
84
|
+
overflow-x: auto;
|
|
85
|
+
border: 1px solid var(--theme-elevation-100);
|
|
86
|
+
border-radius: var(--style-radius-m);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.translator-review table {
|
|
90
|
+
border-collapse: collapse;
|
|
91
|
+
width: 100%;
|
|
92
|
+
font-size: 13px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.translator-review th, .translator-review td {
|
|
96
|
+
border-bottom: 1px solid var(--theme-elevation-100);
|
|
97
|
+
text-align: left;
|
|
98
|
+
vertical-align: top;
|
|
99
|
+
padding: 8px 10px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.translator-review th {
|
|
103
|
+
background: var(--theme-elevation-50);
|
|
104
|
+
white-space: nowrap;
|
|
105
|
+
font-weight: 600;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.translator-review tr:last-child td {
|
|
109
|
+
border-bottom: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.translator-review__doc {
|
|
113
|
+
min-width: 220px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.translator-review__doc small {
|
|
117
|
+
display: block;
|
|
118
|
+
color: var(--theme-elevation-500);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.translator-review__cell {
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
font-variant-numeric: tabular-nums;
|
|
124
|
+
text-decoration: none;
|
|
125
|
+
color: var(--theme-elevation-1000);
|
|
126
|
+
border: 1px solid #0000;
|
|
127
|
+
border-radius: 999px;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: 4px;
|
|
130
|
+
min-width: 64px;
|
|
131
|
+
padding: 2px 8px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.translator-review__cell--ok {
|
|
135
|
+
background: var(--theme-success-100);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.translator-review__cell--partial {
|
|
139
|
+
background: var(--theme-warning-100);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.translator-review__cell--missing {
|
|
143
|
+
background: var(--theme-error-100);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.translator-review__cell--stale {
|
|
147
|
+
border-color: var(--theme-warning-500);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.translator-review__legend {
|
|
151
|
+
display: flex;
|
|
152
|
+
gap: var(--base);
|
|
153
|
+
color: var(--theme-elevation-600);
|
|
154
|
+
margin-top: calc(var(--base) / 2);
|
|
155
|
+
flex-wrap: wrap;
|
|
156
|
+
font-size: 12px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.translator-review__pager {
|
|
160
|
+
display: flex;
|
|
161
|
+
gap: var(--base);
|
|
162
|
+
margin-top: var(--base);
|
|
163
|
+
align-items: center;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.translator-review__state {
|
|
167
|
+
white-space: nowrap;
|
|
168
|
+
border-radius: 999px;
|
|
169
|
+
padding: 1px 8px;
|
|
170
|
+
font-size: 12px;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.translator-review__state--ok {
|
|
174
|
+
background: var(--theme-success-100);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.translator-review__state--missing {
|
|
178
|
+
background: var(--theme-error-100);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.translator-review__state--identical, .translator-review__state--placeholders {
|
|
182
|
+
background: var(--theme-warning-100);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.translator-review__text {
|
|
186
|
+
white-space: pre-wrap;
|
|
187
|
+
word-break: break-word;
|
|
188
|
+
max-width: 420px;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.translator-review__text--empty {
|
|
192
|
+
color: var(--theme-elevation-400);
|
|
193
|
+
font-style: italic;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.translator-review__path {
|
|
197
|
+
font-family: var(--font-mono, monospace);
|
|
198
|
+
color: var(--theme-elevation-600);
|
|
199
|
+
word-break: break-all;
|
|
200
|
+
max-width: 240px;
|
|
201
|
+
font-size: 12px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.translator-review__meta {
|
|
205
|
+
display: flex;
|
|
206
|
+
gap: calc(var(--base) * 1.5);
|
|
207
|
+
color: var(--theme-elevation-600);
|
|
208
|
+
margin-bottom: var(--base);
|
|
209
|
+
flex-wrap: wrap;
|
|
210
|
+
font-size: 13px;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.translator-review__actions {
|
|
214
|
+
display: flex;
|
|
215
|
+
gap: calc(var(--base) / 2);
|
|
216
|
+
flex-wrap: wrap;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.translator-review__actions .btn {
|
|
220
|
+
margin: 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.translator-review__error {
|
|
224
|
+
color: var(--theme-error-500);
|
|
225
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { JSX as JSX_1kxb } from "react
|
|
1
|
+
import { JSX as JSX_1kxb } from "react";
|
|
2
2
|
type Element_12xgc = JSX_1kxb["Element"];
|
|
3
3
|
declare const CustomButtonWithTranslator: ({ type }: {
|
|
4
4
|
type: "publish" | "save";
|
|
5
5
|
}) => Element_12xgc;
|
|
6
|
-
|
|
6
|
+
import { JSX as JSX_1kxb2 } from "react";
|
|
7
|
+
type Element_12xgc2 = JSX_1kxb2["Element"];
|
|
8
|
+
declare const ReviewActions: ({ entity, locale, reviewed }: {
|
|
9
|
+
entity: string;
|
|
10
|
+
locale: string;
|
|
11
|
+
reviewed: boolean;
|
|
12
|
+
}) => Element_12xgc2;
|
|
13
|
+
/** loads the review view styles; the view itself is a server component */
|
|
14
|
+
declare const ReviewStyles: () => null;
|
|
15
|
+
import { JSX as JSX_1kxb3 } from "react";
|
|
16
|
+
type Element_12xgc3 = JSX_1kxb3["Element"];
|
|
17
|
+
declare const TranslationsNavLink: () => Element_12xgc3;
|
|
18
|
+
export { CustomButtonWithTranslator, ReviewActions, ReviewStyles, TranslationsNavLink, CustomButtonWithTranslator as default };
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import {
|
|
3
|
+
REVIEW_VIEW_PATH
|
|
4
|
+
} from "./shared/chunk-31qgv1zk.js";
|
|
5
|
+
|
|
2
6
|
// src/client/components/CustomButton/CustomButtonWithTranslator.tsx
|
|
3
7
|
import { PublishButton, SaveButton, useConfig as useConfig2, useDocumentInfo as useDocumentInfo2 } from "@payloadcms/ui";
|
|
4
8
|
|
|
@@ -85,19 +89,18 @@ var TranslatorProvider = ({ children }) => {
|
|
|
85
89
|
const resolvers = custom?.translator?.resolvers || undefined;
|
|
86
90
|
if (!resolvers)
|
|
87
91
|
return null;
|
|
88
|
-
const
|
|
89
|
-
return
|
|
92
|
+
const resolverConfig = resolvers.find((each) => each.key === resolver);
|
|
93
|
+
return resolverConfig ?? null;
|
|
90
94
|
}, [custom, resolver]);
|
|
91
95
|
if (!localization)
|
|
92
96
|
throw new Error("Localization config is not provided and PluginTranslator is used");
|
|
93
97
|
const localesOptions = localization.locales.filter((each) => each.code !== locale.code);
|
|
94
98
|
const [localeToTranslateFrom, setLocaleToTranslateFrom] = useState("");
|
|
95
99
|
useEffect(() => {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}, [locale, localesOptions, localization.defaultLocale]);
|
|
100
|
+
const options = localization.locales.filter((each) => each.code !== locale.code);
|
|
101
|
+
const defaultFromOptions = options.find((each) => localization.defaultLocale === each.code);
|
|
102
|
+
setLocaleToTranslateFrom((defaultFromOptions ?? options[0])?.code ?? "");
|
|
103
|
+
}, [locale.code, localization.defaultLocale, localization.locales]);
|
|
101
104
|
const closeTranslator = () => modal.closeModal(modalSlug);
|
|
102
105
|
const submit = async ({ emptyOnly }) => {
|
|
103
106
|
if (!resolver)
|
|
@@ -269,12 +272,12 @@ var Content = () => {
|
|
|
269
272
|
// src/client/components/TranslatorModal/TranslatorModal.tsx
|
|
270
273
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
271
274
|
var TranslatorModal = () => {
|
|
272
|
-
const { closeTranslator, modalSlug
|
|
275
|
+
const { closeTranslator, modalSlug, resolver } = useTranslator();
|
|
273
276
|
if (!resolver)
|
|
274
277
|
return;
|
|
275
278
|
return /* @__PURE__ */ jsx5(Modal, {
|
|
276
279
|
className: "translator__modal",
|
|
277
|
-
slug:
|
|
280
|
+
slug: modalSlug,
|
|
278
281
|
children: /* @__PURE__ */ jsxs3("div", {
|
|
279
282
|
className: "translator__wrapper",
|
|
280
283
|
children: [
|
|
@@ -312,9 +315,92 @@ var CustomButtonWithTranslator = ({ type }) => {
|
|
|
312
315
|
});
|
|
313
316
|
};
|
|
314
317
|
|
|
318
|
+
// src/client/components/Review/ReviewActions.tsx
|
|
319
|
+
import { Button as Button3, toast as toast2, useConfig as useConfig3 } from "@payloadcms/ui";
|
|
320
|
+
import { useState as useState2 } from "react";
|
|
321
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
322
|
+
|
|
323
|
+
var ReviewActions = ({ entity, locale, reviewed }) => {
|
|
324
|
+
const { config: { routes: { api }, serverURL } } = useConfig3();
|
|
325
|
+
const [pending, setPending] = useState2(null);
|
|
326
|
+
const run = async (action) => {
|
|
327
|
+
if (action === "translate-all" && !window.confirm(`Re-translate every field in ${locale}? Existing ${locale} copy is replaced.`))
|
|
328
|
+
return;
|
|
329
|
+
setPending(action);
|
|
330
|
+
try {
|
|
331
|
+
const path = action === "mark-reviewed" ? "mark-reviewed" : "translate";
|
|
332
|
+
const res = await fetch(`${serverURL ?? ""}${api}/translator/review/${path}`, {
|
|
333
|
+
method: "POST",
|
|
334
|
+
credentials: "include",
|
|
335
|
+
headers: { "Content-Type": "application/json" },
|
|
336
|
+
body: JSON.stringify({ entity, locale, mode: action === "translate-all" ? "all" : "missing" })
|
|
337
|
+
});
|
|
338
|
+
const result = await res.json().catch(() => ({}));
|
|
339
|
+
if (!res.ok || !result.success)
|
|
340
|
+
throw new Error(result?.errors?.[0]?.message ?? "request failed");
|
|
341
|
+
toast2.success(action === "mark-reviewed" ? `${locale} marked as reviewed` : `${locale} translated`);
|
|
342
|
+
window.location.reload();
|
|
343
|
+
} catch (error) {
|
|
344
|
+
toast2.error(`Could not ${action.replace("-", " ")}: ${error instanceof Error ? error.message : String(error)}`);
|
|
345
|
+
} finally {
|
|
346
|
+
setPending(null);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
return /* @__PURE__ */ jsxs5("div", {
|
|
350
|
+
className: "translator-review__actions",
|
|
351
|
+
children: [
|
|
352
|
+
/* @__PURE__ */ jsx7(Button3, {
|
|
353
|
+
buttonStyle: "primary",
|
|
354
|
+
disabled: Boolean(pending),
|
|
355
|
+
onClick: () => run("translate-missing"),
|
|
356
|
+
size: "small",
|
|
357
|
+
children: pending === "translate-missing" ? "Translating…" : "Translate missing fields"
|
|
358
|
+
}),
|
|
359
|
+
/* @__PURE__ */ jsx7(Button3, {
|
|
360
|
+
buttonStyle: "secondary",
|
|
361
|
+
disabled: Boolean(pending),
|
|
362
|
+
onClick: () => run("translate-all"),
|
|
363
|
+
size: "small",
|
|
364
|
+
children: pending === "translate-all" ? "Translating…" : "Re-translate all"
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ jsx7(Button3, {
|
|
367
|
+
buttonStyle: "secondary",
|
|
368
|
+
disabled: Boolean(pending) || reviewed,
|
|
369
|
+
onClick: () => run("mark-reviewed"),
|
|
370
|
+
size: "small",
|
|
371
|
+
children: reviewed ? "Reviewed" : "Mark reviewed"
|
|
372
|
+
})
|
|
373
|
+
]
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
// src/client/components/Review/ReviewStyles.tsx
|
|
377
|
+
|
|
378
|
+
var ReviewStyles = () => null;
|
|
379
|
+
// src/client/components/Review/TranslationsNavLink.tsx
|
|
380
|
+
import { useConfig as useConfig4 } from "@payloadcms/ui";
|
|
381
|
+
import { formatAdminURL } from "payload/shared";
|
|
382
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
383
|
+
|
|
384
|
+
var TranslationsNavLink = () => {
|
|
385
|
+
const { config: { routes: { admin } } } = useConfig4();
|
|
386
|
+
const href = formatAdminURL({ adminRoute: admin, path: REVIEW_VIEW_PATH });
|
|
387
|
+
return /* @__PURE__ */ jsx8("a", {
|
|
388
|
+
className: "nav__link",
|
|
389
|
+
href,
|
|
390
|
+
id: "nav-translations",
|
|
391
|
+
children: /* @__PURE__ */ jsx8("span", {
|
|
392
|
+
className: "nav__link-label",
|
|
393
|
+
children: "Translations"
|
|
394
|
+
})
|
|
395
|
+
});
|
|
396
|
+
};
|
|
397
|
+
|
|
315
398
|
// src/exports/client.ts
|
|
316
399
|
var client_default = CustomButtonWithTranslator;
|
|
317
400
|
export {
|
|
318
|
-
|
|
319
|
-
|
|
401
|
+
CustomButtonWithTranslator,
|
|
402
|
+
ReviewActions,
|
|
403
|
+
ReviewStyles,
|
|
404
|
+
TranslationsNavLink,
|
|
405
|
+
client_default as default
|
|
320
406
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,14 @@ type TranslatorConfig = {
|
|
|
51
51
|
globals: GlobalSlug[];
|
|
52
52
|
resolvers: TranslateResolver[];
|
|
53
53
|
autoTranslate?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* what a publish in the default locale does to the other locales.
|
|
56
|
+
* `missing` (default) fills empty fields and keeps existing translations and slugs;
|
|
57
|
+
* `all` re-translates every field.
|
|
58
|
+
*/
|
|
59
|
+
autoTranslateMode?: "all" | "missing";
|
|
60
|
+
/** adds the /admin/translations review view, its endpoints and the status collection (default true) */
|
|
61
|
+
review?: boolean;
|
|
54
62
|
_options?: {
|
|
55
63
|
additionalTraverseRichText?: (args: {
|
|
56
64
|
onText: (siblingData: Record<string, unknown>, attribute?: string) => void;
|
|
@@ -60,4 +68,8 @@ type TranslatorConfig = {
|
|
|
60
68
|
};
|
|
61
69
|
};
|
|
62
70
|
declare const translator: (pluginConfig: TranslatorConfig) => Plugin;
|
|
63
|
-
|
|
71
|
+
import { CollectionConfig } from "payload";
|
|
72
|
+
/** one row per entity and target locale: what source it was translated from, and who reviewed it */
|
|
73
|
+
declare const createTranslationStatusCollection: () => CollectionConfig;
|
|
74
|
+
declare const TRANSLATION_STATUS_SLUG = "translation-status";
|
|
75
|
+
export { TRANSLATION_STATUS_SLUG, TranslateResolver, TranslateResolverArgs, TranslateResolverResponse, createTranslationStatusCollection, translator as default, translateOperation, translator };
|