diff --git a/config/LingoCloud.yaml b/config/LingoCloud.yaml new file mode 100644 index 0000000..a0914b0 --- /dev/null +++ b/config/LingoCloud.yaml @@ -0,0 +1,7 @@ +en: + - zh +ja: + - zh +zh: + - ja + - en diff --git a/lib/mt/LingoCloud.js b/lib/mt/LingoCloud.js new file mode 100644 index 0000000..76498ad --- /dev/null +++ b/lib/mt/LingoCloud.js @@ -0,0 +1,101 @@ +'use strict'; + +const preq = require( 'preq' ), + MTClient = require( './MTClient.js' ); + +class LingoCloud extends MTClient { + + /** + * Translate html or plain text content with Yandex. + * Yandex is capable of translating plain text and html with + * annotations mapping (keeps markup retained in translated content). + * Hence overriding translate method of MTClient. + * + * @param {string} sourceLang Source language code + * @param {string} targetLang Target language code + * @param {string} sourceText Source language text + * @return {Q.Promise} Target language text + */ + translateText( sourceLang, targetLang, sourceText ) { + var key, postData; + + key = this.conf.mt.LingoCloud.key; + if ( key === null ) { + return Promise.reject( new Error( 'LingoCloud service is misconfigured' ) ); + } + + if ( sourceText.length > 10000 ) { + return Promise.reject( new Error( 'Source text too long: ' + + sourceLang + '-' + targetLang ) ); + } + + postData = { + uri: this.conf.mt.LingoCloud.api + '/v1/translator', + headers: { + 'x-authorization': 'token ' + key, + 'cache-control': 'no-cache', + 'content-type': 'application/json' + }, + body: { + request_id: 'wikimedia', replaced: true, cached: true, + trans_type: sourceLang + '2' + targetLang, + source: [ sourceText ], + model: 'v2' + } + }; + + return preq.post( postData ) + .then( ( response ) => { + var target, body = response.body; + if ( 'target' in body ) { + target = response.body.target; + if ( target instanceof Array ) { + return target.join( '' ); + } else { + return target; + } + } else { + if ( response.status === 200 ) { + throw new Error( 'Translation with LingoCloud failed. Error: ' + + this.getErrorName( response.body.error ) + + ` for ${sourceLang} + '>' + ${targetLang}: ` ); + } else { + throw new Error( 'Translation with LingoCloud failed. Error: ' + + this.getErrorName( response.status ) + + ` for ${sourceLang} + '>' + ${targetLang}: ` ); + } + } + } ); + } + + /** + * Returns error name from error code. + * + * @param {number} code Error code + * @return {string} + */ + getErrorName( code ) { + const errormap = { + 200: 'ERR_OK', + 401: 'ERR_KEY_INVALID', + 402: 'ERR_KEY_BLOCKED', + 403: 'ERR_DAILY_REQ_LIMIT_EXCEEDED', + 404: 'ERR_DAILY_CHAR_LIMIT_EXCEEDED', + 413: 'ERR_TEXT_TOO_LONG', + 422: 'ERR_UNPROCESSABLE_TEXT', + 501: 'ERR_LANG_NOT_SUPPORTED' + }; + + if ( code in errormap ) { + return errormap[ code ]; + } + + return `${code}`; + } + + requiresAuthorization() { + return false; + } +} + +module.exports = LingoCloud; diff --git a/test/mt/LingoCloud.test.js b/test/mt/LingoCloud.test.js new file mode 100644 index 0000000..5aa596c --- /dev/null +++ b/test/mt/LingoCloud.test.js @@ -0,0 +1,22 @@ +'use strict'; + +const assert = require( '../utils/assert.js' ); +const server = require( '../utils/server.js' ); +const LingoCloud = require( '../../lib/mt' ).LingoCloud; + +describe( 'Youdao machine translation', function () { + it( 'Should fail because of wrong key ', () => { + const cxConfig = server.config.service; + cxConfig.conf.mt.LingoCloud.key = 'wrongkey'; + const youdao = new LingoCloud( cxConfig ); + const testSourceContent = '

This is a test

'; + assert.fails( + youdao.translate( 'en', 'zh', testSourceContent ), + function ( err ) { + if ( ( err instanceof Error ) && /value/.test( err ) ) { + return true; + } + } + ); + } ); +} ); diff --git a/config.dev.yaml b/config.dev.yaml index 39fe097..e0a7697 100644 --- a/config.dev.yaml +++ b/config.dev.yaml @@ -87,6 +87,10 @@ services: api: http://matxin.elhuyar.eus/API languages: config/Matxin.yaml key: null + LingoCloud: + api: https://api.interpreter.caiyunai.com + languages: config/LingoCloud.yaml + key: null dictionary: Dictd: languages: config/Dictd.yaml diff --git a/config/mt-defaults.wikimedia.yaml b/config/mt-defaults.wikimedia.yaml index f0537a0..1cea9c5 100644 --- a/config/mt-defaults.wikimedia.yaml +++ b/config/mt-defaults.wikimedia.yaml @@ -981,3 +981,9 @@ 'is-sv': Apertium 'kk-tt': Apertium 'hi-ur': Apertium +'en-zh': LingoCloud +'ja-zh': LingoCloud +'zh-en': LingoCloud +'zh-ja': LingoCloud + + diff --git a/lib/mt/index.js b/lib/mt/index.js index d05029a..7bd7a35 100644 --- a/lib/mt/index.js +++ b/lib/mt/index.js @@ -5,5 +5,6 @@ module.exports = { Matxin: require( './Matxin' ), TestClient: require( './TestClient' ), Yandex: require( './Yandex' ), - Youdao: require( './Youdao' ) + Youdao: require( './Youdao' ), + LingoCloud: require( './LingoCloud' ) }; diff --git a/spec.yaml b/spec.yaml index 1cfdd81..93cdac0 100644 --- a/spec.yaml +++ b/spec.yaml @@ -180,6 +180,7 @@ paths: enum: - Apertium - Matxin + - LingoCloud - name: html in: formData description: The HTML or plaintext content to translate @@ -335,6 +336,7 @@ paths: required: false enum: - Apertium + - LingoCloud - name: html in: formData description: The HTML content to translate