b71da18b03
Co-authored-by: naskya <m@naskya.net>
93 lines
2.5 KiB
TypeScript
93 lines
2.5 KiB
TypeScript
import fetch from "node-fetch";
|
|
import { Converter } from "opencc-js";
|
|
import { getAgentByUrl } from "@/misc/fetch.js";
|
|
import { fetchMeta } from "backend-rs";
|
|
import type { PostLanguage } from "@/misc/langmap";
|
|
import * as deepl from "deepl-node";
|
|
|
|
// DeepL translate and LibreTranslate don't provide
|
|
// zh-Hant-TW translations, so we convert zh-Hans-CN
|
|
// translations into zh-Hant-TW using opencc-js.
|
|
function convertChinese(convert: boolean, src: string) {
|
|
if (!convert) return src;
|
|
const converter = Converter({ from: "cn", to: "twp" });
|
|
return converter(src);
|
|
}
|
|
|
|
function stem(lang: PostLanguage): string {
|
|
let toReturn = lang as string;
|
|
if (toReturn.includes("-")) toReturn = toReturn.split("-")[0];
|
|
if (toReturn.includes("_")) toReturn = toReturn.split("_")[0];
|
|
return toReturn;
|
|
}
|
|
|
|
export async function translate(
|
|
text: string,
|
|
from: PostLanguage | null,
|
|
to: PostLanguage,
|
|
) {
|
|
const instance = await fetchMeta(true);
|
|
|
|
if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
|
|
throw Error("No translator is set up on this server.");
|
|
}
|
|
|
|
const source = from == null ? null : stem(from);
|
|
const target = stem(to);
|
|
|
|
if (instance.libreTranslateApiUrl != null) {
|
|
const jsonBody = {
|
|
q: text,
|
|
source: source ?? "auto",
|
|
target,
|
|
format: "text",
|
|
api_key: instance.libreTranslateApiKey ?? "",
|
|
};
|
|
|
|
const url = new URL(instance.libreTranslateApiUrl);
|
|
if (url.pathname.endsWith("/")) {
|
|
url.pathname = url.pathname.slice(0, -1);
|
|
}
|
|
if (!url.pathname.endsWith("/translate")) {
|
|
url.pathname += "/translate";
|
|
}
|
|
const res = await fetch(url.toString(), {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(jsonBody),
|
|
agent: getAgentByUrl,
|
|
});
|
|
|
|
const json = (await res.json()) as {
|
|
detectedLanguage?: {
|
|
confidence: number;
|
|
language: string;
|
|
};
|
|
translatedText: string;
|
|
};
|
|
|
|
return {
|
|
sourceLang: source ?? json.detectedLanguage?.language,
|
|
text: convertChinese(
|
|
["zh-hant", "zh-TW"].includes(to),
|
|
json.translatedText,
|
|
),
|
|
};
|
|
}
|
|
|
|
const deeplTranslator = new deepl.Translator(instance.deeplAuthKey ?? "");
|
|
const result = await deeplTranslator.translateText(
|
|
text,
|
|
source as deepl.SourceLanguageCode | null,
|
|
// DeepL API requires us to specify "en-US" or "en-GB" for English
|
|
// translations ("en" does not work), so we need to address it
|
|
(target === "en" ? to : target) as deepl.TargetLanguageCode,
|
|
);
|
|
|
|
return {
|
|
sourceLang: source ?? result.detectedSourceLang,
|
|
text: convertChinese(["zh-hant", "zh-TW"].includes(to), result.text),
|
|
};
|
|
}
|