Skip to content

Internationalization (i18n)

notectl ships with built-in support for 9 languages. All user-facing strings in the toolbar, context menus, announcements, and ARIA labels are fully localizable.

LocaleLanguageConstant
enEnglishLocale.EN
deGermanLocale.DE
esSpanishLocale.ES
frFrenchLocale.FR
zhChinese (Simplified)Locale.ZH
ruRussianLocale.RU
arArabicLocale.AR
hiHindiLocale.HI
ptPortugueseLocale.PT
browserAuto-detectLocale.BROWSER

Set the editor language via the locale config option. All plugins automatically resolve their strings from this setting.

import { createEditor, Locale } from '@notectl/core';
const editor = await createEditor({
locale: Locale.DE,
toolbar: [/* ... */],
});

When set to Locale.BROWSER (the default), the editor detects the language from navigator.language and uses the best available match. If the detected language has no translation, it falls back to English.

<!-- Not yet supported as HTML attribute — use the config option -->

Every plugin that renders user-facing text accepts an optional locale config parameter. This allows overriding the global locale for a specific plugin.

import { createEditor, Locale } from '@notectl/core';
import { TablePlugin, loadTableLocale } from '@notectl/core/plugins/table';
// Load French locale for the table plugin
const tableFr = await loadTableLocale('fr');
// Editor in German, but table plugin in French
const editor = await createEditor({
locale: Locale.DE,
toolbar: [
[new TablePlugin({ locale: tableFr })],
],
});

Plugins resolve their locale in this order:

  1. Per-plugin config override — if provided in the plugin constructor, it wins
  2. Global LocaleService — reads the editor’s locale setting and loads the matching translation asynchronously
  3. English fallback — if no translation exists for the resolved language

Every plugin exports an async loadXxxLocale(lang) function that loads translation data on demand. This keeps locale data out of the main bundle — only the requested language is fetched at runtime.

import { loadTableLocale } from '@notectl/core/plugins/table';
// Load German table strings (async, code-split)
const deLocale = await loadTableLocale('de');
// Falls back to English for unknown languages
const fallback = await loadTableLocale('unknown'); // → English
PluginLoaderEN Constant
Text FormattingloadTextFormattingLocale()TEXT_FORMATTING_LOCALE_EN
HeadingloadHeadingLocale()HEADING_LOCALE_EN
ListloadListLocale()LIST_LOCALE_EN
LinkloadLinkLocale()LINK_LOCALE_EN
TableloadTableLocale()TABLE_LOCALE_EN
Code BlockloadCodeBlockLocale()CODE_BLOCK_LOCALE_EN
BlockquoteloadBlockquoteLocale()BLOCKQUOTE_LOCALE_EN
ImageloadImageLocale()IMAGE_LOCALE_EN
FontloadFontLocale()FONT_LOCALE_EN
Font SizeloadFontSizeLocale()FONT_SIZE_LOCALE_EN
Text ColorloadTextColorLocale()TEXT_COLOR_LOCALE_EN
AlignmentloadAlignmentLocale()ALIGNMENT_LOCALE_EN
StrikethroughloadStrikethroughLocale()STRIKETHROUGH_LOCALE_EN
Superscript / SubscriptloadSuperSubLocale()SUPER_SUB_LOCALE_EN
HighlightloadHighlightLocale()HIGHLIGHT_LOCALE_EN
Horizontal RuleloadHorizontalRuleLocale()HORIZONTAL_RULE_LOCALE_EN
PrintloadPrintLocale()PRINT_LOCALE_EN
Text DirectionloadTextDirectionLocale()TEXT_DIRECTION_LOCALE_EN
ToolbarloadToolbarLocale()TOOLBAR_LOCALE_EN

You can provide a fully custom locale by implementing the plugin’s locale interface:

import type { TableLocale } from '@notectl/core';
const myTableLocale: TableLocale = {
insertRowAbove: 'Add row above',
insertRowBelow: 'Add row below',
insertColumnLeft: 'Add column left',
insertColumnRight: 'Add column right',
deleteRow: 'Remove row',
deleteColumn: 'Remove column',
borderColorLabel: 'Border color...',
deleteTable: 'Remove table',
tableActions: 'Table actions',
menuKeyboardHint: 'Arrows to navigate, Enter to select, Esc to close',
insertRow: 'Insert row',
insertColumn: 'Insert column',
addRow: 'Add row',
addColumn: 'Add column',
tableActionsHint: 'Table actions (Right-click or Shift+F10)',
contextMenuHint: 'Right-click or Shift+F10 for table actions',
borderColor: 'Border color',
defaultColor: 'Default',
noBorders: 'No borders',
borderColorPicker: 'Border color picker',
announceBorderColorSet: (name) => `Border color set to ${name}`,
announceBorderReset: 'Borders reset to default',
borderSwatchLabel: (name) => `Border ${name}`,
announceRowInsertedAbove: 'Row added above',
announceRowInsertedBelow: 'Row added below',
announceColumnInserted: (side) => `Column added ${side}`,
announceRowDeleted: 'Row removed',
announceColumnDeleted: 'Column removed',
announceTableDeleted: 'Table removed',
insertTable: 'Insert Table',
tableAriaLabel: (rows, cols) => `Table: ${rows} rows, ${cols} columns`,
tableAriaDescription: 'Right-click or Shift+F10 for actions',
};
new TablePlugin({ locale: myTableLocale });
ExportKindDescription
LocaleConst objectEN, DE, ES, FR, ZH, RU, AR, HI, PT, BROWSER
LocaleServiceClassResolves the active language from config
LocaleServiceKeyServiceKeyService key for accessing LocaleService