@file-viewer/core 2.2.3 → 2.2.5
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/README.en.md +17 -0
- package/README.md +17 -0
- package/dist/browser/controller.js +2 -2
- package/dist/contracts/types.d.ts +59 -4
- package/dist/features/printMask.d.ts +3 -2
- package/dist/features/printMask.js +74 -12
- package/dist/features/printMaskDesigner.d.ts +2 -1
- package/dist/features/printMaskDesigner.js +186 -13
- package/dist/headless.d.ts +5 -3
- package/dist/headless.js +3 -2
- package/dist/i18n/messages.d.ts +4 -2
- package/dist/i18n/messages.ja.d.ts +7 -0
- package/dist/i18n/messages.ja.js +435 -0
- package/dist/i18n/messages.js +59 -17
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/lifecycle/operations.d.ts +6 -4
- package/dist/lifecycle/operations.js +12 -5
- package/dist/output/export.js +2 -1
- package/dist/platform/assets.d.ts +8 -5
- package/dist/platform/assets.js +67 -13
- package/dist/renderers/image.js +48 -12
- package/dist/source/precheck.d.ts +36 -0
- package/dist/source/precheck.js +250 -0
- package/dist/viewer/createViewer.js +2 -1
- package/dist/viewer/operations.js +4 -3
- package/dist/viewer/state.js +19 -7
- package/package.json +1 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { DEFAULT_RENDERER_DEFINITIONS, DEFAULT_SUPPORTED_EXTENSIONS } from '../registry/formats.js';
|
|
2
|
+
import { getExtension, normalizeFileExtension, normalizeFilename, normalizeSource, } from './index.js';
|
|
3
|
+
const DEFAULT_MAX_PACKAGE_METADATA_BYTES = 8 * 1024 * 1024;
|
|
4
|
+
const ZIP_LOCAL_SIGNATURE = 0x04034b50;
|
|
5
|
+
const ZIP_CENTRAL_SIGNATURE = 0x02014b50;
|
|
6
|
+
const ZIP_END_SIGNATURE = 0x06054b50;
|
|
7
|
+
const ZIP64_SENTINEL = 0xffffffff;
|
|
8
|
+
const OLE_SIGNATURE = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
|
|
9
|
+
const OPEN_XML_REQUIRED_PARTS = {
|
|
10
|
+
docx: ['[content_types].xml', 'word/document.xml'],
|
|
11
|
+
docm: ['[content_types].xml', 'word/document.xml'],
|
|
12
|
+
dotx: ['[content_types].xml', 'word/document.xml'],
|
|
13
|
+
dotm: ['[content_types].xml', 'word/document.xml'],
|
|
14
|
+
xlsx: ['[content_types].xml', 'xl/workbook.xml'],
|
|
15
|
+
xltx: ['[content_types].xml', 'xl/workbook.xml'],
|
|
16
|
+
xlsm: ['[content_types].xml', 'xl/workbook.xml'],
|
|
17
|
+
xltm: ['[content_types].xml', 'xl/workbook.xml'],
|
|
18
|
+
xlsb: ['[content_types].xml', 'xl/workbook.bin'],
|
|
19
|
+
pptx: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
20
|
+
pptm: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
21
|
+
potx: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
22
|
+
potm: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
23
|
+
ppsx: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
24
|
+
ppsm: ['[content_types].xml', 'ppt/presentation.xml'],
|
|
25
|
+
odt: ['content.xml'],
|
|
26
|
+
ods: ['content.xml'],
|
|
27
|
+
odp: ['content.xml'],
|
|
28
|
+
ofd: ['ofd.xml'],
|
|
29
|
+
numbers: ['index/document.iwa'],
|
|
30
|
+
epub: ['meta-inf/container.xml'],
|
|
31
|
+
xps: ['[content_types].xml'],
|
|
32
|
+
dwfx: ['[content_types].xml'],
|
|
33
|
+
};
|
|
34
|
+
const ZIP_EXTENSIONS = new Set([
|
|
35
|
+
...Object.keys(OPEN_XML_REQUIRED_PARTS),
|
|
36
|
+
'zip', 'zipx', 'jar', 'war', 'ear', 'apk', 'cbz',
|
|
37
|
+
]);
|
|
38
|
+
const OLE_EXTENSIONS = new Set(['doc', 'dot', 'xls', 'xlt', 'ppt', 'msg']);
|
|
39
|
+
const TEXT_DECODER = new TextDecoder('utf-8');
|
|
40
|
+
const isArrayBuffer = (value) => value instanceof ArrayBuffer;
|
|
41
|
+
const isBlob = (value) => (typeof Blob !== 'undefined' && value instanceof Blob);
|
|
42
|
+
const toSource = (input, options) => {
|
|
43
|
+
if (isArrayBuffer(input)) {
|
|
44
|
+
return { buffer: input, filename: options.filename, type: options.type };
|
|
45
|
+
}
|
|
46
|
+
if (isBlob(input)) {
|
|
47
|
+
return { file: input, filename: options.filename, type: options.type };
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
...input,
|
|
51
|
+
filename: options.filename || input.filename,
|
|
52
|
+
type: options.type || input.type,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
const startsWithBytes = (bytes, expected) => (expected.every((value, index) => bytes[index] === value));
|
|
56
|
+
const findEndOfCentralDirectory = (bytes) => {
|
|
57
|
+
for (let offset = bytes.byteLength - 22; offset >= 0; offset -= 1) {
|
|
58
|
+
if (bytes[offset] === 0x50 &&
|
|
59
|
+
bytes[offset + 1] === 0x4b &&
|
|
60
|
+
bytes[offset + 2] === 0x05 &&
|
|
61
|
+
bytes[offset + 3] === 0x06) {
|
|
62
|
+
return offset;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return -1;
|
|
66
|
+
};
|
|
67
|
+
const collectCentralDirectoryEntries = (bytes) => {
|
|
68
|
+
const entries = new Set();
|
|
69
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
70
|
+
let offset = 0;
|
|
71
|
+
while (offset + 46 <= bytes.byteLength) {
|
|
72
|
+
if (view.getUint32(offset, true) !== ZIP_CENTRAL_SIGNATURE) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
const filenameLength = view.getUint16(offset + 28, true);
|
|
76
|
+
const extraLength = view.getUint16(offset + 30, true);
|
|
77
|
+
const commentLength = view.getUint16(offset + 32, true);
|
|
78
|
+
const end = offset + 46 + filenameLength;
|
|
79
|
+
if (end > bytes.byteLength) {
|
|
80
|
+
return { entries, complete: false };
|
|
81
|
+
}
|
|
82
|
+
entries.add(TEXT_DECODER.decode(bytes.subarray(offset + 46, end)).replace(/^\/+/, '').toLowerCase());
|
|
83
|
+
offset = end + extraLength + commentLength;
|
|
84
|
+
}
|
|
85
|
+
return { entries, complete: offset === bytes.byteLength };
|
|
86
|
+
};
|
|
87
|
+
const inspectZipBuffer = (buffer) => {
|
|
88
|
+
const bytes = new Uint8Array(buffer);
|
|
89
|
+
if (bytes.byteLength < 22) {
|
|
90
|
+
return { signatureValid: false, complete: true, entries: new Set() };
|
|
91
|
+
}
|
|
92
|
+
const view = new DataView(buffer);
|
|
93
|
+
const firstSignature = view.getUint32(0, true);
|
|
94
|
+
if (firstSignature !== ZIP_LOCAL_SIGNATURE && firstSignature !== ZIP_END_SIGNATURE) {
|
|
95
|
+
return { signatureValid: false, complete: true, entries: new Set() };
|
|
96
|
+
}
|
|
97
|
+
const endOffset = findEndOfCentralDirectory(bytes);
|
|
98
|
+
if (endOffset < 0) {
|
|
99
|
+
return { signatureValid: true, complete: false, entries: new Set() };
|
|
100
|
+
}
|
|
101
|
+
const centralSize = view.getUint32(endOffset + 12, true);
|
|
102
|
+
const centralOffset = view.getUint32(endOffset + 16, true);
|
|
103
|
+
if (centralSize === ZIP64_SENTINEL || centralOffset === ZIP64_SENTINEL) {
|
|
104
|
+
return { signatureValid: true, complete: false, entries: new Set() };
|
|
105
|
+
}
|
|
106
|
+
if (centralOffset + centralSize > bytes.byteLength) {
|
|
107
|
+
return { signatureValid: true, complete: false, entries: new Set() };
|
|
108
|
+
}
|
|
109
|
+
const result = collectCentralDirectoryEntries(bytes.subarray(centralOffset, centralOffset + centralSize));
|
|
110
|
+
return { signatureValid: true, complete: result.complete, entries: result.entries };
|
|
111
|
+
};
|
|
112
|
+
const inspectZipBlob = async (blob, maxPackageMetadataBytes) => {
|
|
113
|
+
if (blob.size < 22) {
|
|
114
|
+
return { signatureValid: false, complete: true, entries: new Set() };
|
|
115
|
+
}
|
|
116
|
+
const prefix = new Uint8Array(await blob.slice(0, 4).arrayBuffer());
|
|
117
|
+
const prefixView = new DataView(prefix.buffer, prefix.byteOffset, prefix.byteLength);
|
|
118
|
+
const firstSignature = prefixView.getUint32(0, true);
|
|
119
|
+
if (firstSignature !== ZIP_LOCAL_SIGNATURE && firstSignature !== ZIP_END_SIGNATURE) {
|
|
120
|
+
return { signatureValid: false, complete: true, entries: new Set() };
|
|
121
|
+
}
|
|
122
|
+
const tailStart = Math.max(0, blob.size - 65557);
|
|
123
|
+
const tail = new Uint8Array(await blob.slice(tailStart).arrayBuffer());
|
|
124
|
+
const endOffset = findEndOfCentralDirectory(tail);
|
|
125
|
+
if (endOffset < 0) {
|
|
126
|
+
return { signatureValid: true, complete: false, entries: new Set() };
|
|
127
|
+
}
|
|
128
|
+
const tailView = new DataView(tail.buffer, tail.byteOffset, tail.byteLength);
|
|
129
|
+
const centralSize = tailView.getUint32(endOffset + 12, true);
|
|
130
|
+
const centralOffset = tailView.getUint32(endOffset + 16, true);
|
|
131
|
+
if (centralSize === ZIP64_SENTINEL ||
|
|
132
|
+
centralOffset === ZIP64_SENTINEL ||
|
|
133
|
+
centralSize > maxPackageMetadataBytes ||
|
|
134
|
+
centralOffset + centralSize > blob.size) {
|
|
135
|
+
return { signatureValid: true, complete: false, entries: new Set() };
|
|
136
|
+
}
|
|
137
|
+
const central = new Uint8Array(await blob.slice(centralOffset, centralOffset + centralSize).arrayBuffer());
|
|
138
|
+
const result = collectCentralDirectoryEntries(central);
|
|
139
|
+
return { signatureValid: true, complete: result.complete, entries: result.entries };
|
|
140
|
+
};
|
|
141
|
+
const inspectZip = async (source, maxPackageMetadataBytes) => {
|
|
142
|
+
if (source.buffer) {
|
|
143
|
+
return inspectZipBuffer(source.buffer);
|
|
144
|
+
}
|
|
145
|
+
if (source.file) {
|
|
146
|
+
return inspectZipBlob(source.file, maxPackageMetadataBytes);
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
};
|
|
150
|
+
const readPrefix = async (source, byteLength = 1024) => {
|
|
151
|
+
if (source.buffer) {
|
|
152
|
+
return new Uint8Array(source.buffer, 0, Math.min(source.buffer.byteLength, byteLength));
|
|
153
|
+
}
|
|
154
|
+
if (source.file) {
|
|
155
|
+
return new Uint8Array(await source.file.slice(0, byteLength).arrayBuffer());
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
};
|
|
159
|
+
const inspectStructuredContent = async (source, extension, maxPackageMetadataBytes) => {
|
|
160
|
+
var _a, _b, _c;
|
|
161
|
+
const size = (_b = (_a = source.buffer) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : (_c = source.file) === null || _c === void 0 ? void 0 : _c.size;
|
|
162
|
+
if (size === 0 && (ZIP_EXTENSIONS.has(extension) || OLE_EXTENSIONS.has(extension) || extension === 'pdf')) {
|
|
163
|
+
return { inspected: true, valid: false, reason: 'empty-structured-file' };
|
|
164
|
+
}
|
|
165
|
+
if (ZIP_EXTENSIONS.has(extension)) {
|
|
166
|
+
const zip = await inspectZip(source, maxPackageMetadataBytes);
|
|
167
|
+
if (!zip) {
|
|
168
|
+
return { inspected: false, valid: null, reason: 'content-not-inspected' };
|
|
169
|
+
}
|
|
170
|
+
if (!zip.signatureValid) {
|
|
171
|
+
return { inspected: true, valid: false, reason: 'signature-mismatch' };
|
|
172
|
+
}
|
|
173
|
+
const required = OPEN_XML_REQUIRED_PARTS[extension] || [];
|
|
174
|
+
if (!zip.complete) {
|
|
175
|
+
return { inspected: true, valid: null, reason: 'content-inconclusive' };
|
|
176
|
+
}
|
|
177
|
+
const missingParts = required.filter(part => !zip.entries.has(part));
|
|
178
|
+
if (missingParts.length) {
|
|
179
|
+
return { inspected: true, valid: false, reason: 'missing-package-part', missingParts };
|
|
180
|
+
}
|
|
181
|
+
return { inspected: true, valid: true, reason: 'content-valid' };
|
|
182
|
+
}
|
|
183
|
+
const prefix = await readPrefix(source);
|
|
184
|
+
if (!prefix) {
|
|
185
|
+
return { inspected: false, valid: null, reason: 'content-not-inspected' };
|
|
186
|
+
}
|
|
187
|
+
if (OLE_EXTENSIONS.has(extension)) {
|
|
188
|
+
return startsWithBytes(prefix, OLE_SIGNATURE)
|
|
189
|
+
? { inspected: true, valid: true, reason: 'content-valid' }
|
|
190
|
+
: { inspected: true, valid: false, reason: 'signature-mismatch' };
|
|
191
|
+
}
|
|
192
|
+
if (extension === 'pdf') {
|
|
193
|
+
const header = TEXT_DECODER.decode(prefix);
|
|
194
|
+
return /%PDF-\d\.\d/.test(header)
|
|
195
|
+
? { inspected: true, valid: true, reason: 'content-valid' }
|
|
196
|
+
: { inspected: true, valid: false, reason: 'signature-mismatch' };
|
|
197
|
+
}
|
|
198
|
+
if (extension === 'rtf') {
|
|
199
|
+
const header = TEXT_DECODER.decode(prefix);
|
|
200
|
+
return /^\s*\{\\rtf\d/.test(header)
|
|
201
|
+
? { inspected: true, valid: true, reason: 'content-valid' }
|
|
202
|
+
: { inspected: true, valid: false, reason: 'signature-mismatch' };
|
|
203
|
+
}
|
|
204
|
+
return { inspected: false, valid: null, reason: 'content-not-inspected' };
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Performs a cheap, renderer-free capability and structure check.
|
|
208
|
+
*
|
|
209
|
+
* This intentionally does not promise rendering fidelity. A `ready` result
|
|
210
|
+
* means the extension is available and any known container/signature checks
|
|
211
|
+
* passed; the real renderer remains the final authority for malformed content.
|
|
212
|
+
*/
|
|
213
|
+
export const precheckFileViewerSource = async (input, options = {}) => {
|
|
214
|
+
var _a;
|
|
215
|
+
const source = toSource(input, options);
|
|
216
|
+
const normalized = normalizeSource(source);
|
|
217
|
+
const extension = normalizeFileExtension(options.type || normalized.extension || getExtension(options.filename || normalized.filename));
|
|
218
|
+
const filename = normalizeFilename(options.filename || normalized.filename);
|
|
219
|
+
const supportedExtensions = new Set(Array.from(options.supportedExtensions || DEFAULT_SUPPORTED_EXTENSIONS, normalizeFileExtension));
|
|
220
|
+
const supported = supportedExtensions.has(extension);
|
|
221
|
+
const rendererId = ((_a = DEFAULT_RENDERER_DEFINITIONS.find(definition => definition.extensions.some(candidate => normalizeFileExtension(candidate) === extension))) === null || _a === void 0 ? void 0 : _a.id) || null;
|
|
222
|
+
if (!supported) {
|
|
223
|
+
return {
|
|
224
|
+
filename,
|
|
225
|
+
extension,
|
|
226
|
+
rendererId,
|
|
227
|
+
supported: false,
|
|
228
|
+
inspected: false,
|
|
229
|
+
valid: null,
|
|
230
|
+
previewable: false,
|
|
231
|
+
status: 'unsupported',
|
|
232
|
+
reason: 'unsupported-extension',
|
|
233
|
+
missingParts: [],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const inspection = await inspectStructuredContent(source, extension, Math.max(64 * 1024, options.maxPackageMetadataBytes || DEFAULT_MAX_PACKAGE_METADATA_BYTES));
|
|
237
|
+
const valid = inspection.valid;
|
|
238
|
+
return {
|
|
239
|
+
filename,
|
|
240
|
+
extension,
|
|
241
|
+
rendererId,
|
|
242
|
+
supported: true,
|
|
243
|
+
inspected: inspection.inspected,
|
|
244
|
+
valid,
|
|
245
|
+
previewable: valid !== false,
|
|
246
|
+
status: valid === false ? 'invalid' : 'ready',
|
|
247
|
+
reason: inspection.reason,
|
|
248
|
+
missingParts: inspection.missingParts || [],
|
|
249
|
+
};
|
|
250
|
+
};
|
|
@@ -636,13 +636,14 @@ export const createViewer = (container, createOptions = {}) => {
|
|
|
636
636
|
});
|
|
637
637
|
},
|
|
638
638
|
async printWithMask(printOptions = {}) {
|
|
639
|
-
var _a, _b, _c, _d;
|
|
639
|
+
var _a, _b, _c, _d, _e;
|
|
640
640
|
const result = await openFileViewerPrintMaskDesignerAsync({
|
|
641
641
|
root: container,
|
|
642
642
|
pages: (_b = (_a = renderSurfaceState.exportAdapter) === null || _a === void 0 ? void 0 : _a.getPrintMaskPages) === null || _b === void 0 ? void 0 : _b.call(_a),
|
|
643
643
|
i18n: options,
|
|
644
644
|
color: (_c = printOptions.mask) === null || _c === void 0 ? void 0 : _c.color,
|
|
645
645
|
initialRegions: (_d = printOptions.mask) === null || _d === void 0 ? void 0 : _d.regions,
|
|
646
|
+
initialStamps: (_e = printOptions.mask) === null || _e === void 0 ? void 0 : _e.stamps,
|
|
646
647
|
});
|
|
647
648
|
if (!(result === null || result === void 0 ? void 0 : result.mask)) {
|
|
648
649
|
return;
|
|
@@ -262,7 +262,7 @@ export const createFileViewerOperationActionHandlers = ({ getBuffer, getFile, ge
|
|
|
262
262
|
}
|
|
263
263
|
},
|
|
264
264
|
async printWithMask(options = {}) {
|
|
265
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
265
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
266
266
|
try {
|
|
267
267
|
const source = getRenderedSource();
|
|
268
268
|
if (!source) {
|
|
@@ -276,6 +276,7 @@ export const createFileViewerOperationActionHandlers = ({ getBuffer, getFile, ge
|
|
|
276
276
|
i18n: resolveI18n(),
|
|
277
277
|
color: (_c = options.mask) === null || _c === void 0 ? void 0 : _c.color,
|
|
278
278
|
initialRegions: (_d = options.mask) === null || _d === void 0 ? void 0 : _d.regions,
|
|
279
|
+
initialStamps: (_e = options.mask) === null || _e === void 0 ? void 0 : _e.stamps,
|
|
279
280
|
});
|
|
280
281
|
if (!(result === null || result === void 0 ? void 0 : result.mask)) {
|
|
281
282
|
return undefined;
|
|
@@ -283,9 +284,9 @@ export const createFileViewerOperationActionHandlers = ({ getBuffer, getFile, ge
|
|
|
283
284
|
return await executeFileViewerPrintOperation({
|
|
284
285
|
...getRenderedOperationInput(),
|
|
285
286
|
...options,
|
|
286
|
-
watermarkInlineStyle: (
|
|
287
|
+
watermarkInlineStyle: (_g = (_f = options.watermarkInlineStyle) !== null && _f !== void 0 ? _f : getWatermarkInlineStyle === null || getWatermarkInlineStyle === void 0 ? void 0 : getWatermarkInlineStyle()) !== null && _g !== void 0 ? _g : undefined,
|
|
287
288
|
mask: result.mask,
|
|
288
|
-
printAvailable: (
|
|
289
|
+
printAvailable: (_h = getPrintAvailable === null || getPrintAvailable === void 0 ? void 0 : getPrintAvailable()) !== null && _h !== void 0 ? _h : true,
|
|
289
290
|
});
|
|
290
291
|
}
|
|
291
292
|
catch (error) {
|
package/dist/viewer/state.js
CHANGED
|
@@ -19,9 +19,19 @@ export const DEFAULT_FILE_VIEWER_STATE_THEME = Object.freeze({
|
|
|
19
19
|
hint: '正在整理内容结构并生成预览。',
|
|
20
20
|
});
|
|
21
21
|
export const DEFAULT_FILE_VIEWER_UNSUPPORTED_DESCRIPTION = '支持 Office、PDF、OFD、Typst、压缩包、邮件、OLB/DRA、CAD、地理数据、3D 模型、Excalidraw、draw.io、EPUB、UMD、Markdown、代码/文本、图片、音视频、字体和数据资产的在线预览';
|
|
22
|
-
const extensionLabel = (extension) => {
|
|
22
|
+
const extensionLabel = (extension, i18n) => {
|
|
23
23
|
const normalized = normalizeFileExtension(extension);
|
|
24
|
-
|
|
24
|
+
if (normalized) {
|
|
25
|
+
return `.${normalized}`;
|
|
26
|
+
}
|
|
27
|
+
const locale = resolveFileViewerLocale(i18n);
|
|
28
|
+
if (locale === 'zh-CN') {
|
|
29
|
+
return '当前文件';
|
|
30
|
+
}
|
|
31
|
+
if (locale === 'ja-JP') {
|
|
32
|
+
return '現在のファイル';
|
|
33
|
+
}
|
|
34
|
+
return 'current file';
|
|
25
35
|
};
|
|
26
36
|
const rendererPackageById = {
|
|
27
37
|
'office-word-openxml': '@file-viewer/renderer-word',
|
|
@@ -159,14 +169,16 @@ export const createFileViewerEmptyState = (extension = '', theme = DEFAULT_FILE_
|
|
|
159
169
|
recoverable: true,
|
|
160
170
|
});
|
|
161
171
|
export const createFileViewerUnsupportedState = (extension = '', theme = DEFAULT_FILE_VIEWER_STATE_THEME, i18n) => {
|
|
162
|
-
const label = extensionLabel(extension);
|
|
172
|
+
const label = extensionLabel(extension, i18n);
|
|
163
173
|
const installHint = resolveFileViewerRendererInstallHint(extension);
|
|
164
174
|
if (installHint) {
|
|
165
175
|
const locale = resolveFileViewerLocale(i18n);
|
|
166
176
|
const localeRendererTip = installHint.rendererPackage
|
|
167
177
|
? locale === 'zh-CN'
|
|
168
178
|
? `;如果需要极致裁剪,也可以只安装 ${installHint.rendererPackage}`
|
|
169
|
-
:
|
|
179
|
+
: locale === 'ja-JP'
|
|
180
|
+
? `;厳密に最小構成へ絞る場合は ${installHint.rendererPackage} のみをインストールすることもできます`
|
|
181
|
+
: `; for a strict custom cut, install only ${installHint.rendererPackage}`
|
|
170
182
|
: '';
|
|
171
183
|
return createFileViewerStateDescriptor({
|
|
172
184
|
state: 'unsupported',
|
|
@@ -258,9 +270,9 @@ export const formatFileViewerErrorMessage = (prefix, error, i18n) => {
|
|
|
258
270
|
if (!detail) {
|
|
259
271
|
return prefix;
|
|
260
272
|
}
|
|
261
|
-
return resolveFileViewerLocale(i18n) === '
|
|
262
|
-
? `${prefix}
|
|
263
|
-
: `${prefix}
|
|
273
|
+
return resolveFileViewerLocale(i18n) === 'en-US'
|
|
274
|
+
? `${prefix}: ${detail}`
|
|
275
|
+
: `${prefix}:${detail}`;
|
|
264
276
|
};
|
|
265
277
|
export const createFileViewerErrorState = (extension = '', error = undefined, theme = DEFAULT_FILE_VIEWER_STATE_THEME, i18n) => createFileViewerStateDescriptor({
|
|
266
278
|
state: 'error',
|
package/package.json
CHANGED