@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
package/dist/rsc.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import"./shared/chunk-
|
|
1
|
+
import"./shared/chunk-d0n3f8ad.js";
|
|
2
2
|
import {
|
|
3
3
|
readLocales,
|
|
4
4
|
loadCollectionReview,
|
|
5
5
|
loadGlobalsReview,
|
|
6
|
-
loadEntityLocaleReview
|
|
7
|
-
|
|
6
|
+
loadEntityLocaleReview,
|
|
7
|
+
loadJobsProgress
|
|
8
|
+
} from "./shared/chunk-4ftfmxgs.js";
|
|
8
9
|
import {
|
|
9
10
|
REVIEW_VIEW_PATH
|
|
10
11
|
} from "./shared/chunk-31qgv1zk.js";
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
// src/review/view/TranslationsView.tsx
|
|
13
14
|
import { DefaultTemplate } from "@payloadcms/next/templates";
|
|
14
15
|
import { Gutter } from "@payloadcms/ui";
|
|
15
|
-
import {
|
|
16
|
+
import { BulkActions } from "@justanarthur/payload-plugin-translator/client";
|
|
16
17
|
|
|
17
18
|
// src/review/view/Detail.tsx
|
|
18
19
|
import { ReviewActions } from "@justanarthur/payload-plugin-translator/client";
|
|
@@ -30,38 +31,50 @@ var editHref = (adminRoute, { collectionSlug, globalSlug, id }, locale) => `${fo
|
|
|
30
31
|
|
|
31
32
|
// src/review/view/Detail.tsx
|
|
32
33
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
33
|
-
var
|
|
34
|
-
identical: "same as source",
|
|
35
|
-
missing: "missing",
|
|
36
|
-
ok: "translated",
|
|
37
|
-
placeholders: "placeholders differ"
|
|
34
|
+
var STATE = {
|
|
35
|
+
identical: { label: "same as source", tone: "warn" },
|
|
36
|
+
missing: { label: "missing", tone: "bad" },
|
|
37
|
+
ok: { label: "translated", tone: "ok" },
|
|
38
|
+
placeholders: { label: "placeholders differ", tone: "warn" }
|
|
38
39
|
};
|
|
39
40
|
var preview = (text) => text.length > 600 ? `${text.slice(0, 597)}…` : text;
|
|
40
41
|
var readablePath = (path) => path.replace(/\[(\d+)\]/g, (_, index) => ` ${Number(index) + 1}`).replace(/\(([^)]+)\)/g, " · $1").replace(/#(\d+)$/, (_, index) => ` (part ${Number(index) + 1})`).split(".").join(" › ");
|
|
41
|
-
var Detail = ({ adminRoute, review, onlyIssues, tab }) => {
|
|
42
|
+
var Detail = ({ adminRoute, review, onlyIssues, tab, page }) => {
|
|
42
43
|
const rows = onlyIssues ? review.fields.filter((field) => field.state !== "ok") : review.fields;
|
|
43
44
|
const { summary } = review;
|
|
45
|
+
const tone = summary.slugMissing || summary.coverage < 50 ? "bad" : summary.coverage < 100 ? "warn" : "ok";
|
|
46
|
+
const counters = [
|
|
47
|
+
{ label: "translated", value: `${summary.coverage}%`, note: `${summary.ok} of ${summary.total} fields`, bar: true },
|
|
48
|
+
{ label: "missing", value: summary.missing, note: "empty in this locale" },
|
|
49
|
+
{ label: "same as source", value: summary.identical, note: `identical to ${review.defaultLocale}` },
|
|
50
|
+
{ label: "placeholders", value: summary.placeholders, note: "differ from source" }
|
|
51
|
+
];
|
|
44
52
|
return /* @__PURE__ */ jsxs(Fragment, {
|
|
45
53
|
children: [
|
|
46
54
|
/* @__PURE__ */ jsxs("div", {
|
|
47
|
-
className: "
|
|
55
|
+
className: "tr__head",
|
|
48
56
|
children: [
|
|
49
57
|
/* @__PURE__ */ jsxs("div", {
|
|
50
58
|
children: [
|
|
51
59
|
/* @__PURE__ */ jsxs("a", {
|
|
52
|
-
|
|
60
|
+
className: "tr__back",
|
|
61
|
+
href: reviewHref(adminRoute, { tab, page }),
|
|
53
62
|
children: [
|
|
54
63
|
"← All ",
|
|
55
|
-
tab
|
|
64
|
+
tab
|
|
56
65
|
]
|
|
57
66
|
}),
|
|
58
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ jsx("h1", {
|
|
68
|
+
children: review.label
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ jsxs("p", {
|
|
71
|
+
className: "tr__lead",
|
|
59
72
|
children: [
|
|
60
|
-
review.
|
|
61
|
-
" · ",
|
|
62
|
-
review.defaultLocale,
|
|
73
|
+
review.defaultLocale.toUpperCase(),
|
|
63
74
|
" → ",
|
|
64
|
-
review.locale
|
|
75
|
+
review.locale.toUpperCase(),
|
|
76
|
+
" · ",
|
|
77
|
+
review.entity
|
|
65
78
|
]
|
|
66
79
|
})
|
|
67
80
|
]
|
|
@@ -73,86 +86,106 @@ var Detail = ({ adminRoute, review, onlyIssues, tab }) => {
|
|
|
73
86
|
})
|
|
74
87
|
]
|
|
75
88
|
}),
|
|
89
|
+
/* @__PURE__ */ jsx("div", {
|
|
90
|
+
className: "tr__stats",
|
|
91
|
+
children: counters.map((counter) => /* @__PURE__ */ jsxs("div", {
|
|
92
|
+
className: "tr__stat",
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx("span", {
|
|
95
|
+
className: "tr__stat-label",
|
|
96
|
+
children: counter.label
|
|
97
|
+
}),
|
|
98
|
+
/* @__PURE__ */ jsx("span", {
|
|
99
|
+
className: "tr__stat-value",
|
|
100
|
+
children: counter.value
|
|
101
|
+
}),
|
|
102
|
+
counter.bar && /* @__PURE__ */ jsx("div", {
|
|
103
|
+
className: "tr__bar",
|
|
104
|
+
style: { ["--tr-tone"]: `var(--tr-${tone})` },
|
|
105
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
106
|
+
style: { width: `${summary.coverage}%` }
|
|
107
|
+
})
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsx("span", {
|
|
110
|
+
className: "tr__stat-note",
|
|
111
|
+
children: counter.note
|
|
112
|
+
})
|
|
113
|
+
]
|
|
114
|
+
}, counter.label))
|
|
115
|
+
}),
|
|
76
116
|
/* @__PURE__ */ jsxs("div", {
|
|
77
|
-
className: "
|
|
117
|
+
className: "tr__meta",
|
|
78
118
|
children: [
|
|
79
|
-
/* @__PURE__ */ jsxs("span", {
|
|
80
|
-
children: [
|
|
81
|
-
summary.ok,
|
|
82
|
-
"/",
|
|
83
|
-
summary.total,
|
|
84
|
-
" translated (",
|
|
85
|
-
summary.coverage,
|
|
86
|
-
"%)"
|
|
87
|
-
]
|
|
88
|
-
}),
|
|
89
|
-
summary.missing > 0 && /* @__PURE__ */ jsxs("span", {
|
|
90
|
-
children: [
|
|
91
|
-
summary.missing,
|
|
92
|
-
" missing"
|
|
93
|
-
]
|
|
94
|
-
}),
|
|
95
|
-
summary.identical > 0 && /* @__PURE__ */ jsxs("span", {
|
|
96
|
-
children: [
|
|
97
|
-
summary.identical,
|
|
98
|
-
" same as ",
|
|
99
|
-
review.defaultLocale
|
|
100
|
-
]
|
|
101
|
-
}),
|
|
102
|
-
summary.placeholders > 0 && /* @__PURE__ */ jsxs("span", {
|
|
103
|
-
children: [
|
|
104
|
-
summary.placeholders,
|
|
105
|
-
" placeholder mismatches"
|
|
106
|
-
]
|
|
107
|
-
}),
|
|
108
119
|
summary.slugMissing && /* @__PURE__ */ jsxs("span", {
|
|
109
|
-
className: "
|
|
120
|
+
className: "tr__chip tr__chip--bad",
|
|
110
121
|
children: [
|
|
111
|
-
"no slug
|
|
122
|
+
"no slug: the page 404s in ",
|
|
112
123
|
review.locale
|
|
113
124
|
]
|
|
114
125
|
}),
|
|
115
126
|
review.stale && /* @__PURE__ */ jsx("span", {
|
|
116
|
-
|
|
127
|
+
className: "tr__chip",
|
|
128
|
+
children: "↻ source changed since the last translation"
|
|
117
129
|
}),
|
|
118
130
|
review.translatedAt && /* @__PURE__ */ jsxs("span", {
|
|
131
|
+
className: "tr__chip",
|
|
119
132
|
children: [
|
|
120
133
|
"translated ",
|
|
121
134
|
new Date(review.translatedAt).toLocaleString()
|
|
122
135
|
]
|
|
123
136
|
}),
|
|
124
137
|
review.reviewedAt && /* @__PURE__ */ jsxs("span", {
|
|
138
|
+
className: "tr__chip",
|
|
125
139
|
children: [
|
|
126
|
-
"reviewed ",
|
|
140
|
+
"✓ reviewed ",
|
|
127
141
|
new Date(review.reviewedAt).toLocaleString(),
|
|
128
142
|
" by ",
|
|
129
143
|
review.reviewedBy
|
|
130
144
|
]
|
|
131
145
|
}),
|
|
132
146
|
review.lastJob && /* @__PURE__ */ jsxs("span", {
|
|
133
|
-
className: review.lastJob.error ? "
|
|
147
|
+
className: `tr__chip${review.lastJob.error ? " tr__chip--bad" : ""}`,
|
|
148
|
+
title: review.lastJob.error,
|
|
134
149
|
children: [
|
|
135
|
-
"
|
|
150
|
+
"job #",
|
|
136
151
|
review.lastJob.id,
|
|
137
152
|
": ",
|
|
138
|
-
review.lastJob.error ? `failed — ${preview(review.lastJob.error)}` : review.lastJob.completedAt ? "completed" : review.lastJob.processing ? "running" : "queued"
|
|
153
|
+
review.lastJob.error ? `failed — ${preview(review.lastJob.error).slice(0, 80)}` : review.lastJob.completedAt ? "completed" : review.lastJob.processing ? "running" : "queued"
|
|
139
154
|
]
|
|
140
155
|
}),
|
|
141
156
|
/* @__PURE__ */ jsxs("a", {
|
|
157
|
+
className: "tr__chip",
|
|
142
158
|
href: editHref(adminRoute, review, review.locale),
|
|
143
159
|
children: [
|
|
144
160
|
"Edit in ",
|
|
145
|
-
review.locale
|
|
161
|
+
review.locale.toUpperCase(),
|
|
162
|
+
" ↗"
|
|
163
|
+
]
|
|
164
|
+
})
|
|
165
|
+
]
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ jsxs("div", {
|
|
168
|
+
className: "tr__toolbar",
|
|
169
|
+
children: [
|
|
170
|
+
/* @__PURE__ */ jsxs("span", {
|
|
171
|
+
className: "tr__filters",
|
|
172
|
+
children: [
|
|
173
|
+
rows.length,
|
|
174
|
+
" of ",
|
|
175
|
+
review.fields.length,
|
|
176
|
+
" fields"
|
|
146
177
|
]
|
|
147
178
|
}),
|
|
148
179
|
/* @__PURE__ */ jsx("a", {
|
|
149
|
-
|
|
150
|
-
|
|
180
|
+
"aria-pressed": onlyIssues,
|
|
181
|
+
className: "tr__toggle",
|
|
182
|
+
href: reviewHref(adminRoute, { tab, page, entity: review.entity, locale: review.locale, issues: onlyIssues ? undefined : 1 }),
|
|
183
|
+
children: "Only problems"
|
|
151
184
|
})
|
|
152
185
|
]
|
|
153
186
|
}),
|
|
154
187
|
/* @__PURE__ */ jsx("div", {
|
|
155
|
-
className: "
|
|
188
|
+
className: "tr__card",
|
|
156
189
|
children: /* @__PURE__ */ jsxs("table", {
|
|
157
190
|
children: [
|
|
158
191
|
/* @__PURE__ */ jsx("thead", {
|
|
@@ -165,10 +198,10 @@ var Detail = ({ adminRoute, review, onlyIssues, tab }) => {
|
|
|
165
198
|
children: "State"
|
|
166
199
|
}),
|
|
167
200
|
/* @__PURE__ */ jsx("th", {
|
|
168
|
-
children: review.defaultLocale
|
|
201
|
+
children: review.defaultLocale.toUpperCase()
|
|
169
202
|
}),
|
|
170
203
|
/* @__PURE__ */ jsx("th", {
|
|
171
|
-
children: review.locale
|
|
204
|
+
children: review.locale.toUpperCase()
|
|
172
205
|
})
|
|
173
206
|
]
|
|
174
207
|
})
|
|
@@ -178,28 +211,30 @@ var Detail = ({ adminRoute, review, onlyIssues, tab }) => {
|
|
|
178
211
|
rows.map((field) => /* @__PURE__ */ jsxs("tr", {
|
|
179
212
|
children: [
|
|
180
213
|
/* @__PURE__ */ jsx("td", {
|
|
181
|
-
className: "
|
|
214
|
+
className: "tr__path",
|
|
182
215
|
title: field.path,
|
|
183
216
|
children: readablePath(field.path)
|
|
184
217
|
}),
|
|
185
218
|
/* @__PURE__ */ jsx("td", {
|
|
186
219
|
children: /* @__PURE__ */ jsx("span", {
|
|
187
|
-
className:
|
|
188
|
-
|
|
220
|
+
className: "tr__pill",
|
|
221
|
+
"data-tone": STATE[field.state].tone,
|
|
222
|
+
children: STATE[field.state].label
|
|
189
223
|
})
|
|
190
224
|
}),
|
|
191
225
|
/* @__PURE__ */ jsx("td", {
|
|
192
|
-
className: "
|
|
226
|
+
className: "tr__text",
|
|
193
227
|
children: preview(field.sourceText)
|
|
194
228
|
}),
|
|
195
229
|
/* @__PURE__ */ jsx("td", {
|
|
196
|
-
className: `
|
|
230
|
+
className: `tr__text${field.targetText.trim() ? "" : " tr__text--empty"}`,
|
|
197
231
|
children: field.targetText.trim() ? preview(field.targetText) : "empty"
|
|
198
232
|
})
|
|
199
233
|
]
|
|
200
234
|
}, field.path)),
|
|
201
235
|
rows.length === 0 && /* @__PURE__ */ jsx("tr", {
|
|
202
236
|
children: /* @__PURE__ */ jsx("td", {
|
|
237
|
+
className: "tr__empty",
|
|
203
238
|
colSpan: 4,
|
|
204
239
|
children: "Every field is translated."
|
|
205
240
|
})
|
|
@@ -215,24 +250,55 @@ var Detail = ({ adminRoute, review, onlyIssues, tab }) => {
|
|
|
215
250
|
|
|
216
251
|
// src/review/view/Overview.tsx
|
|
217
252
|
import { jsx as jsx2, jsxs as jsxs2, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
218
|
-
var
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab }) => {
|
|
225
|
-
const rows = onlyIssues ? entities.filter((entity) => Object.values(entity.locales).some((each) => each.summary.coverage < 100 || each.summary.slugMissing || each.stale)) : entities;
|
|
226
|
-
const totals = Object.fromEntries(locales.map((locale) => {
|
|
253
|
+
var toneOf = ({ summary }) => summary.slugMissing || summary.coverage < 50 ? "bad" : summary.coverage < 100 ? "warn" : "ok";
|
|
254
|
+
var coverageTone = (coverage) => coverage < 50 ? "bad" : coverage < 100 ? "warn" : "ok";
|
|
255
|
+
var isIncomplete = ({ summary, stale }) => summary.coverage < 100 || summary.slugMissing || stale;
|
|
256
|
+
var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab, page }) => {
|
|
257
|
+
const rows = onlyIssues ? entities.filter((entity) => Object.values(entity.locales).some(isIncomplete)) : entities;
|
|
258
|
+
const stats = locales.map((locale) => {
|
|
227
259
|
const reviews = entities.map((entity) => entity.locales[locale]);
|
|
228
260
|
const fields = reviews.reduce((sum, each) => sum + each.summary.total, 0);
|
|
229
261
|
const ok = reviews.reduce((sum, each) => sum + each.summary.ok, 0);
|
|
230
|
-
return
|
|
231
|
-
|
|
262
|
+
return {
|
|
263
|
+
locale,
|
|
264
|
+
coverage: fields ? Math.floor(ok / fields * 100) : 100,
|
|
265
|
+
incomplete: reviews.filter(isIncomplete).length
|
|
266
|
+
};
|
|
267
|
+
});
|
|
232
268
|
return /* @__PURE__ */ jsxs2(Fragment2, {
|
|
233
269
|
children: [
|
|
234
270
|
/* @__PURE__ */ jsx2("div", {
|
|
235
|
-
className: "
|
|
271
|
+
className: "tr__stats",
|
|
272
|
+
children: stats.map(({ locale, coverage, incomplete }) => /* @__PURE__ */ jsxs2("div", {
|
|
273
|
+
className: "tr__stat",
|
|
274
|
+
children: [
|
|
275
|
+
/* @__PURE__ */ jsx2("span", {
|
|
276
|
+
className: "tr__stat-label",
|
|
277
|
+
children: locale
|
|
278
|
+
}),
|
|
279
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
280
|
+
className: "tr__stat-value",
|
|
281
|
+
children: [
|
|
282
|
+
coverage,
|
|
283
|
+
"%"
|
|
284
|
+
]
|
|
285
|
+
}),
|
|
286
|
+
/* @__PURE__ */ jsx2("div", {
|
|
287
|
+
className: "tr__bar",
|
|
288
|
+
style: { ["--tr-tone"]: `var(--tr-${coverageTone(coverage)})` },
|
|
289
|
+
children: /* @__PURE__ */ jsx2("span", {
|
|
290
|
+
style: { width: `${coverage}%` }
|
|
291
|
+
})
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ jsx2("span", {
|
|
294
|
+
className: "tr__stat-note",
|
|
295
|
+
children: incomplete ? `${incomplete} incomplete` : "all complete"
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
}, locale))
|
|
299
|
+
}),
|
|
300
|
+
/* @__PURE__ */ jsx2("div", {
|
|
301
|
+
className: "tr__card",
|
|
236
302
|
children: /* @__PURE__ */ jsxs2("table", {
|
|
237
303
|
children: [
|
|
238
304
|
/* @__PURE__ */ jsx2("thead", {
|
|
@@ -241,17 +307,9 @@ var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab
|
|
|
241
307
|
/* @__PURE__ */ jsx2("th", {
|
|
242
308
|
children: "Document"
|
|
243
309
|
}),
|
|
244
|
-
locales.map((locale) => /* @__PURE__ */
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
" ",
|
|
248
|
-
/* @__PURE__ */ jsxs2("small", {
|
|
249
|
-
children: [
|
|
250
|
-
totals[locale],
|
|
251
|
-
"%"
|
|
252
|
-
]
|
|
253
|
-
})
|
|
254
|
-
]
|
|
310
|
+
locales.map((locale) => /* @__PURE__ */ jsx2("th", {
|
|
311
|
+
className: "tr__locale-col",
|
|
312
|
+
children: locale.toUpperCase()
|
|
255
313
|
}, locale))
|
|
256
314
|
]
|
|
257
315
|
})
|
|
@@ -261,37 +319,56 @@ var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab
|
|
|
261
319
|
rows.map((entity) => /* @__PURE__ */ jsxs2("tr", {
|
|
262
320
|
children: [
|
|
263
321
|
/* @__PURE__ */ jsxs2("td", {
|
|
264
|
-
className: "
|
|
322
|
+
className: "tr__doc",
|
|
265
323
|
children: [
|
|
266
324
|
/* @__PURE__ */ jsx2("a", {
|
|
267
325
|
href: editHref(adminRoute, entity, defaultLocale),
|
|
268
326
|
children: entity.label
|
|
269
327
|
}),
|
|
270
|
-
/* @__PURE__ */ jsx2("
|
|
328
|
+
/* @__PURE__ */ jsx2("span", {
|
|
329
|
+
className: "tr__key",
|
|
271
330
|
children: entity.key
|
|
272
331
|
})
|
|
273
332
|
]
|
|
274
333
|
}),
|
|
275
334
|
locales.map((locale) => {
|
|
276
335
|
const review = entity.locales[locale];
|
|
336
|
+
const { summary } = review;
|
|
277
337
|
const title = [
|
|
278
|
-
`${
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
review.stale &&
|
|
338
|
+
`${summary.ok}/${summary.total} fields translated`,
|
|
339
|
+
summary.missing && `${summary.missing} missing`,
|
|
340
|
+
summary.identical && `${summary.identical} same as ${defaultLocale}`,
|
|
341
|
+
summary.placeholders && `${summary.placeholders} broken placeholders`,
|
|
342
|
+
summary.slugMissing && "no slug: the page 404s",
|
|
343
|
+
review.stale && "source changed since translation",
|
|
284
344
|
review.reviewed && "reviewed"
|
|
285
345
|
].filter(Boolean).join(" · ");
|
|
286
346
|
return /* @__PURE__ */ jsx2("td", {
|
|
347
|
+
className: "tr__locale-col",
|
|
287
348
|
children: /* @__PURE__ */ jsxs2("a", {
|
|
288
|
-
className:
|
|
289
|
-
|
|
349
|
+
className: "tr__cell",
|
|
350
|
+
"data-tone": toneOf(review),
|
|
351
|
+
href: reviewHref(adminRoute, { tab, page, entity: entity.key, locale, issues: isIncomplete(review) ? 1 : undefined }),
|
|
290
352
|
title,
|
|
291
353
|
children: [
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
354
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
355
|
+
children: [
|
|
356
|
+
summary.slugMissing ? "404" : `${summary.coverage}%`,
|
|
357
|
+
(review.stale || review.reviewed) && /* @__PURE__ */ jsxs2("span", {
|
|
358
|
+
className: "tr__marks",
|
|
359
|
+
children: [
|
|
360
|
+
" ",
|
|
361
|
+
[review.stale && "↻", review.reviewed && "✓"].filter(Boolean).join(" ")
|
|
362
|
+
]
|
|
363
|
+
})
|
|
364
|
+
]
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ jsx2("span", {
|
|
367
|
+
className: "tr__bar",
|
|
368
|
+
children: /* @__PURE__ */ jsx2("span", {
|
|
369
|
+
style: { width: `${summary.slugMissing ? 100 : summary.coverage}%` }
|
|
370
|
+
})
|
|
371
|
+
})
|
|
295
372
|
]
|
|
296
373
|
})
|
|
297
374
|
}, locale);
|
|
@@ -300,8 +377,9 @@ var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab
|
|
|
300
377
|
}, entity.key)),
|
|
301
378
|
rows.length === 0 && /* @__PURE__ */ jsx2("tr", {
|
|
302
379
|
children: /* @__PURE__ */ jsx2("td", {
|
|
380
|
+
className: "tr__empty",
|
|
303
381
|
colSpan: locales.length + 1,
|
|
304
|
-
children: "
|
|
382
|
+
children: "Everything here is fully translated."
|
|
305
383
|
})
|
|
306
384
|
})
|
|
307
385
|
]
|
|
@@ -310,19 +388,40 @@ var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab
|
|
|
310
388
|
})
|
|
311
389
|
}),
|
|
312
390
|
/* @__PURE__ */ jsxs2("div", {
|
|
313
|
-
className: "
|
|
391
|
+
className: "tr__legend",
|
|
314
392
|
children: [
|
|
315
|
-
/* @__PURE__ */
|
|
316
|
-
children:
|
|
393
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsx2("i", {
|
|
396
|
+
className: "tr__dot",
|
|
397
|
+
style: { ["--tr-tone"]: "var(--tr-ok)" }
|
|
398
|
+
}),
|
|
399
|
+
"fully translated"
|
|
400
|
+
]
|
|
317
401
|
}),
|
|
318
|
-
/* @__PURE__ */
|
|
319
|
-
children:
|
|
402
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
403
|
+
children: [
|
|
404
|
+
/* @__PURE__ */ jsx2("i", {
|
|
405
|
+
className: "tr__dot",
|
|
406
|
+
style: { ["--tr-tone"]: "var(--tr-warn)" }
|
|
407
|
+
}),
|
|
408
|
+
"partly translated"
|
|
409
|
+
]
|
|
410
|
+
}),
|
|
411
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
412
|
+
children: [
|
|
413
|
+
/* @__PURE__ */ jsx2("i", {
|
|
414
|
+
className: "tr__dot",
|
|
415
|
+
style: { ["--tr-tone"]: "var(--tr-bad)" }
|
|
416
|
+
}),
|
|
417
|
+
"under half, or 404 without a slug"
|
|
418
|
+
]
|
|
320
419
|
}),
|
|
321
420
|
/* @__PURE__ */ jsx2("span", {
|
|
322
421
|
children: "↻ source changed since the last translation"
|
|
323
422
|
}),
|
|
324
423
|
/* @__PURE__ */ jsx2("span", {
|
|
325
|
-
children: "✓ reviewed
|
|
424
|
+
children: "✓ reviewed"
|
|
326
425
|
})
|
|
327
426
|
]
|
|
328
427
|
})
|
|
@@ -330,8 +429,93 @@ var Overview = ({ adminRoute, defaultLocale, entities, locales, onlyIssues, tab
|
|
|
330
429
|
});
|
|
331
430
|
};
|
|
332
431
|
|
|
432
|
+
// src/review/view/styles.ts
|
|
433
|
+
var reviewStyles = `
|
|
434
|
+
.tr { --tr-ok: var(--theme-success-500); --tr-ok-bg: var(--theme-success-100); --tr-warn: var(--theme-warning-500); --tr-warn-bg: var(--theme-warning-100); --tr-bad: var(--theme-error-500); --tr-bad-bg: var(--theme-error-100); --tr-line: var(--theme-elevation-100); --tr-muted: var(--theme-elevation-500); --tr-card: var(--theme-elevation-50); padding-block: calc(var(--base) * 2) calc(var(--base) * 4); }
|
|
435
|
+
.tr a { text-decoration: none; color: inherit; }
|
|
436
|
+
.tr__head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--base); margin-bottom: calc(var(--base) * 1.5); }
|
|
437
|
+
.tr__head h1 { margin: 0 0 4px; }
|
|
438
|
+
.tr__lead { margin: 0; color: var(--tr-muted); max-width: 60ch; }
|
|
439
|
+
.tr__back { display: inline-flex; gap: 6px; color: var(--tr-muted); font-size: 13px; margin-bottom: 8px; }
|
|
440
|
+
.tr__back:hover { color: var(--theme-text); }
|
|
441
|
+
|
|
442
|
+
.tr__stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-bottom: calc(var(--base) * 1.5); }
|
|
443
|
+
.tr__stat { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border: 1px solid var(--tr-line); border-radius: var(--style-radius-m); background: var(--tr-card); }
|
|
444
|
+
.tr__stat-label { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--tr-muted); }
|
|
445
|
+
.tr__stat-value { font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.1; }
|
|
446
|
+
.tr__stat-note { font-size: 12px; color: var(--tr-muted); }
|
|
447
|
+
|
|
448
|
+
.tr__bar { height: 4px; border-radius: 999px; background: var(--theme-elevation-150); overflow: hidden; }
|
|
449
|
+
.tr__bar > span { display: block; height: 100%; border-radius: inherit; background: var(--tr-tone, var(--tr-ok)); }
|
|
450
|
+
|
|
451
|
+
.tr__toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
|
|
452
|
+
.tr__tabs { display: inline-flex; padding: 3px; gap: 2px; border-radius: 999px; background: var(--theme-elevation-100); }
|
|
453
|
+
.tr__tab { padding: 5px 14px; border-radius: 999px; font-size: 13px; color: var(--theme-elevation-700); text-transform: capitalize; }
|
|
454
|
+
.tr__tab:hover { color: var(--theme-text); }
|
|
455
|
+
.tr__tab[aria-current='true'] { background: var(--theme-elevation-0); color: var(--theme-text); box-shadow: 0 1px 2px rgba(0,0,0,.2); }
|
|
456
|
+
.tr__filters { display: inline-flex; align-items: center; gap: 12px; font-size: 13px; color: var(--tr-muted); }
|
|
457
|
+
.tr__toggle { display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px; border: 1px solid var(--tr-line); border-radius: 999px; color: var(--theme-elevation-800); }
|
|
458
|
+
.tr__toggle::before { content: ''; width: 26px; height: 14px; border-radius: 999px; background: var(--theme-elevation-200) radial-gradient(circle at 7px 50%, var(--theme-elevation-0) 4px, transparent 4.5px); }
|
|
459
|
+
.tr__toggle[aria-pressed='true']::before { background: var(--tr-ok) radial-gradient(circle at 19px 50%, var(--theme-elevation-0) 4px, transparent 4.5px); }
|
|
460
|
+
|
|
461
|
+
.tr__bulk { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: calc(var(--base) * 1.25); padding: 10px 12px; border: 1px dashed var(--tr-line); border-radius: var(--style-radius-m); }
|
|
462
|
+
.tr__bulk-main, .tr__bulk-progress { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
463
|
+
.tr__bulk .btn { margin: 0; }
|
|
464
|
+
.tr__select { height: 28px; padding: 0 8px; border: 1px solid var(--tr-line); border-radius: var(--style-radius-s, 4px); background: var(--theme-input-bg, var(--theme-elevation-0)); color: var(--theme-text); font: inherit; font-size: 13px; }
|
|
465
|
+
.tr__card { border: 1px solid var(--tr-line); border-radius: var(--style-radius-m); overflow: auto; background: var(--theme-elevation-0); }
|
|
466
|
+
.tr table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; }
|
|
467
|
+
.tr th { position: sticky; top: 0; z-index: 1; background: var(--tr-card); text-align: left; font-weight: 500; color: var(--tr-muted); padding: 10px 12px; border-bottom: 1px solid var(--tr-line); white-space: nowrap; }
|
|
468
|
+
.tr th small { display: block; font-size: 11px; font-weight: 400; }
|
|
469
|
+
.tr td { padding: 6px 12px; border-bottom: 1px solid var(--tr-line); vertical-align: middle; }
|
|
470
|
+
.tr tbody tr:last-child td { border-bottom: 0; }
|
|
471
|
+
.tr tbody tr:hover td { background: var(--theme-elevation-50); }
|
|
472
|
+
.tr__locale-col { text-align: center !important; }
|
|
473
|
+
.tr__doc { min-width: 240px; }
|
|
474
|
+
.tr__doc a { font-weight: 500; }
|
|
475
|
+
.tr__doc a:hover { text-decoration: underline; }
|
|
476
|
+
.tr__key { display: block; margin-top: 2px; font-family: var(--font-mono, ui-monospace, monospace); font-size: 11px; color: var(--tr-muted); }
|
|
477
|
+
|
|
478
|
+
.tr__cell { display: flex; flex-direction: column; gap: 4px; min-width: 64px; padding: 6px 8px; border-radius: 6px; text-align: center; font-variant-numeric: tabular-nums; font-weight: 500; transition: background .12s; }
|
|
479
|
+
.tr__cell:hover { background: var(--theme-elevation-100); }
|
|
480
|
+
.tr__cell[data-tone='ok'] { --tr-tone: var(--tr-ok); color: var(--tr-ok); }
|
|
481
|
+
.tr__cell[data-tone='warn'] { --tr-tone: var(--tr-warn); color: var(--tr-warn); }
|
|
482
|
+
.tr__cell[data-tone='bad'] { --tr-tone: var(--tr-bad); color: var(--tr-bad); }
|
|
483
|
+
.tr__marks { font-size: 11px; color: var(--tr-muted); }
|
|
484
|
+
|
|
485
|
+
.tr__legend { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 12px; font-size: 12px; color: var(--tr-muted); }
|
|
486
|
+
.tr__legend span { display: inline-flex; align-items: center; gap: 6px; }
|
|
487
|
+
.tr__dot { width: 8px; height: 8px; border-radius: 999px; background: var(--tr-tone); }
|
|
488
|
+
|
|
489
|
+
.tr__pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; font-size: 13px; color: var(--tr-muted); }
|
|
490
|
+
.tr__pager nav { display: inline-flex; gap: 6px; }
|
|
491
|
+
.tr__pager a, .tr__pager span[aria-disabled] { padding: 5px 12px; border: 1px solid var(--tr-line); border-radius: 999px; color: var(--theme-elevation-800); }
|
|
492
|
+
.tr__pager span[aria-disabled] { opacity: .4; }
|
|
493
|
+
.tr__pager a:hover { background: var(--theme-elevation-100); }
|
|
494
|
+
|
|
495
|
+
.tr__pill { display: inline-flex; align-items: center; gap: 6px; padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 500; white-space: nowrap; background: var(--theme-elevation-100); }
|
|
496
|
+
.tr__pill::before { content: ''; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
|
|
497
|
+
.tr__pill[data-tone='ok'] { color: var(--tr-ok); background: var(--tr-ok-bg); }
|
|
498
|
+
.tr__pill[data-tone='warn'] { color: var(--tr-warn); background: var(--tr-warn-bg); }
|
|
499
|
+
.tr__pill[data-tone='bad'] { color: var(--tr-bad); background: var(--tr-bad-bg); }
|
|
500
|
+
|
|
501
|
+
.tr__meta { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
|
|
502
|
+
.tr__chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border: 1px solid var(--tr-line); border-radius: 999px; font-size: 12px; color: var(--theme-elevation-800); }
|
|
503
|
+
.tr__chip--bad { color: var(--tr-bad); border-color: var(--tr-bad); }
|
|
504
|
+
a.tr__chip:hover { background: var(--theme-elevation-100); }
|
|
505
|
+
|
|
506
|
+
.tr__path { width: 22%; font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px; color: var(--theme-elevation-700); word-break: break-word; }
|
|
507
|
+
.tr__text { width: 34%; white-space: pre-wrap; word-break: break-word; line-height: 1.45; }
|
|
508
|
+
.tr__text--empty { color: var(--tr-muted); font-style: italic; }
|
|
509
|
+
.tr__empty { padding: 32px; text-align: center; color: var(--tr-muted); }
|
|
510
|
+
.tr__error { color: var(--tr-bad); }
|
|
511
|
+
|
|
512
|
+
.translator-review__actions { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
513
|
+
.translator-review__actions .btn { margin: 0; }
|
|
514
|
+
`;
|
|
515
|
+
|
|
333
516
|
// src/review/view/TranslationsView.tsx
|
|
334
517
|
import { jsx as jsx3, jsxs as jsxs3, Fragment as Fragment3 } from "react/jsx-runtime";
|
|
518
|
+
var PAGE_SIZE = 50;
|
|
335
519
|
var param = (value) => Array.isArray(value) ? value[0] : value;
|
|
336
520
|
var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
337
521
|
const { req, permissions, visibleEntities, locale } = initPageResult;
|
|
@@ -350,6 +534,7 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
350
534
|
const content = async () => {
|
|
351
535
|
if (!req.user)
|
|
352
536
|
return /* @__PURE__ */ jsx3("p", {
|
|
537
|
+
className: "tr__empty",
|
|
353
538
|
children: "Log in to review translations."
|
|
354
539
|
});
|
|
355
540
|
if (!tab)
|
|
@@ -362,12 +547,13 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
362
547
|
return /* @__PURE__ */ jsx3(Detail, {
|
|
363
548
|
adminRoute,
|
|
364
549
|
onlyIssues,
|
|
550
|
+
page,
|
|
365
551
|
review,
|
|
366
552
|
tab
|
|
367
553
|
});
|
|
368
554
|
} catch (error) {
|
|
369
555
|
return /* @__PURE__ */ jsxs3("p", {
|
|
370
|
-
className: "
|
|
556
|
+
className: "tr__error",
|
|
371
557
|
children: [
|
|
372
558
|
"Could not load ",
|
|
373
559
|
entity,
|
|
@@ -388,7 +574,10 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
388
574
|
tab
|
|
389
575
|
});
|
|
390
576
|
}
|
|
391
|
-
const review = await loadCollectionReview({ req, collectionSlug: tab, page });
|
|
577
|
+
const review = await loadCollectionReview({ req, collectionSlug: tab, page, limit: PAGE_SIZE });
|
|
578
|
+
const first = review.totalDocs ? (review.page - 1) * PAGE_SIZE + 1 : 0;
|
|
579
|
+
const last = Math.min(review.page * PAGE_SIZE, review.totalDocs);
|
|
580
|
+
const pageHref = (target) => reviewHref(adminRoute, { tab, page: target, issues: onlyIssues ? 1 : undefined });
|
|
392
581
|
return /* @__PURE__ */ jsxs3(Fragment3, {
|
|
393
582
|
children: [
|
|
394
583
|
/* @__PURE__ */ jsx3(Overview, {
|
|
@@ -397,29 +586,47 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
397
586
|
entities: review.entities,
|
|
398
587
|
locales: review.locales,
|
|
399
588
|
onlyIssues,
|
|
589
|
+
page,
|
|
400
590
|
tab
|
|
401
591
|
}),
|
|
402
|
-
|
|
403
|
-
className: "
|
|
592
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
593
|
+
className: "tr__pager",
|
|
404
594
|
children: [
|
|
405
|
-
page > 1 && /* @__PURE__ */ jsx3("a", {
|
|
406
|
-
href: reviewHref(adminRoute, { tab, page: page - 1, issues: onlyIssues ? 1 : undefined }),
|
|
407
|
-
children: "← Newer"
|
|
408
|
-
}),
|
|
409
595
|
/* @__PURE__ */ jsxs3("span", {
|
|
410
596
|
children: [
|
|
411
|
-
|
|
412
|
-
|
|
597
|
+
first,
|
|
598
|
+
"–",
|
|
599
|
+
last,
|
|
413
600
|
" of ",
|
|
414
|
-
review.totalPages,
|
|
415
|
-
" · ",
|
|
416
601
|
review.totalDocs,
|
|
417
|
-
" documents"
|
|
602
|
+
" documents",
|
|
603
|
+
onlyIssues ? " (complete ones hidden)" : ""
|
|
418
604
|
]
|
|
419
605
|
}),
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
606
|
+
review.totalPages > 1 && /* @__PURE__ */ jsxs3("nav", {
|
|
607
|
+
children: [
|
|
608
|
+
review.page > 1 ? /* @__PURE__ */ jsx3("a", {
|
|
609
|
+
href: pageHref(review.page - 1),
|
|
610
|
+
children: "← Newer"
|
|
611
|
+
}) : /* @__PURE__ */ jsx3("span", {
|
|
612
|
+
"aria-disabled": true,
|
|
613
|
+
children: "← Newer"
|
|
614
|
+
}),
|
|
615
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
616
|
+
children: [
|
|
617
|
+
review.page,
|
|
618
|
+
" / ",
|
|
619
|
+
review.totalPages
|
|
620
|
+
]
|
|
621
|
+
}),
|
|
622
|
+
review.page < review.totalPages ? /* @__PURE__ */ jsx3("a", {
|
|
623
|
+
href: pageHref(review.page + 1),
|
|
624
|
+
children: "Older →"
|
|
625
|
+
}) : /* @__PURE__ */ jsx3("span", {
|
|
626
|
+
"aria-disabled": true,
|
|
627
|
+
children: "Older →"
|
|
628
|
+
})
|
|
629
|
+
]
|
|
423
630
|
})
|
|
424
631
|
]
|
|
425
632
|
})
|
|
@@ -427,6 +634,7 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
427
634
|
});
|
|
428
635
|
};
|
|
429
636
|
const adminLocale = req.locale;
|
|
637
|
+
const progress = entity || !req.user ? null : await loadJobsProgress(req);
|
|
430
638
|
const body = await content();
|
|
431
639
|
req.locale = adminLocale;
|
|
432
640
|
return /* @__PURE__ */ jsxs3(DefaultTemplate, {
|
|
@@ -439,32 +647,56 @@ var TranslationsView = async ({ initPageResult, params, searchParams }) => {
|
|
|
439
647
|
user: req.user || undefined,
|
|
440
648
|
visibleEntities,
|
|
441
649
|
children: [
|
|
442
|
-
/* @__PURE__ */ jsx3(
|
|
650
|
+
/* @__PURE__ */ jsx3("style", {
|
|
651
|
+
dangerouslySetInnerHTML: { __html: reviewStyles }
|
|
652
|
+
}),
|
|
443
653
|
/* @__PURE__ */ jsxs3(Gutter, {
|
|
444
|
-
className: "
|
|
654
|
+
className: "tr",
|
|
445
655
|
children: [
|
|
446
656
|
!entity && /* @__PURE__ */ jsxs3(Fragment3, {
|
|
447
657
|
children: [
|
|
658
|
+
/* @__PURE__ */ jsx3("div", {
|
|
659
|
+
className: "tr__head",
|
|
660
|
+
children: /* @__PURE__ */ jsxs3("div", {
|
|
661
|
+
children: [
|
|
662
|
+
/* @__PURE__ */ jsx3("h1", {
|
|
663
|
+
children: "Translations"
|
|
664
|
+
}),
|
|
665
|
+
/* @__PURE__ */ jsxs3("p", {
|
|
666
|
+
className: "tr__lead",
|
|
667
|
+
children: [
|
|
668
|
+
"How much of each document is translated from ",
|
|
669
|
+
defaultLocale.toUpperCase(),
|
|
670
|
+
". Open a cell to compare it field by field."
|
|
671
|
+
]
|
|
672
|
+
})
|
|
673
|
+
]
|
|
674
|
+
})
|
|
675
|
+
}),
|
|
448
676
|
/* @__PURE__ */ jsxs3("div", {
|
|
449
|
-
className: "
|
|
677
|
+
className: "tr__toolbar",
|
|
450
678
|
children: [
|
|
451
|
-
/* @__PURE__ */ jsx3("
|
|
452
|
-
|
|
679
|
+
/* @__PURE__ */ jsx3("nav", {
|
|
680
|
+
className: "tr__tabs",
|
|
681
|
+
children: tabs.map((each) => /* @__PURE__ */ jsx3("a", {
|
|
682
|
+
"aria-current": each === tab,
|
|
683
|
+
className: "tr__tab",
|
|
684
|
+
href: reviewHref(adminRoute, { tab: each, issues: onlyIssues ? 1 : undefined }),
|
|
685
|
+
children: each
|
|
686
|
+
}, each))
|
|
453
687
|
}),
|
|
454
688
|
/* @__PURE__ */ jsx3("a", {
|
|
689
|
+
"aria-pressed": onlyIssues,
|
|
690
|
+
className: "tr__toggle",
|
|
455
691
|
href: reviewHref(adminRoute, { tab, issues: onlyIssues ? undefined : 1 }),
|
|
456
|
-
children:
|
|
692
|
+
children: "Only incomplete"
|
|
457
693
|
})
|
|
458
694
|
]
|
|
459
695
|
}),
|
|
460
|
-
/* @__PURE__ */ jsx3(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
className: "translator-review__tab",
|
|
465
|
-
href: reviewHref(adminRoute, { tab: each, issues: onlyIssues ? 1 : undefined }),
|
|
466
|
-
children: each
|
|
467
|
-
}, each))
|
|
696
|
+
req.user && tab && /* @__PURE__ */ jsx3(BulkActions, {
|
|
697
|
+
locales: targetLocales,
|
|
698
|
+
progress,
|
|
699
|
+
tab
|
|
468
700
|
})
|
|
469
701
|
]
|
|
470
702
|
}),
|