@nocobase/plugin-localization 2.1.0-beta.34 → 2.1.0-beta.36
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/dist/ai/ai-employees/lina.js +11 -11
- package/dist/client/300.1f79b801d226f40d.js +10 -0
- package/dist/client/index.js +1 -1
- package/dist/client-v2/796.0ec484505de4b04a.js +10 -0
- package/dist/client-v2/index.js +1 -1
- package/dist/externalVersion.js +12 -11
- package/dist/locale/en-US.json +23 -0
- package/dist/locale/zh-CN.json +23 -0
- package/dist/server/actions/aiTranslate.js +45 -21
- package/dist/server/tasks/localization-ai-translate.d.ts +24 -7
- package/dist/server/tasks/localization-ai-translate.js +267 -257
- package/dist/server/translation-scope.d.ts +31 -0
- package/dist/server/translation-scope.js +107 -0
- package/package.json +2 -2
- package/dist/client/300.3a4b9b688d36da96.js +0 -10
- package/dist/client-v2/796.b9d793cda3c8b932.js +0 -10
|
@@ -27,21 +27,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
27
27
|
var localization_ai_translate_exports = {};
|
|
28
28
|
__export(localization_ai_translate_exports, {
|
|
29
29
|
LOCALIZATION_AI_TRANSLATE_TASK_TYPE: () => LOCALIZATION_AI_TRANSLATE_TASK_TYPE,
|
|
30
|
-
LocalizationAITranslateTask: () => LocalizationAITranslateTask
|
|
30
|
+
LocalizationAITranslateTask: () => LocalizationAITranslateTask,
|
|
31
|
+
pickBuiltInResourceReference: () => pickBuiltInResourceReference
|
|
31
32
|
});
|
|
32
33
|
module.exports = __toCommonJS(localization_ai_translate_exports);
|
|
33
34
|
var import_plugin_async_task_manager = require("@nocobase/plugin-async-task-manager");
|
|
34
35
|
var import_messages = require("@langchain/core/messages");
|
|
36
|
+
var import_translation_scope = require("../translation-scope");
|
|
35
37
|
const LOCALIZATION_AI_TRANSLATE_TASK_TYPE = "localization:ai-translate";
|
|
36
|
-
const TRANSLATION_BATCH_SIZE = 10;
|
|
37
38
|
const DEFAULT_TRANSLATION_WORKER_COUNT = 10;
|
|
38
39
|
const MIN_TRANSLATION_WORKER_COUNT = 1;
|
|
39
40
|
const MAX_TRANSLATION_WORKER_COUNT = 20;
|
|
40
|
-
const
|
|
41
|
+
const TRANSLATION_CHUNK_SIZE = 200;
|
|
41
42
|
const elapsed = (start) => Date.now() - start;
|
|
42
|
-
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
43
43
|
const truncateForLog = (value, maxLength = 500) => value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
|
|
44
44
|
const LEGACY_SYMBOL_TRANSLATIONS = /* @__PURE__ */ new Set(["<", "=", ">"]);
|
|
45
|
+
const isString = (value) => typeof value === "string" && value.length > 0;
|
|
45
46
|
const getTranslationWorkerCount = () => {
|
|
46
47
|
const value = Number.parseInt(process.env.AI_LOCALIZATION_CONCURRENCY || "", 10);
|
|
47
48
|
if (Number.isInteger(value) && value >= MIN_TRANSLATION_WORKER_COUNT && value <= MAX_TRANSLATION_WORKER_COUNT) {
|
|
@@ -49,6 +50,16 @@ const getTranslationWorkerCount = () => {
|
|
|
49
50
|
}
|
|
50
51
|
return DEFAULT_TRANSLATION_WORKER_COUNT;
|
|
51
52
|
};
|
|
53
|
+
const pickBuiltInResourceReference = (row, references, locales) => {
|
|
54
|
+
var _a;
|
|
55
|
+
for (const locale of [locales.primary, locales.fallback].filter(isString)) {
|
|
56
|
+
const translation = (_a = references.get(locale)) == null ? void 0 : _a.get(String(row.id));
|
|
57
|
+
if (translation) {
|
|
58
|
+
return { locale, translation };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {};
|
|
62
|
+
};
|
|
52
63
|
class LocalizationAITranslationError extends Error {
|
|
53
64
|
constructor(message, details) {
|
|
54
65
|
super(message);
|
|
@@ -74,11 +85,21 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
74
85
|
const resolvedModel = await aiPlugin.aiEmployeesManager.resolveModel(employee, params.model);
|
|
75
86
|
const { provider, model, service } = await aiPlugin.aiManager.getLLMService(resolvedModel);
|
|
76
87
|
const defaultReferenceLocale = await this.getSystemDefaultLocale();
|
|
77
|
-
const builtInReferenceResources = await this.app.localeManager.getBuiltInResources("zh-CN");
|
|
78
88
|
const builtInMatchResources = await this.app.localeManager.getBuiltInResources("en-US");
|
|
89
|
+
const referenceLocales = this.resolveReferenceLocales(params.referenceLocales, defaultReferenceLocale);
|
|
90
|
+
const findTextsOptions = await (0, import_translation_scope.buildFindTextsOptions)({
|
|
91
|
+
app: this.app,
|
|
92
|
+
mode: params.mode,
|
|
93
|
+
locale,
|
|
94
|
+
scope: params.scope || "all",
|
|
95
|
+
textIds: params.textIds,
|
|
96
|
+
fields: ["id", "text", "module"],
|
|
97
|
+
sort: ["id"]
|
|
98
|
+
});
|
|
79
99
|
const workerCount = getTranslationWorkerCount();
|
|
100
|
+
const chunkSize = TRANSLATION_CHUNK_SIZE;
|
|
80
101
|
const countStart = Date.now();
|
|
81
|
-
const total = await this.countTexts(
|
|
102
|
+
const total = await this.countTexts(findTextsOptions);
|
|
82
103
|
(_a = this.logger) == null ? void 0 : _a.debug("Localization AI translation task started", {
|
|
83
104
|
taskId: this.record.id,
|
|
84
105
|
mode: params.mode,
|
|
@@ -86,96 +107,86 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
86
107
|
total,
|
|
87
108
|
countElapsedMs: elapsed(countStart),
|
|
88
109
|
workerCount,
|
|
89
|
-
|
|
110
|
+
chunkSize,
|
|
90
111
|
defaultReferenceLocale,
|
|
112
|
+
referenceLocales,
|
|
113
|
+
scope: params.scope || "all",
|
|
91
114
|
provider: service == null ? void 0 : service.provider,
|
|
92
115
|
llmService: service == null ? void 0 : service.name,
|
|
93
116
|
model
|
|
94
117
|
});
|
|
95
118
|
let translated = 0;
|
|
96
119
|
let chunkIndex = 0;
|
|
97
|
-
let producerDone = false;
|
|
98
|
-
let firstError;
|
|
99
|
-
const queue = [];
|
|
100
120
|
this.reportProgress({ total, current: 0 });
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
await this.app.db.getRepository("localizationTexts").chunkWithCursor({
|
|
127
|
-
...this.buildFindTextsOptions(params.mode, locale, params.textIds),
|
|
128
|
-
chunkSize: TRANSLATION_BATCH_SIZE,
|
|
129
|
-
beforeFind: async () => {
|
|
130
|
-
while (!firstError && queue.length >= MAX_TRANSLATION_QUEUE_SIZE) {
|
|
131
|
-
await sleep(100);
|
|
132
|
-
}
|
|
133
|
-
if (firstError) {
|
|
134
|
-
throw firstError;
|
|
121
|
+
const repository = this.app.db.getRepository("localizationTexts");
|
|
122
|
+
const chunk = params.mode === "selected" ? repository.chunk.bind(repository) : repository.chunkWithCursor.bind(repository);
|
|
123
|
+
await chunk({
|
|
124
|
+
...findTextsOptions,
|
|
125
|
+
chunkSize,
|
|
126
|
+
callback: async (rows) => {
|
|
127
|
+
var _a2, _b2, _c;
|
|
128
|
+
chunkIndex += 1;
|
|
129
|
+
const chunkStart = Date.now();
|
|
130
|
+
const textRows = rows.map((row) => (0, import_translation_scope.normalizeTextRecord)(row)).filter(Boolean);
|
|
131
|
+
const rowsWithScope = textRows.map((row) => ({
|
|
132
|
+
row,
|
|
133
|
+
isBuiltIn: (0, import_translation_scope.isBuiltInText)(row, builtInMatchResources)
|
|
134
|
+
}));
|
|
135
|
+
(_a2 = this.logger) == null ? void 0 : _a2.debug("Localization AI translation chunk loaded", {
|
|
136
|
+
taskId: this.record.id,
|
|
137
|
+
chunkIndex,
|
|
138
|
+
rows: textRows.length,
|
|
139
|
+
workerCount,
|
|
140
|
+
translated,
|
|
141
|
+
total
|
|
142
|
+
});
|
|
143
|
+
for (let start = 0; start < rowsWithScope.length; start += workerCount) {
|
|
144
|
+
if (this.isCanceled) {
|
|
145
|
+
throw new import_plugin_async_task_manager.CancelError();
|
|
135
146
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
147
|
+
const batchStart = Date.now();
|
|
148
|
+
const batch = rowsWithScope.slice(start, start + workerCount);
|
|
149
|
+
const items = await this.buildTranslationItems(batch, referenceLocales, chunkIndex);
|
|
150
|
+
await Promise.all(
|
|
151
|
+
items.map(
|
|
152
|
+
(item, index) => this.translateItem({
|
|
153
|
+
workerIndex: index + 1,
|
|
154
|
+
item,
|
|
155
|
+
total,
|
|
156
|
+
getTranslated: () => translated,
|
|
157
|
+
incrementTranslated: () => {
|
|
158
|
+
translated += 1;
|
|
159
|
+
return translated;
|
|
160
|
+
},
|
|
161
|
+
locale,
|
|
162
|
+
employeeUsername,
|
|
163
|
+
employee,
|
|
164
|
+
provider,
|
|
165
|
+
service,
|
|
166
|
+
model
|
|
167
|
+
})
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
(_b2 = this.logger) == null ? void 0 : _b2.debug("Localization AI translation batch completed", {
|
|
158
171
|
taskId: this.record.id,
|
|
159
172
|
chunkIndex,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
referenceTranslations: queueItems.filter((item) => item.referenceTranslation).length,
|
|
164
|
-
builtInReferences: queueItems.filter((item) => item.isBuiltIn && item.referenceTranslation).length,
|
|
165
|
-
queueSize: queue.length,
|
|
166
|
-
elapsedMs: elapsed(chunkStart),
|
|
173
|
+
batchSize: items.length,
|
|
174
|
+
referenceTranslations: items.filter((item) => item.referenceTranslation).length,
|
|
175
|
+
elapsedMs: elapsed(batchStart),
|
|
167
176
|
translated,
|
|
168
177
|
total
|
|
169
178
|
});
|
|
170
179
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
(_c = this.logger) == null ? void 0 : _c.debug("Localization AI translation chunk completed", {
|
|
181
|
+
taskId: this.record.id,
|
|
182
|
+
chunkIndex,
|
|
183
|
+
rows: textRows.length,
|
|
184
|
+
elapsedMs: elapsed(chunkStart),
|
|
185
|
+
translated,
|
|
186
|
+
total
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
179
190
|
(_b = this.logger) == null ? void 0 : _b.debug("Localization AI translation task completed", {
|
|
180
191
|
taskId: this.record.id,
|
|
181
192
|
translated,
|
|
@@ -186,34 +197,8 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
186
197
|
total
|
|
187
198
|
};
|
|
188
199
|
}
|
|
189
|
-
async countTexts(
|
|
190
|
-
return await this.app.db.getRepository("localizationTexts").count(
|
|
191
|
-
}
|
|
192
|
-
buildFindTextsOptions(mode, locale, textIds) {
|
|
193
|
-
const options = {
|
|
194
|
-
fields: ["id", "text", "module"],
|
|
195
|
-
sort: ["id"]
|
|
196
|
-
};
|
|
197
|
-
if (mode === "selected") {
|
|
198
|
-
options.filter = {
|
|
199
|
-
id: {
|
|
200
|
-
$in: textIds || []
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
if (mode === "incremental") {
|
|
205
|
-
options.include = [{ association: "translations", where: { locale }, required: false }];
|
|
206
|
-
options.where = {
|
|
207
|
-
"$translations.id$": null
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
return options;
|
|
211
|
-
}
|
|
212
|
-
normalizeTextRecord(row) {
|
|
213
|
-
if (!row) {
|
|
214
|
-
return void 0;
|
|
215
|
-
}
|
|
216
|
-
return typeof row.toJSON === "function" ? row.toJSON() : row;
|
|
200
|
+
async countTexts(options) {
|
|
201
|
+
return await this.app.db.getRepository("localizationTexts").count(options);
|
|
217
202
|
}
|
|
218
203
|
async getLocaleReferences(textIds, locale) {
|
|
219
204
|
const references = /* @__PURE__ */ new Map();
|
|
@@ -223,10 +208,10 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
223
208
|
const rows = await this.app.db.getRepository("localizationTranslations").find({
|
|
224
209
|
fields: ["textId", "translation"],
|
|
225
210
|
filter: {
|
|
226
|
-
locale,
|
|
227
211
|
textId: {
|
|
228
212
|
$in: textIds
|
|
229
|
-
}
|
|
213
|
+
},
|
|
214
|
+
locale
|
|
230
215
|
}
|
|
231
216
|
});
|
|
232
217
|
for (const row of rows) {
|
|
@@ -237,34 +222,101 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
237
222
|
}
|
|
238
223
|
return references;
|
|
239
224
|
}
|
|
225
|
+
async getReferenceMaps(textIds, locales) {
|
|
226
|
+
const result = /* @__PURE__ */ new Map();
|
|
227
|
+
await Promise.all(
|
|
228
|
+
Array.from(new Set(locales)).map(async (locale) => {
|
|
229
|
+
result.set(locale, await this.getLocaleReferences(textIds, locale));
|
|
230
|
+
})
|
|
231
|
+
);
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
async getBuiltInReferenceMaps(rows, locales) {
|
|
235
|
+
const result = /* @__PURE__ */ new Map();
|
|
236
|
+
if (!rows.length) {
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
await Promise.all(
|
|
240
|
+
Array.from(new Set(locales)).map(async (locale) => {
|
|
241
|
+
var _a;
|
|
242
|
+
const resources = await this.app.localeManager.getCacheResources(locale);
|
|
243
|
+
const references = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const row of rows) {
|
|
245
|
+
const moduleName = (0, import_translation_scope.getModuleName)(row);
|
|
246
|
+
if (!moduleName) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const modules = Array.from(/* @__PURE__ */ new Set([(0, import_translation_scope.normalizeModuleName)(moduleName), moduleName]));
|
|
250
|
+
for (const module2 of modules) {
|
|
251
|
+
const translation = (_a = resources == null ? void 0 : resources[module2]) == null ? void 0 : _a[row.text];
|
|
252
|
+
if (translation) {
|
|
253
|
+
references.set(String(row.id), translation);
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
result.set(locale, references);
|
|
259
|
+
})
|
|
260
|
+
);
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
pickDbReference(row, references, locales) {
|
|
264
|
+
var _a;
|
|
265
|
+
for (const locale of [locales.primary, locales.fallback].filter(isString)) {
|
|
266
|
+
const translation = (_a = references.get(locale)) == null ? void 0 : _a.get(String(row.id));
|
|
267
|
+
if (translation) {
|
|
268
|
+
return { locale, translation };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return {};
|
|
272
|
+
}
|
|
240
273
|
async getSystemDefaultLocale() {
|
|
241
274
|
var _a;
|
|
242
275
|
const systemSetting = await ((_a = this.app.db.getRepository("systemSettings")) == null ? void 0 : _a.findOne());
|
|
243
276
|
const enabledLanguages = (systemSetting == null ? void 0 : systemSetting.get("enabledLanguages")) || [];
|
|
244
277
|
return (enabledLanguages == null ? void 0 : enabledLanguages[0]) || process.env.APP_LANG || "en-US";
|
|
245
278
|
}
|
|
246
|
-
|
|
247
|
-
var _a;
|
|
248
|
-
return
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
279
|
+
resolveReferenceLocales(referenceLocales, defaultReferenceLocale) {
|
|
280
|
+
var _a, _b, _c, _d;
|
|
281
|
+
return {
|
|
282
|
+
builtIn: {
|
|
283
|
+
primary: ((_a = referenceLocales == null ? void 0 : referenceLocales.builtIn) == null ? void 0 : _a.primary) || "zh-CN",
|
|
284
|
+
fallback: ((_b = referenceLocales == null ? void 0 : referenceLocales.builtIn) == null ? void 0 : _b.fallback) || "ja-JP"
|
|
285
|
+
},
|
|
286
|
+
custom: {
|
|
287
|
+
primary: ((_c = referenceLocales == null ? void 0 : referenceLocales.custom) == null ? void 0 : _c.primary) || defaultReferenceLocale,
|
|
288
|
+
fallback: ((_d = referenceLocales == null ? void 0 : referenceLocales.custom) == null ? void 0 : _d.fallback) || "zh-CN"
|
|
289
|
+
}
|
|
290
|
+
};
|
|
254
291
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
292
|
+
async buildTranslationItems(batch, referenceLocales, chunkIndex) {
|
|
293
|
+
const builtInRows = batch.filter((item) => item.isBuiltIn).map((item) => item.row);
|
|
294
|
+
const customTextIds = batch.filter((item) => !item.isBuiltIn).map((item) => item.row.id);
|
|
295
|
+
const builtInReferences = await this.getBuiltInReferenceMaps(
|
|
296
|
+
builtInRows,
|
|
297
|
+
[referenceLocales.builtIn.primary, referenceLocales.builtIn.fallback].filter(isString)
|
|
298
|
+
);
|
|
299
|
+
const customReferences = await this.getReferenceMaps(
|
|
300
|
+
customTextIds,
|
|
301
|
+
[referenceLocales.custom.primary, referenceLocales.custom.fallback].filter(isString)
|
|
302
|
+
);
|
|
303
|
+
return batch.map(({ row, isBuiltIn }) => {
|
|
304
|
+
const references = isBuiltIn ? referenceLocales.builtIn : referenceLocales.custom;
|
|
305
|
+
const reference = isBuiltIn ? pickBuiltInResourceReference(row, builtInReferences, references) : this.pickDbReference(row, customReferences, references);
|
|
306
|
+
return {
|
|
307
|
+
row,
|
|
308
|
+
chunkIndex,
|
|
309
|
+
referenceTranslation: reference.translation,
|
|
310
|
+
referenceLocale: reference.locale,
|
|
311
|
+
isBuiltIn
|
|
312
|
+
};
|
|
313
|
+
});
|
|
259
314
|
}
|
|
260
|
-
async
|
|
315
|
+
async translateItem(options) {
|
|
261
316
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
262
317
|
const {
|
|
263
318
|
workerIndex,
|
|
264
|
-
|
|
265
|
-
isDone,
|
|
266
|
-
getError,
|
|
267
|
-
setError,
|
|
319
|
+
item,
|
|
268
320
|
total,
|
|
269
321
|
getTranslated,
|
|
270
322
|
incrementTranslated,
|
|
@@ -275,102 +327,85 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
275
327
|
service,
|
|
276
328
|
model
|
|
277
329
|
} = options;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
330
|
+
if (this.isCanceled) {
|
|
331
|
+
throw new import_plugin_async_task_manager.CancelError();
|
|
332
|
+
}
|
|
333
|
+
const { row, chunkIndex, referenceTranslation, referenceLocale, isBuiltIn } = item;
|
|
334
|
+
try {
|
|
335
|
+
const textStart = Date.now();
|
|
336
|
+
(_c = (_a = this.logger) == null ? void 0 : _a.trace) == null ? void 0 : _c.call(_a, "Localization AI translation text started", {
|
|
337
|
+
taskId: this.record.id,
|
|
338
|
+
workerIndex,
|
|
339
|
+
chunkIndex,
|
|
340
|
+
textId: row.id,
|
|
341
|
+
textLength: ((_b = row.text) == null ? void 0 : _b.length) ?? 0,
|
|
342
|
+
hasReferenceTranslation: Boolean(referenceTranslation),
|
|
343
|
+
referenceLocale,
|
|
344
|
+
isBuiltIn,
|
|
345
|
+
translated: getTranslated(),
|
|
346
|
+
total
|
|
347
|
+
});
|
|
348
|
+
const isLegacySymbolTranslation = LEGACY_SYMBOL_TRANSLATIONS.has(row.text);
|
|
349
|
+
if (isLegacySymbolTranslation) {
|
|
350
|
+
(_e = (_d = this.logger) == null ? void 0 : _d.trace) == null ? void 0 : _e.call(_d, "Localization AI translation legacy symbol skipped", {
|
|
294
351
|
taskId: this.record.id,
|
|
295
352
|
workerIndex,
|
|
296
353
|
chunkIndex,
|
|
297
354
|
textId: row.id,
|
|
298
|
-
|
|
299
|
-
hasEnglishReference: Boolean(englishReference),
|
|
300
|
-
hasReferenceTranslation: Boolean(referenceTranslation),
|
|
301
|
-
referenceLocale,
|
|
302
|
-
isBuiltIn,
|
|
303
|
-
queueSize: queue.length,
|
|
304
|
-
translated: getTranslated(),
|
|
305
|
-
total
|
|
306
|
-
});
|
|
307
|
-
const isLegacySymbolTranslation = LEGACY_SYMBOL_TRANSLATIONS.has(row.text);
|
|
308
|
-
if (isLegacySymbolTranslation) {
|
|
309
|
-
(_e = (_d = this.logger) == null ? void 0 : _d.trace) == null ? void 0 : _e.call(_d, "Localization AI translation legacy symbol skipped", {
|
|
310
|
-
taskId: this.record.id,
|
|
311
|
-
workerIndex,
|
|
312
|
-
chunkIndex,
|
|
313
|
-
textId: row.id,
|
|
314
|
-
text: row.text
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
const translation = isLegacySymbolTranslation ? row.text : await this.translateText({
|
|
318
|
-
text: row.text,
|
|
319
|
-
module: row.module,
|
|
320
|
-
englishReference,
|
|
321
|
-
referenceTranslation,
|
|
322
|
-
referenceLocale,
|
|
323
|
-
isBuiltIn,
|
|
324
|
-
locale,
|
|
325
|
-
employeeUsername,
|
|
326
|
-
employee,
|
|
327
|
-
provider,
|
|
328
|
-
service,
|
|
329
|
-
model
|
|
330
|
-
});
|
|
331
|
-
const aiElapsedMs = elapsed(textStart);
|
|
332
|
-
const writeStart = Date.now();
|
|
333
|
-
await this.app.db.getRepository("localizationTranslations").updateOrCreate({
|
|
334
|
-
filterKeys: ["textId", "locale"],
|
|
335
|
-
values: {
|
|
336
|
-
textId: row.id,
|
|
337
|
-
locale,
|
|
338
|
-
translation
|
|
339
|
-
}
|
|
355
|
+
text: row.text
|
|
340
356
|
});
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
357
|
+
}
|
|
358
|
+
const translation = isLegacySymbolTranslation ? row.text : await this.translateText({
|
|
359
|
+
text: row.text,
|
|
360
|
+
module: row.module,
|
|
361
|
+
referenceTranslation,
|
|
362
|
+
referenceLocale,
|
|
363
|
+
isBuiltIn,
|
|
364
|
+
locale,
|
|
365
|
+
employeeUsername,
|
|
366
|
+
employee,
|
|
367
|
+
provider,
|
|
368
|
+
service,
|
|
369
|
+
model
|
|
370
|
+
});
|
|
371
|
+
const aiElapsedMs = elapsed(textStart);
|
|
372
|
+
const writeStart = Date.now();
|
|
373
|
+
await this.app.db.getRepository("localizationTranslations").updateOrCreate({
|
|
374
|
+
filterKeys: ["textId", "locale"],
|
|
375
|
+
values: {
|
|
348
376
|
textId: row.id,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
aiElapsedMs,
|
|
352
|
-
writeElapsedMs,
|
|
353
|
-
totalElapsedMs: elapsed(textStart),
|
|
354
|
-
translated,
|
|
355
|
-
total,
|
|
356
|
-
queueSize: queue.length
|
|
357
|
-
});
|
|
358
|
-
} catch (error) {
|
|
359
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
360
|
-
const details = {
|
|
361
|
-
id: row.id,
|
|
362
|
-
text: row.text,
|
|
363
|
-
error: message
|
|
364
|
-
};
|
|
365
|
-
(_h = this.logger) == null ? void 0 : _h.error(`Failed to translate localization text ${row.id}: ${message}`, { error });
|
|
366
|
-
if (error instanceof import_plugin_async_task_manager.CancelError) {
|
|
367
|
-
throw error;
|
|
377
|
+
locale,
|
|
378
|
+
translation
|
|
368
379
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
380
|
+
});
|
|
381
|
+
const writeElapsedMs = elapsed(writeStart);
|
|
382
|
+
const translated = incrementTranslated();
|
|
383
|
+
this.reportProgress({ total, current: translated });
|
|
384
|
+
(_g = this.logger) == null ? void 0 : _g.debug("Localization AI translation text completed", {
|
|
385
|
+
taskId: this.record.id,
|
|
386
|
+
workerIndex,
|
|
387
|
+
chunkIndex,
|
|
388
|
+
textId: row.id,
|
|
389
|
+
textLength: ((_f = row.text) == null ? void 0 : _f.length) ?? 0,
|
|
390
|
+
translationLength: translation.length,
|
|
391
|
+
aiElapsedMs,
|
|
392
|
+
writeElapsedMs,
|
|
393
|
+
totalElapsedMs: elapsed(textStart),
|
|
394
|
+
translated,
|
|
395
|
+
total
|
|
396
|
+
});
|
|
397
|
+
} catch (error) {
|
|
398
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
399
|
+
const details = {
|
|
400
|
+
id: row.id,
|
|
401
|
+
text: row.text,
|
|
402
|
+
error: message
|
|
403
|
+
};
|
|
404
|
+
(_h = this.logger) == null ? void 0 : _h.error(`Failed to translate localization text ${row.id}: ${message}`, { error });
|
|
405
|
+
if (error instanceof import_plugin_async_task_manager.CancelError) {
|
|
406
|
+
throw error;
|
|
373
407
|
}
|
|
408
|
+
throw new LocalizationAITranslationError(`Failed to translate localization text ${row.id}: ${message}`, details);
|
|
374
409
|
}
|
|
375
410
|
}
|
|
376
411
|
async translateText(options) {
|
|
@@ -378,7 +413,6 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
378
413
|
const {
|
|
379
414
|
text,
|
|
380
415
|
module: module2,
|
|
381
|
-
englishReference,
|
|
382
416
|
referenceTranslation,
|
|
383
417
|
referenceLocale,
|
|
384
418
|
isBuiltIn,
|
|
@@ -390,14 +424,13 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
390
424
|
employee
|
|
391
425
|
} = options;
|
|
392
426
|
const setupStart = Date.now();
|
|
393
|
-
const sourceText =
|
|
394
|
-
const sourceLang = englishReference ? "English" : "auto";
|
|
427
|
+
const sourceText = text;
|
|
395
428
|
const targetLang = this.getLanguageName(locale);
|
|
396
429
|
const context = this.buildProviderContext({
|
|
430
|
+
systemPrompt: this.getEmployeeSystemPrompt(employee),
|
|
397
431
|
sourceText,
|
|
398
432
|
targetLang,
|
|
399
|
-
|
|
400
|
-
referenceTargetTerm: referenceTranslation
|
|
433
|
+
referenceTranslation
|
|
401
434
|
});
|
|
402
435
|
const invokeStart = Date.now();
|
|
403
436
|
(_b = (_a = this.logger) == null ? void 0 : _a.trace) == null ? void 0 : _b.call(_a, "Localization AI translation invoke started", {
|
|
@@ -405,44 +438,29 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
405
438
|
textLength: (text == null ? void 0 : text.length) ?? 0,
|
|
406
439
|
sourceTextLength: (sourceText == null ? void 0 : sourceText.length) ?? 0,
|
|
407
440
|
locale,
|
|
408
|
-
sourceLang,
|
|
409
441
|
targetLang,
|
|
410
442
|
module: module2,
|
|
411
443
|
employeeUsername,
|
|
412
444
|
provider: service == null ? void 0 : service.provider,
|
|
413
445
|
llmService: service == null ? void 0 : service.name,
|
|
414
446
|
model,
|
|
415
|
-
hasEnglishReference: Boolean(englishReference),
|
|
416
447
|
hasReferenceTranslation: Boolean(referenceTranslation),
|
|
417
448
|
referenceLocale,
|
|
418
449
|
isBuiltIn
|
|
419
450
|
});
|
|
420
|
-
const result = await provider.invoke(context
|
|
421
|
-
modelRequestParams: {
|
|
422
|
-
sourceText,
|
|
423
|
-
sourceLang,
|
|
424
|
-
targetLang,
|
|
425
|
-
terms: this.buildTranslationTerms({
|
|
426
|
-
sourceTerm: sourceText,
|
|
427
|
-
targetTerm: referenceTranslation,
|
|
428
|
-
targetLang
|
|
429
|
-
})
|
|
430
|
-
}
|
|
431
|
-
});
|
|
451
|
+
const result = await provider.invoke(context);
|
|
432
452
|
const invokeElapsedMs = elapsed(invokeStart);
|
|
433
453
|
(_d = (_c = this.logger) == null ? void 0 : _c.trace) == null ? void 0 : _d.call(_c, "Localization AI translation invoke completed", {
|
|
434
454
|
taskId: this.record.id,
|
|
435
455
|
textLength: (text == null ? void 0 : text.length) ?? 0,
|
|
436
456
|
sourceTextLength: (sourceText == null ? void 0 : sourceText.length) ?? 0,
|
|
437
457
|
locale,
|
|
438
|
-
sourceLang,
|
|
439
458
|
targetLang,
|
|
440
459
|
module: module2,
|
|
441
460
|
employeeUsername,
|
|
442
461
|
provider: service == null ? void 0 : service.provider,
|
|
443
462
|
llmService: service == null ? void 0 : service.name,
|
|
444
463
|
model,
|
|
445
|
-
hasEnglishReference: Boolean(englishReference),
|
|
446
464
|
hasReferenceTranslation: Boolean(referenceTranslation),
|
|
447
465
|
referenceLocale,
|
|
448
466
|
isBuiltIn,
|
|
@@ -460,14 +478,12 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
460
478
|
sourceTextLength: (sourceText == null ? void 0 : sourceText.length) ?? 0,
|
|
461
479
|
translationLength: translation.length,
|
|
462
480
|
locale,
|
|
463
|
-
sourceLang,
|
|
464
481
|
targetLang,
|
|
465
482
|
module: module2,
|
|
466
483
|
employeeUsername,
|
|
467
484
|
provider: service == null ? void 0 : service.provider,
|
|
468
485
|
llmService: service == null ? void 0 : service.name,
|
|
469
486
|
model,
|
|
470
|
-
hasEnglishReference: Boolean(englishReference),
|
|
471
487
|
hasReferenceTranslation: Boolean(referenceTranslation),
|
|
472
488
|
referenceLocale,
|
|
473
489
|
isBuiltIn,
|
|
@@ -477,32 +493,25 @@ class LocalizationAITranslateTask extends import_plugin_async_task_manager.TaskT
|
|
|
477
493
|
});
|
|
478
494
|
return translation;
|
|
479
495
|
}
|
|
496
|
+
getEmployeeSystemPrompt(employee) {
|
|
497
|
+
var _a, _b;
|
|
498
|
+
return ((_a = employee == null ? void 0 : employee.get) == null ? void 0 : _a.call(employee, "about")) || ((_b = employee == null ? void 0 : employee.get) == null ? void 0 : _b.call(employee, "defaultPrompt")) || (employee == null ? void 0 : employee.about) || (employee == null ? void 0 : employee.defaultPrompt) || "";
|
|
499
|
+
}
|
|
480
500
|
buildProviderContext(options) {
|
|
481
|
-
const { sourceText, targetLang,
|
|
482
|
-
const
|
|
483
|
-
|
|
501
|
+
const { systemPrompt, sourceText, targetLang, referenceTranslation } = options;
|
|
502
|
+
const prompt = (systemPrompt || "").trim();
|
|
503
|
+
const reference = referenceTranslation ? `Refer to the following translation:
|
|
504
|
+
${sourceText} is translated as ${referenceTranslation}
|
|
484
505
|
|
|
485
506
|
` : "";
|
|
486
|
-
const
|
|
487
|
-
|
|
507
|
+
const task = `Translate the following text into ${targetLang}. Output only the translated result without any additional explanation:
|
|
488
508
|
${sourceText}
|
|
489
509
|
`;
|
|
510
|
+
const content = [prompt, `${reference}${task}`].filter(Boolean).join("\n\n");
|
|
490
511
|
return {
|
|
491
512
|
messages: [new import_messages.HumanMessage(content)]
|
|
492
513
|
};
|
|
493
514
|
}
|
|
494
|
-
buildTranslationTerms(options) {
|
|
495
|
-
const { sourceTerm, targetTerm, targetLang } = options;
|
|
496
|
-
if (!sourceTerm || !targetTerm || !["Chinese", "Traditional Chinese"].includes(targetLang)) {
|
|
497
|
-
return void 0;
|
|
498
|
-
}
|
|
499
|
-
return [
|
|
500
|
-
{
|
|
501
|
-
source: sourceTerm,
|
|
502
|
-
target: targetTerm
|
|
503
|
-
}
|
|
504
|
-
];
|
|
505
|
-
}
|
|
506
515
|
getLanguageName(locale) {
|
|
507
516
|
const normalized = locale.replace("_", "-");
|
|
508
517
|
const map = {
|
|
@@ -592,5 +601,6 @@ ${sourceText}
|
|
|
592
601
|
// Annotate the CommonJS export names for ESM import in node:
|
|
593
602
|
0 && (module.exports = {
|
|
594
603
|
LOCALIZATION_AI_TRANSLATE_TASK_TYPE,
|
|
595
|
-
LocalizationAITranslateTask
|
|
604
|
+
LocalizationAITranslateTask,
|
|
605
|
+
pickBuiltInResourceReference
|
|
596
606
|
});
|