DeepL-Anbindung für automatische Übersetzung
app/api/translate ruft DeepL für EN+PL auf und schreibt das Ergebnis in die jeweilige _en/_pl-Spalte (Staff/Admin-only, Service-Role-Key). Ohne DEEPL_API_KEY (neue Docker-Variable) antwortet die Route mit configured:false, das Frontend zeigt dann den Hinweis zur manuellen Eingabe statt eines Fehlers.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/lib/supabase/server";
|
||||
import { createAdminClient } from "@/lib/supabase/admin";
|
||||
import { isSameOrigin } from "@/lib/origin";
|
||||
|
||||
// Übersetzt einen deutschen Text nach Englisch/Polnisch via DeepL und
|
||||
// schreibt das Ergebnis in die _en/_pl-Spalte der angegebenen Zeile.
|
||||
// Ohne DEEPL_API_KEY läuft die Route kontrolliert ins Leere (configured:
|
||||
// false), damit das UI die manuelle Eingabe anbieten kann.
|
||||
|
||||
const ALLOWED_TABLES: Record<string, { idColumn: string; textColumn: string }> = {
|
||||
dishes: { idColumn: "id", textColumn: "name" },
|
||||
sections: { idColumn: "key", textColumn: "label" },
|
||||
allergens: { idColumn: "code", textColumn: "name" },
|
||||
additives: { idColumn: "code", textColumn: "name" },
|
||||
};
|
||||
|
||||
async function translateWithDeepL(text: string, targetLang: "EN" | "PL", apiKey: string) {
|
||||
const host = apiKey.endsWith(":fx")
|
||||
? "https://api-free.deepl.com"
|
||||
: "https://api.deepl.com";
|
||||
const res = await fetch(`${host}/v2/translate`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `DeepL-Auth-Key ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text: [text],
|
||||
target_lang: targetLang,
|
||||
source_lang: "DE",
|
||||
}),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`DeepL antwortete mit ${res.status}: ${await res.text()}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
return data.translations?.[0]?.text as string | undefined;
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
if (!isSameOrigin(request)) {
|
||||
return NextResponse.json({ error: "Nicht erlaubt." }, { status: 403 });
|
||||
}
|
||||
|
||||
const supabase = await createClient();
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
if (!user) return NextResponse.json({ error: "Nicht angemeldet." }, { status: 401 });
|
||||
|
||||
const admin = createAdminClient();
|
||||
const { data: profile } = await admin
|
||||
.from("profiles")
|
||||
.select("role")
|
||||
.eq("id", user.id)
|
||||
.single();
|
||||
if (!profile || !["staff", "admin"].includes(profile.role)) {
|
||||
return NextResponse.json({ error: "Nicht berechtigt." }, { status: 403 });
|
||||
}
|
||||
|
||||
const body = await request.json().catch(() => null);
|
||||
const { table, id, text } = body ?? {};
|
||||
const config = ALLOWED_TABLES[table];
|
||||
if (!config || typeof text !== "string" || !text.trim()) {
|
||||
return NextResponse.json({ error: "Ungültige Eingaben." }, { status: 400 });
|
||||
}
|
||||
// Bei einem noch nicht gespeicherten (neuen) Eintrag gibt es keine
|
||||
// Zeile zum Aktualisieren – nur übersetzen, das Speichern übernimmt
|
||||
// anschließend das reguläre Formular.
|
||||
const persist = typeof id === "string" && id.length > 0;
|
||||
|
||||
const apiKey = process.env.DEEPL_API_KEY;
|
||||
if (!apiKey) {
|
||||
return NextResponse.json({ configured: false });
|
||||
}
|
||||
|
||||
try {
|
||||
const [en, pl] = await Promise.all([
|
||||
translateWithDeepL(text, "EN", apiKey),
|
||||
translateWithDeepL(text, "PL", apiKey),
|
||||
]);
|
||||
if (!en || !pl) throw new Error("Keine Übersetzung erhalten.");
|
||||
|
||||
if (persist) {
|
||||
const { error } = await admin
|
||||
.from(table)
|
||||
.update({ [`${config.textColumn}_en`]: en, [`${config.textColumn}_pl`]: pl })
|
||||
.eq(config.idColumn, id);
|
||||
if (error) throw new Error(error.message);
|
||||
}
|
||||
|
||||
return NextResponse.json({ configured: true, en, pl });
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: err instanceof Error ? err.message : "Übersetzung fehlgeschlagen." },
|
||||
{ status: 502 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user