import { memo, useEffect, useMemo, useState } from "react"; import { Check } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { unflattenValues } from "@/lib/i18n-structure"; import { useClipboard } from "@/hooks/use-clipboard"; type Props = { open: boolean; onOpenChange: (next: boolean) => void; languages: string[]; valuesByLang: Record>; orderedPaths?: string[]; // 优先按照结构顺序导出 }; function ExportLanguageModalImpl({ open, onOpenChange, languages, valuesByLang, orderedPaths, }: Props) { const [selected, setSelected] = useState(""); const { copied, copy } = useClipboard({ resetAfterMs: 1500 }); useEffect(() => { if (open) { setSelected((prev) => prev && languages.includes(prev) ? prev : languages[0] ?? "" ); } }, [open, languages]); const jsonText = useMemo(() => { if (!selected) return ""; const flat = valuesByLang[selected] ?? {}; // 若提供结构顺序,则按结构顺序构建嵌套对象,保证键序与表格一致 if (orderedPaths && orderedPaths.length > 0) { const root: Record = {}; const added = new Set(); const setByPath = (path: string, val: string) => { const parts = path.split("."); let cur: Record = root; for (let i = 0; i < parts.length; i += 1) { const key = parts[i]!; const isLeaf = i === parts.length - 1; if (isLeaf) { cur[key] = val; } else { const next = cur[key]; if (next && typeof next === "object" && !Array.isArray(next)) { cur = next as Record; } else { const obj: Record = {}; cur[key] = obj; cur = obj; } } } }; for (const p of orderedPaths) { const v = Object.prototype.hasOwnProperty.call(flat, p) ? flat[p] : ""; setByPath(p, v); added.add(p); } // 追加结构外的剩余键,避免丢数据 for (const p of Object.keys(flat)) { if (!added.has(p)) setByPath(p, flat[p]!); } try { return JSON.stringify(root, null, 2); } catch { return "{}"; } } // 回退:无结构顺序时使用普通反扁平 try { return JSON.stringify(unflattenValues(flat), null, 2); } catch { return "{}"; } }, [selected, valuesByLang, orderedPaths]); function handleDownload() { if (!selected) return; const blob = new Blob([jsonText || "{}"], { type: "application/json;charset=utf-8", }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${selected}.json`; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } const handleCopy = () => { if (!jsonText) return; copy(jsonText); } return ( 导出语言 JSON
{languages.length === 0 ? (
暂无可导出的语言
) : ( languages.map((lang) => ( )) )}
); } export const ExportLanguageModal = memo(ExportLanguageModalImpl);