@yxw007/translate 0.1.6 → 0.2.2

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.
@@ -1,9 +1,9 @@
1
- // translate v0.1.6 Copyright (c) 2024 Potter<aa4790139@gmail.com> and contributors
1
+ // translate v0.2.2 Copyright (c) 2025 Potter<aa4790139@gmail.com> and contributors
2
2
  (function (global, factory) {
3
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@aws-sdk/client-translate')) :
4
- typeof define === 'function' && define.amd ? define(['exports', '@aws-sdk/client-translate'], factory) :
5
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.translate = {}, global.clientTranslate));
6
- })(this, (function (exports, clientTranslate) { 'use strict';
3
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs/promises'), require('fs'), require('path'), require('@aws-sdk/client-translate')) :
4
+ typeof define === 'function' && define.amd ? define(['exports', 'fs/promises', 'fs', 'path', '@aws-sdk/client-translate'], factory) :
5
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.translate = {}, null, null, null, global.clientTranslate));
6
+ })(this, (function (exports, pfs, fs, path, clientTranslate) { 'use strict';
7
7
 
8
8
  class TranslationError extends Error {
9
9
  region;
@@ -117,6 +117,9 @@
117
117
  };
118
118
  }
119
119
 
120
+ function sleep(ms) {
121
+ return new Promise((resolve) => setTimeout(resolve, ms));
122
+ }
120
123
  function getGapLine() {
121
124
  return "-".repeat(20);
122
125
  }
@@ -134,6 +137,66 @@
134
137
  catch (e) { }
135
138
  return new TranslationError(name, `Translate fail ! ${res.status}: ${res.statusText} ${bodyRes?.message ?? ""}`);
136
139
  }
140
+ function splitText(text, maxCharacterNum) {
141
+ const SPLIT_PRIORITY = [
142
+ /\n\n+/, // 段落分隔(优先保留空行)
143
+ /[.。!??!\n]/, // 中日韩句子结束符+英文标点+换行
144
+ /[;;]/, // 分号(中英文)
145
+ /[,,]/g, // 逗号(中英文)
146
+ /\s/, // 空格(避免切分单词)
147
+ ];
148
+ const BEST_MATCH_RATIO = 0.7;
149
+ const chunks = [];
150
+ while (text.length > 0) {
151
+ const chunk = text.slice(0, maxCharacterNum);
152
+ // Scene 1:Prioritization of cases not subject to severance
153
+ if (text.length <= maxCharacterNum) {
154
+ chunks.push(text);
155
+ break;
156
+ }
157
+ // Scene 2:Finding Split Points by Priority
158
+ let splitPos = -1;
159
+ for (const delimiter of SPLIT_PRIORITY) {
160
+ const regex = new RegExp(delimiter.source + "(?=[^]*)", "g"); // back-to-front search
161
+ let m, longestMatch;
162
+ while ((m = regex.exec(chunk)) !== null) {
163
+ if (m.index === regex.lastIndex) {
164
+ regex.lastIndex++;
165
+ }
166
+ if (longestMatch != null) {
167
+ longestMatch = m.index > longestMatch.index ? m : longestMatch;
168
+ }
169
+ else {
170
+ longestMatch = m;
171
+ }
172
+ }
173
+ if (longestMatch?.index !== undefined && longestMatch.index >= maxCharacterNum * BEST_MATCH_RATIO) {
174
+ splitPos = longestMatch.index;
175
+ break; // Finding Quality Split Points
176
+ }
177
+ }
178
+ // Scene 3:Conservative splitting in the absence of a suitable separator
179
+ if (splitPos === -1) {
180
+ splitPos = chunk.lastIndexOf(" ", maxCharacterNum); // look for the space
181
+ splitPos = splitPos === -1 ? maxCharacterNum : splitPos; // forcible division
182
+ }
183
+ if (splitPos == 0) {
184
+ text = text.slice(splitPos + 1);
185
+ }
186
+ else {
187
+ chunks.push(text.slice(0, splitPos));
188
+ text = text.slice(splitPos);
189
+ }
190
+ }
191
+ return chunks;
192
+ }
193
+ function isOverMaxCharacterNum(text, max_character_num) {
194
+ if (!text || text.length <= 0) {
195
+ return false;
196
+ }
197
+ const total = text.reduce((pre, cur) => pre + cur.length, 0);
198
+ return total > max_character_num;
199
+ }
137
200
 
138
201
  function google(options) {
139
202
  const base = "https://translate.googleapis.com/translate_a/single";
@@ -2379,15 +2442,20 @@
2379
2442
  }
2380
2443
 
2381
2444
  const appName = "Translate";
2445
+ const defaultMaxCharacterNum = 1000;
2382
2446
 
2383
2447
  const logger = useLogger();
2384
2448
  const cache = new Cache();
2385
2449
  class Translator {
2386
2450
  engines;
2387
2451
  cache_time;
2388
- constructor(cache_time = 60 * 1000) {
2452
+ concurrencyMax;
2453
+ concurrencyDelay;
2454
+ constructor(cache_time = 60 * 1000, concurrencyMax = 4, concurrencyDelay = 20) {
2389
2455
  this.engines = new Map();
2390
2456
  this.cache_time = cache_time;
2457
+ this.concurrencyMax = concurrencyMax;
2458
+ this.concurrencyDelay = concurrencyDelay;
2391
2459
  }
2392
2460
  /**
2393
2461
  * This method is obsolete, please use the addEngine method
@@ -2435,8 +2503,7 @@
2435
2503
  if (cache.get(key)) {
2436
2504
  return Promise.resolve(cache.get(key)?.value);
2437
2505
  }
2438
- return engineInstance
2439
- .translate(text, options)
2506
+ return this.concurrencyHandle(engineInstance, text, options)
2440
2507
  .then((translated) => {
2441
2508
  cache.set(key, translated, cache_time ?? this.cache_time);
2442
2509
  return translated;
@@ -2451,6 +2518,55 @@
2451
2518
  }
2452
2519
  });
2453
2520
  }
2521
+ async concurrencyHandle(engine, text, options) {
2522
+ const { max_character_num = defaultMaxCharacterNum } = options;
2523
+ const maxCharacterNum = max_character_num > 0 ? max_character_num : defaultMaxCharacterNum;
2524
+ if (Array.isArray(text)) {
2525
+ if (isOverMaxCharacterNum(text, max_character_num)) {
2526
+ throw new TranslationError(appName, "String arrays do not support automatic character splitting, and the total number of characters in a string array exceeds the limit on the number of translated characters.");
2527
+ }
2528
+ return engine.translate(text, options);
2529
+ }
2530
+ else {
2531
+ return this.concurrencyTranslate(engine, text, options, maxCharacterNum);
2532
+ }
2533
+ }
2534
+ async concurrencyTranslate(engine, text, options, maxCharacterMum) {
2535
+ const pendingTasks = splitText(text, maxCharacterMum).map((content, index) => ({ content, index }));
2536
+ const result = [];
2537
+ let activeTasks = 0;
2538
+ const concurrencyDelay = this.concurrencyDelay;
2539
+ const concurrencyMax = this.concurrencyMax;
2540
+ return new Promise((resolve, reject) => {
2541
+ function processTasks() {
2542
+ while (activeTasks < concurrencyMax && pendingTasks.length > 0) {
2543
+ const { content, index } = pendingTasks.shift();
2544
+ activeTasks++;
2545
+ engine
2546
+ .translate(content, options)
2547
+ .then((res) => {
2548
+ result.push({
2549
+ translated: res,
2550
+ index,
2551
+ });
2552
+ })
2553
+ .catch((error) => reject(error))
2554
+ .finally(async () => {
2555
+ activeTasks--;
2556
+ if (activeTasks === 0 && pendingTasks.length <= 0) {
2557
+ result.sort((a, b) => a.index - b.index);
2558
+ const arr = result.reduce((pre, cur) => pre.concat(cur.translated), []);
2559
+ return resolve([arr.join("")]);
2560
+ }
2561
+ await sleep(concurrencyDelay);
2562
+ processTasks();
2563
+ });
2564
+ }
2565
+ }
2566
+ processTasks();
2567
+ return result;
2568
+ });
2569
+ }
2454
2570
  }
2455
2571
  const translator = new Translator();
2456
2572
  var index = {