mirror of
https://github.com/zadam/trilium.git
synced 2025-11-17 18:50:41 +01:00
feat(ckeditor5): set up multi-language support
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
||||||
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor, TemplateDefinition } from "@triliumnext/ckeditor5";
|
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import { buildConfig, BuildEditorOptions } from "./config";
|
import { buildConfig, BuildEditorOptions } from "./config";
|
||||||
import { useKeyboardShortcuts, useLegacyImperativeHandlers, useNoteContext, useSyncedRef } from "../../react/hooks";
|
import { useKeyboardShortcuts, useLegacyImperativeHandlers, useNoteContext, useSyncedRef, useTriliumOption } from "../../react/hooks";
|
||||||
import link from "../../../services/link";
|
import link from "../../../services/link";
|
||||||
import froca from "../../../services/froca";
|
import froca from "../../../services/froca";
|
||||||
|
import { DISPLAYABLE_LOCALE_IDS } from "@triliumnext/commons";
|
||||||
|
|
||||||
export type BoxSize = "small" | "medium" | "full";
|
export type BoxSize = "small" | "medium" | "full";
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ interface CKEditorWithWatchdogProps extends Pick<HTMLProps<HTMLDivElement>, "cla
|
|||||||
export default function CKEditorWithWatchdog({ containerRef: externalContainerRef, content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) {
|
export default function CKEditorWithWatchdog({ containerRef: externalContainerRef, content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) {
|
||||||
const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
|
const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
|
||||||
const watchdogRef = useRef<EditorWatchdog>(null);
|
const watchdogRef = useRef<EditorWatchdog>(null);
|
||||||
|
const [ uiLanguage ] = useTriliumOption("locale");
|
||||||
const [ editor, setEditor ] = useState<CKTextEditor>();
|
const [ editor, setEditor ] = useState<CKTextEditor>();
|
||||||
const { parentComponent } = useNoteContext();
|
const { parentComponent } = useNoteContext();
|
||||||
|
|
||||||
@@ -156,6 +158,7 @@ export default function CKEditorWithWatchdog({ containerRef: externalContainerRe
|
|||||||
const editor = await buildEditor(container, !!isClassicEditor, {
|
const editor = await buildEditor(container, !!isClassicEditor, {
|
||||||
forceGplLicense: false,
|
forceGplLicense: false,
|
||||||
isClassicEditor: !!isClassicEditor,
|
isClassicEditor: !!isClassicEditor,
|
||||||
|
uiLanguage: uiLanguage as DISPLAYABLE_LOCALE_IDS,
|
||||||
contentLanguage: contentLanguage ?? null,
|
contentLanguage: contentLanguage ?? null,
|
||||||
templates
|
templates
|
||||||
});
|
});
|
||||||
@@ -180,7 +183,7 @@ export default function CKEditorWithWatchdog({ containerRef: externalContainerRe
|
|||||||
watchdog.create(container);
|
watchdog.create(container);
|
||||||
|
|
||||||
return () => watchdog.destroy();
|
return () => watchdog.destroy();
|
||||||
}, [ contentLanguage, templates ]);
|
}, [ contentLanguage, templates, uiLanguage ]);
|
||||||
|
|
||||||
// React to content changes.
|
// React to content changes.
|
||||||
useEffect(() => editor?.setData(content ?? ""), [ editor, content ]);
|
useEffect(() => editor?.setData(content ?? ""), [ editor, content ]);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ALLOWED_PROTOCOLS, MIME_TYPE_AUTO } from "@triliumnext/commons";
|
import { ALLOWED_PROTOCOLS, DISPLAYABLE_LOCALE_IDS, MIME_TYPE_AUTO } from "@triliumnext/commons";
|
||||||
import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS, TemplateDefinition } from "@triliumnext/ckeditor5";
|
import { buildExtraCommands, type EditorConfig, getCkLocale, PREMIUM_PLUGINS, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
||||||
import options from "../../../services/options.js";
|
import options from "../../../services/options.js";
|
||||||
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
||||||
@@ -17,6 +17,7 @@ export const OPEN_SOURCE_LICENSE_KEY = "GPL";
|
|||||||
export interface BuildEditorOptions {
|
export interface BuildEditorOptions {
|
||||||
forceGplLicense: boolean;
|
forceGplLicense: boolean;
|
||||||
isClassicEditor: boolean;
|
isClassicEditor: boolean;
|
||||||
|
uiLanguage: DISPLAYABLE_LOCALE_IDS;
|
||||||
contentLanguage: string | null;
|
contentLanguage: string | null;
|
||||||
templates: TemplateDefinition[];
|
templates: TemplateDefinition[];
|
||||||
}
|
}
|
||||||
@@ -161,9 +162,8 @@ export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfi
|
|||||||
htmlSupport: {
|
htmlSupport: {
|
||||||
allow: JSON.parse(options.get("allowedHtmlTags"))
|
allow: JSON.parse(options.get("allowedHtmlTags"))
|
||||||
},
|
},
|
||||||
// This value must be kept in sync with the language defined in webpack.config.js.
|
removePlugins: getDisabledPlugins(),
|
||||||
language: "en",
|
...await getCkLocale(opts.uiLanguage)
|
||||||
removePlugins: getDisabledPlugins()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up content language.
|
// Set up content language.
|
||||||
|
|||||||
90
packages/ckeditor5/src/i18n.ts
Normal file
90
packages/ckeditor5/src/i18n.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { DISPLAYABLE_LOCALE_IDS } from "@triliumnext/commons";
|
||||||
|
import { EditorConfig, Translations } from "ckeditor5";
|
||||||
|
|
||||||
|
interface LocaleMapping {
|
||||||
|
languageCode: string;
|
||||||
|
coreTranslation: () => Promise<{ default: Translations }>;
|
||||||
|
premiumFeaturesTranslation: () => Promise<{ default: Translations }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOCALE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, LocaleMapping | null> = {
|
||||||
|
en: null,
|
||||||
|
en_rtl: null,
|
||||||
|
ar: {
|
||||||
|
languageCode: "ar",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/ar.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/ar.js"),
|
||||||
|
},
|
||||||
|
cn: {
|
||||||
|
languageCode: "zh",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/zh-cn.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/zh-cn.js"),
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
languageCode: "de",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/de.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/de.js"),
|
||||||
|
},
|
||||||
|
es: {
|
||||||
|
languageCode: "es",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/es.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/es.js"),
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
languageCode: "fr",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/fr.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/fr.js"),
|
||||||
|
},
|
||||||
|
it: {
|
||||||
|
languageCode: "it",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/it.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/it.js"),
|
||||||
|
},
|
||||||
|
ja: {
|
||||||
|
languageCode: "ja",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/ja.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/ja.js"),
|
||||||
|
},
|
||||||
|
pt: {
|
||||||
|
languageCode: "pt",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/pt.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/pt.js"),
|
||||||
|
},
|
||||||
|
pt_br: {
|
||||||
|
languageCode: "pt-br",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/pt-br.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/pt-br.js"),
|
||||||
|
},
|
||||||
|
ro: {
|
||||||
|
languageCode: "ro",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/ro.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/ro.js"),
|
||||||
|
},
|
||||||
|
tw: {
|
||||||
|
languageCode: "zh-tw",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/zh.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/zh.js"),
|
||||||
|
},
|
||||||
|
uk: {
|
||||||
|
languageCode: "uk",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/uk.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/uk.js"),
|
||||||
|
},
|
||||||
|
ru: {
|
||||||
|
languageCode: "ru",
|
||||||
|
coreTranslation: () => import("ckeditor5/translations/ru.js"),
|
||||||
|
premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/ru.js")
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function getCkLocale(locale: DISPLAYABLE_LOCALE_IDS): Promise<Pick<EditorConfig, "language" | "translations">> {
|
||||||
|
const mapping = LOCALE_MAPPINGS[locale];
|
||||||
|
if (!mapping) return {};
|
||||||
|
|
||||||
|
const coreTranslation = (await (mapping.coreTranslation())).default;
|
||||||
|
const premiumFeaturesTranslation = (await (mapping.premiumFeaturesTranslation())).default;
|
||||||
|
return {
|
||||||
|
language: mapping.languageCode,
|
||||||
|
translations: [ coreTranslation, premiumFeaturesTranslation ]
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ export { PREMIUM_PLUGINS } from "./plugins.js";
|
|||||||
export type { EditorConfig, MentionFeed, MentionFeedObjectItem, ModelNode, ModelPosition, ModelElement, WatchdogConfig, WatchdogState } from "ckeditor5";
|
export type { EditorConfig, MentionFeed, MentionFeedObjectItem, ModelNode, ModelPosition, ModelElement, WatchdogConfig, WatchdogState } from "ckeditor5";
|
||||||
export type { TemplateDefinition } from "ckeditor5-premium-features";
|
export type { TemplateDefinition } from "ckeditor5-premium-features";
|
||||||
export { default as buildExtraCommands } from "./extra_slash_commands.js";
|
export { default as buildExtraCommands } from "./extra_slash_commands.js";
|
||||||
|
export { default as getCkLocale } from "./i18n.js";
|
||||||
|
|
||||||
// Import with sideffects to ensure that type augmentations are present.
|
// Import with sideffects to ensure that type augmentations are present.
|
||||||
import "@triliumnext/ckeditor5-math";
|
import "@triliumnext/ckeditor5-math";
|
||||||
|
|||||||
Reference in New Issue
Block a user