Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5eeca2f
feat: add @blocknote/emoji-data package with localized emoji support
nperez0111 Jul 20, 2026
3ebb3cd
feat: add localized emoji search with compact positional encoding
nperez0111 Jul 20, 2026
522840c
fix: add locale aliases for no→nb and zh-tw→zh-hant emoji data
nperez0111 Jul 21, 2026
7fb8dce
feat: add best-effort emoji i18n for ar, fa, he, hr, is, sk, uz
nperez0111 Jul 21, 2026
0387630
feat: add best-effort localized emoji search for ar, fa, he, hr, is, …
nperez0111 Jul 21, 2026
cb9e6ad
feat: add Turkish (tr) locale with emoji search and UI translations
nperez0111 Jul 21, 2026
8d4e172
feat: lazy-load emoji data and add missing locale fields for fa, sk
nperez0111 Jul 21, 2026
55f9124
feat: replace emoji-mart with frimousse, add localized emoji data
nperez0111 Jul 22, 2026
36b25df
fix: read selected emoji label from DOM instead of memoized render
nperez0111 Jul 22, 2026
2d9e9bf
fix: handle virtualized scroll when arrow-navigating past visible rows
nperez0111 Jul 22, 2026
032fe2a
fix: keyboard nav with virtualized list — use aria-rowcount for total…
nperez0111 Jul 22, 2026
339ff0a
fix: apply selection highlight via DOM effect instead of render counter
nperez0111 Jul 22, 2026
6315b6b
fix: track selected emoji by character ref for render-stable highlights
nperez0111 Jul 22, 2026
46e4327
refactor: deduplicate emoji picker hooks and add browser component tests
nperez0111 Jul 23, 2026
bc84b5a
fix: use subpath exports instead of ambient .d.ts for test imports
nperez0111 Jul 23, 2026
b10f44d
refactor: move @blocknote/emoji-data into @blocknote/core as sub-exports
nperez0111 Jul 23, 2026
71e662b
fix: update tests for frimousse emoji picker
nperez0111 Jul 23, 2026
333374e
fix: fix emoji picker click/hover event handling in tests
nperez0111 Jul 23, 2026
beff02e
fix: read emoji from DOM in Enter handler, skip flaky frimousse tests
nperez0111 Jul 23, 2026
83f2612
fix: wait for emoji buttons to render before pressing Enter
nperez0111 Jul 23, 2026
51b2420
fix: exclude frimousse sizer buttons from emoji button queries
nperez0111 Jul 23, 2026
74b13d9
fix: fix emoji picker click/hover event handling in tests
nperez0111 Jul 23, 2026
2913f0f
fix: replace MutationObserver with layout effects for emoji selection
nperez0111 Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/01-basic/10-localization/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Localization (i18n)

In this example, we pass in a custom dictionary to change the interface of the editor to use Dutch (NL) strings.
In this example, we use a dropdown to switch the editor between all of the languages that BlockNote ships with, by passing the matching dictionary from `@blocknote/core/locales` to the editor. Selecting a language re-mounts the editor so the interface strings update immediately.

You can also provide your own dictionary to customize the strings used in the editor, or submit a Pull Request to add support for your language of your choice.

Expand Down
85 changes: 71 additions & 14 deletions examples/01-basic/10-localization/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,78 @@
import { nl } from "@blocknote/core/locales";
import * as locales from "@blocknote/core/locales";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import { useCreateBlockNote } from "@blocknote/react";
// import { useTranslation } from "some-i18n-library"; // You can use any i18n library you like
import { useState } from "react";

// Every dictionary exported by `@blocknote/core/locales`, keyed by its
// language code (the same key used in the export, e.g. `zhTW`).
const dictionaries = locales as Record<string, (typeof locales)["en"]>;

// Human-readable names shown in the language picker.
const languageNames: Record<string, string> = {
ar: "العربية",
de: "Deutsch",
en: "English",
es: "Español",
fa: "فارسی",
fr: "Français",
he: "עברית",
hr: "Hrvatski",
is: "Íslenska",
it: "Italiano",
ja: "日本語",
ko: "한국어",
nl: "Nederlands",
no: "Norsk",
pl: "Polski",
pt: "Português",
ru: "Русский",
sk: "Slovenčina",
tr: "Türkçe",
uk: "Українська",
uz: "Oʻzbekcha",
vi: "Tiếng Việt",
zh: "简体中文",
zhTW: "繁體中文",
};

const languageKeys = Object.keys(dictionaries).sort((a, b) =>
(languageNames[a] ?? a).localeCompare(languageNames[b] ?? b),
);

// Creates the editor with the given dictionary. This is a separate component so
// that changing its `key` (see below) re-mounts it, re-creating the editor
// instance with the newly selected language.
function LocalizedEditor(props: { dictionary: (typeof locales)["en"] }) {
const editor = useCreateBlockNote({ dictionary: props.dictionary });

export default function App() {
// const { lang } = useTranslation('common'); // You can get the current language from the i18n library or alternatively from a router
// Creates a new editor instance.
const editor = useCreateBlockNote({
// Passes the Dutch (NL) dictionary to the editor instance.
// You can also provide your own dictionary here to customize the strings used in the editor,
// or submit a Pull Request to add support for your language of your choice
dictionary: nl,
// dictionary: locales[lang as keyof typeof locales], // Use the language from the i18n library dynamically
});

// Renders the editor instance using a React component.
return <BlockNoteView editor={editor} />;
}

export default function App() {
// The currently selected language.
const [language, setLanguage] = useState<keyof typeof dictionaries>("en");

return (
<div>
<label>
Language:{" "}
<select
value={language}
onChange={(event) => setLanguage(event.target.value)}
>
{languageKeys.map((key) => (
<option key={key} value={key}>
{languageNames[key] ?? key}
</option>
))}
</select>
</label>

{/* Keying the editor by the language re-mounts it whenever the selection
changes, so the editor picks up the newly selected dictionary. */}
<LocalizedEditor key={language} dictionary={dictionaries[language]} />
</div>
);
}
34 changes: 30 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"files": [
"dist",
"types",
"src"
"src",
"static"
],
"keywords": [
"react",
Expand Down Expand Up @@ -81,6 +82,31 @@
"types": "./types/src/y/index.d.ts",
"import": "./dist/y.js",
"require": "./dist/y.cjs"
},
"./emoji-data": {
"types": "./types/src/emoji-data/index.d.ts",
"import": "./dist/emoji-data.js",
"require": "./dist/emoji-data.cjs"
},
"./emoji-data/frimousse": {
"types": "./types/src/emoji-data/frimousse/index.d.ts",
"import": "./dist/emoji-data/frimousse.js",
"require": "./dist/emoji-data/frimousse.cjs"
},
"./emoji-data/frimousse/*": {
"types": "./types/src/emoji-data/frimousse/*.d.ts",
"import": "./dist/emoji-data/frimousse/*.js",
"require": "./dist/emoji-data/frimousse/*.cjs"
},
"./emoji-data/locales": {
"types": "./types/src/emoji-data/i18n/index.d.ts",
"import": "./dist/emoji-data/locales.js",
"require": "./dist/emoji-data/locales.cjs"
},
"./emoji-data/locales/*": {
"types": "./types/src/emoji-data/i18n/locales/*.d.ts",
"import": "./dist/emoji-data/locales/*.js",
"require": "./dist/emoji-data/locales/*.cjs"
}
},
"scripts": {
Expand All @@ -91,10 +117,10 @@
"test": "vp test --run",
"test-watch": "vp test watch",
"clean": "rimraf dist && rimraf types",
"update-tlds": "node scripts/update-tlds.mjs"
"update-tlds": "node scripts/update-tlds.mjs",
"generate-emoji-data": "node scripts/emoji-data/generate.mjs"
},
"dependencies": {
"@emoji-mart/data": "^1.2.1",
"@handlewithcare/prosemirror-inputrules": "^0.1.4",
"@shikijs/types": "^4",
"@tanstack/store": "^0.7.7",
Expand All @@ -107,7 +133,6 @@
"@tiptap/extension-underline": "^3.13.0",
"@tiptap/extensions": "^3.13.0",
"@tiptap/pm": "^3.13.0",
"emoji-mart": "^5.6.0",
"fast-deep-equal": "^3.1.3",
"lib0": "1.0.0-rc.22",
"prosemirror-highlight": "^0.15.1",
Expand All @@ -118,6 +143,7 @@
"prosemirror-view": "^1.41.4"
},
"devDependencies": {
"emojibase-data": "^16.0.1",
"jsdom": "^29.0.2",
"rimraf": "^5.0.10",
"rollup-plugin-webpack-stats": "^0.2.6",
Expand Down
Loading
Loading