Automatisch-übersetzen-Button nur bei konfiguriertem DEEPL_API_KEY

Statt den Button immer anzuzeigen und erst nach Klick auf die
fehlende Konfiguration hinzuweisen, wird er serverseitig anhand von
process.env.DEEPL_API_KEY ein-/ausgeblendet (Gerichte, Allergene,
Zusatzstoffe). Die dadurch überflüssige "translateUnavailable"-
Meldung wurde aus allen drei Sprachen entfernt.
This commit is contained in:
2026-07-18 08:14:49 +02:00
parent 868a5d2fcf
commit 51fdb93e97
5 changed files with 55 additions and 68 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
import DishManager from "@/components/DishManager"; import DishManager from "@/components/DishManager";
export default function GerichtePage() { export default function GerichtePage() {
return <DishManager />; return <DishManager translateEnabled={!!process.env.DEEPL_API_KEY} />;
} }
+3 -2
View File
@@ -1,10 +1,11 @@
import CodeListManager from "@/components/CodeListManager"; import CodeListManager from "@/components/CodeListManager";
export default function KennzeichnungPage() { export default function KennzeichnungPage() {
const translateEnabled = !!process.env.DEEPL_API_KEY;
return ( return (
<div className="grid gap-6 lg:grid-cols-2"> <div className="grid gap-6 lg:grid-cols-2">
<CodeListManager table="allergens" /> <CodeListManager table="allergens" translateEnabled={translateEnabled} />
<CodeListManager table="additives" /> <CodeListManager table="additives" translateEnabled={translateEnabled} />
</div> </div>
); );
} }
+24 -29
View File
@@ -12,8 +12,10 @@ import { useDict, useLocale } from "@/components/i18n/LocaleProvider";
export default function CodeListManager({ export default function CodeListManager({
table, table,
translateEnabled,
}: { }: {
table: "allergens" | "additives"; table: "allergens" | "additives";
translateEnabled: boolean;
}) { }) {
const supabase = useMemo(() => createClient(), []); const supabase = useMemo(() => createClient(), []);
const dict = useDict(); const dict = useDict();
@@ -34,9 +36,9 @@ export default function CodeListManager({
namePl: string; namePl: string;
} | null>(null); } | null>(null);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [translateState, setTranslateState] = useState< const [translateState, setTranslateState] = useState<"idle" | "busy" | "done">(
"idle" | "busy" | "done" | "unavailable" "idle"
>("idle"); );
const load = useCallback(async () => { const load = useCallback(async () => {
const { data, error } = await supabase.from(table).select("*").order("sort"); const { data, error } = await supabase.from(table).select("*").order("sort");
@@ -115,10 +117,6 @@ export default function CodeListManager({
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok) throw new Error(data?.error ?? `Fehler (${res.status})`); if (!res.ok) throw new Error(data?.error ?? `Fehler (${res.status})`);
if (data.configured === false) {
setTranslateState("unavailable");
return;
}
setEditing((prev) => setEditing((prev) =>
prev ? { ...prev, nameEn: data.en ?? prev.nameEn, namePl: data.pl ?? prev.namePl } : prev prev ? { ...prev, nameEn: data.en ?? prev.nameEn, namePl: data.pl ?? prev.namePl } : prev
); );
@@ -191,28 +189,25 @@ export default function CodeListManager({
/> />
</div> </div>
</div> </div>
<div> {translateEnabled && (
<button <div>
type="button" <button
className="btn btn-neutral" type="button"
onClick={autoTranslate} className="btn btn-neutral"
disabled={translateState === "busy" || !editing.name.trim()} onClick={autoTranslate}
> disabled={translateState === "busy" || !editing.name.trim()}
{translateState === "busy" >
? dict.dishManager.translating {translateState === "busy"
: dict.dishManager.autoTranslate} ? dict.dishManager.translating
</button> : dict.dishManager.autoTranslate}
{translateState === "done" && ( </button>
<span className="ml-2 text-sm text-green-700"> {translateState === "done" && (
{dict.dishManager.translated} <span className="ml-2 text-sm text-green-700">
</span> {dict.dishManager.translated}
)} </span>
{translateState === "unavailable" && ( )}
<span className="ml-2 text-sm text-gray-500"> </div>
{dict.dishManager.translateUnavailable} )}
</span>
)}
</div>
<div className="flex gap-2"> <div className="flex gap-2">
<button type="submit" className="btn btn-add"> <button type="submit" className="btn btn-add">
{dict.common.save} {dict.common.save}
+27 -30
View File
@@ -29,7 +29,11 @@ const EMPTY_FORM: DishForm = {
additives: [], additives: [],
}; };
export default function DishManager() { export default function DishManager({
translateEnabled,
}: {
translateEnabled: boolean;
}) {
const supabase = useMemo(() => createClient(), []); const supabase = useMemo(() => createClient(), []);
const dict = useDict(); const dict = useDict();
const locale = useLocale(); const locale = useLocale();
@@ -42,9 +46,9 @@ export default function DishManager() {
const [selected, setSelected] = useState<Set<string>>(new Set()); const [selected, setSelected] = useState<Set<string>>(new Set());
const [bulkBusy, setBulkBusy] = useState(false); const [bulkBusy, setBulkBusy] = useState(false);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [translateState, setTranslateState] = useState< const [translateState, setTranslateState] = useState<"idle" | "busy" | "done">(
"idle" | "busy" | "done" | "unavailable" "idle"
>("idle"); );
// Live-Suche: filtert die Liste bereits während des Tippens // Live-Suche: filtert die Liste bereits während des Tippens
const visible = useMemo(() => { const visible = useMemo(() => {
@@ -199,10 +203,6 @@ export default function DishManager() {
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok) throw new Error(data?.error ?? `Fehler (${res.status})`); if (!res.ok) throw new Error(data?.error ?? `Fehler (${res.status})`);
if (data.configured === false) {
setTranslateState("unavailable");
return;
}
setForm((prev) => setForm((prev) =>
prev ? { ...prev, nameEn: data.en ?? prev.nameEn, namePl: data.pl ?? prev.namePl } : prev prev ? { ...prev, nameEn: data.en ?? prev.nameEn, namePl: data.pl ?? prev.namePl } : prev
); );
@@ -296,28 +296,25 @@ export default function DishManager() {
/> />
</div> </div>
</div> </div>
<div> {translateEnabled && (
<button <div>
type="button" <button
className="btn btn-neutral" type="button"
onClick={autoTranslate} className="btn btn-neutral"
disabled={translateState === "busy" || !form.name.trim()} onClick={autoTranslate}
> disabled={translateState === "busy" || !form.name.trim()}
{translateState === "busy" >
? dict.dishManager.translating {translateState === "busy"
: dict.dishManager.autoTranslate} ? dict.dishManager.translating
</button> : dict.dishManager.autoTranslate}
{translateState === "done" && ( </button>
<span className="ml-2 text-sm text-green-700"> {translateState === "done" && (
{dict.dishManager.translated} <span className="ml-2 text-sm text-green-700">
</span> {dict.dishManager.translated}
)} </span>
{translateState === "unavailable" && ( )}
<span className="ml-2 text-sm text-gray-500"> </div>
{dict.dishManager.translateUnavailable} )}
</span>
)}
</div>
<ChipPicker <ChipPicker
label={dict.codeList.allergensTitle} label={dict.codeList.allergensTitle}
-6
View File
@@ -88,8 +88,6 @@ const de = {
autoTranslate: "Automatisch übersetzen", autoTranslate: "Automatisch übersetzen",
translating: "Übersetze…", translating: "Übersetze…",
translated: "Übersetzt.", translated: "Übersetzt.",
translateUnavailable:
"Automatische Übersetzung ist nicht eingerichtet. Bitte Englisch/Polnisch manuell ausfüllen.",
priceLabel: "Preis in €", priceLabel: "Preis in €",
pricePlaceholder: "3,50", pricePlaceholder: "3,50",
searchPlaceholder: "Gericht suchen…", searchPlaceholder: "Gericht suchen…",
@@ -346,8 +344,6 @@ const en: Dict = {
autoTranslate: "Auto-translate", autoTranslate: "Auto-translate",
translating: "Translating…", translating: "Translating…",
translated: "Translated.", translated: "Translated.",
translateUnavailable:
"Automatic translation is not set up. Please fill in English/Polish manually.",
priceLabel: "Price in €", priceLabel: "Price in €",
pricePlaceholder: "3.50", pricePlaceholder: "3.50",
searchPlaceholder: "Search dishes…", searchPlaceholder: "Search dishes…",
@@ -602,8 +598,6 @@ const pl: Dict = {
autoTranslate: "Przetłumacz automatycznie", autoTranslate: "Przetłumacz automatycznie",
translating: "Tłumaczenie…", translating: "Tłumaczenie…",
translated: "Przetłumaczono.", translated: "Przetłumaczono.",
translateUnavailable:
"Automatyczne tłumaczenie nie jest skonfigurowane. Wypełnij angielski/polski ręcznie.",
priceLabel: "Cena w €", priceLabel: "Cena w €",
pricePlaceholder: "3,50", pricePlaceholder: "3,50",
searchPlaceholder: "Szukaj dania…", searchPlaceholder: "Szukaj dania…",