Browser-side syntax highlighter and IDE-style editor for ICU MessageFormat 2.0 (MF2) messages. Drop-in Phoenix LiveView hook.
The hook runs the mf2_treesitter grammar directly in the browser via web-tree-sitter. Keystrokes are highlighted and diagnostics surface without leaving the client — no server round trip per edit. The server stays in the loop only for authoritative operations (formatting, validation, persistence) that it actually owns.
What ships in this package
Three browser-side artefacts plus the Elixir glue to serve them:
- Web-tree-sitter runtime (
tree-sitter.js,tree-sitter.wasm) — vendored from theweb-tree-sitternpm package, MIT-licensed. - Compiled MF2 grammar (
tree-sitter-mf2.wasm) — vendored from thetree-sitter-mf2npm package. - LiveView hook (
mf2_editor.js) — the IDE-style editor runtime. Parse-and-paint on every keystroke with diagnostics, auto-close, bracket matching, tooltips, goto-definition, rename-in-scope, outline picker, structural selection, smart indent, completion,.matchpluralisation skeletons, and server-push text replacement. Full list in the features guide.
Plus 30 drop-in colour themes under priv/themes/ and the mix mf2_wasm_editor.sync task that keeps the vendored grammar in step with a pinned tree-sitter-mf2 npm release.
Sibling packages cover the rest of the MF2 ecosystem:
mf2_treesitter— the grammar itself (published on npm astree-sitter-mf2).localize_mf2_treesitter— server-side MF2 parsing in Elixir (NIF).mf2_editor_extensions— Zed / Helix / Neovim / VS Code / Emacs / Vim integrations.
This package is ecosystem-neutral — it doesn't depend on the Localize hex package. It works for any Phoenix LiveView app editing MF2 messages.
Installation
def deps do
[
{:mf2_wasm_editor, "~> 0.1"}
]
endNo compile-time toolchain is required for consumers — the WASM artefacts and JS hook are pre-built and shipped.
Quick start
# endpoint.ex — serve the hook's static assets
plug Plug.Static,
at: "/mf2_editor",
from: {:mf2_wasm_editor, "priv/static"},
gzip: false,
only: Mf2WasmEditor.static_paths()<%!-- root layout: MUST come before app.js --%>
{raw(Mf2WasmEditor.script_tags())}// assets/js/app.js — merge the hook into LiveSocket
const Hooks = Object.assign({}, window.Mf2WasmEditor?.Hooks || {})
const liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks, ...})<%!-- any LiveView template --%>
<div phx-hook="MF2Editor" id="my-editor">
<pre class="mf2-highlight" aria-hidden="true" phx-update="ignore" id="my-editor-pre"><code></code></pre>
<textarea name="message" phx-update="ignore" phx-debounce="100" rows="8" spellcheck="false">{@message}</textarea>
</div>Add the monokai theme (or one of 29 others) for colour, and you're done.
Guides
- Wiring — full setup recipe, configuration, caveats, server-side diagnostics integration, grammar refresh workflow, troubleshooting.
- Features — editing features and keyboard bindings, CSS class reference, themes and how to customise them.
Status
Reasonably complete for an in-textarea editor. The hook is 100%-conformant against the MF2 WG syntax test suite, and the IDE-style layer covers most of what a translator or developer expects.
Licence
Apache-2.0 for this package. Third-party notices in LICENSE.md.