add: DeepLX-JS support

Closes #324
This commit is contained in:
Marie 2024-01-26 21:29:38 +01:00
parent e5c060eecf
commit c6e3ec07d1
No known key found for this signature in database
GPG key ID: 56569BBE47D2C828
7 changed files with 103 additions and 14 deletions

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class Deeplx1706232992000 {
name = 'Deeplx1706232992000';
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "deeplFreeMode" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "deeplFreeInstance" character varying(1024)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplFreeMode"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplFreeInstance"`);
}
}

View file

@ -353,6 +353,17 @@ export class MiMeta {
}) })
public deeplIsPro: boolean; public deeplIsPro: boolean;
@Column('boolean', {
default: false,
})
public deeplFreeMode: boolean;
@Column('varchar', {
length: 1024,
nullable: true,
})
public deeplFreeInstance: string | null;
@Column('varchar', { @Column('varchar', {
length: 1024, length: 1024,
nullable: true, nullable: true,

View file

@ -395,6 +395,14 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
deeplFreeMode: {
type: 'boolean',
optional: false, nullable: false,
},
deeplFreeInstance: {
type: 'string',
optional: false, nullable: true,
},
defaultDarkTheme: { defaultDarkTheme: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@ -576,6 +584,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
deeplAuthKey: instance.deeplAuthKey, deeplAuthKey: instance.deeplAuthKey,
deeplIsPro: instance.deeplIsPro, deeplIsPro: instance.deeplIsPro,
deeplFreeMode: instance.deeplFreeMode,
deeplFreeInstance: instance.deeplFreeInstance,
enableIpLogging: instance.enableIpLogging, enableIpLogging: instance.enableIpLogging,
enableActiveEmailValidation: instance.enableActiveEmailValidation, enableActiveEmailValidation: instance.enableActiveEmailValidation,
enableVerifymailApi: instance.enableVerifymailApi, enableVerifymailApi: instance.enableVerifymailApi,

View file

@ -91,6 +91,8 @@ export const paramDef = {
summalyProxy: { type: 'string', nullable: true }, summalyProxy: { type: 'string', nullable: true },
deeplAuthKey: { type: 'string', nullable: true }, deeplAuthKey: { type: 'string', nullable: true },
deeplIsPro: { type: 'boolean' }, deeplIsPro: { type: 'boolean' },
deeplFreeMode: { type: 'boolean' },
deeplFreeInstance: { type: 'string', nullable: true },
enableEmail: { type: 'boolean' }, enableEmail: { type: 'boolean' },
email: { type: 'string', nullable: true }, email: { type: 'string', nullable: true },
smtpSecure: { type: 'boolean' }, smtpSecure: { type: 'boolean' },
@ -479,6 +481,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.deeplIsPro = ps.deeplIsPro; set.deeplIsPro = ps.deeplIsPro;
} }
if (ps.deeplFreeMode !== undefined) {
set.deeplFreeMode = ps.deeplFreeMode;
}
if (ps.deeplFreeInstance !== undefined) {
if (ps.deeplFreeInstance === '') {
set.deeplFreeInstance = null;
} else {
set.deeplFreeInstance = ps.deeplFreeInstance;
}
}
if (ps.enableIpLogging !== undefined) { if (ps.enableIpLogging !== undefined) {
set.enableIpLogging = ps.enableIpLogging; set.enableIpLogging = ps.enableIpLogging;
} }

View file

@ -411,7 +411,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
enableEmail: instance.enableEmail, enableEmail: instance.enableEmail,
enableServiceWorker: instance.enableServiceWorker, enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable: instance.deeplAuthKey != null || instance.deeplFreeMode && instance.deeplFreeInstance,
serverRules: instance.serverRules, serverRules: instance.serverRules,

View file

@ -81,19 +81,23 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const instance = await this.metaService.fetch(); const instance = await this.metaService.fetch();
if (instance.deeplAuthKey == null) { if (instance.deeplAuthKey == null && !instance.deeplFreeMode) {
return 204; // TODO: 良い感じのエラー返す return 204; // TODO: 良い感じのエラー返す
} }
if (instance.deeplFreeMode && !instance.deeplFreeInstance) {
return 204;
}
let targetLang = ps.targetLang; let targetLang = ps.targetLang;
if (targetLang.includes('-')) targetLang = targetLang.split('-')[0]; if (targetLang.includes('-')) targetLang = targetLang.split('-')[0];
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append('auth_key', instance.deeplAuthKey); if (instance.deeplAuthKey) params.append('auth_key', instance.deeplAuthKey);
params.append('text', note.text); params.append('text', note.text);
params.append('target_lang', targetLang); params.append('target_lang', targetLang);
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate'; const endpoint = instance.deeplFreeMode && instance.deeplFreeInstance ? `https://${instance.deeplFreeInstance}` : instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
const res = await this.httpRequestService.send(endpoint, { const res = await this.httpRequestService.send(endpoint, {
method: 'POST', method: 'POST',
@ -103,18 +107,37 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}, },
body: params.toString(), body: params.toString(),
}); });
if (instance.deeplAuthKey) {
const json = (await res.json()) as {
translations: {
detected_source_language: string;
text: string;
}[];
};
const json = (await res.json()) as { return {
translations: { sourceLang: json.translations[0].detected_source_language,
detected_source_language: string; text: json.translations[0].text,
text: string; };
}[]; } else {
}; const json = (await res.json()) as {
code: number,
message: string,
data: string,
source_lang: string,
target_lang: string,
alternatives: string[],
};
return { const languageNames = new Intl.DisplayNames(['en'], {
sourceLang: json.translations[0].detected_source_language, type: 'language',
text: json.translations[0].text, });
};
return {
sourceLang: languageNames.of(json.source_lang),
text: json.data,
};
}
}); });
} }
} }

View file

@ -19,6 +19,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="deeplIsPro"> <MkSwitch v-model="deeplIsPro">
<template #label>Pro account</template> <template #label>Pro account</template>
</MkSwitch> </MkSwitch>
<MkSwitch v-model="deeplFreeMode">
<template #label>Use DeepLX-JS (No Auth Key)</template>
</MkSwitch>
<MkInput v-if="deeplFreeMode" v-model="deeplFreeInstance" :placeholder="'example.com/translate'">
<template #prefix>https://</template>
<template #label>DeepLX-JS URL</template>
</MkInput>
</div> </div>
</FormSection> </FormSection>
</FormSuspense> </FormSuspense>
@ -49,17 +56,23 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
const deeplAuthKey = ref<string>(''); const deeplAuthKey = ref<string>('');
const deeplIsPro = ref<boolean>(false); const deeplIsPro = ref<boolean>(false);
const deeplFreeMode = ref<boolean>(false);
const deeplFreeInstance = ref<string>('');
async function init() { async function init() {
const meta = await misskeyApi('admin/meta'); const meta = await misskeyApi('admin/meta');
deeplAuthKey.value = meta.deeplAuthKey; deeplAuthKey.value = meta.deeplAuthKey;
deeplIsPro.value = meta.deeplIsPro; deeplIsPro.value = meta.deeplIsPro;
deeplFreeMode.value = meta.deeplFreeMode;
deeplFreeInstance.value = meta.deeplFreeInstance;
} }
function save() { function save() {
os.apiWithDialog('admin/update-meta', { os.apiWithDialog('admin/update-meta', {
deeplAuthKey: deeplAuthKey.value, deeplAuthKey: deeplAuthKey.value,
deeplIsPro: deeplIsPro.value, deeplIsPro: deeplIsPro.value,
deeplFreeMode: deeplFreeMode.value,
deeplFreeInstance: deeplFreeInstance.value,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });