@yxw007/translate 0.3.2 → 0.4.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/README.md CHANGED
@@ -73,7 +73,7 @@ English | [简体中文](./README_zh-CN.md)
73
73
  const { translator, engines } = required("@yxw007/translate")
74
74
  ```
75
75
 
76
- - example
76
+ - Translation examples
77
77
  ```typescript
78
78
  translator.addEngine(engines.google());
79
79
  const res1 = await translator.translate("hello", { from: "en", to: "zh" });
@@ -83,11 +83,22 @@ English | [简体中文](./README_zh-CN.md)
83
83
  console.log(res2);
84
84
  ```
85
85
 
86
- 输出结果
86
+ Output results
87
87
  ```bash
88
88
  ['你好']
89
89
  ["你好", "好的"]
90
90
  ```
91
+ - Language detection examples
92
+ ```typescript
93
+ translator.addEngine(engines.google());
94
+ const res1 = await translator.checkLanguage("hello", { engine:"google" });
95
+ console.log(res1);
96
+
97
+ ```
98
+ Output results
99
+ ```bash
100
+ en
101
+ ```
91
102
 
92
103
  ### Browser
93
104
 
@@ -363,6 +374,9 @@ export interface TencentEngineOption extends BaseEngineOption {
363
374
  const base = "https://translate.yandex.net/api/v1.5/tr.json/translate";
364
375
  return {
365
376
  name: "yandex",
377
+ async checkLanguage<T extends Engines>(text: string): Promise<string> {
378
+ //TODO: This can be done with translate, in which case the target language configuration is reused.
379
+ },
366
380
  async translate<T extends Engines>(text: string | string[], opts: EngineTranslateOptions<T>) {
367
381
  const { from, to } = opts;
368
382
  if (!Array.isArray(text)) {
package/README_zh-CN.md CHANGED
@@ -76,7 +76,7 @@ Translate 是一个支持多翻译引擎的翻译工具库,它提供了一套
76
76
  const { translator, engines } = required("@yxw007/translate")
77
77
  ```
78
78
 
79
- - example
79
+ - 翻译例子
80
80
  ```typescript
81
81
  translator.addEngine(engines.google());
82
82
  const res1 = await translator.translate("hello", { from: "en", to: "zh" });
@@ -91,6 +91,17 @@ Translate 是一个支持多翻译引擎的翻译工具库,它提供了一套
91
91
  ['你好']
92
92
  ["你好", "好的"]
93
93
  ```
94
+ - 语言检测例子
95
+ ```typescript
96
+ translator.addEngine(engines.google());
97
+ const res1 = await translator.checkLanguage("hello", { engine:"google" });
98
+ console.log(res1);
99
+ ```
100
+
101
+ 输出结果
102
+ ```bash
103
+ en
104
+ ```
94
105
 
95
106
  ### Browser
96
107
 
@@ -365,6 +376,9 @@ export interface TencentEngineOption extends BaseEngineOption {
365
376
  const base = "https://translate.yandex.net/api/v1.5/tr.json/translate";
366
377
  return {
367
378
  name: "xx",
379
+ async checkLanguage<T extends Engines>(text: string): Promise<string> {
380
+ //TODO: 可以用translate来实现,这样的话就复用target语言配置
381
+ },
368
382
  async translate<T extends Engines>(text: string | string[], opts: EngineTranslateOptions<T>) {
369
383
  const { from, to } = opts;
370
384
  if (!Array.isArray(text)) {
@@ -1,4 +1,4 @@
1
- // translate v0.3.2 Copyright (c) 2025 Potter<aa4790139@gmail.com> and contributors
1
+ // translate v0.4.1 Copyright (c) 2025 Potter<aa4790139@gmail.com> and contributors
2
2
  'use strict';
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
@@ -17,6 +17,14 @@ class TranslationError extends Error {
17
17
  Error.captureStackTrace(this, this.constructor);
18
18
  }
19
19
  }
20
+ class CheckLanguageError extends Error {
21
+ region;
22
+ constructor(region, message) {
23
+ super(message);
24
+ this.region = region;
25
+ Error.captureStackTrace(this, this.constructor);
26
+ }
27
+ }
20
28
  const OPEN_AI_MODELS = [
21
29
  "o1-preview",
22
30
  "o1-preview-2024-09-12",
@@ -231,6 +239,22 @@ function google(options) {
231
239
  }
232
240
  return translations;
233
241
  },
242
+ async checkLanguage(text) {
243
+ const url = `${base}?client=gtx&sl=auto&tl=en&dt=t&q=${encodeURI(text)}`;
244
+ const res = await fetch(url);
245
+ if (!res.ok) {
246
+ throw await throwResponseError(this.name, res);
247
+ }
248
+ const body = await res.json();
249
+ if (!body || body.length < 3) {
250
+ throw new CheckLanguageError(this.name, "Check language fail! No result returned");
251
+ }
252
+ const detectedLanguage = body[2];
253
+ if (!detectedLanguage) {
254
+ throw new CheckLanguageError(this.name, "Check language fail! Language not detected");
255
+ }
256
+ return detectedLanguage;
257
+ },
234
258
  };
235
259
  }
236
260
 
@@ -270,7 +294,7 @@ function azure$1(options) {
270
294
  }
271
295
  const bodyRes = await res.json();
272
296
  if (bodyRes.error) {
273
- throw new TranslationError(this.name, `Translate fail ! code: ${bodyRes.error.code}, message: ${bodyRes.error.message}`);
297
+ throw new TranslationError(this.name, `Translate fail ! code: ${bodyRes.error.code}, message: ${bodyRes.error.message} \n Go to https://learn.microsoft.com/zh-cn/azure/ai-services/translator/text-translation/reference/v3/translate view details`);
274
298
  }
275
299
  const body = bodyRes;
276
300
  if (!body || body.length === 0) {
@@ -285,6 +309,34 @@ function azure$1(options) {
285
309
  }
286
310
  return translations;
287
311
  },
312
+ async checkLanguage(text) {
313
+ checkOptions();
314
+ const url = `${base}&to=en`;
315
+ const res = await fetch(url, {
316
+ method: "POST",
317
+ headers: {
318
+ "Content-Type": "application/json; charset=UTF-8",
319
+ "Ocp-Apim-Subscription-Key": key,
320
+ "Ocp-Apim-Subscription-Region": region,
321
+ },
322
+ body: JSON.stringify([{ Text: text }]),
323
+ });
324
+ if (!res.ok) {
325
+ throw await throwResponseError(this.name, res);
326
+ }
327
+ const bodyRes = await res.json();
328
+ if (bodyRes.error) {
329
+ throw new CheckLanguageError(this.name, `checkLanguage fail ! code: ${bodyRes.error.code}, message: ${bodyRes.error.message} \n Go to https://learn.microsoft.com/zh-cn/azure/ai-services/translator/text-translation/reference/v3/translate view details`);
330
+ }
331
+ if (!bodyRes || !Array.isArray(bodyRes) || bodyRes.length === 0) {
332
+ throw new CheckLanguageError(this.name, "Check language fail! No result returned");
333
+ }
334
+ const detectedLanguage = bodyRes[0]?.detectedLanguage?.language;
335
+ if (!detectedLanguage) {
336
+ throw new CheckLanguageError(this.name, "Check language fail! Language not detected");
337
+ }
338
+ return detectedLanguage;
339
+ },
288
340
  };
289
341
  }
290
342
 
@@ -319,6 +371,28 @@ function amazon$1(options) {
319
371
  }
320
372
  return translations;
321
373
  },
374
+ async checkLanguage(text) {
375
+ checkOptions();
376
+ const translateClient = new clientTranslate.TranslateClient({
377
+ region: region,
378
+ credentials: { accessKeyId, secretAccessKey },
379
+ });
380
+ const command = new clientTranslate.TranslateTextCommand({
381
+ SourceLanguageCode: "auto",
382
+ TargetLanguageCode: "en",
383
+ Text: text,
384
+ });
385
+ try {
386
+ const response = await translateClient.send(command);
387
+ if (!response.SourceLanguageCode) {
388
+ throw new TranslationError(name, "Check language fail! Source language not detected");
389
+ }
390
+ return response.SourceLanguageCode;
391
+ }
392
+ catch (error) {
393
+ throw new TranslationError(name, `Check language fail! ${error.message || error}`);
394
+ }
395
+ },
322
396
  };
323
397
  }
324
398
 
@@ -1445,7 +1519,7 @@ function requireCore () {
1445
1519
  var md5Exports = md5$1.exports;
1446
1520
  var md5 = /*@__PURE__*/getDefaultExportFromCjs(md5Exports);
1447
1521
 
1448
- function baidu$1(options) {
1522
+ function baidu$2(options) {
1449
1523
  const { appId, secretKey } = options;
1450
1524
  const url = "https://fanyi-api.baidu.com/api/trans/vip/fieldtranslate";
1451
1525
  const name = "baidu";
@@ -1486,7 +1560,7 @@ function baidu$1(options) {
1486
1560
  }
1487
1561
  const data = await res.json();
1488
1562
  if (!data || data.error_code || !data.trans_result || data.trans_result.length === 0) {
1489
- throw new TranslationError(this.name, `Translate fail ! error_code:${data.error_code}, error_msg: ${data.error_msg}`);
1563
+ throw new TranslationError(this.name, `Translate fail ! error_code:${data.error_code}, error_msg: ${data.error_msg} \n Go to https://fanyi-api.baidu.com/product/123 view details`);
1490
1564
  }
1491
1565
  const translations = [];
1492
1566
  for (const translation of data.trans_result) {
@@ -1496,6 +1570,31 @@ function baidu$1(options) {
1496
1570
  }
1497
1571
  return translations;
1498
1572
  },
1573
+ async checkLanguage(text) {
1574
+ checkOptions();
1575
+ const salt = Date.now();
1576
+ const sign = md5(`${appId}${text}${salt}${secretKey}`).toString();
1577
+ const body = new URLSearchParams();
1578
+ body.append("q", text);
1579
+ body.append("appid", appId);
1580
+ body.append("salt", salt.toString());
1581
+ body.append("sign", sign);
1582
+ const res = await fetch("https://fanyi-api.baidu.com/api/trans/vip/language", {
1583
+ method: "POST",
1584
+ headers: {
1585
+ "Content-Type": "application/x-www-form-urlencoded",
1586
+ },
1587
+ body: body.toString(),
1588
+ });
1589
+ if (!res.ok) {
1590
+ throw await throwResponseError(this.name, res);
1591
+ }
1592
+ const response = await res.json();
1593
+ if (!response || response.error_code != 0) {
1594
+ throw new CheckLanguageError(this.name, `Check language fail ! error_code:${response.error_code}, error_msg: ${response.error_msg} \n Go to https://fanyi-api.baidu.com/product/143 view details`);
1595
+ }
1596
+ return response.data.src;
1597
+ },
1499
1598
  };
1500
1599
  }
1501
1600
 
@@ -1546,6 +1645,39 @@ function deepl$2(options) {
1546
1645
  const translations = body.map((t) => t.text);
1547
1646
  return translations;
1548
1647
  },
1648
+ async checkLanguage(text) {
1649
+ checkOptions();
1650
+ const res = await fetch(url, {
1651
+ method: "POST",
1652
+ headers: {
1653
+ "Content-Type": "application/json; charset=UTF-8",
1654
+ Authorization: `DeepL-Auth-Key ${key}`,
1655
+ Accept: "*/*",
1656
+ Host: "api-free.deepl.com",
1657
+ Connection: "keep-alive",
1658
+ },
1659
+ body: JSON.stringify({
1660
+ text: [text],
1661
+ target_lang: "EN",
1662
+ }),
1663
+ });
1664
+ if (!res.ok) {
1665
+ throw await throwResponseError(this.name, res);
1666
+ }
1667
+ const bodyRes = await res.json();
1668
+ if (bodyRes.error) {
1669
+ throw new CheckLanguageError(this.name, `Check language fail ! code: ${bodyRes.error.code}, message: ${bodyRes.error.message}`);
1670
+ }
1671
+ const body = bodyRes.translations;
1672
+ if (!body || body.length === 0) {
1673
+ throw new CheckLanguageError(this.name, "Check language fail! No result returned");
1674
+ }
1675
+ const detectedLanguage = body[0].detected_source_language;
1676
+ if (!detectedLanguage) {
1677
+ throw new CheckLanguageError(this.name, "Check language fail! Language not detected");
1678
+ }
1679
+ return detectedLanguage;
1680
+ },
1549
1681
  };
1550
1682
  }
1551
1683
 
@@ -1728,7 +1860,7 @@ function tencent$2(options) {
1728
1860
  }
1729
1861
  const data = await res.json();
1730
1862
  if (data.Response?.Error) {
1731
- throw new TranslationError(name, `Tencent translate fail: ${data.Response.Error.Code}, ${data.Response.Error.Message}`);
1863
+ throw new TranslationError(name, `Tencent translate fail: ${data.Response.Error.Code}, ${data.Response.Error.Message} \n Go to https://cloud.tencent.com/document/product/551/15619 view details`);
1732
1864
  }
1733
1865
  const translatedResults = data.Response?.TargetText.split("\n") ?? [];
1734
1866
  if (!Array.isArray(translatedResults) || translatedResults.length === 0) {
@@ -1742,6 +1874,51 @@ function tencent$2(options) {
1742
1874
  throw new TranslationError(name, `Translation failed: ${error}`);
1743
1875
  }
1744
1876
  },
1877
+ async checkLanguage(text) {
1878
+ checkOptions();
1879
+ const payloadObj = {
1880
+ SourceText: text,
1881
+ Source: "auto",
1882
+ Target: "en",
1883
+ ProjectId: 0,
1884
+ };
1885
+ const payload = JSON.stringify(payloadObj);
1886
+ const headers = buildAuthorization({
1887
+ secretId,
1888
+ secretKey,
1889
+ service,
1890
+ host,
1891
+ payload,
1892
+ httpRequestMethod: "POST",
1893
+ action,
1894
+ apiVersion,
1895
+ region,
1896
+ });
1897
+ try {
1898
+ const res = await fetch(endpoint, {
1899
+ method: "POST",
1900
+ headers,
1901
+ body: payload,
1902
+ });
1903
+ if (!res.ok) {
1904
+ throw new CheckLanguageError(name, `HTTP ${res.status}: ${await res.text()}`);
1905
+ }
1906
+ const data = await res.json();
1907
+ if (data.Response?.Error) {
1908
+ throw new CheckLanguageError(name, `Tencent language detect fail: ${data.Response.Error.Code}, ${data.Response.Error.Message} \n Go to https://cloud.tencent.com/document/product/551/15619 view details`);
1909
+ }
1910
+ const detectedLanguage = data.Response?.Source;
1911
+ if (!detectedLanguage) {
1912
+ throw new CheckLanguageError(name, "Language detect fail! No result returned");
1913
+ }
1914
+ return detectedLanguage;
1915
+ }
1916
+ catch (error) {
1917
+ if (error instanceof CheckLanguageError)
1918
+ throw error;
1919
+ throw new CheckLanguageError(name, `Language detection failed: ${error}`);
1920
+ }
1921
+ },
1745
1922
  };
1746
1923
  }
1747
1924
 
@@ -1749,7 +1926,7 @@ const engines = {
1749
1926
  google,
1750
1927
  azure: azure$1,
1751
1928
  amazon: amazon$1,
1752
- baidu: baidu$1,
1929
+ baidu: baidu$2,
1753
1930
  deepl: deepl$2,
1754
1931
  openai: openai$1,
1755
1932
  tencent: tencent$2,
@@ -2139,7 +2316,7 @@ var openai = {
2139
2316
  Zulu: "zu",
2140
2317
  };
2141
2318
 
2142
- var baidu = {
2319
+ var baidu$1 = {
2143
2320
  Achinese: "ach",
2144
2321
  Afrikaans: "afr",
2145
2322
  Akan: "aka",
@@ -2489,7 +2666,7 @@ var amazon = {
2489
2666
  const originLanguages = {
2490
2667
  azure: azure,
2491
2668
  google: openai,
2492
- baidu: baidu,
2669
+ baidu: baidu$1,
2493
2670
  deepl: deepl$1,
2494
2671
  amazon: amazon,
2495
2672
  openai: openai,
@@ -2559,13 +2736,26 @@ var tencent = {
2559
2736
  const targetLanguages = {
2560
2737
  azure: azure,
2561
2738
  google: openai,
2562
- baidu: baidu,
2739
+ baidu: baidu$1,
2563
2740
  deepl: deepl,
2564
2741
  amazon: amazon,
2565
2742
  openai: openai,
2566
2743
  tencent: tencent,
2567
2744
  };
2568
2745
 
2746
+ var baidu = {
2747
+ Chinese: "zh",
2748
+ English: "en",
2749
+ Japanese: "jp",
2750
+ Korean: "kor",
2751
+ Thai: "th",
2752
+ Russian: "ru",
2753
+ };
2754
+
2755
+ const checkLanguages = Object.assign(Object.assign({}, originLanguages), {
2756
+ baidu: baidu,
2757
+ });
2758
+
2569
2759
  function normalFromLanguage(from, engine) {
2570
2760
  if (from === "auto") {
2571
2761
  return "auto";
@@ -2644,6 +2834,42 @@ class Translator {
2644
2834
  }
2645
2835
  this.engines.delete(engineName);
2646
2836
  }
2837
+ isSupportCheckLanguage(engineName) {
2838
+ if (!engineName || !this.engines.has(engineName)) {
2839
+ logger.warn("Engine name is required or not found");
2840
+ return false;
2841
+ }
2842
+ const engine = this.engines.get(engineName);
2843
+ if (!engine) {
2844
+ logger.warn(`Engine ${engineName} not found`);
2845
+ return false;
2846
+ }
2847
+ return !!engine.checkLanguage;
2848
+ }
2849
+ async checkLanguage(text, options) {
2850
+ const { engine = "google", max_character_num = defaultMaxCharacterNum } = options;
2851
+ if (!this.engines.has(engine)) {
2852
+ throw new CheckLanguageError(appName, `Engine ${engine} not found`);
2853
+ }
2854
+ const engineInstance = this.engines.get(engine);
2855
+ if (!engineInstance) {
2856
+ throw new CheckLanguageError(appName, `Engine ${engine} is null`);
2857
+ }
2858
+ if (!engineInstance.checkLanguage) {
2859
+ throw new CheckLanguageError(appName, `Engine ${engine} does not support checkLanguage method`);
2860
+ }
2861
+ const sample = max_character_num > 0 ? text.substring(0, max_character_num) : text;
2862
+ if (sample.length <= 0) {
2863
+ throw new TranslationError(appName, "Text is empty or too short to check language");
2864
+ }
2865
+ return engineInstance
2866
+ .checkLanguage(sample)
2867
+ .then((r) => r)
2868
+ .catch((e) => {
2869
+ logger.error(`${appName} Failed to check language for text: \n${getGapLine()}\n${text}\n${getGapLine()}\n error: ${getErrorMessages(e)}`);
2870
+ throw e;
2871
+ });
2872
+ }
2647
2873
  async translate(text, options) {
2648
2874
  const { engine = "google", cache_time = 60 * 1000 } = options;
2649
2875
  let { from = "auto", to } = options;
@@ -2655,7 +2881,7 @@ class Translator {
2655
2881
  }
2656
2882
  const engineInstance = this.engines.get(engine);
2657
2883
  if (!engineInstance) {
2658
- throw new TranslationError(appName, `Engine ${engine} not found`);
2884
+ throw new TranslationError(appName, `Engine ${engine} is null`);
2659
2885
  }
2660
2886
  if (!from) {
2661
2887
  throw new TranslationError(appName, `Invalid origin language ${from}`);
@@ -2743,11 +2969,16 @@ var index = {
2743
2969
  };
2744
2970
 
2745
2971
  exports.Cache = Cache;
2972
+ exports.CheckLanguageError = CheckLanguageError;
2746
2973
  exports.OPEN_AI_MODELS = OPEN_AI_MODELS;
2747
2974
  exports.TranslationError = TranslationError;
2748
2975
  exports.Translator = Translator;
2976
+ exports.checkLanguages = checkLanguages;
2749
2977
  exports.default = index;
2750
2978
  exports.engines = engines;
2751
2979
  exports.getLanguage = getLanguage;
2980
+ exports.normalFromLanguage = normalFromLanguage;
2981
+ exports.normalToLanguage = normalToLanguage;
2982
+ exports.originLanguages = originLanguages;
2983
+ exports.targetLanguages = targetLanguages;
2752
2984
  exports.translator = translator;
2753
- //# sourceMappingURL=index.cjs.map