@blocklet/editor 1.6.198 → 1.6.200
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/lib/ext/AITranslationPlugin/selection.d.ts +2 -2
- package/lib/ext/AITranslationPlugin/translation.d.ts +2 -2
- package/lib/ext/AITranslationPlugin/translation.js +16 -2
- package/lib/ext/AITranslationPlugin/types.d.ts +11 -2
- package/lib/ext/AITranslationPlugin/utils.js +18 -9
- package/lib/ext/utils.d.ts +1 -0
- package/lib/ext/utils.js +10 -0
- package/package.json +3 -3
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { LexicalEditor } from 'lexical';
|
|
2
|
-
import type { TranslationOptions,
|
|
3
|
-
export declare const translateSelection: (editor: LexicalEditor, options: TranslationOptions) => Promise<
|
|
2
|
+
import type { TranslationOptions, TranslationResult } from './types';
|
|
3
|
+
export declare const translateSelection: (editor: LexicalEditor, options: TranslationOptions) => Promise<TranslationResult | null>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type LexicalEditor } from 'lexical';
|
|
2
|
-
import type { TranslationOptions,
|
|
3
|
-
export declare const translateFullContent: (editor: LexicalEditor, options: TranslationOptions) => Promise<
|
|
2
|
+
import type { TranslationOptions, TranslationResult } from './types';
|
|
3
|
+
export declare const translateFullContent: (editor: LexicalEditor, options: TranslationOptions) => Promise<TranslationResult | null>;
|
|
@@ -12,8 +12,16 @@ export const translateFullContent = async (editor, options) => {
|
|
|
12
12
|
sourceTextsWithPlaceholder[key] = processPlaceholders(text);
|
|
13
13
|
});
|
|
14
14
|
const targetTexts = {};
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const errorsMap = {};
|
|
16
|
+
await translateAPI({ texts: sourceTextsWithPlaceholder, sourceLanguage, targetLanguage }, ({ data, progress, error }) => {
|
|
17
|
+
const sourceText = sourceTexts[data.key];
|
|
18
|
+
if (error) {
|
|
19
|
+
targetTexts[data.key] = sourceText;
|
|
20
|
+
errorsMap[data.key] = error;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
targetTexts[data.key] = restorePlaceholders(sourceText, data.text);
|
|
24
|
+
}
|
|
17
25
|
if (options.onProgress && progress) {
|
|
18
26
|
options.onProgress(progress);
|
|
19
27
|
}
|
|
@@ -28,8 +36,13 @@ export const translateFullContent = async (editor, options) => {
|
|
|
28
36
|
};
|
|
29
37
|
})
|
|
30
38
|
.filter((x) => !!x.text);
|
|
39
|
+
const errors = translationBlocks
|
|
40
|
+
.filter((x) => !!errorsMap[x.key])
|
|
41
|
+
.map((item) => ({ ...item, error: errorsMap[item.key] }));
|
|
31
42
|
// eslint-disable-next-line no-console
|
|
32
43
|
console.log('translations: ', translations);
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.log('errors: ', errors);
|
|
33
46
|
// 默认自动替换
|
|
34
47
|
const autoReplace = options.autoReplace !== false;
|
|
35
48
|
if (autoReplace && !signal?.aborted) {
|
|
@@ -39,6 +52,7 @@ export const translateFullContent = async (editor, options) => {
|
|
|
39
52
|
}
|
|
40
53
|
return {
|
|
41
54
|
translations,
|
|
55
|
+
errors,
|
|
42
56
|
preview: () => {
|
|
43
57
|
return editor.getEditorState().read(() => $preview(translations));
|
|
44
58
|
},
|
|
@@ -20,9 +20,10 @@ export interface TranslatePayload {
|
|
|
20
20
|
[key: string]: string;
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
export type TranslateAPI = (payload: TranslatePayload, onData: ({ data, progress }: {
|
|
23
|
+
export type TranslateAPI = (payload: TranslatePayload, onData: ({ data, progress, error }: {
|
|
24
24
|
data: TranslationBlock;
|
|
25
25
|
progress?: number;
|
|
26
|
+
error?: string;
|
|
26
27
|
}) => void) => Promise<void>;
|
|
27
28
|
export interface TranslationOptions {
|
|
28
29
|
sourceLanguage?: string;
|
|
@@ -33,8 +34,16 @@ export interface TranslationOptions {
|
|
|
33
34
|
autoReplace?: boolean;
|
|
34
35
|
}
|
|
35
36
|
export interface TranslateSelectionOperations {
|
|
36
|
-
translations: TranslationBlock[];
|
|
37
37
|
preview: () => string;
|
|
38
38
|
replace: (editor?: LexicalEditor) => void;
|
|
39
39
|
insertBelow: () => void;
|
|
40
40
|
}
|
|
41
|
+
export interface TranslationError {
|
|
42
|
+
key: string;
|
|
43
|
+
text: string;
|
|
44
|
+
error: string;
|
|
45
|
+
}
|
|
46
|
+
export interface TranslationResult extends TranslateSelectionOperations {
|
|
47
|
+
translations: TranslationBlock[];
|
|
48
|
+
errors?: TranslationError[];
|
|
49
|
+
}
|
|
@@ -4,8 +4,9 @@ import { $isListNode, $isListItemNode } from '@lexical/list';
|
|
|
4
4
|
import { $dfs, $findMatchingParent } from '@lexical/utils';
|
|
5
5
|
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
|
6
6
|
import { $createLinkNode, $isLinkNode } from '@lexical/link';
|
|
7
|
-
import { blockletExists, getBlockletMountPointInfo } from '../utils';
|
|
7
|
+
import { blockletExists, getBlockletMountPointInfo, isValidUrl } from '../utils';
|
|
8
8
|
import { $getDepth } from '../../lexical-utils';
|
|
9
|
+
const PLACEHOLDER = '[[PLACEHOLDER]]';
|
|
9
10
|
export const defaultTranslateAPI = async ({ texts, sourceLanguage, targetLanguage }, onData) => {
|
|
10
11
|
if (!blockletExists('did-comments')) {
|
|
11
12
|
throw new Error('Discuss Kit component must be installed.');
|
|
@@ -23,11 +24,12 @@ export const defaultTranslateAPI = async ({ texts, sourceLanguage, targetLanguag
|
|
|
23
24
|
// @see: https://github.com/Azure/fetch-event-source/issues/36
|
|
24
25
|
openWhenHidden: true,
|
|
25
26
|
onmessage: (ev) => {
|
|
26
|
-
const parsed = JSON.parse(ev.data);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const { error, ...parsed } = JSON.parse(ev.data);
|
|
28
|
+
const data = {
|
|
29
|
+
data: parsed,
|
|
30
|
+
progress: Number((++done / total).toFixed(2)) * 100,
|
|
31
|
+
error,
|
|
32
|
+
};
|
|
31
33
|
// eslint-disable-next-line no-console
|
|
32
34
|
console.log('onmessage: ', ev, data);
|
|
33
35
|
onData(data);
|
|
@@ -158,7 +160,14 @@ export const $extractTranslationBlocks = (translationNodes) => {
|
|
|
158
160
|
const text = $extractTextContentFromTranslationNode(node);
|
|
159
161
|
return { key: node.getKey(), text };
|
|
160
162
|
})
|
|
161
|
-
.filter((item) =>
|
|
163
|
+
.filter((item) => {
|
|
164
|
+
const trim = item.text?.trim();
|
|
165
|
+
// 如果为空或 url, 则不翻译
|
|
166
|
+
if (!trim || isValidUrl(trim)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
});
|
|
162
171
|
};
|
|
163
172
|
/**
|
|
164
173
|
* 处理带有 `###key###` 的文本, 将普通文本转成 TextNode, 将 `###key###` 替换成 key 对应的 Node
|
|
@@ -366,14 +375,14 @@ export const $extractTranslationBlocksFromSelection = (selection) => {
|
|
|
366
375
|
// console.log({ firstTranslationBlock, blocks, lastTranslationBlock });
|
|
367
376
|
return [firstTranslationBlock, ...blocks, lastTranslationBlock].filter((item) => !!item?.text);
|
|
368
377
|
};
|
|
369
|
-
export const processPlaceholders = (text, placeholder =
|
|
378
|
+
export const processPlaceholders = (text, placeholder = PLACEHOLDER) => {
|
|
370
379
|
const matches = text.match(/###\d+###/g);
|
|
371
380
|
if (matches) {
|
|
372
381
|
return text.replaceAll(/###\d+###/g, placeholder);
|
|
373
382
|
}
|
|
374
383
|
return text;
|
|
375
384
|
};
|
|
376
|
-
export const restorePlaceholders = (original, replacedText, placeholder =
|
|
385
|
+
export const restorePlaceholders = (original, replacedText, placeholder = PLACEHOLDER) => {
|
|
377
386
|
const matches = original.match(/###\d+###/g);
|
|
378
387
|
if (matches) {
|
|
379
388
|
return matches.reduce((acc, cur) => {
|
package/lib/ext/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LinkNode } from '@lexical/link';
|
|
2
2
|
import { type LexicalEditor } from 'lexical';
|
|
3
3
|
export declare function joinUrl(...paths: string[]): string;
|
|
4
|
+
export declare function isValidUrl(url: string): boolean;
|
|
4
5
|
export declare const safeParseJSON: (json: string, defaultValue?: any) => any;
|
|
5
6
|
export declare const getBlockletMountPointInfo: (name: string) => any;
|
|
6
7
|
export declare const blockletExists: (name: string) => boolean;
|
package/lib/ext/utils.js
CHANGED
|
@@ -7,6 +7,16 @@ function dedupeSlashes(path) {
|
|
|
7
7
|
export function joinUrl(...paths) {
|
|
8
8
|
return dedupeSlashes(paths.join('/'));
|
|
9
9
|
}
|
|
10
|
+
export function isValidUrl(url) {
|
|
11
|
+
try {
|
|
12
|
+
// eslint-disable-next-line no-new
|
|
13
|
+
new URL(url);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
10
20
|
export const safeParseJSON = (json, defaultValue = null) => {
|
|
11
21
|
try {
|
|
12
22
|
return JSON.parse(json);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/editor",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.200",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npm run storybook",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@arcblock/ux": "^2.9.63",
|
|
41
41
|
"@blocklet/embed": "^0.1.11",
|
|
42
|
-
"@blocklet/pdf": "1.6.
|
|
42
|
+
"@blocklet/pdf": "1.6.200",
|
|
43
43
|
"@excalidraw/excalidraw": "^0.14.2",
|
|
44
44
|
"@iconify/iconify": "^3.0.1",
|
|
45
45
|
"@lexical/clipboard": "0.13.1",
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"react": "*",
|
|
109
109
|
"react-dom": "*"
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "9a1304683bb3a7775d995c6cb5e5ffcee39be438"
|
|
112
112
|
}
|