Translate with Google(NoAPI)
This commit is contained in:
parent
ba14fdc2f4
commit
737868f309
|
@ -30,6 +30,7 @@
|
|||
"cleanall": "npm run clean-all"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitalets/google-translate-api": "8.0.0",
|
||||
"execa": "5.1.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
export class multipleTranslationServices1660183643857 {
|
||||
name = 'multipleTranslationServices1660183643857'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "translatorType" character varying(32)`);
|
||||
await queryRunner.query('SELECT "deeplAuthKey" FROM "meta" where "deeplAuthKey" is not null')
|
||||
.then(deeplAuthKey => {
|
||||
if (deeplAuthKey.length > 0) {
|
||||
return queryRunner.query('UPDATE "meta" SET "translatorType" = "DeepL"');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "translatorType"`);
|
||||
}
|
||||
}
|
|
@ -335,6 +335,12 @@ export class Meta {
|
|||
})
|
||||
public discordClientSecret: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 32,
|
||||
nullable: true,
|
||||
})
|
||||
public translatorType: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128,
|
||||
nullable: true,
|
||||
|
|
|
@ -155,6 +155,10 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
translatorType: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
proxyAccountName: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
|
@ -380,7 +384,9 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
enableGithubIntegration: instance.enableGithubIntegration,
|
||||
enableDiscordIntegration: instance.enableDiscordIntegration,
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
// translatorAvailable: instance.deeplAuthKey != null,
|
||||
translatorAvailable: instance.translatorType != null,
|
||||
translatorType: instance.translatorType,
|
||||
pinnedPages: instance.pinnedPages,
|
||||
pinnedClipId: instance.pinnedClipId,
|
||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||
|
|
|
@ -63,6 +63,7 @@ export const paramDef = {
|
|||
type: 'string',
|
||||
} },
|
||||
summalyProxy: { type: 'string', nullable: true },
|
||||
translatorType: { type: 'string', nullable: true },
|
||||
deeplAuthKey: { type: 'string', nullable: true },
|
||||
deeplIsPro: { type: 'boolean' },
|
||||
enableTwitterIntegration: { type: 'boolean' },
|
||||
|
@ -406,6 +407,14 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle;
|
||||
}
|
||||
|
||||
if (ps.translatorType !== undefined) {
|
||||
if (ps.translatorType === '') {
|
||||
set.translatorType = null;
|
||||
} else {
|
||||
set.translatorType = ps.translatorType;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.deeplAuthKey !== undefined) {
|
||||
if (ps.deeplAuthKey === '') {
|
||||
set.deeplAuthKey = null;
|
||||
|
|
|
@ -377,7 +377,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
// translatorAvailable: instance.deeplAuthKey != null,
|
||||
translatorAvailable: instance.translatorType != null,
|
||||
|
||||
...(ps.detail ? {
|
||||
pinnedPages: instance.pinnedPages,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { URLSearchParams } from 'node:url';
|
||||
import googletr from '@vitalets/google-translate-api';
|
||||
import fetch from 'node-fetch';
|
||||
import config from '@/config/index.js';
|
||||
import { getAgentByUrl } from '@/misc/fetch.js';
|
||||
|
@ -24,6 +25,11 @@ export const meta = {
|
|||
code: 'NO_SUCH_NOTE',
|
||||
id: 'bea9b03f-36e0-49c5-a4db-627a029f8971',
|
||||
},
|
||||
noTranslateService: {
|
||||
message: 'Translate service is not available.',
|
||||
code: 'NO_TRANSLATE_SERVICE',
|
||||
id: 'bef6e895-c05d-4499-9815-035ed18b0e31',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -42,6 +48,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||
throw e;
|
||||
});
|
||||
const translatorServices = [
|
||||
'DeepL',
|
||||
'GoogleNoAPI',
|
||||
];
|
||||
|
||||
if (!(await Notes.isVisibleForMe(note, user ? user.id : null))) {
|
||||
return 204; // TODO: 良い感じのエラー返す
|
||||
|
@ -53,42 +63,62 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
|
||||
const instance = await fetchMeta();
|
||||
|
||||
if (instance.deeplAuthKey == null) {
|
||||
return 204; // TODO: 良い感じのエラー返す
|
||||
if (instance.translatorType == null || !translatorServices.includes(instance.translatorType)) {
|
||||
throw new ApiError(meta.errors.noTranslateService);
|
||||
}
|
||||
|
||||
let targetLang = ps.targetLang;
|
||||
if (targetLang.includes('-')) targetLang = targetLang.split('-')[0];
|
||||
if (instance.translatorType === 'DeepL') {
|
||||
if (instance.deeplAuthKey == null) {
|
||||
return 204; // TODO: 良い感じのエラー返す
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('auth_key', instance.deeplAuthKey);
|
||||
params.append('text', note.text);
|
||||
params.append('target_lang', targetLang);
|
||||
let targetLang = ps.targetLang;
|
||||
if (targetLang.includes('-')) targetLang = targetLang.split('-')[0];
|
||||
|
||||
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
|
||||
const params = new URLSearchParams();
|
||||
params.append('auth_key', instance.deeplAuthKey);
|
||||
params.append('text', note.text);
|
||||
params.append('target_lang', targetLang);
|
||||
|
||||
const res = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': config.userAgent,
|
||||
Accept: 'application/json, */*',
|
||||
},
|
||||
body: params,
|
||||
// TODO
|
||||
//timeout: 10000,
|
||||
agent: getAgentByUrl,
|
||||
});
|
||||
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
|
||||
|
||||
const json = (await res.json()) as {
|
||||
translations: {
|
||||
detected_source_language: string;
|
||||
text: string;
|
||||
}[];
|
||||
};
|
||||
const res = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': config.userAgent,
|
||||
Accept: 'application/json, */*',
|
||||
},
|
||||
body: params,
|
||||
// TODO
|
||||
//timeout: 10000,
|
||||
agent: getAgentByUrl,
|
||||
});
|
||||
|
||||
return {
|
||||
sourceLang: json.translations[0].detected_source_language,
|
||||
text: json.translations[0].text,
|
||||
};
|
||||
const json = (await res.json()) as {
|
||||
translations: {
|
||||
detected_source_language: string;
|
||||
text: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
return {
|
||||
sourceLang: json.translations[0].detected_source_language,
|
||||
text: json.translations[0].text,
|
||||
translator: translatorServices,
|
||||
};
|
||||
} else if (instance.translatorType === 'GoogleNoAPI') {
|
||||
let targetLang = ps.targetLang;
|
||||
if (targetLang.includes('-')) targetLang = targetLang.split('-')[0];
|
||||
|
||||
const json = await googletr(note.text, { to: targetLang });
|
||||
|
||||
return {
|
||||
sourceLang: json.from.language.iso,
|
||||
text: json.text,
|
||||
translator: translatorServices,
|
||||
};
|
||||
}
|
||||
|
||||
return 204; // TODO: 良い感じのエラー返す
|
||||
});
|
||||
|
|
|
@ -130,15 +130,24 @@
|
|||
</FormSection>
|
||||
|
||||
<FormSection>
|
||||
<template #label>DeepL Translation</template>
|
||||
<template #label>Translation</template>
|
||||
|
||||
<FormInput v-model="deeplAuthKey" class="_formBlock">
|
||||
<template #prefix><i class="fas fa-key"></i></template>
|
||||
<template #label>DeepL Auth Key</template>
|
||||
</FormInput>
|
||||
<FormSwitch v-model="deeplIsPro" class="_formBlock">
|
||||
<template #label>Pro account</template>
|
||||
</FormSwitch>
|
||||
<FormRadios v-model="translatorType" class="_formBlock">
|
||||
<template #label>Translator type</template>
|
||||
<option :value="null">{{ i18n.ts.none }}</option>
|
||||
<option value="DeepL">DeepL</option>
|
||||
<option value="GoogleNoAPI">Google Translate(without API)</option>
|
||||
</FormRadios>
|
||||
|
||||
<template v-if="translatorType === 'DeepL'">
|
||||
<FormInput v-model="deeplAuthKey" class="_formBlock">
|
||||
<template #prefix><i class="fas fa-key"></i></template>
|
||||
<template #label>DeepL Auth Key</template>
|
||||
</FormInput>
|
||||
<FormSwitch v-model="deeplIsPro" class="_formBlock">
|
||||
<template #label>Pro account</template>
|
||||
</FormSwitch>
|
||||
</template>
|
||||
</FormSection>
|
||||
</div>
|
||||
</FormSuspense>
|
||||
|
@ -157,6 +166,7 @@ import FormInfo from '@/components/ui/info.vue';
|
|||
import FormSection from '@/components/form/section.vue';
|
||||
import FormSplit from '@/components/form/split.vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import FormRadios from '@/components/form/radios.vue'
|
||||
import * as os from '@/os';
|
||||
import { fetchInstance } from '@/instance';
|
||||
import { i18n } from '@/i18n';
|
||||
|
@ -184,6 +194,7 @@ let emailRequiredForSignup: boolean = $ref(false);
|
|||
let enableServiceWorker: boolean = $ref(false);
|
||||
let swPublicKey: any = $ref(null);
|
||||
let swPrivateKey: any = $ref(null);
|
||||
let translatorType: string | null = $ref(null);
|
||||
let deeplAuthKey: string = $ref('');
|
||||
let deeplIsPro: boolean = $ref(false);
|
||||
|
||||
|
@ -211,6 +222,7 @@ async function init() {
|
|||
enableServiceWorker = meta.enableServiceWorker;
|
||||
swPublicKey = meta.swPublickey;
|
||||
swPrivateKey = meta.swPrivateKey;
|
||||
translatorType = meta.translatorType;
|
||||
deeplAuthKey = meta.deeplAuthKey;
|
||||
deeplIsPro = meta.deeplIsPro;
|
||||
}
|
||||
|
@ -239,6 +251,7 @@ function save() {
|
|||
enableServiceWorker,
|
||||
swPublicKey,
|
||||
swPrivateKey,
|
||||
translatorType,
|
||||
deeplAuthKey,
|
||||
deeplIsPro,
|
||||
}).then(() => {
|
||||
|
|
Loading…
Reference in a new issue