fix: 术语表导入丢失中文列(BOM) + 导出改用数据库实际内容
- handleGlossaryFiles: 加 transformHeader 剥离BOM+规范化表头, 修复Excel/PapaParse读取带BOM的CSV时第一列名变成 zh 导致中文列被丢弃 - exportGlossaryCsv: 改为从 /service/glossary 拉取数据库实际内容再导出, 避免导出未保存的本地脏数据;导出文件加UTF-8 BOM保证Excel中文不乱码 - 导入成功后提示已导入条数并提醒保存 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -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."
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user