import { useMemo, useState } from "react"; import { Plus, Trash2 } from "lucide-react"; import { SettingRow } from "@/components/settings/SettingRow"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { withCurrentLanguageOption, type SettingOption } from "@/lib/languageOptions"; import { getLanguageName } from "@/lib/languageNames"; import { ORIGINAL_METADATA_LANGUAGE, withMetadataLanguageOverride, withoutMetadataLanguageOverride, type MetadataLanguageOverrides, } from "@/lib/metadataLanguagePreferences"; interface MetadataLanguageSettingProps { fallback: string | null; overrides: MetadataLanguageOverrides; languageOptions: readonly SettingOption[]; disabled?: boolean; onFallbackChange: (language: string | null) => void; onOverridesChange: (overrides: MetadataLanguageOverrides) => void | Promise; } const NO_PREFERENCE = "__library_default"; function overridesEqual( left: MetadataLanguageOverrides, right: MetadataLanguageOverrides, ): boolean { const leftEntries = Object.entries(left); return ( leftEntries.length === Object.keys(right).length && leftEntries.every(([source, target]) => right[source] === target) ); } export function MetadataLanguageSetting({ fallback, overrides, languageOptions, disabled = false, onFallbackChange, onOverridesChange, }: MetadataLanguageSettingProps) { const [newSource, setNewSource] = useState(""); const [optimisticOverrides, setOptimisticOverrides] = useState<{ base: MetadataLanguageOverrides; value: MetadataLanguageOverrides; } | null>(null); const currentOverrides = optimisticOverrides !== null && overridesEqual(overrides, optimisticOverrides.base) ? optimisticOverrides.value : overrides; const entries = useMemo( () => Object.entries(currentOverrides).sort(([left], [right]) => getLanguageName(left).localeCompare(getLanguageName(right)), ), [currentOverrides], ); const namedOptions = useMemo( () => languageOptions.filter((language) => language.value !== ORIGINAL_METADATA_LANGUAGE), [languageOptions], ); const availableSources = namedOptions.filter((language) => !(language.value in currentOverrides)); const optionsForTarget = (target: string) => { if (target === ORIGINAL_METADATA_LANGUAGE) return namedOptions; return withCurrentLanguageOption(namedOptions, target); }; const changeOverrides = async (next: MetadataLanguageOverrides) => { const pending = { base: overrides, value: next }; setOptimisticOverrides(pending); try { await onOverridesChange(next); } catch { setOptimisticOverrides((current) => (current === pending ? null : current)); } }; const addException = () => { if (!newSource) return; void changeOverrides( withMetadataLanguageOverride(currentOverrides, newSource, ORIGINAL_METADATA_LANGUAGE), ); setNewSource(""); }; return ( (
{entries.length > 0 ? (
{entries.map(([source, target]) => (
{getLanguageName(source)}
))}
) : null} {availableSources.length > 0 ? (
) : null}
)} /> ); }