@file-viewer/renderer-archive 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.
Files changed (2) hide show
  1. package/dist/archive.js +43 -30
  2. package/package.json +2 -2
package/dist/archive.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolveFileViewerArchiveWasmUrl, resolveFileViewerArchiveWorkerUrl, } from '@file-viewer/core/assets';
2
- import { disposeFileViewerRendered, } from '@file-viewer/core';
2
+ import { createFileViewerTranslator, disposeFileViewerRendered, } from '@file-viewer/core';
3
3
  import { buildArchiveNestedRenderContext, createArchiveCacheKey, flattenArchiveObject, formatArchiveBytes, getArchiveEntryExtension, } from './archiveShared.js';
4
4
  import { readArchiveCache, writeArchiveCache } from './archiveCache.js';
5
5
  import { loadArchiveEntriesWithoutWorker } from './archiveFallback.js';
@@ -98,7 +98,7 @@ const getWorkerConstructor = (documentRef) => {
98
98
  const WorkerCtor = ((_a = documentRef.defaultView) === null || _a === void 0 ? void 0 : _a.Worker) ||
99
99
  (typeof Worker !== 'undefined' ? Worker : undefined);
100
100
  if (!WorkerCtor) {
101
- throw new Error('当前浏览器不支持 Web Worker');
101
+ throw new Error('Web Worker is not supported by this browser.');
102
102
  }
103
103
  return WorkerCtor;
104
104
  };
@@ -157,7 +157,7 @@ const prepareWorkerUrl = async (candidate, objectUrls) => {
157
157
  }
158
158
  const response = await fetch(candidate.workerUrl, { cache: 'no-cache' });
159
159
  if (!response.ok) {
160
- throw new Error(`无法读取 libarchive Worker: ${response.status}`);
160
+ throw new Error(`Unable to read libarchive Worker: ${response.status}`);
161
161
  }
162
162
  const source = await response.text();
163
163
  const workerUrl = URL.createObjectURL(new Blob([
@@ -174,7 +174,7 @@ const resolveWorkerCandidates = async (documentRef, options) => {
174
174
  : undefined;
175
175
  if (options === null || options === void 0 ? void 0 : options.workerUrl) {
176
176
  candidates.push({
177
- label: '自定义 libarchive Worker',
177
+ label: 'custom libarchive Worker',
178
178
  workerUrl: resolveFileViewerArchiveWorkerUrl(options, baseUrl),
179
179
  wasmUrl,
180
180
  });
@@ -183,7 +183,7 @@ const resolveWorkerCandidates = async (documentRef, options) => {
183
183
  const publicWorkerUrl = resolveFileViewerArchiveWorkerUrl(undefined, baseUrl);
184
184
  if (await probeWorkerUrl(publicWorkerUrl)) {
185
185
  candidates.push({
186
- label: '静态 libarchive Worker',
186
+ label: 'static libarchive Worker',
187
187
  workerUrl: publicWorkerUrl,
188
188
  wasmUrl,
189
189
  });
@@ -191,10 +191,11 @@ const resolveWorkerCandidates = async (documentRef, options) => {
191
191
  return candidates;
192
192
  };
193
193
  const renderNestedWithCoreFallback = async (buffer, type, target, context) => {
194
+ const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
194
195
  const { fileViewerCoreRendererDispatcher } = await import('@file-viewer/core');
195
196
  const handler = fileViewerCoreRendererDispatcher.resolve(type);
196
197
  if (!handler) {
197
- target.textContent = `不支持.${type}格式的在线预览,请下载后预览或转换为支持的格式`;
198
+ target.textContent = t('archive.error.nestedUnsupported', { type });
198
199
  return undefined;
199
200
  }
200
201
  return handler(buffer, target, type, {
@@ -219,8 +220,9 @@ export default async function renderArchive(buffer, target, _type, context) {
219
220
  let selectedEntry = null;
220
221
  let nestedRendered;
221
222
  let loading = false;
222
- let loadingText = '正在读取压缩包目录...';
223
- let loadingHint = '大文件会在 Worker 中解析,避免阻塞主线程。';
223
+ const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
224
+ let loadingText = t('archive.loading.readingDirectory');
225
+ let loadingHint = t('archive.loading.readingDirectoryHint');
224
226
  let errorText = '';
225
227
  let archiveNotice = '';
226
228
  let encrypted = null;
@@ -237,15 +239,15 @@ export default async function renderArchive(buffer, target, _type, context) {
237
239
  const info = createElement(documentRef, 'div', 'archive-info');
238
240
  const search = createElement(documentRef, 'input', 'archive-search');
239
241
  search.type = 'search';
240
- search.placeholder = '筛选压缩包内文件';
242
+ search.placeholder = t('archive.search.placeholder');
241
243
  const list = createElement(documentRef, 'div', 'archive-list');
242
244
  list.setAttribute('role', 'list');
243
245
  sidebar.append(head, warning, info, search, list);
244
246
  const preview = createElement(documentRef, 'main', 'archive-preview');
245
247
  const toolbar = createElement(documentRef, 'div', 'archive-preview-toolbar');
246
248
  const toolbarTitle = createElement(documentRef, 'div');
247
- toolbarTitle.append(createElement(documentRef, 'span', undefined, '压缩包内预览'), createElement(documentRef, 'strong', undefined, '请选择一个文件'));
248
- const downloadButton = createElement(documentRef, 'button', undefined, '下载文件');
249
+ toolbarTitle.append(createElement(documentRef, 'span', undefined, t('archive.preview.title')), createElement(documentRef, 'strong', undefined, t('archive.preview.chooseFile')));
250
+ const downloadButton = createElement(documentRef, 'button', undefined, t('archive.preview.downloadFile'));
249
251
  downloadButton.type = 'button';
250
252
  toolbar.append(toolbarTitle, downloadButton);
251
253
  const nestedTarget = createElement(documentRef, 'div', 'archive-nested-target');
@@ -262,7 +264,7 @@ export default async function renderArchive(buffer, target, _type, context) {
262
264
  state.append(stateContent);
263
265
  root.append(state);
264
266
  const error = createElement(documentRef, 'div', 'archive-error');
265
- const errorTitle = createElement(documentRef, 'strong', undefined, '压缩包预览提示');
267
+ const errorTitle = createElement(documentRef, 'strong', undefined, t('archive.error.title'));
266
268
  const errorMessage = createElement(documentRef, 'p');
267
269
  error.append(errorTitle, errorMessage);
268
270
  root.append(error);
@@ -299,8 +301,12 @@ export default async function renderArchive(buffer, target, _type, context) {
299
301
  };
300
302
  const syncState = () => {
301
303
  const archiveStats = getArchiveStats();
302
- stats.textContent = `${archiveStats.count} 个文件 · ${formatArchiveBytes(archiveStats.totalSize)} · ${archiveStats.previewableCount} 个可直接预览`;
303
- warning.textContent = '检测到加密内容,当前在线预览不接收密码,建议下载后本地解压。';
304
+ stats.textContent = t('archive.stats.summary', {
305
+ count: archiveStats.count,
306
+ size: formatArchiveBytes(archiveStats.totalSize),
307
+ previewable: archiveStats.previewableCount,
308
+ });
309
+ warning.textContent = t('archive.warning.encrypted');
304
310
  warning.classList.toggle('archive-hidden', !encrypted);
305
311
  info.textContent = archiveNotice;
306
312
  info.classList.toggle('archive-hidden', !archiveNotice);
@@ -312,7 +318,7 @@ export default async function renderArchive(buffer, target, _type, context) {
312
318
  downloadButton.hidden = !selectedEntry;
313
319
  const activeTitle = toolbarTitle.querySelector('strong');
314
320
  if (activeTitle) {
315
- activeTitle.textContent = (selectedEntry === null || selectedEntry === void 0 ? void 0 : selectedEntry.name) || '请选择一个文件';
321
+ activeTitle.textContent = (selectedEntry === null || selectedEntry === void 0 ? void 0 : selectedEntry.name) || t('archive.preview.chooseFile');
316
322
  }
317
323
  };
318
324
  const renderEmptyState = () => {
@@ -320,7 +326,7 @@ export default async function renderArchive(buffer, target, _type, context) {
320
326
  return;
321
327
  }
322
328
  const empty = createElement(documentRef, 'div', 'archive-empty');
323
- empty.append(createElement(documentRef, 'strong', undefined, '选择左侧文件即可预览'), createElement(documentRef, 'p', undefined, '压缩包只读取目录;文件内容会在点击后按需解压,并在体积允许时缓存到 IndexedDB。'));
329
+ empty.append(createElement(documentRef, 'strong', undefined, t('archive.empty.title')), createElement(documentRef, 'p', undefined, t('archive.empty.message')));
324
330
  nestedTarget.replaceChildren(empty);
325
331
  };
326
332
  const renderEntryList = () => {
@@ -371,13 +377,13 @@ export default async function renderArchive(buffer, target, _type, context) {
371
377
  return worker;
372
378
  },
373
379
  });
374
- setLoading(true, `正在初始化${candidate.label}...`, '如果当前服务器没有正确发布 Worker/WASM,会自动切换兼容模式。');
380
+ setLoading(true, t('archive.loading.initializingCandidate', { label: candidate.label }), t('archive.loading.initializingCandidateHint'));
375
381
  const archiveFile = createArchiveFile(documentRef, buffer, filename);
376
- const archive = await withTimeout(Archive.open(archiveFile), workerTimeoutMs, `${candidate.label} 初始化超时`, targetWindow);
382
+ const archive = await withTimeout(Archive.open(archiveFile), workerTimeoutMs, t('archive.error.candidateInitTimeout', { label: candidate.label }), targetWindow);
377
383
  archiveReader = archive;
378
- encrypted = await withTimeout(archive.hasEncryptedData(), workerTimeoutMs, `${candidate.label} 加密检测超时`, targetWindow).catch(() => null);
379
- setLoading(true, '正在读取压缩包目录...', '目录读取完成后,点击内部文件才会按需解压。');
380
- const fileTree = await withTimeout(archive.getFilesObject(), workerTimeoutMs, `${candidate.label} 读取目录超时`, targetWindow);
384
+ encrypted = await withTimeout(archive.hasEncryptedData(), workerTimeoutMs, t('archive.error.encryptedCheckTimeout', { label: candidate.label }), targetWindow).catch(() => null);
385
+ setLoading(true, t('archive.loading.readingDirectory'), t('archive.loading.directoryReadyHint'));
386
+ const fileTree = await withTimeout(archive.getFilesObject(), workerTimeoutMs, t('archive.error.candidateReadTimeout', { label: candidate.label }), targetWindow);
381
387
  entries = flattenArchiveObject(fileTree)
382
388
  .sort((left, right) => left.path.localeCompare(right.path));
383
389
  syncState();
@@ -393,14 +399,14 @@ export default async function renderArchive(buffer, target, _type, context) {
393
399
  }
394
400
  };
395
401
  const tryOpenArchiveWithFallback = async () => {
396
- setLoading(true, 'Worker 不可用,正在切换 ZIP/TAR 兼容模式...', '兼容模式无需额外静态 Worker,适合手机 WebView 或本地临时服务器。');
402
+ setLoading(true, t('archive.loading.workerFallback'), t('archive.loading.workerFallbackHint'));
397
403
  const fallbackEntries = await loadArchiveEntriesWithoutWorker(buffer, filename);
398
404
  if (!fallbackEntries) {
399
405
  return false;
400
406
  }
401
407
  entries = fallbackEntries.sort((left, right) => left.path.localeCompare(right.path));
402
408
  encrypted = null;
403
- archiveNotice = '当前环境的 libarchive Worker 未能启动,已自动切换到 ZIP/TAR/GZIP 兼容模式。RAR、7z 等格式仍建议发布 vendor/libarchive/worker-bundle.js 与 libarchive.wasm。';
409
+ archiveNotice = t('archive.notice.workerFallback');
404
410
  syncState();
405
411
  renderEntryList();
406
412
  renderEmptyState();
@@ -408,10 +414,13 @@ export default async function renderArchive(buffer, target, _type, context) {
408
414
  };
409
415
  const openArchive = async () => {
410
416
  if (buffer.byteLength > maxArchiveSize) {
411
- setError(`压缩包体积 ${formatArchiveBytes(buffer.byteLength)} 超过安全上限 ${formatArchiveBytes(maxArchiveSize)},请下载后在本地解压。`);
417
+ setError(t('archive.error.tooLarge', {
418
+ size: formatArchiveBytes(buffer.byteLength),
419
+ limit: formatArchiveBytes(maxArchiveSize),
420
+ }));
412
421
  return;
413
422
  }
414
- setLoading(true, '正在初始化压缩包解析 Worker...', '大文件会在 Worker 中解析,避免阻塞主线程。');
423
+ setLoading(true, t('archive.loading.initializingWorker'), t('archive.loading.initializingWorkerHint'));
415
424
  setError('');
416
425
  archiveNotice = '';
417
426
  try {
@@ -434,7 +443,7 @@ export default async function renderArchive(buffer, target, _type, context) {
434
443
  if (await tryOpenArchiveWithFallback()) {
435
444
  return;
436
445
  }
437
- throw new Error(errors.join('') || '压缩包 Worker 初始化失败');
446
+ throw new Error(errors.join('; ') || t('archive.error.workerInitFailed'));
438
447
  }
439
448
  catch (nextError) {
440
449
  console.error(nextError);
@@ -479,14 +488,18 @@ export default async function renderArchive(buffer, target, _type, context) {
479
488
  renderEntryList();
480
489
  syncState();
481
490
  if (entry.size > maxEntryPreviewSize) {
482
- setError(`压缩包内文件 ${entry.name} 体积 ${formatArchiveBytes(entry.size)} 超过预览上限 ${formatArchiveBytes(maxEntryPreviewSize)}。`);
491
+ setError(t('archive.error.entryTooLarge', {
492
+ name: entry.name,
493
+ size: formatArchiveBytes(entry.size),
494
+ limit: formatArchiveBytes(maxEntryPreviewSize),
495
+ }));
483
496
  return;
484
497
  }
485
- setLoading(true, `正在按需解压 ${entry.name}...`);
498
+ setLoading(true, t('archive.loading.extracting', { name: entry.name }));
486
499
  setError('');
487
500
  try {
488
501
  const entryBuffer = await extractEntryBuffer(entry);
489
- setLoading(true, `正在渲染 ${entry.name}...`);
502
+ setLoading(true, t('archive.loading.rendering', { name: entry.name }));
490
503
  await renderEntryBuffer(entry, entryBuffer);
491
504
  }
492
505
  catch (nextError) {
@@ -498,7 +511,7 @@ export default async function renderArchive(buffer, target, _type, context) {
498
511
  }
499
512
  }
500
513
  const downloadEntry = async (entry) => {
501
- setLoading(true, `正在导出 ${entry.name}...`);
514
+ setLoading(true, t('archive.loading.exporting', { name: entry.name }));
502
515
  try {
503
516
  const entryBuffer = await extractEntryBuffer(entry);
504
517
  const url = URL.createObjectURL(new Blob([entryBuffer]));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/renderer-archive",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone archive renderer plugin for Flyfish File Viewer with libarchive worker, ZIP/TAR fallback, IndexedDB cache, and nested previews.",
@@ -56,7 +56,7 @@
56
56
  "LICENSE"
57
57
  ],
58
58
  "dependencies": {
59
- "@file-viewer/core": "^2.1.2",
59
+ "@file-viewer/core": "^2.1.4",
60
60
  "jszip": "^3.10.1",
61
61
  "libarchive.js": "^2.0.2"
62
62
  },