Skip to content

Commit

Permalink
feat: update supported maximum text length for translation & add scri…
Browse files Browse the repository at this point in the history
…pt to fetch config from bing website
  • Loading branch information
plainheart committed Nov 18, 2023
1 parent 926e2e7 commit 0ed46a4
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 79 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- AUTO-GENERATED. SEE scripts/README.tpl.md FOR ORIGINAL TEMPLATE -->

# bing-translate-api
[![NPM version](https://img.shields.io/npm/v/bing-translate-api.svg?style=flat)](https://www.npmjs.org/package/bing-translate-api)
[![Auto Test](https://github.com/plainheart/bing-translate-api/actions/workflows/autotest.yml/badge.svg)](https://github.com/plainheart/bing-translate-api/actions/workflows/autotest.yml)
Expand Down Expand Up @@ -57,24 +59,23 @@ Translation result
### translate(text, [from], [to], [correct], [raw], [userAgent], [proxyAgents])

#### _text_

Type: `string`

The text to be translated, can't be blank. The **maximum** text length is **1000**.
The text to be translated, can't be blank. The **maximum** text length is **5000**.

##### _from_
Type: `string` Default: `auto-detect`

The language code of source text.

**MUST** be `auto-detect` or one of the codes/names (not case sensitive) contained in [lang.json](https://github.com/plainheart/bing-translate-api/blob/master/src/lang.json)
**MUST** be `auto-detect` or one of the codes/names (not case sensitive) contained in [lang.json](src/lang.json)

##### _to_
Type: `string` Default: `en`

The language in which the text should be translated.

**MUST** be one of the codes/names (not case sensitive) contained in [lang.json](https://github.com/plainheart/bing-translate-api/blob/master/src/lang.json).
**MUST** be one of the codes/names (not case sensitive) contained in [lang.json](src/lang.json).

##### _correct_
Type: `boolean` Default: `false` Since: `v1.1.0`
Expand All @@ -83,7 +84,7 @@ Whether to correct the input text.

Note that:
1) There is currently a **limit** of **50 characters** for correction service.
2) **Only** [the languages in the list](https://github.com/plainheart/bing-translate-api/blob/master/src/lang.js#L10-L29) are supported to be corrected.
2) **Only** [the languages in the list](src/config.json#L7-L28) are supported to be corrected.

##### _raw_
Type: `boolean` Default: `false`
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"typings": "index.d.ts",
"scripts": {
"test": "node test/index.js && node test/lang.js",
"gen:langmap": "node scripts/generate-lang-map.js",
"gen:dts": "node scripts/generate-dts.js"
"gen:config": "node scripts/generate-config.js"
},
"keywords": [
"bing",
Expand Down
116 changes: 116 additions & 0 deletions scripts/README.tpl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# bing-translate-api
[![NPM version](https://img.shields.io/npm/v/bing-translate-api.svg?style=flat)](https://www.npmjs.org/package/bing-translate-api)
[![Auto Test](https://github.com/plainheart/bing-translate-api/actions/workflows/autotest.yml/badge.svg)](https://github.com/plainheart/bing-translate-api/actions/workflows/autotest.yml)
[![NPM Downloads](https://img.shields.io/npm/dm/bing-translate-api.svg)](https://npmcharts.com/compare/bing-translate-api?minimal=true)
[![License](https://img.shields.io/npm/l/bing-translate-api.svg)](https://github.com/plainheart/bing-translate-api/blob/master/LICENSE)

A **simple** and **free** API for [Bing Translator](https://bing.com/translator) for Node.js.

## Install

```
npm install bing-translate-api
```

## Usage

From auto-detected language to English:

```js
const { translate } = require('bing-translate-api');

translate('你好', null, 'en').then(res => {
console.log(res.translation);
}).catch(err => {
console.error(err);
});
```

Translation result

```js
{
// original text
"text": "你好",
// user-specified language code
"userLang": "auto-detect",
// translated text
"translation": "Hello",
// `correctedText` is returned only when `correct` is set as `true`
// supported since v1.1.0
"correctedText": "",
// detected language
"language": {
// language code of translated text
"to": "en",
// detected language code of original text
"from": "zh-Hans",
// score of language detection
// supported since v1.1.0
"score": 1
}
}
```

## API

### translate(text, [from], [to], [correct], [raw], [userAgent], [proxyAgents])

#### _text_
Type: `string`

The text to be translated, can't be blank. The **maximum** text length is **{{maxTextLen}}**.

##### _from_
Type: `string` Default: `auto-detect`

The language code of source text.

**MUST** be `auto-detect` or one of the codes/names (not case sensitive) contained in [lang.json](src/lang.json)

##### _to_
Type: `string` Default: `en`

The language in which the text should be translated.

**MUST** be one of the codes/names (not case sensitive) contained in [lang.json](src/lang.json).

##### _correct_
Type: `boolean` Default: `false` Since: `v1.1.0`

Whether to correct the input text.

Note that:
1) There is currently a **limit** of **{{maxCorrectableTextLen}} characters** for correction service.
2) **Only** [the languages in the list](src/config.json#L7-L28) are supported to be corrected.

##### _raw_
Type: `boolean` Default: `false`

Whether the translation result contains raw response from Bing API.

##### _userAgent_
Type: `string`

The header value of `user-agent` used in API requests.

Default:
```
{{userAgent}}
```

##### _proxyAgents_
Type: [`Got['Agents']`](https://github.com/sindresorhus/got/blob/v11.8.6/source/core/index.ts#L60-L64) Default: `undefined` Since: `v2.4.0`

Set [agents](https://github.com/sindresorhus/got/blob/main/documentation/tips.md#proxying) of [`got`](https://github.com/sindresorhus/got) for proxy.

## License

MIT &copy; 2021-2023 [plainheart](https://github.com/plainheart).

## Thanks

Great thanks to [Bing Translator](https://bing.com/translator) for providing so excellent translation service.

## Related projects
- [Capacitor Bing Translator](https://github.com/sabereen/capacitor-bing-translator) - A fork of this project that works in [Capacitor](https://capacitorjs.com).
59 changes: 59 additions & 0 deletions scripts/generate-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const got = require('got')
const cheerio = require('cheerio')
const fs = require('node:fs')
const path = require('node:path')

const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'

;(async () => {
const { body } = await got('https://bing.com/translator', {
headers: {
'Accept-Language': 'en-US,en'
}
})

// fetch config
const richTranslateParams = JSON.parse(
body.match(/params_RichTranslate\s?=\s?([^;]+);/)[1]
)
const config = {
websiteEndpoint: richTranslateParams[1],
translateEndpoint: richTranslateParams[0],
spellCheckEndpoint: richTranslateParams[33],
maxTextLen: richTranslateParams[5],
maxCorrectableTextLen: richTranslateParams[30],
correctableLangs: richTranslateParams[31],
userAgent: DEFAULT_USER_AGENT
}
fs.writeFileSync(
path.resolve(__dirname, '../src/config.json'),
JSON.stringify(config, null, 2),
{ charset: 'utf-8' }
)
console.log('✔️ Generated config\n', config)

// fetch supported languages
const $ = cheerio.load(body)
const options = $('#t_tgtAllLang').children('option')
const langMap = {}
for (let i = 0, len = options.length, option; i < len; i++) {
option = $(options[i])
langMap[option.attr('value')] = option.text().trim()
}
fs.writeFileSync(
path.resolve(__dirname, '../src/lang.json'),
JSON.stringify(langMap, null, 2),
{ charset: 'utf-8' }
)
console.log()
console.log('✔️ Generated language map\n', langMap)
console.log()

// update ts definition
require('./generate-dts')

console.log()

// generate README
require('./generate-readme')
})()
28 changes: 0 additions & 28 deletions scripts/generate-lang-map.js

This file was deleted.

18 changes: 18 additions & 0 deletions scripts/generate-readme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const fs = require('node:fs')
const path = require('node:path')
const config = require('../src/config')

// generate README from template
let readmeTpl = fs.readFileSync(path.resolve(__dirname, './README.tpl.md'), 'utf-8')
Object.entries(config).forEach(([key, value]) => {
readmeTpl = readmeTpl.replace(`{{${key}}}`, value)
})

fs.writeFileSync(
path.resolve(__dirname, '../README.md'),
'<!-- AUTO-GENERATED. SEE scripts/README.tpl.md FOR ORIGINAL TEMPLATE -->\n\n'
+ readmeTpl,
{ charset: 'utf-8' }
)

console.log('✔️ Generated README.md from template')
30 changes: 30 additions & 0 deletions src/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"websiteEndpoint": "/translator",
"translateEndpoint": "/ttranslatev3?isVertical=1&",
"spellCheckEndpoint": "/tspellcheckv3?isVertical=1&",
"maxTextLen": 5000,
"maxCorrectableTextLen": 50,
"correctableLangs": [
"da",
"en",
"nl",
"fi",
"fr",
"fr-CA",
"de",
"it",
"ja",
"ko",
"no",
"pl",
"pt",
"pt-PT",
"ru",
"es",
"sv",
"tr",
"zh-Hant",
"zh-Hans"
],
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
29 changes: 12 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@
const got = require('got')

const lang = require('./lang')
const config = require('./config.json')

const TRANSLATE_API_ROOT = 'https://{s}bing.com'
const TRANSLATE_WEBSITE = TRANSLATE_API_ROOT + '/translator'
const TRANSLATE_API = TRANSLATE_API_ROOT + '/ttranslatev3?isVertical=1'
const TRANSLATE_API_SPELL_CHECK = TRANSLATE_API_ROOT + '/tspellcheckv3?isVertical=1'

const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'

// PENDING: fetch from `params_RichTranslate`?
const MAX_TEXT_LEN = 1000
// PENDING
const MAX_CORRECT_TEXT_LEN = 50
const TRANSLATE_WEBSITE = TRANSLATE_API_ROOT + config.websiteEndpoint
const TRANSLATE_API = TRANSLATE_API_ROOT + config.translateEndpoint
const TRANSLATE_API_SPELL_CHECK = TRANSLATE_API_ROOT + config.spellCheckEndpoint

// PENDING: make it configurable?
const MAX_RETRY_COUNT = 3
Expand Down Expand Up @@ -80,7 +74,7 @@ async function fetchGlobalConfig(userAgent, proxyAgents) {
replaceSubdomain(TRANSLATE_WEBSITE, subdomain),
{
headers: {
'user-agent': userAgent || USER_AGENT
'user-agent': userAgent || config.userAgent
},
agent: proxyAgents,
retry: {
Expand Down Expand Up @@ -163,7 +157,8 @@ function makeRequestBody(isSpellCheck, text, fromLang, toLang) {
fromLang,
text,
token,
key
key,
edgepdftranslator: 1
}
if (!isSpellCheck) {
toLang && (body.to = toLang)
Expand Down Expand Up @@ -191,8 +186,8 @@ async function translate(text, from, to, correct, raw, userAgent, proxyAgents) {
return
}

if (text.length > MAX_TEXT_LEN) {
throw new Error(`The supported maximum length of text is ${MAX_TEXT_LEN}. Please shorten the text.`)
if (text.length > config.maxTextLen) {
throw new Error(`The supported maximum length of text is ${config.maxTextLen}. Please shorten the text.`)
}

if (!globalConfigPromise) {
Expand Down Expand Up @@ -224,7 +219,7 @@ async function translate(text, from, to, correct, raw, userAgent, proxyAgents) {
const requestBody = makeRequestBody(false, text, from, to === 'auto-detect' ? 'en' : to)

const requestHeaders = {
'user-agent': userAgent || USER_AGENT,
'user-agent': userAgent || config.userAgent,
referer: replaceSubdomain(TRANSLATE_WEBSITE, globalConfig.subdomain),
cookie: globalConfig.cookie
}
Expand Down Expand Up @@ -289,7 +284,7 @@ async function translate(text, from, to, correct, raw, userAgent, proxyAgents) {
// currently, there is a limit of 50 characters for correction service
// and only parts of languages are supported
// otherwise, it will return status code 400
if (len <= MAX_CORRECT_TEXT_LEN && lang.isCorrectable(correctLang)) {
if (len <= config.maxCorrectableTextLen && lang.isCorrectable(correctLang)) {
const requestURL = makeRequestURL(true)
const requestBody = makeRequestBody(true, text, correctLang)

Expand All @@ -304,7 +299,7 @@ async function translate(text, from, to, correct, raw, userAgent, proxyAgents) {
res.correctedText = body && body.correctedText
}
else {
console.warn(`The detected language '${correctLang}' is not supported to be corrected or the length of text is more than ${MAX_CORRECT_TEXT_LEN}.`)
console.warn(`The detected language '${correctLang}' is not supported to be corrected or the length of text is more than ${config.maxCorrectableTextLen}.`)
}
}

Expand Down
Loading

0 comments on commit 0ed46a4

Please sign in to comment.