Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ddict/translate

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ddict/translate - npm Package Compare versions

Comparing version 0.1.3 to 1.0.0

.eslintrc.cjs

21

package.json
{
"name": "@ddict/translate",
"version": "0.1.3",
"version": "1.0.0",
"description": "",

@@ -8,3 +8,6 @@ "main": "src",

"scripts": {
"test": "ava src"
"test": "ava src",
"lint": "eslint . --ext .js --fix --ignore-path .gitignore",
"format": "prettier --write src/",
"format-check": "prettier --check src/"
},

@@ -14,13 +17,9 @@ "repository": "git@github.com:ddict/translate.git",

"license": "UNLICENSED",
"dependencies": {},
"devDependencies": {
"ava": "^4.0.1",
"esm": "^3.2.25",
"node-fetch": "^2.1.2"
},
"ava": {
"require": [
"esm"
]
"@rushstack/eslint-patch": "^1.10.3",
"ava": "^6.1.3",
"eslint": "^8.57.0",
"node-fetch": "^3.3.2",
"prettier": "^3.3.3"
}
}
export default {
getLanguages,
translate,
tts,
getLanguages,
translate,
tts,
reviseTranslation,
}

@@ -9,3 +10,2 @@

const DEFAULT_COUNTRY = 'US'
const DEFAULT_LANG = 'en'

@@ -21,47 +21,47 @@ const DEFAULT_ENCODING = 'UTF-8'

function getLanguages(lang = 'en') {
const endpoint = 'https://translate.google.com/translate_a/l'
const qs = {
hl: lang,
client: 'it',
oe: DEFAULT_ENCODING,
ie: DEFAULT_ENCODING,
}
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
},
}
const endpoint = 'https://translate.google.com/translate_a/l'
const qs = {
hl: lang,
client: 'it',
oe: DEFAULT_ENCODING,
ie: DEFAULT_ENCODING,
}
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
},
}
}
function translate(lang = DEFAULT_LANG, question, src, target, simple = false) {
if (question.length > MAX_LENGTH) {
throw new Error(`Maximum text length exceeded: ${MAX_LENGTH}`)
}
if (question.length > MAX_LENGTH) {
throw new Error(`Maximum text length exceeded: ${MAX_LENGTH}`)
}
const endpoint = 'https://translate.google.com/translate_a/single'
const qs = {
q: question,
sl: src,
tl: target,
hl: lang,
client: 'it',
dt: ['t', 'rmt', 'bd', 'rms', 'qca', 'ss', 'md', 'ld', 'ex', 'rw'],
otf: '2', // ?
dj: '1', // json object instead of array
ie: DEFAULT_ENCODING,
oe: DEFAULT_ENCODING,
}
const endpoint = 'https://translate.google.com/translate_a/single'
const qs = {
q: question,
sl: src,
tl: target,
hl: lang,
client: 'it',
dt: ['t', 'rmt', 'bd', 'rms', 'qca', 'ss', 'md', 'ld', 'ex', 'rw'],
otf: '2', // ?
dj: '1', // json object instead of array
ie: DEFAULT_ENCODING,
oe: DEFAULT_ENCODING,
}
// simple
if (simple) qs.dt = 't'
// simple
if (simple) qs.dt = 't'
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
},
}
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
},
}
}

@@ -72,33 +72,101 @@

function tts(lang = DEFAULT_LANG, question, src = 'input', target) {
// TODO: break by \n \r\n . ,
// TODO: break by \n \r\n . ,
// cap by MAX_TTS_LENGTH
question = question.substring(0, MAX_TTS_LENGTH)
// cap by MAX_TTS_LENGTH
question = question.substring(0, MAX_TTS_LENGTH)
// src can be 'input' or 'target'
if (src !== 'input' && src !== 'target') {
src = 'input'
}
// src can be 'input' or 'target'
if (src !== 'input' && src !== 'target') {
src = 'input'
}
const endpoint = 'https://translate.google.com/translate_tts'
const qs = {
q: question,
tl: target,
hl: lang,
client: 'it',
total: '1', // 1 or 2
idx: '0',
textlen: question.length,
prev: src,
ie: DEFAULT_ENCODING,
}
const endpoint = 'https://translate.google.com/translate_tts'
const qs = {
q: question,
tl: target,
hl: lang,
client: 'it',
total: '1', // 1 or 2
idx: '0',
textlen: question.length,
prev: src,
ie: DEFAULT_ENCODING,
}
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
Connection: 'keep-alive',
},
}
}
return {
url: Helper.makeURL(endpoint, qs),
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
Connection: 'keep-alive',
},
}
}
function reviseTranslation(googleData, target, text) {
if (!target || typeof target !== 'string' || target.length < 2) {
throw new Error('Invalid input format: target code language')
}
if (!googleData || typeof googleData !== 'object') {
throw new Error('Invalid input format: expected an object')
}
const { sentences, dict, src, definitions, examples, synsets } = googleData
if (!sentences || !Array.isArray(sentences) || sentences.length === 0) {
throw new Error('Invalid input format: missing or empty sentences array')
}
const ddictData = {
service: 'google',
src: src || '',
target,
text,
phonetic: {},
result: sentences.map((sentence) => sentence.trans).join(''),
dictionary: [],
definitions: [],
synonyms: [],
examples: [],
}
// Set phonetic
ddictData.phonetic.src = sentences.find((s) => s.src_translit)?.src_translit || ''
// Set dictionary
if (dict && Array.isArray(dict)) {
ddictData.dictionary = dict.map((entry) => ({
pos: entry.pos || '',
terms: entry.terms || [],
items: entry.entry || [],
}))
}
// Set definitions
if (definitions && Array.isArray(definitions)) {
ddictData.definitions = definitions.map((def) => ({
pos: def.pos || '',
items: def.entry.map((item) => ({
gloss: item.gloss || '',
example: item.example || '',
})),
}))
}
// Set examples
if (examples && examples.example && Array.isArray(examples.example)) {
ddictData.examples = examples.example.map((ex) => ex.text || '')
}
// Set synonyms
if (synsets && Array.isArray(synsets)) {
ddictData.synonyms = synsets.map((syn) => ({
pos: syn.pos || '',
terms: syn.terms || [],
items: syn.entry || [],
}))
}
return ddictData
}
import test from 'ava'
import { readFileSync } from 'fs'

@@ -10,2 +11,3 @@ import Google from './index.js'

const TEST_QUESTION = 'hello'
const TEST_QUESTION_2 = 'hello world, my name is John'
const TEST_SRC = 'en'

@@ -16,74 +18,163 @@ const TEST_TARGET = 'vi'

const agent = new https.Agent({
keepAlive: true,
keepAlive: true,
})
test('getLanguages', async (t) => {
const rq = Google.getLanguages(TEST_LANG)
const rq = Google.getLanguages(TEST_LANG)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const json = await res.json()
// console.log('getLanguages:', JSON.stringify(json, undefined, 2))
const json = await res.json()
// console.log('getLanguages:', JSON.stringify(json, undefined, 2))
t.true(json.hasOwnProperty('sl'))
t.true(json.hasOwnProperty('tl'))
t.true(Object.prototype.hasOwnProperty.call(json, 'sl'))
t.true(Object.prototype.hasOwnProperty.call(json, 'tl'))
})
test('translate', async (t) => {
const rq = Google.translate(TEST_LANG, TEST_QUESTION, TEST_SRC, TEST_TARGET)
const rq = Google.translate(TEST_LANG, TEST_QUESTION, TEST_SRC, TEST_TARGET)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const json = await res.json()
// console.log('translate:', JSON.stringify(json, undefined, 2))
const json = await res.json()
// console.log('translate:', JSON.stringify(json, undefined, 2))
t.true(json.hasOwnProperty('sentences'))
t.true(json.hasOwnProperty('dict'))
t.true(json.hasOwnProperty('src'))
t.true(json.hasOwnProperty('definitions'))
t.true(json.hasOwnProperty('examples'))
// synsets
// related_words
t.true(Object.prototype.hasOwnProperty.call(json, 'sentences'))
t.true(Object.prototype.hasOwnProperty.call(json, 'dict'))
t.true(Object.prototype.hasOwnProperty.call(json, 'src'))
t.true(Object.prototype.hasOwnProperty.call(json, 'definitions'))
t.true(Object.prototype.hasOwnProperty.call(json, 'examples'))
// synsets
// related_words
})
test('translate simple', async (t) => {
const rq = Google.translate(
TEST_LANG,
TEST_QUESTION,
TEST_SRC,
TEST_TARGET,
true
)
const rq = Google.translate(TEST_LANG, TEST_QUESTION, TEST_SRC, TEST_TARGET, true)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const json = await res.json()
const json = await res.json()
t.true(json.hasOwnProperty('sentences'))
t.true(json.hasOwnProperty('src'))
t.true(Object.prototype.hasOwnProperty.call(json, 'sentences'))
t.true(Object.prototype.hasOwnProperty.call(json, 'src'))
})
test('tts', async (t) => {
const rq = Google.tts(TEST_LANG, TEST_QUESTION, 'input', TEST_SRC)
const rq = Google.tts(TEST_LANG, TEST_QUESTION, 'input', TEST_SRC)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const data = await res.blob()
t.is(data.type, 'audio/mpeg')
})
const data = await res.blob()
t.is(data.type, 'audio/mpeg')
})
test('reviseTranslation-data-1', async (t) => {
const sample = JSON.parse(readFileSync('src/sample-data/google-translate-test-1.json'))
const expected = JSON.parse(readFileSync('src/sample-data/google-translate-expect-1.json'))
const target = 'vi'
const text = sample.sentences.map((sentence) => sentence.orig).join('')
t.deepEqual(Google.reviseTranslation(sample, target, text), expected)
})
test('reviseTranslation-data-2', async (t) => {
const sample = JSON.parse(readFileSync('src/sample-data/google-translate-test-2.json'))
const expected = JSON.parse(readFileSync('src/sample-data/google-translate-expect-2.json'))
const target = 'vi'
const text = sample.sentences.map((sentence) => sentence.orig).join('')
t.deepEqual(Google.reviseTranslation(sample, target, text), expected)
})
test('reviseTranslation-data-3', async (t) => {
const sample = JSON.parse(readFileSync('src/sample-data/google-translate-test-3.json'))
const expected = JSON.parse(readFileSync('src/sample-data/google-translate-expect-3.json'))
const target = 'vi'
const text = sample.sentences.map((sentence) => sentence.orig).join('')
t.deepEqual(Google.reviseTranslation(sample, target, text), expected)
})
test('throw an error for invalid input', (t) => {
t.throws(() => Google.reviseTranslation(null, null), {
message: 'Invalid input format: target code language',
})
t.throws(() => Google.reviseTranslation(null, 'vi'), {
message: 'Invalid input format: expected an object',
})
t.throws(() => Google.reviseTranslation({}, 'vi'), {
message: 'Invalid input format: missing or empty sentences array',
})
})
test('handle missing optional fields', (t) => {
const minimalGoogleData = {
sentences: [{ orig: 'test', trans: 'kiểm tra' }],
src: 'en',
}
const target = 've'
const text = 'test'
const expected = {
src: 'en',
target,
text,
phonetic: {
src: '',
},
result: 'kiểm tra',
dictionary: [],
definitions: [],
synonyms: [],
examples: [],
}
t.deepEqual(Google.reviseTranslation(minimalGoogleData, target, text), expected)
})
test('reviseTranslation from GG-Translate real-1', async (t) => {
const rq = Google.translate(TEST_LANG, TEST_QUESTION, TEST_SRC, TEST_TARGET)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const sample = await res.json()
const expected = JSON.parse(readFileSync('src/sample-data/google-translate-expect-real-1.json'))
t.deepEqual(Google.reviseTranslation(sample, TEST_TARGET, TEST_QUESTION), expected)
})
test('reviseTranslation from GG-Translate real-2', async (t) => {
const rq = Google.translate(TEST_LANG, TEST_QUESTION_2, TEST_SRC, TEST_TARGET)
const res = await fetch(rq.url, {
method: rq.method,
headers: rq.headers,
agent: agent,
})
const sample = await res.json()
const expected = JSON.parse(readFileSync('src/sample-data/google-translate-expect-real-2.json'))
t.deepEqual(Google.reviseTranslation(sample, TEST_TARGET, TEST_QUESTION_2), expected)
})
export default { makeURL, qs }
function makeURL(endpoint = '', query = {}) {
return `${endpoint}?${qs(query)}`
return `${endpoint}?${qs(query)}`
}
function qs(query = {}) {
const nonArray = {}
const array = {}
let str = ''
const nonArray = {}
const array = {}
let str = ''
for (const key in query) {
const val = query[key]
if (!Array.isArray(val)) {
nonArray[key] = val
continue
}
array[key] = val
for (const key in query) {
const val = query[key]
if (!Array.isArray(val)) {
nonArray[key] = val
continue
}
str = new URLSearchParams(nonArray).toString()
array[key] = val
}
for (const key in array) {
str += '&'
str = new URLSearchParams(nonArray).toString()
const val = query[key]
const arr = []
for (const key in array) {
str += '&'
for (const ele of val) {
arr.push(new URLSearchParams({ [key]: ele }).toString())
}
const val = query[key]
const arr = []
str += arr.join('&')
for (const ele of val) {
arr.push(new URLSearchParams({ [key]: ele }).toString())
}
return str
str += arr.join('&')
}
return str
}

@@ -6,21 +6,20 @@ import test from 'ava'

test('qs', (t) => {
const qs = Helper.qs({a: 1, b: 2})
t.is(qs, 'a=1&b=2')
const qs = Helper.qs({ a: 1, b: 2 })
t.is(qs, 'a=1&b=2')
})
test('qs:word', (t) => {
const qs = Helper.qs({a: 1, b: 'hello world'})
t.is(qs, 'a=1&b=hello+world')
const qs = Helper.qs({ a: 1, b: 'hello world' })
t.is(qs, 'a=1&b=hello+world')
})
test('qs:array', (t) => {
const qs = Helper.qs({a: 1, b: [2, 3]})
t.is(qs, 'a=1&b=2&b=3')
const qs = Helper.qs({ a: 1, b: [2, 3] })
t.is(qs, 'a=1&b=2&b=3')
})
test('qs:arrayWord', (t) => {
const qs = Helper.qs({a: 'hello world', b: ['ok then', 'i\'m fine']})
console.log(qs)
t.is(qs, 'a=hello+world&b=ok+then&b=i%27m+fine')
const qs = Helper.qs({ a: 'hello world', b: ['ok then', "i'm fine"] })
console.log(qs)
t.is(qs, 'a=hello+world&b=ok+then&b=i%27m+fine')
})
import google from './google'
export default {
google,
}
google,
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc