@file-viewer/renderer-data 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/data.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { resolveFileViewerDataSqlWasmUrl } from '@file-viewer/core/assets';
2
+ import { createFileViewerTranslator } from '@file-viewer/core';
2
3
  const dataStyle = `
3
4
  .data-viewer{min-height:100%;padding:28px;background:#eef1f4;color:#132235}
4
5
  .data-card{max-width:1080px;margin:0 auto;overflow:hidden;border:1px solid rgba(15,23,42,.08);border-radius:8px;background:#fff;box-shadow:0 18px 48px rgba(15,23,42,.12)}
@@ -24,7 +25,6 @@ const fontMimeMap = {
24
25
  woff: 'font/woff',
25
26
  woff2: 'font/woff2',
26
27
  };
27
- const sampleText = 'Flyfish Viewer 轻量预览 AaBbCc 1234567890';
28
28
  const createStyle = (documentRef) => {
29
29
  const style = documentRef.createElement('style');
30
30
  style.textContent = dataStyle;
@@ -86,27 +86,27 @@ const getWindowSqlWasmOverride = (documentRef) => {
86
86
  return documentRef.defaultView?.__FLYFISH_DATA_SQL_WASM_URL__ ||
87
87
  (typeof window !== 'undefined' ? window.__FLYFISH_DATA_SQL_WASM_URL__ : undefined);
88
88
  };
89
- const renderFont = async (documentRef, buffer, type) => {
89
+ const renderFont = async (documentRef, buffer, type, t) => {
90
90
  const family = `FlyfishPreviewFont-${Date.now()}-${Math.random().toString(36).slice(2)}`;
91
91
  const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
92
92
  const FontFaceConstructor = ownerWindow?.FontFace || (typeof FontFace !== 'undefined' ? FontFace : undefined);
93
93
  if (!FontFaceConstructor) {
94
- throw new Error('当前浏览器不支持 FontFace API');
94
+ throw new Error(t('data.error.fontFaceUnsupported'));
95
95
  }
96
96
  const face = new FontFaceConstructor(family, buffer);
97
97
  await face.load();
98
98
  documentRef.fonts?.add(face);
99
99
  return {
100
- title: '字体文件预览',
100
+ title: t('data.title.font'),
101
101
  fontFamily: family,
102
102
  summary: [
103
- { label: '格式', value: type.toUpperCase() },
104
- { label: '大小', value: formatBytes(buffer.byteLength) },
105
- { label: '渲染方式', value: 'Browser FontFace API' },
103
+ { label: t('data.label.format'), value: type.toUpperCase() },
104
+ { label: t('data.label.size'), value: formatBytes(buffer.byteLength) },
105
+ { label: t('data.label.rendering'), value: 'Browser FontFace API' },
106
106
  ],
107
107
  };
108
108
  };
109
- const renderSqlite = async (documentRef, buffer, context) => {
109
+ const renderSqlite = async (documentRef, buffer, context, t) => {
110
110
  const { default: initSqlJs } = await import('sql.js');
111
111
  const sqlWasmUrl = resolveFileViewerDataSqlWasmUrl(context?.options?.data, [
112
112
  getWindowSqlWasmOverride(documentRef),
@@ -121,11 +121,11 @@ const renderSqlite = async (documentRef, buffer, context) => {
121
121
  ? db.exec(`select * from "${firstTable.replace(/"/g, '""')}" limit 30`)[0]
122
122
  : null;
123
123
  return {
124
- title: 'SQLite 数据库预览',
124
+ title: t('data.title.sqlite'),
125
125
  summary: [
126
- { label: '对象数', value: String(tables.length) },
127
- { label: '示例表', value: firstTable || '-' },
128
- { label: '渲染方式', value: 'sql.js WASM' },
126
+ { label: t('data.label.objects'), value: String(tables.length) },
127
+ { label: t('data.label.sampleTable'), value: firstTable || '-' },
128
+ { label: t('data.label.rendering'), value: 'sql.js WASM' },
129
129
  ],
130
130
  rows: rows
131
131
  ? makeRows(rows.values.map((values) => Object.fromEntries(rows.columns.map((column, index) => [column, values[index]]))))
@@ -136,7 +136,7 @@ const renderSqlite = async (documentRef, buffer, context) => {
136
136
  db.close();
137
137
  }
138
138
  };
139
- const renderParquet = async (buffer) => {
139
+ const renderParquet = async (buffer, t) => {
140
140
  const { parquetMetadataAsync, parquetReadObjects } = await import('hyparquet');
141
141
  const file = {
142
142
  byteLength: buffer.byteLength,
@@ -145,16 +145,16 @@ const renderParquet = async (buffer) => {
145
145
  const metadata = await parquetMetadataAsync(file);
146
146
  const rows = await parquetReadObjects({ file, rowFormat: 'object', rowEnd: 30 });
147
147
  return {
148
- title: 'Parquet 列式数据预览',
148
+ title: t('data.title.parquet'),
149
149
  summary: [
150
- { label: '行数', value: metadata.num_rows?.toString?.() || '-' },
151
- { label: '列数', value: String(metadata.schema?.filter(item => item.name).length || 0) },
152
- { label: '渲染方式', value: 'hyparquet' },
150
+ { label: t('data.label.rows'), value: metadata.num_rows?.toString?.() || '-' },
151
+ { label: t('data.label.columns'), value: String(metadata.schema?.filter(item => item.name).length || 0) },
152
+ { label: t('data.label.rendering'), value: 'hyparquet' },
153
153
  ],
154
154
  rows: makeRows(rows),
155
155
  };
156
156
  };
157
- const renderAvro = async (buffer) => {
157
+ const renderAvro = async (buffer, t) => {
158
158
  const avro = await import('avsc/etc/browser/avsc.js');
159
159
  const decoder = avro.createBlobDecoder(new Blob([buffer]));
160
160
  const rows = [];
@@ -172,26 +172,26 @@ const renderAvro = async (buffer) => {
172
172
  decoder.on('error', reject);
173
173
  });
174
174
  return {
175
- title: 'Avro 对象容器预览',
175
+ title: t('data.title.avro'),
176
176
  summary: [
177
- { label: '示例行', value: String(rows.length) },
178
- { label: 'Schema', value: schema ? '已读取' : '未读取' },
179
- { label: '渲染方式', value: 'avsc' },
177
+ { label: t('data.label.sampleRows'), value: String(rows.length) },
178
+ { label: 'Schema', value: schema ? t('data.value.schemaRead') : t('data.value.schemaUnread') },
179
+ { label: t('data.label.rendering'), value: 'avsc' },
180
180
  ],
181
181
  rows: makeRows(rows),
182
182
  text: schema.slice(0, 6000),
183
183
  };
184
184
  };
185
- const renderWasm = async (buffer) => {
185
+ const renderWasm = async (buffer, t) => {
186
186
  const module = await WebAssembly.compile(buffer.slice(0));
187
187
  const imports = WebAssembly.Module.imports(module);
188
188
  const exports = WebAssembly.Module.exports(module);
189
189
  return {
190
- title: 'WebAssembly 模块预览',
190
+ title: t('data.title.wasm'),
191
191
  summary: [
192
- { label: '导入', value: String(imports.length) },
193
- { label: '导出', value: String(exports.length) },
194
- { label: '渲染方式', value: 'WebAssembly.Module' },
192
+ { label: t('data.label.imports'), value: String(imports.length) },
193
+ { label: t('data.label.exports'), value: String(exports.length) },
194
+ { label: t('data.label.rendering'), value: 'WebAssembly.Module' },
195
195
  ],
196
196
  rows: makeRows([
197
197
  ...imports.map(item => ({ kind: 'import', module: item.module, name: item.name, type: item.kind })),
@@ -199,51 +199,51 @@ const renderWasm = async (buffer) => {
199
199
  ]),
200
200
  };
201
201
  };
202
- const renderPostScriptLike = async (buffer, type) => ({
203
- title: type === 'eps' ? 'EPS 矢量文件摘要' : 'Illustrator 文件摘要',
202
+ const renderPostScriptLike = async (buffer, type, t) => ({
203
+ title: type === 'eps' ? t('data.title.eps') : t('data.title.ai'),
204
204
  summary: [
205
- { label: 'Magic', value: readMagic(buffer).replace(/\s/g, ' ') },
206
- { label: '大小', value: formatBytes(buffer.byteLength) },
207
- { label: '说明', value: type === 'ai' ? '非 PDF-compatible AI 按摘要展示' : 'PostScript 摘要展示' },
205
+ { label: t('data.label.magic'), value: readMagic(buffer).replace(/\s/g, ' ') },
206
+ { label: t('data.label.size'), value: formatBytes(buffer.byteLength) },
207
+ { label: t('data.label.note'), value: type === 'ai' ? t('data.note.aiSummary') : t('data.note.postscriptSummary') },
208
208
  ],
209
209
  text: extractReadableText(buffer),
210
210
  });
211
- const renderWebArchive = async (buffer) => ({
212
- title: 'WebArchive 摘要预览',
211
+ const renderWebArchive = async (buffer, t) => ({
212
+ title: t('data.title.webarchive'),
213
213
  summary: [
214
- { label: '容器', value: readMagic(buffer).startsWith('bplist') ? 'Binary plist' : 'WebArchive' },
215
- { label: '大小', value: formatBytes(buffer.byteLength) },
216
- { label: '说明', value: '安全提取可读片段,不执行网页脚本' },
214
+ { label: t('data.label.container'), value: readMagic(buffer).startsWith('bplist') ? 'Binary plist' : 'WebArchive' },
215
+ { label: t('data.label.size'), value: formatBytes(buffer.byteLength) },
216
+ { label: t('data.label.note'), value: t('data.note.webarchive') },
217
217
  ],
218
218
  text: extractReadableText(buffer),
219
219
  });
220
- const buildPreview = async (documentRef, buffer, type, context) => {
220
+ const buildPreview = async (documentRef, buffer, type, context, t) => {
221
221
  if (type in fontMimeMap) {
222
- return renderFont(documentRef, buffer, type);
222
+ return renderFont(documentRef, buffer, type, t);
223
223
  }
224
224
  if (type === 'sqlite') {
225
- return renderSqlite(documentRef, buffer, context);
225
+ return renderSqlite(documentRef, buffer, context, t);
226
226
  }
227
227
  if (type === 'parquet') {
228
- return renderParquet(buffer);
228
+ return renderParquet(buffer, t);
229
229
  }
230
230
  if (type === 'avro') {
231
- return renderAvro(buffer);
231
+ return renderAvro(buffer, t);
232
232
  }
233
233
  if (type === 'wasm') {
234
- return renderWasm(buffer);
234
+ return renderWasm(buffer, t);
235
235
  }
236
236
  if (type === 'ai' || type === 'eps') {
237
- return renderPostScriptLike(buffer, type);
237
+ return renderPostScriptLike(buffer, type, t);
238
238
  }
239
239
  if (type === 'webarchive') {
240
- return renderWebArchive(buffer);
240
+ return renderWebArchive(buffer, t);
241
241
  }
242
242
  return {
243
- title: '数据资产摘要',
243
+ title: t('data.title.summary'),
244
244
  summary: [
245
- { label: '格式', value: type.toUpperCase() },
246
- { label: '大小', value: formatBytes(buffer.byteLength) },
245
+ { label: t('data.label.format'), value: type.toUpperCase() },
246
+ { label: t('data.label.size'), value: formatBytes(buffer.byteLength) },
247
247
  ],
248
248
  text: extractReadableText(buffer),
249
249
  };
@@ -282,7 +282,7 @@ const appendRows = (documentRef, parent, rows) => {
282
282
  wrap.appendChild(table);
283
283
  parent.appendChild(wrap);
284
284
  };
285
- const renderPreviewDom = (documentRef, preview, type) => {
285
+ const renderPreviewDom = (documentRef, preview, type, t) => {
286
286
  const root = createElement(documentRef, 'div', 'data-viewer');
287
287
  const card = createElement(documentRef, 'section', 'data-card');
288
288
  const header = createElement(documentRef, 'header', 'data-header');
@@ -290,7 +290,7 @@ const renderPreviewDom = (documentRef, preview, type) => {
290
290
  card.appendChild(header);
291
291
  appendSummary(documentRef, card, preview.summary);
292
292
  if (preview.fontFamily) {
293
- const fontPreview = createElement(documentRef, 'div', 'font-preview', sampleText);
293
+ const fontPreview = createElement(documentRef, 'div', 'font-preview', t('data.font.sample'));
294
294
  fontPreview.style.fontFamily = preview.fontFamily;
295
295
  card.appendChild(fontPreview);
296
296
  }
@@ -298,7 +298,7 @@ const renderPreviewDom = (documentRef, preview, type) => {
298
298
  const imageWrap = createElement(documentRef, 'div', 'asset-image');
299
299
  const image = createElement(documentRef, 'img');
300
300
  image.src = preview.image;
301
- image.alt = '资产预览';
301
+ image.alt = t('data.image.alt');
302
302
  imageWrap.appendChild(image);
303
303
  card.appendChild(imageWrap);
304
304
  }
@@ -312,6 +312,7 @@ const renderPreviewDom = (documentRef, preview, type) => {
312
312
  export default async function renderDataAsset(buffer, target, type = 'bin', context) {
313
313
  const documentRef = target.ownerDocument || document;
314
314
  const normalizedType = type.toLowerCase();
315
+ const t = createFileViewerTranslator(context?.options);
315
316
  if (normalizedType === 'ai' && readMagic(buffer, 5) === '%PDF-' && context?.renderNestedBuffer) {
316
317
  const rendered = await context.renderNestedBuffer(buffer, 'pdf', target, context);
317
318
  if (rendered) {
@@ -320,10 +321,10 @@ export default async function renderDataAsset(buffer, target, type = 'bin', cont
320
321
  }
321
322
  if (normalizedType === 'psd') {
322
323
  const { default: renderPsdAsset } = await import('./psd.js');
323
- return renderPsdAsset(buffer, target);
324
+ return renderPsdAsset(buffer, target, context);
324
325
  }
325
- const preview = await buildPreview(documentRef, buffer, normalizedType, context);
326
- const root = renderPreviewDom(documentRef, preview, normalizedType);
326
+ const preview = await buildPreview(documentRef, buffer, normalizedType, context, t);
327
+ const root = renderPreviewDom(documentRef, preview, normalizedType, t);
327
328
  target.replaceChildren(createStyle(documentRef), root);
328
329
  return {
329
330
  $el: root,
package/dist/psd.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { type FileViewerRenderedInstance } from '@file-viewer/core';
2
- export default function renderPsdAsset(buffer: ArrayBuffer, target: HTMLDivElement): Promise<FileViewerRenderedInstance>;
1
+ import { type FileRenderContext, type FileViewerRenderedInstance } from '@file-viewer/core';
2
+ export default function renderPsdAsset(buffer: ArrayBuffer, target: HTMLDivElement, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;
package/dist/psd.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
1
+ import { createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
2
2
  const psdStyle = `
3
3
  .psd-viewer{display:grid;height:100%;min-height:460px;grid-template-rows:auto minmax(0,1fr);--psd-bg:#eef1f4;--psd-surface:#fff;--psd-border:rgba(15,23,42,.1);--psd-text:#132235;--psd-muted:#64748b;--psd-accent:#0f766e;background:var(--psd-bg);color:var(--psd-text);box-sizing:border-box}
4
4
  .psd-toolbar{position:sticky;top:0;z-index:2;display:flex;min-height:52px;align-items:center;justify-content:space-between;gap:14px;padding:10px 16px;border-bottom:1px solid var(--psd-border);background:rgba(255,255,255,.92);backdrop-filter:blur(12px);box-sizing:border-box}
@@ -106,8 +106,9 @@ const flattenLayers = (documentRef, layers, depth = 0, path = '') => {
106
106
  const clampZoom = (value) => {
107
107
  return Math.min(4, Math.max(0.1, Number(value.toFixed(2))));
108
108
  };
109
- export default async function renderPsdAsset(buffer, target) {
109
+ export default async function renderPsdAsset(buffer, target, context) {
110
110
  const documentRef = target.ownerDocument || document;
111
+ const t = createFileViewerTranslator(context?.options);
111
112
  const { readPsd } = await import('ag-psd');
112
113
  const psd = readPsd(buffer, { useImageData: true });
113
114
  const compositeCanvas = toCanvas(documentRef, psd.canvas || psd.imageData);
@@ -120,14 +121,14 @@ export default async function renderPsdAsset(buffer, target) {
120
121
  root.dataset.viewerZoomProvider = 'psd';
121
122
  const toolbar = createElement(documentRef, 'div', 'psd-toolbar');
122
123
  const title = createElement(documentRef, 'div', 'psd-title');
123
- title.append(createElement(documentRef, 'strong', undefined, 'PSD 图层预览'), createElement(documentRef, 'span', undefined, `${psd.width || 0} x ${psd.height || 0} · ${layers.length} layers · ag-psd`));
124
+ title.append(createElement(documentRef, 'strong', undefined, t('psd.title')), createElement(documentRef, 'span', undefined, `${psd.width || 0} x ${psd.height || 0} · ${layers.length} layers · ag-psd`));
124
125
  const actions = createElement(documentRef, 'div', 'psd-actions');
125
126
  const zoomOut = createElement(documentRef, 'button', undefined, '-');
126
127
  const zoomLabel = createElement(documentRef, 'span', undefined, '100%');
127
128
  const zoomIn = createElement(documentRef, 'button', undefined, '+');
128
- const reset = createElement(documentRef, 'button', undefined, '适合');
129
- const showAll = createElement(documentRef, 'button', undefined, '全显');
130
- const hideAll = createElement(documentRef, 'button', undefined, '全隐');
129
+ const reset = createElement(documentRef, 'button', undefined, t('psd.action.fit'));
130
+ const showAll = createElement(documentRef, 'button', undefined, t('psd.action.showAll'));
131
+ const hideAll = createElement(documentRef, 'button', undefined, t('psd.action.hideAll'));
131
132
  [zoomOut, zoomIn, reset, showAll, hideAll].forEach(button => {
132
133
  button.type = 'button';
133
134
  });
@@ -136,7 +137,7 @@ export default async function renderPsdAsset(buffer, target) {
136
137
  const layout = createElement(documentRef, 'div', 'psd-layout');
137
138
  const sidebar = createElement(documentRef, 'aside', 'psd-sidebar');
138
139
  const sidebarHeader = createElement(documentRef, 'div', 'psd-sidebar-header');
139
- sidebarHeader.append(createElement(documentRef, 'span', undefined, '图层'), createElement(documentRef, 'span', undefined, `${drawableLayers.length} 可重绘`));
140
+ sidebarHeader.append(createElement(documentRef, 'span', undefined, t('psd.layers.title')), createElement(documentRef, 'span', undefined, t('psd.layers.redrawable', { count: drawableLayers.length })));
140
141
  const list = createElement(documentRef, 'ul', 'psd-layer-list');
141
142
  sidebar.append(sidebarHeader, list);
142
143
  const stage = createElement(documentRef, 'main', 'psd-stage');
@@ -169,7 +170,7 @@ export default async function renderPsdAsset(buffer, target) {
169
170
  });
170
171
  };
171
172
  if (!layers.length) {
172
- list.appendChild(createElement(documentRef, 'li', 'psd-empty', '未发现可展示图层,使用合成图预览。'));
173
+ list.appendChild(createElement(documentRef, 'li', 'psd-empty', t('psd.layers.empty')));
173
174
  }
174
175
  layers.forEach(layer => {
175
176
  const item = createElement(documentRef, 'li', 'psd-layer');
@@ -188,7 +189,7 @@ export default async function renderPsdAsset(buffer, target) {
188
189
  redraw();
189
190
  });
190
191
  const copy = createElement(documentRef, 'div');
191
- copy.append(createElement(documentRef, 'strong', undefined, layer.name), createElement(documentRef, 'span', undefined, `${layer.left},${layer.top} · ${layer.width} x ${layer.height}${layer.hidden ? ' · hidden' : ''}`));
192
+ copy.append(createElement(documentRef, 'strong', undefined, layer.name), createElement(documentRef, 'span', undefined, `${layer.left},${layer.top} · ${layer.width} x ${layer.height}${layer.hidden ? ` · ${t('psd.layers.hidden')}` : ''}`));
192
193
  item.append(checkbox, copy);
193
194
  list.appendChild(item);
194
195
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/renderer-data",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone data asset renderer plugin for Flyfish File Viewer with PSD, SQLite, Parquet, Avro, WASM, font, AI/EPS, and WebArchive previews.",
@@ -57,7 +57,7 @@
57
57
  "LICENSE"
58
58
  ],
59
59
  "dependencies": {
60
- "@file-viewer/core": "^2.1.2",
60
+ "@file-viewer/core": "^2.1.4",
61
61
  "ag-psd": "^30.1.1",
62
62
  "avsc": "^5.7.9",
63
63
  "hyparquet": "^1.26.0",