diff --git a/docutranslate/static/i18nData.json b/docutranslate/static/i18nData.json index 4174786..1877bf6 100644 --- a/docutranslate/static/i18nData.json +++ b/docutranslate/static/i18nData.json @@ -185,7 +185,8 @@ "glossaryExportCsv": "导出CSV", "glossaryUnsaved": "未保存", "glossarySaved": "术语表已保存,对所有用户生效。", - "glossarySaveFailed": "保存失败" + "glossarySaveFailed": "保存失败", + "glossaryImported": "已导入 {n} 条术语,请点击【保存】使其对所有用户生效。" }, "en": { "pageTitle": "DocuTranslate - Interactive Document Translation", @@ -373,7 +374,8 @@ "glossaryExportCsv": "Export CSV", "glossaryUnsaved": "Unsaved", "glossarySaved": "Glossary saved and applied to all users.", - "glossarySaveFailed": "Save failed" + "glossarySaveFailed": "Save failed", + "glossaryImported": "Imported {n} terms. Click [Save] to apply to all users." }, "id": { "pageTitle": "DocuTranslate - Terjemahan Dokumen Interaktif", @@ -561,6 +563,7 @@ "glossaryExportCsv": "Ekspor CSV", "glossaryUnsaved": "Belum disimpan", "glossarySaved": "Glosarium disimpan, berlaku untuk semua pengguna.", - "glossarySaveFailed": "Gagal menyimpan" + "glossarySaveFailed": "Gagal menyimpan", + "glossaryImported": "Mengimpor {n} istilah. Klik [Simpan] untuk berlaku ke semua pengguna." } } \ No newline at end of file diff --git a/docutranslate/static/index.html b/docutranslate/static/index.html index 761687e..90ce3b0 100644 --- a/docutranslate/static/index.html +++ b/docutranslate/static/index.html @@ -1427,15 +1427,22 @@ glossarySaving.value = false; } }; - const exportGlossaryCsv = () => { - const rows = glossaryRows.value; + const exportGlossaryCsv = async () => { + // 从服务端拉取数据库实际内容再导出(避免导出未保存的本地脏数据) + let rows = glossaryRows.value; + try { + const res = await fetch('/service/glossary'); + const data = await res.json(); + if (data && Array.isArray(data.rows)) rows = data.rows; + } catch (e) { console.error('export fetch failed, using local', e); } const esc = (s) => { s = String(s||''); return /[",\n]/.test(s) ? '"' + s.replace(/"/g,'""') + '"' : s; }; - let csv = 'zh,en,id\n'; + let csv = 'zh,en,id\n'; rows.forEach(r => { csv += [esc(r.zh), esc(r.en), esc(r.id)].join(',') + '\n'; }); - const blob = new Blob([csv], {type: 'text/csv;charset=utf-8'}); + // 加 UTF-8 BOM,保证 Excel 正确识别中文 + const blob = new Blob(['' + csv], {type: 'text/csv;charset=utf-8'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'glossary.csv'; a.click(); @@ -1448,8 +1455,11 @@ Array.from(files).forEach(f => { Papa.parse(f, { header: true, skipEmptyLines: true, + // 剥离 BOM + 规范化表头(小写、去空白),兼容 Excel 另存的 CSV + transformHeader: (h) => String(h||'').replace(/^/, '').trim().toLowerCase(), complete: (res) => { if (!res.data) return; + let added = 0; res.data.forEach(r => { const row = {zh:'', en:'', id:''}; if ('zh' in r || 'en' in r || 'id' in r) { @@ -1461,8 +1471,10 @@ if (row.zh || row.en || row.id) { glossaryRows.value.push(row); glossaryDirty.value = true; + added++; } }); + if (added) alert(t('glossaryImported').replace('{n}', added)); } }); });