client: Add LibreTranslate support

This adds a new "Translation Settings" page to the admin interface where
the admin can configure the instance's translation settings. The
existing settigns for DeepL translation settings will now be located in
that page alongside the new LibreTranslate stuff.

Also made the translation service settings localizable, which funnily
enough was not already the case.
This commit is contained in:
Norm 2022-11-01 01:40:54 -04:00
parent 8cde66b8ac
commit cfe0f3ca67
Signed by untrusted user: norm
GPG key ID: 7123E30E441E80DE
4 changed files with 102 additions and 19 deletions

View file

@ -849,6 +849,8 @@ misskeyUpdated: "FoundKey has been updated!"
whatIsNew: "Show changes"
translate: "Translate"
translatedFrom: "Translated from {x}"
translationSettings: "Translation Settings"
translationService: "Translation Service"
accountDeletionInProgress: "Account deletion is currently in progress."
usernameInfo: "A name that identifies your account from others on this server. You\
\ can use the alphabet (a~z, A~Z), digits (0~9) or underscores (_). Usernames cannot\
@ -1525,3 +1527,10 @@ _services:
_github:
connected: "GitHub: @{login} connected to FoundKey: @{userName}!"
disconnected: "GitHub linkage has been removed."
_translationService:
_deepl:
authKey: "DeepL Auth Key"
pro: "Pro Account"
_libreTranslate:
endpoint: "LibreTranslate API Endpoint"
authKey: "LibreTranslate Auth Key (optional)"

View file

@ -172,6 +172,11 @@ const menuDef = $computed(() => [{
text: i18n.ts.proxyAccount,
to: '/admin/proxy-account',
active: props.initialPage === 'proxy-account',
}, {
icon: 'fas fa-language',
text: i18n.ts.translationSettings,
to: '/admin/translation-settings',
active: props.initialPage === 'translation-settings',
}],
}, {
title: i18n.ts.info,
@ -202,6 +207,7 @@ const component = $computed(() => {
case 'integrations': return defineAsyncComponent(() => import('./integrations.vue'));
case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue'));
case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue'));
case 'translation-settings': return defineAsyncComponent(() => import('./translation-settings.vue'));
default: return null;
}
});

View file

@ -128,18 +128,6 @@
</FormInput>
</template>
</FormSection>
<FormSection>
<template #label>DeepL 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>
</FormSection>
</div>
</FormSuspense>
</MkSpacer>
@ -182,8 +170,6 @@ let emailRequiredForSignup: boolean = $ref(false);
let enableServiceWorker: boolean = $ref(false);
let swPublicKey: any = $ref(null);
let swPrivateKey: any = $ref(null);
let deeplAuthKey: string = $ref('');
let deeplIsPro: boolean = $ref(false);
async function init(): Promise<void> {
const meta = await os.api('admin/meta');
@ -209,11 +195,9 @@ async function init(): Promise<void> {
enableServiceWorker = meta.enableServiceWorker;
swPublicKey = meta.swPublickey;
swPrivateKey = meta.swPrivateKey;
deeplAuthKey = meta.deeplAuthKey;
deeplIsPro = meta.deeplIsPro;
}
function save() {
function save(): void {
os.apiWithDialog('admin/update-meta', {
name,
description,
@ -237,8 +221,6 @@ function save() {
enableServiceWorker,
swPublicKey,
swPrivateKey,
deeplAuthKey,
deeplIsPro,
}).then(() => {
fetchInstance();
});

View file

@ -0,0 +1,86 @@
<template>
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions"/></template>
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init">
<div class="_formRoot">
<FormSelect v-model="translationService" class="_formBlock">
<template #label>{{ i18n.ts.translationService }}</template>
<option value="none">{{ i18n.ts.none }}</option>
<option value="deepl">DeepL</option>
<option value="libretranslate">LibreTranslate</option>
</FormSelect>
<template v-if="translationService === 'deepl'">
<FormSwitch v-model="deeplIsPro" class="_formBlock">
<template #label>{{ i18n.ts._translationService._deepl.pro }}</template>
</FormSwitch>
<FormInput v-model="deeplAuthKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>{{ i18n.ts._translationService._deepl.authKey }}</template>
</FormInput>
</template>
<template v-else-if="translationService === 'libretranslate'">
<FormInput v-model="libreTranslateEndpoint" class="_formBlock">
<template #label>{{ i18n.ts._translationService._libreTranslate.endpoint }}</template>
</FormInput>
<FormInput v-model="libreTranslateAuthKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>{{ i18n.ts._translationService._libreTranslate.authKey }}</template>
</FormInput>
</template>
</div>
</FormSuspense>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import FormInput from '@/components/form/input.vue';
import FormSelect from '@/components/form/select.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSwitch from '@/components/form/switch.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { fetchInstance } from '@/instance';
import { definePageMetadata } from '@/scripts/page-metadata';
let translationService: string = $ref('none');
let deeplIsPro: boolean = $ref(false);
let deeplAuthKey: string = $ref('');
let libreTranslateEndpoint: string = $ref('');
let libreTranslateAuthKey: string = $ref('');
async function init(): Promise<void> {
const meta = await os.api('admin/meta');
translationService = meta.translationService ?? 'none';
deeplIsPro = meta.deeplIsPro;
deeplAuthKey = meta.deeplAuthKey;
libreTranslateEndpoint = meta.libreTranslateEndpoint;
libreTranslateAuthKey = meta.libreTranslateAuthKey;
}
function save(): void {
os.apiWithDialog('admin/update-meta', {
translationService: translationService === 'none' ? null : translationService,
deeplAuthKey,
deeplIsPro,
libreTranslateEndpoint,
libreTranslateAuthKey,
}).then(() => {
fetchInstance();
});
}
const headerActions = $computed(() => [{
asFullButton: true,
icon: 'fas fa-check',
text: i18n.ts.save,
handler: save,
}]);
definePageMetadata({
title: i18n.ts.translationSettings,
icon: 'fas fa-language',
});
</script>