Merge pull request #3219 from SillyTavern/pt-br Translate: Split Portuguese languages

7490357d9e674ed977e80121669cd68f3f80ea43

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
4 files changed, +73 -38Showing whitespace changes
package-lock.json+4 -4
@@ -18,7 +18,7 @@
18 "@popperjs/core": "^2.11.8",18 "@popperjs/core": "^2.11.8",
19 "@zeldafan0225/ai_horde": "^5.1.0",19 "@zeldafan0225/ai_horde": "^5.1.0",
20 "archiver": "^7.0.1",20 "archiver": "^7.0.1",
21 "bing-translate-api": "^2.9.1",21 "bing-translate-api": "^4.0.2",
22 "body-parser": "^1.20.2",22 "body-parser": "^1.20.2",
23 "bowser": "^2.11.0",23 "bowser": "^2.11.0",
24 "command-exists": "^1.2.9",24 "command-exists": "^1.2.9",
@@ -2161,9 +2161,9 @@
2161 }2161 }
2162 },2162 },
2163 "node_modules/bing-translate-api": {2163 "node_modules/bing-translate-api": {
2164 "version": "2.9.1",2164 "version": "4.0.2",
2165 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-2.9.1.tgz",2165 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.0.2.tgz",
2166 "integrity": "sha512-DaYqa7iupfj+fj/KeaeZSp5FUY/ZR4sZ6jqoTP0RHkYOUfo7wwoxlhYDkh4VcvBBzuVORnBEgdXBVQrfM4kk7g==",2166 "integrity": "sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==",
2167 "license": "MIT",2167 "license": "MIT",
2168 "dependencies": {2168 "dependencies": {
2169 "got": "^11.8.6"2169 "got": "^11.8.6"
package.json+1 -1
@@ -8,7 +8,7 @@
8 "@popperjs/core": "^2.11.8",8 "@popperjs/core": "^2.11.8",
9 "@zeldafan0225/ai_horde": "^5.1.0",9 "@zeldafan0225/ai_horde": "^5.1.0",
10 "archiver": "^7.0.1",10 "archiver": "^7.0.1",
11 "bing-translate-api": "^2.9.1",11 "bing-translate-api": "^4.0.2",
12 "body-parser": "^1.20.2",12 "body-parser": "^1.20.2",
13 "bowser": "^2.11.0",13 "bowser": "^2.11.0",
14 "command-exists": "^1.2.9",14 "command-exists": "^1.2.9",
public/scripts/extensions/translate/index.js+2 -1
@@ -106,7 +106,8 @@ const languageCodes = {
106 'Pashto': 'ps',106 'Pashto': 'ps',
107 'Persian': 'fa',107 'Persian': 'fa',
108 'Polish': 'pl',108 'Polish': 'pl',
109 'Portuguese (Portugal, Brazil)': 'pt',109 'Portuguese (Portugal)': 'pt-PT',
110 'Portuguese (Brazil)': 'pt-BR',
110 'Punjabi': 'pa',111 'Punjabi': 'pa',
111 'Romanian': 'ro',112 'Romanian': 'ro',
112 'Russian': 'ru',113 'Russian': 'ru',
src/endpoints/translate.js+66 -32
@@ -1,10 +1,10 @@
1import https from 'node:https';
2import { createRequire } from 'node:module';1import { createRequire } from 'node:module';
32
4import fetch from 'node-fetch';3import fetch from 'node-fetch';
5import express from 'express';4import express from 'express';
6import bingTranslateApi from 'bing-translate-api';5import { translate as bingTranslate } from 'bing-translate-api';
7import iconv from 'iconv-lite';6import iconv from 'iconv-lite';
7import urlJoin from 'url-join';
88
9import { readSecret, SECRET_KEYS } from './secrets.js';9import { readSecret, SECRET_KEYS } from './secrets.js';
10import { getConfigValue, uuidv4 } from '../util.js';10import { getConfigValue, uuidv4 } from '../util.js';
@@ -12,6 +12,7 @@ import { jsonParser } from '../express-common.js';
1212
13const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate';13const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate';
14const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate';14const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate';
15const LINGVA_DEFAULT = 'https://lingva.ml/api/v1';
1516
16export const router = express.Router();17export const router = express.Router();
1718
@@ -56,6 +57,10 @@ router.post('/libre', jsonParser, async (request, response) => {
56 request.body.lang = 'zt';57 request.body.lang = 'zt';
57 }58 }
5859
60 if (request.body.lang === 'pt-BR' || request.body.lang === 'pt-PT') {
61 request.body.lang = 'pt';
62 }
63
59 const text = request.body.text;64 const text = request.body.text;
60 const lang = request.body.lang;65 const lang = request.body.lang;
6166
@@ -81,7 +86,7 @@ router.post('/libre', jsonParser, async (request, response) => {
81 if (!result.ok) {86 if (!result.ok) {
82 const error = await result.text();87 const error = await result.text();
83 console.log('LibreTranslate error: ', result.statusText, error);88 console.log('LibreTranslate error: ', result.statusText, error);
84 return response.sendStatus(result.status);89 return response.sendStatus(500);
85 }90 }
8691
87 /** @type {any} */92 /** @type {any} */
@@ -130,6 +135,14 @@ router.post('/google', jsonParser, async (request, response) => {
130135
131router.post('/yandex', jsonParser, async (request, response) => {136router.post('/yandex', jsonParser, async (request, response) => {
132 try {137 try {
138 if (request.body.lang === 'pt-PT') {
139 request.body.lang = 'pt';
140 }
141
142 if (request.body.lang === 'zh-CN' || request.body.lang === 'zh-TW') {
143 request.body.lang = 'zh';
144 }
145
133 const chunks = request.body.chunks;146 const chunks = request.body.chunks;
134 const lang = request.body.lang;147 const lang = request.body.lang;
135148
@@ -178,13 +191,26 @@ router.post('/yandex', jsonParser, async (request, response) => {
178191
179router.post('/lingva', jsonParser, async (request, response) => {192router.post('/lingva', jsonParser, async (request, response) => {
180 try {193 try {
181 const baseUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL);194 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL);
195 const baseUrl = secretUrl || LINGVA_DEFAULT;
196
197 if (!secretUrl && baseUrl === LINGVA_DEFAULT) {
198 console.log('Lingva URL is using default value.', LINGVA_DEFAULT);
199 }
182200
183 if (!baseUrl) {201 if (!baseUrl) {
184 console.log('Lingva URL is not configured.');202 console.log('Lingva URL is not configured.');
185 return response.sendStatus(400);203 return response.sendStatus(400);
186 }204 }
187205
206 if (request.body.lang === 'zh-CN' || request.body.lang === 'zh-TW') {
207 request.body.lang = 'zh';
208 }
209
210 if (request.body.lang === 'pt-BR' || request.body.lang === 'pt-PT') {
211 request.body.lang = 'pt';
212 }
213
188 const text = request.body.text;214 const text = request.body.text;
189 const lang = request.body.lang;215 const lang = request.body.lang;
190216
@@ -193,29 +219,24 @@ router.post('/lingva', jsonParser, async (request, response) => {
193 }219 }
194220
195 console.log('Input text: ' + text);221 console.log('Input text: ' + text);
196 const url = `${baseUrl}/auto/${lang}/${encodeURIComponent(text)}`;
197222
198 https.get(url, (resp) => {223 try {
199 let data = '';224 const url = urlJoin(baseUrl, 'auto', lang, encodeURIComponent(text));
225 const result = await fetch(url);
200226
201 resp.on('data', (chunk) => {227 if (!result.ok) {
202 data += chunk;228 const error = await result.text();
203 });229 console.log('Lingva error: ', result.statusText, error);
230 }
204231
205 resp.on('end', () => {232 /** @type {any} */
206 try {233 const data = await result.json();
207 const result = JSON.parse(data);234 console.log('Translated text: ' + data.translation);
208 console.log('Translated text: ' + result.translation);235 return response.send(data.translation);
209 return response.send(result.translation);
210 } catch (error) {236 } catch (error) {
211 console.log('Translation error', error);237 console.log('Translation error:', error);
212 return response.sendStatus(500);238 return response.sendStatus(500);
213 }239 }
214 });
215 }).on('error', (err) => {
216 console.log('Translation error: ' + err.message);
217 return response.sendStatus(500);
218 });
219 } catch (error) {240 } catch (error) {
220 console.log('Translation error', error);241 console.log('Translation error', error);
221 return response.sendStatus(500);242 return response.sendStatus(500);
@@ -248,8 +269,7 @@ router.post('/deepl', jsonParser, async (request, response) => {
248 params.append('text', text);269 params.append('text', text);
249 params.append('target_lang', lang);270 params.append('target_lang', lang);
250271
251 if (['de', 'fr', 'it', 'es', 'nl', 'ja', 'ru'].includes(lang)) {272 if (['de', 'fr', 'it', 'es', 'nl', 'ja', 'ru', 'pt-BR', 'pt-PT'].includes(lang)) {
252 // We don't specify a Portuguese variant, so ignore formality for it.
253 params.append('formality', formality);273 params.append('formality', formality);
254 }274 }
255275
@@ -267,7 +287,7 @@ router.post('/deepl', jsonParser, async (request, response) => {
267 if (!result.ok) {287 if (!result.ok) {
268 const error = await result.text();288 const error = await result.text();
269 console.log('DeepL error: ', result.statusText, error);289 console.log('DeepL error: ', result.statusText, error);
270 return response.sendStatus(result.status);290 return response.sendStatus(500);
271 }291 }
272292
273 /** @type {any} */293 /** @type {any} */
@@ -294,6 +314,10 @@ router.post('/onering', jsonParser, async (request, response) => {
294 console.log('OneRing URL is using default value.', ONERING_URL_DEFAULT);314 console.log('OneRing URL is using default value.', ONERING_URL_DEFAULT);
295 }315 }
296316
317 if (request.body.lang === 'pt-BR' || request.body.lang === 'pt-PT') {
318 request.body.lang = 'pt';
319 }
320
297 const text = request.body.text;321 const text = request.body.text;
298 const from_lang = request.body.from_lang;322 const from_lang = request.body.from_lang;
299 const to_lang = request.body.to_lang;323 const to_lang = request.body.to_lang;
@@ -320,7 +344,7 @@ router.post('/onering', jsonParser, async (request, response) => {
320 if (!result.ok) {344 if (!result.ok) {
321 const error = await result.text();345 const error = await result.text();
322 console.log('OneRing error: ', result.statusText, error);346 console.log('OneRing error: ', result.statusText, error);
323 return response.sendStatus(result.status);347 return response.sendStatus(500);
324 }348 }
325349
326 /** @type {any} */350 /** @type {any} */
@@ -376,7 +400,7 @@ router.post('/deeplx', jsonParser, async (request, response) => {
376 if (!result.ok) {400 if (!result.ok) {
377 const error = await result.text();401 const error = await result.text();
378 console.log('DeepLX error: ', result.statusText, error);402 console.log('DeepLX error: ', result.statusText, error);
379 return response.sendStatus(result.status);403 return response.sendStatus(500);
380 }404 }
381405
382 /** @type {any} */406 /** @type {any} */
@@ -391,6 +415,7 @@ router.post('/deeplx', jsonParser, async (request, response) => {
391});415});
392416
393router.post('/bing', jsonParser, async (request, response) => {417router.post('/bing', jsonParser, async (request, response) => {
418 try {
394 const text = request.body.text;419 const text = request.body.text;
395 let lang = request.body.lang;420 let lang = request.body.lang;
396421
@@ -398,17 +423,26 @@ router.post('/bing', jsonParser, async (request, response) => {
398 lang = 'zh-Hans';423 lang = 'zh-Hans';
399 }424 }
400425
426 if (request.body.lang === 'zh-TW') {
427 lang = 'zh-Hant';
428 }
429
430 if (request.body.lang === 'pt-BR') {
431 lang = 'pt';
432 }
433
401 if (!text || !lang) {434 if (!text || !lang) {
402 return response.sendStatus(400);435 return response.sendStatus(400);
403 }436 }
404437
405 console.log('Input text: ' + text);438 console.log('Input text: ' + text);
406439
407 bingTranslateApi.translate(text, null, lang).then(result => {440 const result = await bingTranslate(text, null, lang);
408 console.log('Translated text: ' + result.translation);441 const translatedText = result?.translation;
409 return response.send(result.translation);442 console.log('Translated text: ' + translatedText);
410 }).catch(err => {443 return response.send(translatedText);
411 console.log('Translation error: ' + err.message);444 } catch (error) {
445 console.log('Translation error', error);
412 return response.sendStatus(500);446 return response.sendStatus(500);
413 });447 }
414});448});