@ollang-dev/sdk 0.3.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.
- package/bin/tms.js +47 -0
- package/dist/browser/index.d.ts +143 -0
- package/dist/browser/index.js +2336 -0
- package/dist/browser/ollang-browser.min.js +1 -0
- package/dist/browser/script-loader.d.ts +1 -0
- package/dist/browser/script-loader.js +53 -0
- package/dist/client.d.ts +13 -0
- package/dist/client.js +60 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +74 -0
- package/dist/resources/cms.d.ts +29 -0
- package/dist/resources/cms.js +34 -0
- package/dist/resources/customInstructions.d.ts +11 -0
- package/dist/resources/customInstructions.js +24 -0
- package/dist/resources/orders.d.ts +13 -0
- package/dist/resources/orders.js +65 -0
- package/dist/resources/projects.d.ts +8 -0
- package/dist/resources/projects.js +29 -0
- package/dist/resources/revisions.d.ts +9 -0
- package/dist/resources/revisions.js +18 -0
- package/dist/resources/scans.d.ts +38 -0
- package/dist/resources/scans.js +52 -0
- package/dist/resources/uploads.d.ts +8 -0
- package/dist/resources/uploads.js +25 -0
- package/dist/tms/config.d.ts +16 -0
- package/dist/tms/config.js +172 -0
- package/dist/tms/detector/audio-detector.d.ts +27 -0
- package/dist/tms/detector/audio-detector.js +168 -0
- package/dist/tms/detector/auto-detect.d.ts +1 -0
- package/dist/tms/detector/auto-detect.js +152 -0
- package/dist/tms/detector/cms-detector.d.ts +17 -0
- package/dist/tms/detector/cms-detector.js +94 -0
- package/dist/tms/detector/content-type-detector.d.ts +79 -0
- package/dist/tms/detector/content-type-detector.js +2 -0
- package/dist/tms/detector/hardcoded-detector.d.ts +11 -0
- package/dist/tms/detector/hardcoded-detector.js +154 -0
- package/dist/tms/detector/i18n-detector.d.ts +16 -0
- package/dist/tms/detector/i18n-detector.js +311 -0
- package/dist/tms/detector/image-detector.d.ts +11 -0
- package/dist/tms/detector/image-detector.js +170 -0
- package/dist/tms/detector/text-detector.d.ts +9 -0
- package/dist/tms/detector/text-detector.js +35 -0
- package/dist/tms/detector/video-detector.d.ts +12 -0
- package/dist/tms/detector/video-detector.js +188 -0
- package/dist/tms/index.d.ts +12 -0
- package/dist/tms/index.js +38 -0
- package/dist/tms/multi-content-tms.d.ts +42 -0
- package/dist/tms/multi-content-tms.js +230 -0
- package/dist/tms/server/index.d.ts +1 -0
- package/dist/tms/server/index.js +1473 -0
- package/dist/tms/server/strapi-pusher.d.ts +31 -0
- package/dist/tms/server/strapi-pusher.js +296 -0
- package/dist/tms/server/strapi-schema.d.ts +47 -0
- package/dist/tms/server/strapi-schema.js +93 -0
- package/dist/tms/tms.d.ts +48 -0
- package/dist/tms/tms.js +875 -0
- package/dist/tms/types.d.ts +189 -0
- package/dist/tms/types.js +2 -0
- package/dist/tms/ui-dist/assets/index-5U1Hw3uo.css +1 -0
- package/dist/tms/ui-dist/assets/index-HvrqZV5Z.js +149 -0
- package/dist/tms/ui-dist/index.html +14 -0
- package/dist/types/index.d.ts +174 -0
- package/dist/types/index.js +2 -0
- package/package.json +98 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface StrapiPusherConfig {
|
|
2
|
+
strapiUrl: string;
|
|
3
|
+
strapiToken: string;
|
|
4
|
+
}
|
|
5
|
+
export interface StrapiTranslationItem {
|
|
6
|
+
contentType: string;
|
|
7
|
+
entryId: number;
|
|
8
|
+
field: string;
|
|
9
|
+
translatedText: string;
|
|
10
|
+
route?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StrapiPushResult {
|
|
13
|
+
success: boolean;
|
|
14
|
+
contentType: string;
|
|
15
|
+
entryId: number;
|
|
16
|
+
field: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class StrapiPusher {
|
|
20
|
+
private client;
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: StrapiPusherConfig);
|
|
23
|
+
private ensureLocale;
|
|
24
|
+
pushTranslation(item: StrapiTranslationItem, targetLocale: string): Promise<StrapiPushResult>;
|
|
25
|
+
pushBatch(items: StrapiTranslationItem[], targetLocale: string): Promise<{
|
|
26
|
+
results: StrapiPushResult[];
|
|
27
|
+
errors: StrapiPushResult[];
|
|
28
|
+
}>;
|
|
29
|
+
private buildNestedUpdate;
|
|
30
|
+
private deepMerge;
|
|
31
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StrapiPusher = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const STRAPI_LOCALE_MAP = {
|
|
9
|
+
af: 'af-ZA',
|
|
10
|
+
ak: 'ak-GH',
|
|
11
|
+
sq: 'sq-AL',
|
|
12
|
+
am: 'am-ET',
|
|
13
|
+
ar: 'ar-SA',
|
|
14
|
+
hy: 'hy-AM',
|
|
15
|
+
as: 'as-IN',
|
|
16
|
+
az: 'az-Latn-AZ',
|
|
17
|
+
bm: 'bm-ML',
|
|
18
|
+
eu: 'eu-ES',
|
|
19
|
+
be: 'be-BY',
|
|
20
|
+
bn: 'bn-BD',
|
|
21
|
+
bs: 'bs-BA',
|
|
22
|
+
br: 'br-FR',
|
|
23
|
+
bg: 'bg-BG',
|
|
24
|
+
my: 'my-MM',
|
|
25
|
+
ca: 'ca-ES',
|
|
26
|
+
zh: 'zh-Hans-CN',
|
|
27
|
+
hr: 'hr-HR',
|
|
28
|
+
cs: 'cs-CZ',
|
|
29
|
+
da: 'da-DK',
|
|
30
|
+
nl: 'nl-NL',
|
|
31
|
+
en: 'en-US',
|
|
32
|
+
eo: 'eo',
|
|
33
|
+
et: 'et-EE',
|
|
34
|
+
ee: 'ee-GH',
|
|
35
|
+
fil: 'fil-PH',
|
|
36
|
+
fi: 'fi-FI',
|
|
37
|
+
fr: 'fr-FR',
|
|
38
|
+
gl: 'gl-ES',
|
|
39
|
+
ka: 'ka-GE',
|
|
40
|
+
de: 'de-DE',
|
|
41
|
+
el: 'el-GR',
|
|
42
|
+
gu: 'gu-IN',
|
|
43
|
+
ha: 'ha-Latn-NG',
|
|
44
|
+
haw: 'haw-US',
|
|
45
|
+
he: 'he-IL',
|
|
46
|
+
hi: 'hi-IN',
|
|
47
|
+
hu: 'hu-HU',
|
|
48
|
+
is: 'is-IS',
|
|
49
|
+
ig: 'ig-NG',
|
|
50
|
+
id: 'id-ID',
|
|
51
|
+
ga: 'ga-IE',
|
|
52
|
+
it: 'it-IT',
|
|
53
|
+
ja: 'ja-JP',
|
|
54
|
+
kn: 'kn-IN',
|
|
55
|
+
kk: 'kk-Cyrl-KZ',
|
|
56
|
+
km: 'km-KH',
|
|
57
|
+
rw: 'rw-RW',
|
|
58
|
+
ko: 'ko',
|
|
59
|
+
ky: 'ky',
|
|
60
|
+
lo: 'lo',
|
|
61
|
+
lv: 'lv-LV',
|
|
62
|
+
ln: 'ln-CD',
|
|
63
|
+
lt: 'lt-LT',
|
|
64
|
+
mk: 'mk-MK',
|
|
65
|
+
mg: 'mg-MG',
|
|
66
|
+
ms: 'ms-MY',
|
|
67
|
+
ml: 'ml-IN',
|
|
68
|
+
mt: 'mt-MT',
|
|
69
|
+
mr: 'mr-IN',
|
|
70
|
+
mn: 'mn',
|
|
71
|
+
ne: 'ne-NP',
|
|
72
|
+
nb: 'nb-NO',
|
|
73
|
+
nn: 'nn-NO',
|
|
74
|
+
or: 'or-IN',
|
|
75
|
+
om: 'om-ET',
|
|
76
|
+
ps: 'ps-AF',
|
|
77
|
+
fa: 'fa-IR',
|
|
78
|
+
pl: 'pl-PL',
|
|
79
|
+
pt: 'pt-PT',
|
|
80
|
+
pa: 'pa-Guru-IN',
|
|
81
|
+
ro: 'ro-RO',
|
|
82
|
+
ru: 'ru-RU',
|
|
83
|
+
sg: 'sg-CF',
|
|
84
|
+
sr: 'sr-Cyrl-RS',
|
|
85
|
+
sn: 'sn-ZW',
|
|
86
|
+
si: 'si-LK',
|
|
87
|
+
sk: 'sk-SK',
|
|
88
|
+
sl: 'sl-SI',
|
|
89
|
+
so: 'so-SO',
|
|
90
|
+
es: 'es-ES',
|
|
91
|
+
sw: 'sw-KE',
|
|
92
|
+
sv: 'sv-SE',
|
|
93
|
+
tg: 'tg',
|
|
94
|
+
ta: 'ta-IN',
|
|
95
|
+
te: 'te-IN',
|
|
96
|
+
th: 'th-TH',
|
|
97
|
+
ti: 'ti-ET',
|
|
98
|
+
to: 'to-TO',
|
|
99
|
+
tr: 'tr-TR',
|
|
100
|
+
tk: 'tk',
|
|
101
|
+
uk: 'uk-UA',
|
|
102
|
+
ur: 'ur-PK',
|
|
103
|
+
uz: 'uz-Latn-UZ',
|
|
104
|
+
vi: 'vi-VN',
|
|
105
|
+
cy: 'cy-GB',
|
|
106
|
+
yo: 'yo-NG',
|
|
107
|
+
zu: 'zu-ZA',
|
|
108
|
+
};
|
|
109
|
+
function normalizeLocaleForStrapi(targetLocale) {
|
|
110
|
+
if (targetLocale.includes('-'))
|
|
111
|
+
return targetLocale;
|
|
112
|
+
return STRAPI_LOCALE_MAP[targetLocale] || targetLocale;
|
|
113
|
+
}
|
|
114
|
+
class StrapiPusher {
|
|
115
|
+
constructor(config) {
|
|
116
|
+
this.config = config;
|
|
117
|
+
const apiBase = config.strapiUrl.replace(/\/$/, '');
|
|
118
|
+
this.client = axios_1.default.create({
|
|
119
|
+
baseURL: `${apiBase}/api`,
|
|
120
|
+
headers: {
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
Authorization: `Bearer ${config.strapiToken}`,
|
|
123
|
+
},
|
|
124
|
+
timeout: 30000,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async ensureLocale(targetLocale) {
|
|
128
|
+
const normalized = normalizeLocaleForStrapi(targetLocale);
|
|
129
|
+
try {
|
|
130
|
+
const res = await this.client.get('/i18n/locales');
|
|
131
|
+
const locales = res.data || [];
|
|
132
|
+
const exact = locales.find((l) => l.code === normalized);
|
|
133
|
+
if (exact)
|
|
134
|
+
return exact.code;
|
|
135
|
+
const fallback = locales.find((l) => l.code.startsWith(normalized.split('-')[0]));
|
|
136
|
+
if (fallback) {
|
|
137
|
+
return fallback.code;
|
|
138
|
+
}
|
|
139
|
+
return normalized;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const msg = error.response?.data?.error?.message || error.message || 'Unknown error';
|
|
143
|
+
return normalized;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async pushTranslation(item, targetLocale) {
|
|
147
|
+
const { contentType, entryId, field, translatedText } = item;
|
|
148
|
+
const normalizedLocale = normalizeLocaleForStrapi(targetLocale);
|
|
149
|
+
const locale = await this.ensureLocale(normalizedLocale);
|
|
150
|
+
try {
|
|
151
|
+
const entryRes = await this.client.get(`/${contentType}/${entryId}?populate=localizations`);
|
|
152
|
+
const attributes = entryRes.data?.data?.attributes || {};
|
|
153
|
+
const originalLocale = attributes.locale;
|
|
154
|
+
const localizations = attributes.localizations?.data || [];
|
|
155
|
+
const existing = localizations.find((loc) => loc.attributes?.locale === locale);
|
|
156
|
+
let updateData = this.buildNestedUpdate(field, translatedText);
|
|
157
|
+
if (item.route && !updateData.route) {
|
|
158
|
+
updateData = { ...updateData, route: item.route };
|
|
159
|
+
}
|
|
160
|
+
if (!existing && locale !== originalLocale) {
|
|
161
|
+
const currentRoute = updateData.route !== undefined ? updateData.route : attributes.route;
|
|
162
|
+
if (currentRoute) {
|
|
163
|
+
const localeSuffix = (targetLocale.split('-')[0] || targetLocale).toLowerCase();
|
|
164
|
+
if (!updateData.route || updateData.route === attributes.route) {
|
|
165
|
+
updateData.route = `${currentRoute}-${localeSuffix}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (locale === originalLocale && !existing) {
|
|
170
|
+
await this.client.put(`/${contentType}/${entryId}`, {
|
|
171
|
+
data: updateData,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
if (existing) {
|
|
176
|
+
await this.client.put(`/${contentType}/${existing.id}`, {
|
|
177
|
+
data: updateData,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
await this.client.post(`/${contentType}/${entryId}/localizations`, {
|
|
182
|
+
locale,
|
|
183
|
+
...updateData,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { success: true, contentType, entryId, field };
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const raw = error.response?.data;
|
|
191
|
+
const msg = raw?.error?.message || raw?.message || error.message || 'Unknown error';
|
|
192
|
+
return { success: false, contentType, entryId, field, error: msg };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async pushBatch(items, targetLocale) {
|
|
196
|
+
const results = [];
|
|
197
|
+
const errors = [];
|
|
198
|
+
const normalizedLocale = normalizeLocaleForStrapi(targetLocale);
|
|
199
|
+
const locale = await this.ensureLocale(normalizedLocale);
|
|
200
|
+
const grouped = new Map();
|
|
201
|
+
for (const item of items) {
|
|
202
|
+
const key = `${item.contentType}:${item.entryId}`;
|
|
203
|
+
if (!grouped.has(key))
|
|
204
|
+
grouped.set(key, []);
|
|
205
|
+
grouped.get(key).push(item);
|
|
206
|
+
}
|
|
207
|
+
for (const [key, entryItems] of grouped) {
|
|
208
|
+
const { contentType, entryId } = entryItems[0];
|
|
209
|
+
try {
|
|
210
|
+
const entryRes = await this.client.get(`/${contentType}/${entryId}?populate=localizations`);
|
|
211
|
+
const attributes = entryRes.data?.data?.attributes || {};
|
|
212
|
+
const originalLocale = attributes.locale;
|
|
213
|
+
const localizations = attributes.localizations?.data || [];
|
|
214
|
+
const existing = localizations.find((loc) => loc.attributes?.locale === locale);
|
|
215
|
+
let mergedUpdate = {};
|
|
216
|
+
for (const item of entryItems) {
|
|
217
|
+
const fieldUpdate = this.buildNestedUpdate(item.field, item.translatedText);
|
|
218
|
+
mergedUpdate = this.deepMerge(mergedUpdate, fieldUpdate);
|
|
219
|
+
}
|
|
220
|
+
const explicitRoute = entryItems.find((i) => i.route)?.route;
|
|
221
|
+
if (explicitRoute && !mergedUpdate.route) {
|
|
222
|
+
mergedUpdate.route = explicitRoute;
|
|
223
|
+
}
|
|
224
|
+
if (!existing && locale !== originalLocale) {
|
|
225
|
+
const baseRoute = mergedUpdate.route !== undefined ? mergedUpdate.route : attributes.route;
|
|
226
|
+
if (baseRoute) {
|
|
227
|
+
const localeSuffix = (targetLocale.split('-')[0] || targetLocale).toLowerCase();
|
|
228
|
+
if (!mergedUpdate.route || mergedUpdate.route === attributes.route) {
|
|
229
|
+
mergedUpdate.route = `${baseRoute}-${localeSuffix}`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (locale === originalLocale && !existing) {
|
|
234
|
+
await this.client.put(`/${contentType}/${entryId}`, {
|
|
235
|
+
data: mergedUpdate,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
if (existing) {
|
|
240
|
+
await this.client.put(`/${contentType}/${existing.id}`, {
|
|
241
|
+
data: mergedUpdate,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
await this.client.post(`/${contentType}/${entryId}/localizations`, {
|
|
246
|
+
locale,
|
|
247
|
+
...mergedUpdate,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const item of entryItems) {
|
|
252
|
+
results.push({ success: true, contentType, entryId, field: item.field });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
const raw = error.response?.data;
|
|
257
|
+
const msg = raw?.error?.message || raw?.message || error.message || 'Unknown error';
|
|
258
|
+
for (const item of entryItems) {
|
|
259
|
+
errors.push({ success: false, contentType, entryId, field: item.field, error: msg });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { results, errors };
|
|
264
|
+
}
|
|
265
|
+
buildNestedUpdate(fieldPath, value) {
|
|
266
|
+
const cleanPath = fieldPath.replace(/\[\d+\]/g, '');
|
|
267
|
+
const parts = cleanPath.split('.');
|
|
268
|
+
if (parts.length === 1)
|
|
269
|
+
return { [parts[0]]: value };
|
|
270
|
+
const result = {};
|
|
271
|
+
let current = result;
|
|
272
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
273
|
+
current[parts[i]] = {};
|
|
274
|
+
current = current[parts[i]];
|
|
275
|
+
}
|
|
276
|
+
current[parts[parts.length - 1]] = value;
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
deepMerge(target, source) {
|
|
280
|
+
const result = { ...target };
|
|
281
|
+
for (const key of Object.keys(source)) {
|
|
282
|
+
if (result[key] &&
|
|
283
|
+
typeof result[key] === 'object' &&
|
|
284
|
+
!Array.isArray(result[key]) &&
|
|
285
|
+
typeof source[key] === 'object' &&
|
|
286
|
+
!Array.isArray(source[key])) {
|
|
287
|
+
result[key] = this.deepMerge(result[key], source[key]);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
result[key] = source[key];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.StrapiPusher = StrapiPusher;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface StrapiSchemaConfig {
|
|
2
|
+
fieldsByContentType: Record<string, string[]>;
|
|
3
|
+
fetchedAt: number;
|
|
4
|
+
}
|
|
5
|
+
interface ContentTypeAttribute {
|
|
6
|
+
type: string;
|
|
7
|
+
pluginOptions?: {
|
|
8
|
+
i18n?: {
|
|
9
|
+
localized?: boolean;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
component?: string;
|
|
13
|
+
repeatable?: boolean;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
interface ContentTypeSchema {
|
|
17
|
+
attributes: Record<string, ContentTypeAttribute>;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
interface ContentTypeItem {
|
|
21
|
+
uid: string;
|
|
22
|
+
apiID?: string;
|
|
23
|
+
schema: ContentTypeSchema;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
interface ComponentAttribute {
|
|
27
|
+
type: string;
|
|
28
|
+
component?: string;
|
|
29
|
+
repeatable?: boolean;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
interface ComponentSchema {
|
|
33
|
+
attributes: Record<string, ComponentAttribute>;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
interface ComponentItem {
|
|
37
|
+
uid: string;
|
|
38
|
+
schema: ComponentSchema;
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
export declare function parseStrapiSchema(contentTypesData: ContentTypeItem[], componentsData: ComponentItem[]): Record<string, string[]>;
|
|
42
|
+
export declare function fetchStrapiSchema(strapiBaseUrl: string, adminJwt: string): Promise<{
|
|
43
|
+
contentTypes: ContentTypeItem[];
|
|
44
|
+
components: ComponentItem[];
|
|
45
|
+
}>;
|
|
46
|
+
export declare function loadStrapiSchema(strapiBaseUrl: string, adminJwt: string): Promise<StrapiSchemaConfig>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseStrapiSchema = parseStrapiSchema;
|
|
4
|
+
exports.fetchStrapiSchema = fetchStrapiSchema;
|
|
5
|
+
exports.loadStrapiSchema = loadStrapiSchema;
|
|
6
|
+
const TRANSLATABLE_TYPES = new Set(['string', 'text', 'richtext']);
|
|
7
|
+
const SCALAR_TYPES = new Set(['string', 'text', 'richtext', 'enumeration', 'email', 'password']);
|
|
8
|
+
function getComponentTranslatablePaths(componentUid, componentsMap, prefix, visited, parentRepeatable) {
|
|
9
|
+
if (visited.has(componentUid))
|
|
10
|
+
return [];
|
|
11
|
+
visited.add(componentUid);
|
|
12
|
+
const schema = componentsMap.get(componentUid);
|
|
13
|
+
if (!schema || !schema.attributes)
|
|
14
|
+
return [];
|
|
15
|
+
const pathPrefix = parentRepeatable && prefix ? `${prefix}[]` : prefix;
|
|
16
|
+
const paths = [];
|
|
17
|
+
for (const [attrName, attr] of Object.entries(schema.attributes)) {
|
|
18
|
+
const fullPath = pathPrefix ? `${pathPrefix}.${attrName}` : attrName;
|
|
19
|
+
if (attr.type === 'component' && attr.component) {
|
|
20
|
+
const nested = getComponentTranslatablePaths(attr.component, componentsMap, fullPath, visited, attr.repeatable);
|
|
21
|
+
paths.push(...nested);
|
|
22
|
+
}
|
|
23
|
+
else if (TRANSLATABLE_TYPES.has(attr.type)) {
|
|
24
|
+
paths.push(attr.repeatable ? `${fullPath}[]` : fullPath);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return paths;
|
|
28
|
+
}
|
|
29
|
+
function parseStrapiSchema(contentTypesData, componentsData) {
|
|
30
|
+
const componentsMap = new Map();
|
|
31
|
+
for (const item of componentsData) {
|
|
32
|
+
if (item.uid && item.schema) {
|
|
33
|
+
componentsMap.set(item.uid, item.schema);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const fieldsByContentType = {};
|
|
37
|
+
for (const item of contentTypesData) {
|
|
38
|
+
if (!item.uid || !item.uid.startsWith('api::'))
|
|
39
|
+
continue;
|
|
40
|
+
const apiID = item.apiID || item.uid.split('.').pop() || item.uid;
|
|
41
|
+
const attrs = item.schema?.attributes;
|
|
42
|
+
if (!attrs)
|
|
43
|
+
continue;
|
|
44
|
+
const paths = [];
|
|
45
|
+
for (const [attrName, attr] of Object.entries(attrs)) {
|
|
46
|
+
const localized = attr.pluginOptions?.i18n?.localized === true;
|
|
47
|
+
if (!localized && attr.type !== 'relation')
|
|
48
|
+
continue;
|
|
49
|
+
if (TRANSLATABLE_TYPES.has(attr.type)) {
|
|
50
|
+
paths.push(attrName);
|
|
51
|
+
}
|
|
52
|
+
else if (attr.type === 'component' && attr.component && localized) {
|
|
53
|
+
const visited = new Set();
|
|
54
|
+
const nested = getComponentTranslatablePaths(attr.component, componentsMap, attrName, visited, attr.repeatable);
|
|
55
|
+
paths.push(...nested);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (paths.length > 0) {
|
|
59
|
+
fieldsByContentType[apiID] = paths;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return fieldsByContentType;
|
|
63
|
+
}
|
|
64
|
+
async function fetchStrapiSchema(strapiBaseUrl, adminJwt) {
|
|
65
|
+
const base = strapiBaseUrl.replace(/\/$/, '');
|
|
66
|
+
const headers = {
|
|
67
|
+
Authorization: `Bearer ${adminJwt}`,
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
};
|
|
70
|
+
const [ctRes, compRes] = await Promise.all([
|
|
71
|
+
fetch(`${base}/content-type-builder/content-types`, { headers }),
|
|
72
|
+
fetch(`${base}/content-type-builder/components`, { headers }),
|
|
73
|
+
]);
|
|
74
|
+
if (!ctRes.ok) {
|
|
75
|
+
const text = await ctRes.text();
|
|
76
|
+
throw new Error(`Content-types request failed (${ctRes.status}): ${text}`);
|
|
77
|
+
}
|
|
78
|
+
if (!compRes.ok) {
|
|
79
|
+
const text = await compRes.text();
|
|
80
|
+
throw new Error(`Components request failed (${compRes.status}): ${text}`);
|
|
81
|
+
}
|
|
82
|
+
const contentTypes = (await ctRes.json()).data || [];
|
|
83
|
+
const components = (await compRes.json()).data || [];
|
|
84
|
+
return { contentTypes, components };
|
|
85
|
+
}
|
|
86
|
+
async function loadStrapiSchema(strapiBaseUrl, adminJwt) {
|
|
87
|
+
const { contentTypes, components } = await fetchStrapiSchema(strapiBaseUrl, adminJwt);
|
|
88
|
+
const fieldsByContentType = parseStrapiSchema(contentTypes, components);
|
|
89
|
+
return {
|
|
90
|
+
fieldsByContentType,
|
|
91
|
+
fetchedAt: Date.now(),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Ollang } from '../index.js';
|
|
2
|
+
import { TMSConfig, TMSState, TextItem, I18nSetupInfo, TranslationOrder, Translation } from './types.js';
|
|
3
|
+
import { VideoContent, ImageContent, AudioContent } from './detector/content-type-detector.js';
|
|
4
|
+
export declare class TranslationManagementSystem {
|
|
5
|
+
private config;
|
|
6
|
+
private configManager;
|
|
7
|
+
private textDetector;
|
|
8
|
+
private videoDetector;
|
|
9
|
+
private imageDetector;
|
|
10
|
+
private audioDetector;
|
|
11
|
+
private ollangClient;
|
|
12
|
+
private state;
|
|
13
|
+
constructor(customConfig?: Partial<TMSConfig>);
|
|
14
|
+
scan(): Promise<TextItem[]>;
|
|
15
|
+
private checkExistingTranslations;
|
|
16
|
+
syncWithCodebase(targetLanguage: string): Promise<void>;
|
|
17
|
+
translate(texts: TextItem[], targetLanguage: string, level?: number, folderName?: string, folderId?: string): Promise<TranslationOrder>;
|
|
18
|
+
private translateMock;
|
|
19
|
+
private createOrder;
|
|
20
|
+
private pollOrderStatus;
|
|
21
|
+
private extractTranslations;
|
|
22
|
+
private createProjectWithVtt;
|
|
23
|
+
private generateVttContent;
|
|
24
|
+
private formatVttTime;
|
|
25
|
+
getState(): TMSState;
|
|
26
|
+
getConfig(): TMSConfig;
|
|
27
|
+
getI18nSetup(): I18nSetupInfo | null;
|
|
28
|
+
getSDK(): Ollang;
|
|
29
|
+
getTexts(): TextItem[];
|
|
30
|
+
getTranslations(): Map<string, Translation>;
|
|
31
|
+
applyTranslations(targetLanguage: string, textIds?: string[]): Promise<number>;
|
|
32
|
+
private findSourceFileForUrl;
|
|
33
|
+
private replaceUrlInFile;
|
|
34
|
+
scanVideos(): Promise<VideoContent[]>;
|
|
35
|
+
scanImages(): Promise<ImageContent[]>;
|
|
36
|
+
scanAudios(): Promise<AudioContent[]>;
|
|
37
|
+
scanAll(): Promise<{
|
|
38
|
+
texts: TextItem[];
|
|
39
|
+
videos: VideoContent[];
|
|
40
|
+
images: ImageContent[];
|
|
41
|
+
audios: AudioContent[];
|
|
42
|
+
total: number;
|
|
43
|
+
}>;
|
|
44
|
+
translateVideo(video: VideoContent, targetLanguage: string, level?: number): Promise<string>;
|
|
45
|
+
translateImage(image: ImageContent, targetLanguage: string, level?: number): Promise<string>;
|
|
46
|
+
translateAudio(audio: AudioContent, targetLanguage: string, level?: number): Promise<string>;
|
|
47
|
+
private createInitialState;
|
|
48
|
+
}
|