ckeditor5-livewire 0.0.1
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/hooks/context/context.d.ts +39 -0
- package/dist/hooks/context/context.d.ts.map +1 -0
- package/dist/hooks/context/contexts-registry.d.ts +9 -0
- package/dist/hooks/context/contexts-registry.d.ts.map +1 -0
- package/dist/hooks/context/index.d.ts +4 -0
- package/dist/hooks/context/index.d.ts.map +1 -0
- package/dist/hooks/context/typings.d.ts +34 -0
- package/dist/hooks/context/typings.d.ts.map +1 -0
- package/dist/hooks/editable.d.ts +40 -0
- package/dist/hooks/editable.d.ts.map +1 -0
- package/dist/hooks/editor/custom-editor-plugins.d.ts +54 -0
- package/dist/hooks/editor/custom-editor-plugins.d.ts.map +1 -0
- package/dist/hooks/editor/editor.d.ts +69 -0
- package/dist/hooks/editor/editor.d.ts.map +1 -0
- package/dist/hooks/editor/editors-registry.d.ts +9 -0
- package/dist/hooks/editor/editors-registry.d.ts.map +1 -0
- package/dist/hooks/editor/index.d.ts +3 -0
- package/dist/hooks/editor/index.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/index.d.ts +3 -0
- package/dist/hooks/editor/plugins/index.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/livewire-sync.d.ts +19 -0
- package/dist/hooks/editor/plugins/livewire-sync.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/sync-editor-with-input.d.ts +6 -0
- package/dist/hooks/editor/plugins/sync-editor-with-input.d.ts.map +1 -0
- package/dist/hooks/editor/typings.d.ts +99 -0
- package/dist/hooks/editor/typings.d.ts.map +1 -0
- package/dist/hooks/editor/utils/create-editor-in-context.d.ts +44 -0
- package/dist/hooks/editor/utils/create-editor-in-context.d.ts.map +1 -0
- package/dist/hooks/editor/utils/get-editor-roots-values.d.ts +9 -0
- package/dist/hooks/editor/utils/get-editor-roots-values.d.ts.map +1 -0
- package/dist/hooks/editor/utils/index.d.ts +12 -0
- package/dist/hooks/editor/utils/index.d.ts.map +1 -0
- package/dist/hooks/editor/utils/is-single-editing-like-editor.d.ts +9 -0
- package/dist/hooks/editor/utils/is-single-editing-like-editor.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-constructor.d.ts +9 -0
- package/dist/hooks/editor/utils/load-editor-constructor.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-plugins.d.ts +20 -0
- package/dist/hooks/editor/utils/load-editor-plugins.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-translations.d.ts +14 -0
- package/dist/hooks/editor/utils/load-editor-translations.d.ts.map +1 -0
- package/dist/hooks/editor/utils/normalize-custom-translations.d.ts +11 -0
- package/dist/hooks/editor/utils/normalize-custom-translations.d.ts.map +1 -0
- package/dist/hooks/editor/utils/query-editor-editables.d.ts +34 -0
- package/dist/hooks/editor/utils/query-editor-editables.d.ts.map +1 -0
- package/dist/hooks/editor/utils/resolve-editor-config-elements-references.d.ts +9 -0
- package/dist/hooks/editor/utils/resolve-editor-config-elements-references.d.ts.map +1 -0
- package/dist/hooks/editor/utils/set-editor-editable-height.d.ts +9 -0
- package/dist/hooks/editor/utils/set-editor-editable-height.d.ts.map +1 -0
- package/dist/hooks/editor/utils/wrap-with-watchdog.d.ts +24 -0
- package/dist/hooks/editor/utils/wrap-with-watchdog.d.ts.map +1 -0
- package/dist/hooks/hook.d.ts +58 -0
- package/dist/hooks/hook.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/ui-part.d.ts +32 -0
- package/dist/hooks/ui-part.d.ts.map +1 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1146 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shared/async-registry.d.ts +131 -0
- package/dist/shared/async-registry.d.ts.map +1 -0
- package/dist/shared/camel-case.d.ts +8 -0
- package/dist/shared/camel-case.d.ts.map +1 -0
- package/dist/shared/debounce.d.ts +2 -0
- package/dist/shared/debounce.d.ts.map +1 -0
- package/dist/shared/deep-camel-case-keys.d.ts +8 -0
- package/dist/shared/deep-camel-case-keys.d.ts.map +1 -0
- package/dist/shared/filter-object-values.d.ts +9 -0
- package/dist/shared/filter-object-values.d.ts.map +1 -0
- package/dist/shared/index.d.ts +13 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/is-empty-object.d.ts +2 -0
- package/dist/shared/is-empty-object.d.ts.map +1 -0
- package/dist/shared/is-plain-object.d.ts +8 -0
- package/dist/shared/is-plain-object.d.ts.map +1 -0
- package/dist/shared/map-object-values.d.ts +11 -0
- package/dist/shared/map-object-values.d.ts.map +1 -0
- package/dist/shared/once.d.ts +2 -0
- package/dist/shared/once.d.ts.map +1 -0
- package/dist/shared/timeout.d.ts +8 -0
- package/dist/shared/timeout.d.ts.map +1 -0
- package/dist/shared/uid.d.ts +7 -0
- package/dist/shared/uid.d.ts.map +1 -0
- package/dist/shared/wait-for.d.ts +20 -0
- package/dist/shared/wait-for.d.ts.map +1 -0
- package/dist/types/can-be-promise.type.d.ts +2 -0
- package/dist/types/can-be-promise.type.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/required-by.type.d.ts +2 -0
- package/dist/types/required-by.type.d.ts.map +1 -0
- package/package.json +40 -0
- package/src/hooks/context/context.test.ts +394 -0
- package/src/hooks/context/context.ts +116 -0
- package/src/hooks/context/contexts-registry.test.ts +10 -0
- package/src/hooks/context/contexts-registry.ts +10 -0
- package/src/hooks/context/index.ts +3 -0
- package/src/hooks/context/typings.ts +39 -0
- package/src/hooks/editable.test.ts +276 -0
- package/src/hooks/editable.ts +122 -0
- package/src/hooks/editor/custom-editor-plugins.test.ts +103 -0
- package/src/hooks/editor/custom-editor-plugins.ts +84 -0
- package/src/hooks/editor/editor.test.ts +782 -0
- package/src/hooks/editor/editor.ts +357 -0
- package/src/hooks/editor/editors-registry.test.ts +10 -0
- package/src/hooks/editor/editors-registry.ts +10 -0
- package/src/hooks/editor/index.ts +2 -0
- package/src/hooks/editor/plugins/index.ts +2 -0
- package/src/hooks/editor/plugins/livewire-sync.ts +85 -0
- package/src/hooks/editor/plugins/sync-editor-with-input.ts +76 -0
- package/src/hooks/editor/typings.ts +114 -0
- package/src/hooks/editor/utils/create-editor-in-context.ts +90 -0
- package/src/hooks/editor/utils/get-editor-roots-values.ts +16 -0
- package/src/hooks/editor/utils/index.ts +11 -0
- package/src/hooks/editor/utils/is-single-editing-like-editor.test.ts +40 -0
- package/src/hooks/editor/utils/is-single-editing-like-editor.ts +11 -0
- package/src/hooks/editor/utils/load-editor-constructor.test.ts +62 -0
- package/src/hooks/editor/utils/load-editor-constructor.ts +27 -0
- package/src/hooks/editor/utils/load-editor-plugins.test.ts +100 -0
- package/src/hooks/editor/utils/load-editor-plugins.ts +71 -0
- package/src/hooks/editor/utils/load-editor-translations.ts +233 -0
- package/src/hooks/editor/utils/normalize-custom-translations.test.ts +152 -0
- package/src/hooks/editor/utils/normalize-custom-translations.ts +18 -0
- package/src/hooks/editor/utils/query-editor-editables.ts +102 -0
- package/src/hooks/editor/utils/resolve-editor-config-elements-references.test.ts +93 -0
- package/src/hooks/editor/utils/resolve-editor-config-elements-references.ts +36 -0
- package/src/hooks/editor/utils/set-editor-editable-height.test.ts +131 -0
- package/src/hooks/editor/utils/set-editor-editable-height.ts +15 -0
- package/src/hooks/editor/utils/wrap-with-watchdog.test.ts +45 -0
- package/src/hooks/editor/utils/wrap-with-watchdog.ts +51 -0
- package/src/hooks/hook.ts +87 -0
- package/src/hooks/index.ts +21 -0
- package/src/hooks/ui-part.test.ts +161 -0
- package/src/hooks/ui-part.ts +80 -0
- package/src/index.ts +5 -0
- package/src/livewire.d.ts +42 -0
- package/src/shared/async-registry.test.ts +658 -0
- package/src/shared/async-registry.ts +308 -0
- package/src/shared/camel-case.test.ts +35 -0
- package/src/shared/camel-case.ts +11 -0
- package/src/shared/debounce.test.ts +72 -0
- package/src/shared/debounce.ts +16 -0
- package/src/shared/deep-camel-case-keys.test.ts +34 -0
- package/src/shared/deep-camel-case-keys.ts +26 -0
- package/src/shared/filter-object-values.test.ts +25 -0
- package/src/shared/filter-object-values.ts +17 -0
- package/src/shared/index.ts +12 -0
- package/src/shared/is-empty-object.test.ts +78 -0
- package/src/shared/is-empty-object.ts +3 -0
- package/src/shared/is-plain-object.test.ts +38 -0
- package/src/shared/is-plain-object.ts +15 -0
- package/src/shared/map-object-values.test.ts +29 -0
- package/src/shared/map-object-values.ts +19 -0
- package/src/shared/once.test.ts +116 -0
- package/src/shared/once.ts +12 -0
- package/src/shared/timeout.test.ts +65 -0
- package/src/shared/timeout.ts +13 -0
- package/src/shared/uid.test.ts +25 -0
- package/src/shared/uid.ts +8 -0
- package/src/shared/wait-for.test.ts +24 -0
- package/src/shared/wait-for.ts +56 -0
- package/src/types/can-be-promise.type.ts +1 -0
- package/src/types/index.ts +2 -0
- package/src/types/required-by.type.ts +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Context, ContextWatchdog, Editor, EditorConfig } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
import type { EditorCreator } from './wrap-with-watchdog';
|
|
4
|
+
|
|
5
|
+
import { uid } from '../../../shared';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Symbol used to store the context watchdog on the editor instance.
|
|
9
|
+
* Internal use only.
|
|
10
|
+
*/
|
|
11
|
+
const CONTEXT_EDITOR_WATCHDOG_SYMBOL = Symbol.for('context-editor-watchdog');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a CKEditor 5 editor instance within a given context watchdog.
|
|
15
|
+
*
|
|
16
|
+
* @param params Parameters for editor creation.
|
|
17
|
+
* @param params.element The DOM element or data for the editor.
|
|
18
|
+
* @param params.context The context watchdog instance.
|
|
19
|
+
* @param params.creator The editor creator utility.
|
|
20
|
+
* @param params.config The editor configuration object.
|
|
21
|
+
* @returns The created editor instance.
|
|
22
|
+
*/
|
|
23
|
+
export async function createEditorInContext({ element, context, creator, config }: Attrs) {
|
|
24
|
+
const editorContextId = uid();
|
|
25
|
+
|
|
26
|
+
await context.add({
|
|
27
|
+
creator: (_element, _config) => creator.create(_element, _config),
|
|
28
|
+
id: editorContextId,
|
|
29
|
+
sourceElementOrData: element,
|
|
30
|
+
type: 'editor',
|
|
31
|
+
config,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const editor = context.getItem(editorContextId) as Editor;
|
|
35
|
+
const contextDescriptor: EditorContextDescriptor = {
|
|
36
|
+
state: 'available',
|
|
37
|
+
editorContextId,
|
|
38
|
+
context,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
(editor as any)[CONTEXT_EDITOR_WATCHDOG_SYMBOL] = contextDescriptor;
|
|
42
|
+
|
|
43
|
+
// Destroying of context is async. There can be situation when the destroy of the context
|
|
44
|
+
// and the destroy of the editor is called in parallel. It often happens during unmounting of
|
|
45
|
+
// phoenix hooks. Let's make sure that descriptor informs other components, that context is being
|
|
46
|
+
// destroyed.
|
|
47
|
+
const originalDestroy = context.destroy.bind(context);
|
|
48
|
+
context.destroy = async () => {
|
|
49
|
+
contextDescriptor.state = 'unavailable';
|
|
50
|
+
return originalDestroy();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...contextDescriptor,
|
|
55
|
+
editor,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Retrieves the context watchdog from an editor instance, if available.
|
|
61
|
+
*
|
|
62
|
+
* @param editor The editor instance.
|
|
63
|
+
* @returns The context watchdog or null if not found.
|
|
64
|
+
*/
|
|
65
|
+
export function unwrapEditorContext(editor: Editor): EditorContextDescriptor | null {
|
|
66
|
+
if (CONTEXT_EDITOR_WATCHDOG_SYMBOL in editor) {
|
|
67
|
+
return (editor as any)[CONTEXT_EDITOR_WATCHDOG_SYMBOL];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Parameters for creating an editor in a context.
|
|
75
|
+
*/
|
|
76
|
+
type Attrs = {
|
|
77
|
+
context: ContextWatchdog<Context>;
|
|
78
|
+
creator: EditorCreator;
|
|
79
|
+
element: HTMLElement;
|
|
80
|
+
config: EditorConfig;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Descriptor for an editor context.
|
|
85
|
+
*/
|
|
86
|
+
type EditorContextDescriptor = {
|
|
87
|
+
state: 'available' | 'unavailable';
|
|
88
|
+
editorContextId: string;
|
|
89
|
+
context: ContextWatchdog<Context>;
|
|
90
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Editor } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gets the values of the editor's roots.
|
|
5
|
+
*
|
|
6
|
+
* @param editor The CKEditor instance.
|
|
7
|
+
* @returns An object mapping root names to their content.
|
|
8
|
+
*/
|
|
9
|
+
export function getEditorRootsValues(editor: Editor) {
|
|
10
|
+
const roots = editor.model.document.getRootNames();
|
|
11
|
+
|
|
12
|
+
return roots.reduce<Record<string, string>>((acc, rootName) => {
|
|
13
|
+
acc[rootName] = editor.getData({ rootName });
|
|
14
|
+
return acc;
|
|
15
|
+
}, Object.create({}));
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './create-editor-in-context';
|
|
2
|
+
export * from './get-editor-roots-values';
|
|
3
|
+
export * from './is-single-editing-like-editor';
|
|
4
|
+
export * from './load-editor-constructor';
|
|
5
|
+
export * from './load-editor-plugins';
|
|
6
|
+
export * from './load-editor-translations';
|
|
7
|
+
export * from './normalize-custom-translations';
|
|
8
|
+
export * from './query-editor-editables';
|
|
9
|
+
export * from './resolve-editor-config-elements-references';
|
|
10
|
+
export * from './set-editor-editable-height';
|
|
11
|
+
export * from './wrap-with-watchdog';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { EditorType } from '../typings';
|
|
4
|
+
|
|
5
|
+
import { isSingleEditingLikeEditor } from './is-single-editing-like-editor';
|
|
6
|
+
|
|
7
|
+
describe('isSingleEditingLikeEditor', () => {
|
|
8
|
+
it('should return true for inline editor', () => {
|
|
9
|
+
expect(isSingleEditingLikeEditor('inline')).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return true for classic editor', () => {
|
|
13
|
+
expect(isSingleEditingLikeEditor('classic')).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return true for balloon editor', () => {
|
|
17
|
+
expect(isSingleEditingLikeEditor('balloon')).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should return false for decoupled editor', () => {
|
|
21
|
+
expect(isSingleEditingLikeEditor('decoupled')).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should return false for multiroot editor', () => {
|
|
25
|
+
expect(isSingleEditingLikeEditor('multiroot')).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle all valid editor types', () => {
|
|
29
|
+
const singleEditingTypes: EditorType[] = ['inline', 'classic', 'balloon', 'decoupled'];
|
|
30
|
+
const multiEditingTypes: EditorType[] = ['multiroot'];
|
|
31
|
+
|
|
32
|
+
singleEditingTypes.forEach((type) => {
|
|
33
|
+
expect(isSingleEditingLikeEditor(type)).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
multiEditingTypes.forEach((type) => {
|
|
37
|
+
expect(isSingleEditingLikeEditor(type)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EditorType } from '../typings';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the given editor type is one of the single editing-like editors.
|
|
5
|
+
*
|
|
6
|
+
* @param editorType - The type of the editor to check.
|
|
7
|
+
* @returns `true` if the editor type is 'inline', 'classic', or 'balloon', otherwise `false`.
|
|
8
|
+
*/
|
|
9
|
+
export function isSingleEditingLikeEditor(editorType: EditorType): boolean {
|
|
10
|
+
return ['inline', 'classic', 'balloon', 'decoupled'].includes(editorType);
|
|
11
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { EditorType } from '../typings';
|
|
4
|
+
|
|
5
|
+
import { loadEditorConstructor } from './load-editor-constructor';
|
|
6
|
+
|
|
7
|
+
// Mock the ckeditor5 package
|
|
8
|
+
vi.mock('ckeditor5', async () => {
|
|
9
|
+
const mockEditorConstructor = vi.fn();
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
InlineEditor: mockEditorConstructor,
|
|
13
|
+
BalloonEditor: mockEditorConstructor,
|
|
14
|
+
ClassicEditor: mockEditorConstructor,
|
|
15
|
+
DecoupledEditor: mockEditorConstructor,
|
|
16
|
+
MultiRootEditor: mockEditorConstructor,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('loadEditorConstructor', () => {
|
|
21
|
+
it('should load InlineEditor for inline type', async () => {
|
|
22
|
+
const constructor = await loadEditorConstructor('inline');
|
|
23
|
+
expect(constructor).toBeDefined();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should load BalloonEditor for balloon type', async () => {
|
|
27
|
+
const constructor = await loadEditorConstructor('balloon');
|
|
28
|
+
expect(constructor).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should load ClassicEditor for classic type', async () => {
|
|
32
|
+
const constructor = await loadEditorConstructor('classic');
|
|
33
|
+
expect(constructor).toBeDefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should load DecoupledEditor for decoupled type', async () => {
|
|
37
|
+
const constructor = await loadEditorConstructor('decoupled');
|
|
38
|
+
expect(constructor).toBeDefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should load MultiRootEditor for multiroot type', async () => {
|
|
42
|
+
const constructor = await loadEditorConstructor('multiroot');
|
|
43
|
+
expect(constructor).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should throw error for unsupported editor type', async () => {
|
|
47
|
+
const invalidType = 'invalid' as EditorType;
|
|
48
|
+
|
|
49
|
+
await expect(loadEditorConstructor(invalidType)).rejects.toThrow(
|
|
50
|
+
'Unsupported editor type: invalid',
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return the correct constructor for each editor type', async () => {
|
|
55
|
+
const editorTypes: EditorType[] = ['inline', 'balloon', 'classic', 'decoupled', 'multiroot'];
|
|
56
|
+
|
|
57
|
+
for (const type of editorTypes) {
|
|
58
|
+
const constructor = await loadEditorConstructor(type);
|
|
59
|
+
expect(constructor).toBeDefined();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EditorType } from '../typings';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the constructor for the specified CKEditor5 editor type.
|
|
5
|
+
*
|
|
6
|
+
* @param type - The type of the editor to load.
|
|
7
|
+
* @returns A promise that resolves to the editor constructor.
|
|
8
|
+
*/
|
|
9
|
+
export async function loadEditorConstructor(type: EditorType) {
|
|
10
|
+
const PKG = await import('ckeditor5');
|
|
11
|
+
|
|
12
|
+
const editorMap = {
|
|
13
|
+
inline: PKG.InlineEditor,
|
|
14
|
+
balloon: PKG.BalloonEditor,
|
|
15
|
+
classic: PKG.ClassicEditor,
|
|
16
|
+
decoupled: PKG.DecoupledEditor,
|
|
17
|
+
multiroot: PKG.MultiRootEditor,
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
const EditorConstructor = editorMap[type];
|
|
21
|
+
|
|
22
|
+
if (!EditorConstructor) {
|
|
23
|
+
throw new Error(`Unsupported editor type: ${type}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return EditorConstructor;
|
|
27
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { EditorPlugin } from '../typings';
|
|
4
|
+
|
|
5
|
+
import { CustomEditorPluginsRegistry } from '../custom-editor-plugins';
|
|
6
|
+
import { loadEditorPlugins } from './load-editor-plugins';
|
|
7
|
+
|
|
8
|
+
class CustomPlugin {
|
|
9
|
+
static get pluginName() {
|
|
10
|
+
return 'CustomPlugin';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('loadEditorPlugins', () => {
|
|
15
|
+
it('should load plugins from base package', async () => {
|
|
16
|
+
const plugins: EditorPlugin[] = ['Bold', 'Italic'];
|
|
17
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
18
|
+
|
|
19
|
+
expect(loadedPlugins).toHaveLength(2);
|
|
20
|
+
expect(loadedPlugins[0]).toBeDefined();
|
|
21
|
+
expect(loadedPlugins[1]).toBeDefined();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should load plugins from premium package', async () => {
|
|
25
|
+
const plugins: EditorPlugin[] = ['ExportInlineStyles', 'Comments'];
|
|
26
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
27
|
+
|
|
28
|
+
expect(loadedPlugins).toHaveLength(2);
|
|
29
|
+
expect(loadedPlugins[0]).toBeDefined();
|
|
30
|
+
expect(loadedPlugins[1]).toBeDefined();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle empty plugin array', async () => {
|
|
34
|
+
const plugins: EditorPlugin[] = [];
|
|
35
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
36
|
+
|
|
37
|
+
expect(loadedPlugins).toHaveLength(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should prioritize base package over premium package', async () => {
|
|
41
|
+
const plugins: EditorPlugin[] = ['Bold'];
|
|
42
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
43
|
+
|
|
44
|
+
expect(loadedPlugins).toHaveLength(1);
|
|
45
|
+
expect(loadedPlugins[0]).toBeDefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should return plugin constructors', async () => {
|
|
49
|
+
const plugins: EditorPlugin[] = ['Bold'];
|
|
50
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
51
|
+
|
|
52
|
+
expect(loadedPlugins).toHaveLength(1);
|
|
53
|
+
expect(typeof loadedPlugins[0]).toBe('function');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should throw an error for unknown plugins', async () => {
|
|
57
|
+
const plugins: EditorPlugin[] = ['UnknownPlugin'];
|
|
58
|
+
await expect(loadEditorPlugins(plugins)).rejects.toThrowError(/not found/);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('custom plugins', () => {
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
CustomEditorPluginsRegistry.the.unregisterAll();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should load custom plugins', async () => {
|
|
67
|
+
CustomEditorPluginsRegistry.the.register('CustomPlugin', () => CustomPlugin);
|
|
68
|
+
|
|
69
|
+
const plugins: EditorPlugin[] = ['CustomPlugin'];
|
|
70
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
71
|
+
|
|
72
|
+
expect(loadedPlugins).toHaveLength(1);
|
|
73
|
+
expect(loadedPlugins[0]).toEqual(CustomPlugin);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should prefer loading custom plugins over base package', async () => {
|
|
77
|
+
CustomEditorPluginsRegistry.the.register('Bold', () => CustomPlugin);
|
|
78
|
+
|
|
79
|
+
const plugins: EditorPlugin[] = ['Bold'];
|
|
80
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
81
|
+
|
|
82
|
+
expect(loadedPlugins).toHaveLength(1);
|
|
83
|
+
expect(loadedPlugins[0]).toEqual(CustomPlugin);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should be possible to load async custom plugins', async () => {
|
|
87
|
+
CustomEditorPluginsRegistry.the.register('AsyncPlugin', async () => {
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
setTimeout(() => resolve(CustomPlugin), 20);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const plugins: EditorPlugin[] = ['AsyncPlugin'];
|
|
94
|
+
const { loadedPlugins } = await loadEditorPlugins(plugins);
|
|
95
|
+
|
|
96
|
+
expect(loadedPlugins).toHaveLength(1);
|
|
97
|
+
expect(loadedPlugins[0]).toEqual(CustomPlugin);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { PluginConstructor } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
import type { EditorPlugin } from '../typings';
|
|
4
|
+
|
|
5
|
+
import { CustomEditorPluginsRegistry } from '../custom-editor-plugins';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Loads CKEditor plugins from base and premium packages.
|
|
9
|
+
* First tries to load from the base 'ckeditor5' package, then falls back to 'ckeditor5-premium-features'.
|
|
10
|
+
*
|
|
11
|
+
* @param plugins - Array of plugin names to load
|
|
12
|
+
* @returns Promise that resolves to an array of loaded Plugin instances
|
|
13
|
+
* @throws Error if a plugin is not found in either package
|
|
14
|
+
*/
|
|
15
|
+
export async function loadEditorPlugins(plugins: EditorPlugin[]): Promise<LoadedPlugins> {
|
|
16
|
+
const basePackage = await import('ckeditor5');
|
|
17
|
+
let premiumPackage: Record<string, any> | null = null;
|
|
18
|
+
|
|
19
|
+
const loaders = plugins.map(async (plugin) => {
|
|
20
|
+
// Let's first try to load the plugin from the base package.
|
|
21
|
+
// Coverage is disabled due to Vitest issues with mocking dynamic imports.
|
|
22
|
+
|
|
23
|
+
// If the plugin is not found in the base package, try custom plugins.
|
|
24
|
+
const customPlugin = await CustomEditorPluginsRegistry.the.get(plugin);
|
|
25
|
+
|
|
26
|
+
if (customPlugin) {
|
|
27
|
+
return customPlugin;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// If not found, try to load from the base package.
|
|
31
|
+
const { [plugin]: basePkgImport } = basePackage as Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
if (basePkgImport) {
|
|
34
|
+
return basePkgImport as PluginConstructor;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Plugin not found in base package, try premium package.
|
|
38
|
+
if (!premiumPackage) {
|
|
39
|
+
try {
|
|
40
|
+
premiumPackage = await import('ckeditor5-premium-features');
|
|
41
|
+
/* v8 ignore next 6 */
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(`Failed to load premium package: ${error}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* v8 ignore next */
|
|
49
|
+
const { [plugin]: premiumPkgImport } = premiumPackage || {};
|
|
50
|
+
|
|
51
|
+
if (premiumPkgImport) {
|
|
52
|
+
return premiumPkgImport as PluginConstructor;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Plugin not found in either package, throw an error.
|
|
56
|
+
throw new Error(`Plugin "${plugin}" not found in base or premium packages.`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
loadedPlugins: await Promise.all(loaders),
|
|
61
|
+
hasPremium: !!premiumPackage,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Type representing the loaded plugins and whether premium features are available.
|
|
67
|
+
*/
|
|
68
|
+
type LoadedPlugins = {
|
|
69
|
+
loadedPlugins: PluginConstructor<any>[];
|
|
70
|
+
hasPremium: boolean;
|
|
71
|
+
};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads all required translations for the editor based on the language configuration.
|
|
3
|
+
*
|
|
4
|
+
* @param language - The language configuration object containing UI and content language codes.
|
|
5
|
+
* @param language.ui - The UI language code.
|
|
6
|
+
* @param language.content - The content language code.
|
|
7
|
+
* @param hasPremium - Whether premium features are enabled and premium translations should be loaded.
|
|
8
|
+
* @returns A promise that resolves to an array of loaded translation objects.
|
|
9
|
+
*/
|
|
10
|
+
export async function loadAllEditorTranslations(
|
|
11
|
+
language: { ui: string; content: string; },
|
|
12
|
+
hasPremium: boolean,
|
|
13
|
+
) {
|
|
14
|
+
const translations = [language.ui, language.content];
|
|
15
|
+
const loadedTranslations = await Promise.all(
|
|
16
|
+
[
|
|
17
|
+
loadEditorPkgTranslations('ckeditor5', translations),
|
|
18
|
+
/* v8 ignore next */
|
|
19
|
+
hasPremium && loadEditorPkgTranslations('ckeditor5-premium-features', translations),
|
|
20
|
+
].filter(pkg => !!pkg),
|
|
21
|
+
)
|
|
22
|
+
.then(translations => translations.flat());
|
|
23
|
+
|
|
24
|
+
return loadedTranslations;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Loads the editor translations for the given languages.
|
|
29
|
+
*
|
|
30
|
+
* Make sure this function is properly compiled and bundled in self hosted environments!
|
|
31
|
+
*
|
|
32
|
+
* @param pkg - The package to load translations from ('ckeditor5' or 'ckeditor5-premium-features').
|
|
33
|
+
* @param translations - The list of language codes to load translations for.
|
|
34
|
+
* @returns A promise that resolves to an array of loaded translation packs.
|
|
35
|
+
*/
|
|
36
|
+
async function loadEditorPkgTranslations(
|
|
37
|
+
pkg: EditorPkgName,
|
|
38
|
+
translations: string[],
|
|
39
|
+
) {
|
|
40
|
+
/* v8 ignore next */
|
|
41
|
+
return await Promise.all(
|
|
42
|
+
translations
|
|
43
|
+
.filter(lang => lang !== 'en') // 'en' is the default language, no need to load it.
|
|
44
|
+
.map(async (lang) => {
|
|
45
|
+
const pack = await loadEditorTranslation(pkg, lang);
|
|
46
|
+
|
|
47
|
+
/* v8 ignore next */
|
|
48
|
+
return pack?.default ?? pack;
|
|
49
|
+
})
|
|
50
|
+
.filter(Boolean),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Type representing the package name for CKEditor 5.
|
|
56
|
+
*/
|
|
57
|
+
type EditorPkgName = 'ckeditor5' | 'ckeditor5-premium-features';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Load translation for CKEditor 5
|
|
61
|
+
* @param pkg - Package type: 'ckeditor5' or 'premium'
|
|
62
|
+
* @param lang - Language code (e.g., 'pl', 'en', 'de')
|
|
63
|
+
* @returns Translation object or null if failed
|
|
64
|
+
*/
|
|
65
|
+
async function loadEditorTranslation(pkg: EditorPkgName, lang: string): Promise<any> {
|
|
66
|
+
try {
|
|
67
|
+
/* v8 ignore next 2 */
|
|
68
|
+
if (pkg === 'ckeditor5') {
|
|
69
|
+
/* v8 ignore next 79 */
|
|
70
|
+
switch (lang) {
|
|
71
|
+
case 'af': return await import('ckeditor5/translations/af.js');
|
|
72
|
+
case 'ar': return await import('ckeditor5/translations/ar.js');
|
|
73
|
+
case 'ast': return await import('ckeditor5/translations/ast.js');
|
|
74
|
+
case 'az': return await import('ckeditor5/translations/az.js');
|
|
75
|
+
case 'bg': return await import('ckeditor5/translations/bg.js');
|
|
76
|
+
case 'bn': return await import('ckeditor5/translations/bn.js');
|
|
77
|
+
case 'bs': return await import('ckeditor5/translations/bs.js');
|
|
78
|
+
case 'ca': return await import('ckeditor5/translations/ca.js');
|
|
79
|
+
case 'cs': return await import('ckeditor5/translations/cs.js');
|
|
80
|
+
case 'da': return await import('ckeditor5/translations/da.js');
|
|
81
|
+
case 'de': return await import('ckeditor5/translations/de.js');
|
|
82
|
+
case 'de-ch': return await import('ckeditor5/translations/de-ch.js');
|
|
83
|
+
case 'el': return await import('ckeditor5/translations/el.js');
|
|
84
|
+
case 'en': return await import('ckeditor5/translations/en.js');
|
|
85
|
+
case 'en-au': return await import('ckeditor5/translations/en-au.js');
|
|
86
|
+
case 'en-gb': return await import('ckeditor5/translations/en-gb.js');
|
|
87
|
+
case 'eo': return await import('ckeditor5/translations/eo.js');
|
|
88
|
+
case 'es': return await import('ckeditor5/translations/es.js');
|
|
89
|
+
case 'es-co': return await import('ckeditor5/translations/es-co.js');
|
|
90
|
+
case 'et': return await import('ckeditor5/translations/et.js');
|
|
91
|
+
case 'eu': return await import('ckeditor5/translations/eu.js');
|
|
92
|
+
case 'fa': return await import('ckeditor5/translations/fa.js');
|
|
93
|
+
case 'fi': return await import('ckeditor5/translations/fi.js');
|
|
94
|
+
case 'fr': return await import('ckeditor5/translations/fr.js');
|
|
95
|
+
case 'gl': return await import('ckeditor5/translations/gl.js');
|
|
96
|
+
case 'gu': return await import('ckeditor5/translations/gu.js');
|
|
97
|
+
case 'he': return await import('ckeditor5/translations/he.js');
|
|
98
|
+
case 'hi': return await import('ckeditor5/translations/hi.js');
|
|
99
|
+
case 'hr': return await import('ckeditor5/translations/hr.js');
|
|
100
|
+
case 'hu': return await import('ckeditor5/translations/hu.js');
|
|
101
|
+
case 'hy': return await import('ckeditor5/translations/hy.js');
|
|
102
|
+
case 'id': return await import('ckeditor5/translations/id.js');
|
|
103
|
+
case 'it': return await import('ckeditor5/translations/it.js');
|
|
104
|
+
case 'ja': return await import('ckeditor5/translations/ja.js');
|
|
105
|
+
case 'jv': return await import('ckeditor5/translations/jv.js');
|
|
106
|
+
case 'kk': return await import('ckeditor5/translations/kk.js');
|
|
107
|
+
case 'km': return await import('ckeditor5/translations/km.js');
|
|
108
|
+
case 'kn': return await import('ckeditor5/translations/kn.js');
|
|
109
|
+
case 'ko': return await import('ckeditor5/translations/ko.js');
|
|
110
|
+
case 'ku': return await import('ckeditor5/translations/ku.js');
|
|
111
|
+
case 'lt': return await import('ckeditor5/translations/lt.js');
|
|
112
|
+
case 'lv': return await import('ckeditor5/translations/lv.js');
|
|
113
|
+
case 'ms': return await import('ckeditor5/translations/ms.js');
|
|
114
|
+
case 'nb': return await import('ckeditor5/translations/nb.js');
|
|
115
|
+
case 'ne': return await import('ckeditor5/translations/ne.js');
|
|
116
|
+
case 'nl': return await import('ckeditor5/translations/nl.js');
|
|
117
|
+
case 'no': return await import('ckeditor5/translations/no.js');
|
|
118
|
+
case 'oc': return await import('ckeditor5/translations/oc.js');
|
|
119
|
+
case 'pl': return await import('ckeditor5/translations/pl.js');
|
|
120
|
+
case 'pt': return await import('ckeditor5/translations/pt.js');
|
|
121
|
+
case 'pt-br': return await import('ckeditor5/translations/pt-br.js');
|
|
122
|
+
case 'ro': return await import('ckeditor5/translations/ro.js');
|
|
123
|
+
case 'ru': return await import('ckeditor5/translations/ru.js');
|
|
124
|
+
case 'si': return await import('ckeditor5/translations/si.js');
|
|
125
|
+
case 'sk': return await import('ckeditor5/translations/sk.js');
|
|
126
|
+
case 'sl': return await import('ckeditor5/translations/sl.js');
|
|
127
|
+
case 'sq': return await import('ckeditor5/translations/sq.js');
|
|
128
|
+
case 'sr': return await import('ckeditor5/translations/sr.js');
|
|
129
|
+
case 'sr-latn': return await import('ckeditor5/translations/sr-latn.js');
|
|
130
|
+
case 'sv': return await import('ckeditor5/translations/sv.js');
|
|
131
|
+
case 'th': return await import('ckeditor5/translations/th.js');
|
|
132
|
+
case 'tk': return await import('ckeditor5/translations/tk.js');
|
|
133
|
+
case 'tr': return await import('ckeditor5/translations/tr.js');
|
|
134
|
+
case 'tt': return await import('ckeditor5/translations/tt.js');
|
|
135
|
+
case 'ug': return await import('ckeditor5/translations/ug.js');
|
|
136
|
+
case 'uk': return await import('ckeditor5/translations/uk.js');
|
|
137
|
+
case 'ur': return await import('ckeditor5/translations/ur.js');
|
|
138
|
+
case 'uz': return await import('ckeditor5/translations/uz.js');
|
|
139
|
+
case 'vi': return await import('ckeditor5/translations/vi.js');
|
|
140
|
+
case 'zh': return await import('ckeditor5/translations/zh.js');
|
|
141
|
+
case 'zh-cn': return await import('ckeditor5/translations/zh-cn.js');
|
|
142
|
+
default:
|
|
143
|
+
console.warn(`Language ${lang} not found in ckeditor5 translations`);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/* v8 ignore next 79 */
|
|
148
|
+
else {
|
|
149
|
+
// Premium features translations
|
|
150
|
+
switch (lang) {
|
|
151
|
+
case 'af': return await import('ckeditor5-premium-features/translations/af.js');
|
|
152
|
+
case 'ar': return await import('ckeditor5-premium-features/translations/ar.js');
|
|
153
|
+
case 'ast': return await import('ckeditor5-premium-features/translations/ast.js');
|
|
154
|
+
case 'az': return await import('ckeditor5-premium-features/translations/az.js');
|
|
155
|
+
case 'bg': return await import('ckeditor5-premium-features/translations/bg.js');
|
|
156
|
+
case 'bn': return await import('ckeditor5-premium-features/translations/bn.js');
|
|
157
|
+
case 'bs': return await import('ckeditor5-premium-features/translations/bs.js');
|
|
158
|
+
case 'ca': return await import('ckeditor5-premium-features/translations/ca.js');
|
|
159
|
+
case 'cs': return await import('ckeditor5-premium-features/translations/cs.js');
|
|
160
|
+
case 'da': return await import('ckeditor5-premium-features/translations/da.js');
|
|
161
|
+
case 'de': return await import('ckeditor5-premium-features/translations/de.js');
|
|
162
|
+
case 'de-ch': return await import('ckeditor5-premium-features/translations/de-ch.js');
|
|
163
|
+
case 'el': return await import('ckeditor5-premium-features/translations/el.js');
|
|
164
|
+
case 'en': return await import('ckeditor5-premium-features/translations/en.js');
|
|
165
|
+
case 'en-au': return await import('ckeditor5-premium-features/translations/en-au.js');
|
|
166
|
+
case 'en-gb': return await import('ckeditor5-premium-features/translations/en-gb.js');
|
|
167
|
+
case 'eo': return await import('ckeditor5-premium-features/translations/eo.js');
|
|
168
|
+
case 'es': return await import('ckeditor5-premium-features/translations/es.js');
|
|
169
|
+
case 'es-co': return await import('ckeditor5-premium-features/translations/es-co.js');
|
|
170
|
+
case 'et': return await import('ckeditor5-premium-features/translations/et.js');
|
|
171
|
+
case 'eu': return await import('ckeditor5-premium-features/translations/eu.js');
|
|
172
|
+
case 'fa': return await import('ckeditor5-premium-features/translations/fa.js');
|
|
173
|
+
case 'fi': return await import('ckeditor5-premium-features/translations/fi.js');
|
|
174
|
+
case 'fr': return await import('ckeditor5-premium-features/translations/fr.js');
|
|
175
|
+
case 'gl': return await import('ckeditor5-premium-features/translations/gl.js');
|
|
176
|
+
case 'gu': return await import('ckeditor5-premium-features/translations/gu.js');
|
|
177
|
+
case 'he': return await import('ckeditor5-premium-features/translations/he.js');
|
|
178
|
+
case 'hi': return await import('ckeditor5-premium-features/translations/hi.js');
|
|
179
|
+
case 'hr': return await import('ckeditor5-premium-features/translations/hr.js');
|
|
180
|
+
case 'hu': return await import('ckeditor5-premium-features/translations/hu.js');
|
|
181
|
+
case 'hy': return await import('ckeditor5-premium-features/translations/hy.js');
|
|
182
|
+
case 'id': return await import('ckeditor5-premium-features/translations/id.js');
|
|
183
|
+
case 'it': return await import('ckeditor5-premium-features/translations/it.js');
|
|
184
|
+
case 'ja': return await import('ckeditor5-premium-features/translations/ja.js');
|
|
185
|
+
case 'jv': return await import('ckeditor5-premium-features/translations/jv.js');
|
|
186
|
+
case 'kk': return await import('ckeditor5-premium-features/translations/kk.js');
|
|
187
|
+
case 'km': return await import('ckeditor5-premium-features/translations/km.js');
|
|
188
|
+
case 'kn': return await import('ckeditor5-premium-features/translations/kn.js');
|
|
189
|
+
case 'ko': return await import('ckeditor5-premium-features/translations/ko.js');
|
|
190
|
+
case 'ku': return await import('ckeditor5-premium-features/translations/ku.js');
|
|
191
|
+
case 'lt': return await import('ckeditor5-premium-features/translations/lt.js');
|
|
192
|
+
case 'lv': return await import('ckeditor5-premium-features/translations/lv.js');
|
|
193
|
+
case 'ms': return await import('ckeditor5-premium-features/translations/ms.js');
|
|
194
|
+
case 'nb': return await import('ckeditor5-premium-features/translations/nb.js');
|
|
195
|
+
case 'ne': return await import('ckeditor5-premium-features/translations/ne.js');
|
|
196
|
+
case 'nl': return await import('ckeditor5-premium-features/translations/nl.js');
|
|
197
|
+
case 'no': return await import('ckeditor5-premium-features/translations/no.js');
|
|
198
|
+
case 'oc': return await import('ckeditor5-premium-features/translations/oc.js');
|
|
199
|
+
case 'pl': return await import('ckeditor5-premium-features/translations/pl.js');
|
|
200
|
+
case 'pt': return await import('ckeditor5-premium-features/translations/pt.js');
|
|
201
|
+
case 'pt-br': return await import('ckeditor5-premium-features/translations/pt-br.js');
|
|
202
|
+
case 'ro': return await import('ckeditor5-premium-features/translations/ro.js');
|
|
203
|
+
case 'ru': return await import('ckeditor5-premium-features/translations/ru.js');
|
|
204
|
+
case 'si': return await import('ckeditor5-premium-features/translations/si.js');
|
|
205
|
+
case 'sk': return await import('ckeditor5-premium-features/translations/sk.js');
|
|
206
|
+
case 'sl': return await import('ckeditor5-premium-features/translations/sl.js');
|
|
207
|
+
case 'sq': return await import('ckeditor5-premium-features/translations/sq.js');
|
|
208
|
+
case 'sr': return await import('ckeditor5-premium-features/translations/sr.js');
|
|
209
|
+
case 'sr-latn': return await import('ckeditor5-premium-features/translations/sr-latn.js');
|
|
210
|
+
case 'sv': return await import('ckeditor5-premium-features/translations/sv.js');
|
|
211
|
+
case 'th': return await import('ckeditor5-premium-features/translations/th.js');
|
|
212
|
+
case 'tk': return await import('ckeditor5-premium-features/translations/tk.js');
|
|
213
|
+
case 'tr': return await import('ckeditor5-premium-features/translations/tr.js');
|
|
214
|
+
case 'tt': return await import('ckeditor5-premium-features/translations/tt.js');
|
|
215
|
+
case 'ug': return await import('ckeditor5-premium-features/translations/ug.js');
|
|
216
|
+
case 'uk': return await import('ckeditor5-premium-features/translations/uk.js');
|
|
217
|
+
case 'ur': return await import('ckeditor5-premium-features/translations/ur.js');
|
|
218
|
+
case 'uz': return await import('ckeditor5-premium-features/translations/uz.js');
|
|
219
|
+
case 'vi': return await import('ckeditor5-premium-features/translations/vi.js');
|
|
220
|
+
case 'zh': return await import('ckeditor5-premium-features/translations/zh.js');
|
|
221
|
+
case 'zh-cn': return await import('ckeditor5-premium-features/translations/zh-cn.js');
|
|
222
|
+
default:
|
|
223
|
+
console.warn(`Language ${lang} not found in premium translations`);
|
|
224
|
+
return await import('ckeditor5-premium-features/translations/en.js'); // fallback to English
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/* v8 ignore next 7 */
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.error(`Failed to load translation for ${pkg}/${lang}:`, error);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|