Messages tree. You can override any subset by passing a messages callback to <App>. Wire that callback to your i18n library and locale changes propagate into FlowDrop without a subscription.
FlowDrop is not an i18n library. It is a consumer of one. Translations live in your app, alongside the rest of your UI copy.
Quick start
Override a single string with a value:messages is DeepPartial<Messages> — every key is optional, missing keys fall through to the English defaults.
You can also pass a callback. The two forms are equivalent for static overrides; the callback is useful when your translations come from a function call you’d rather not invoke unless the prop is actually read:
Translating with paraglide-js
Paraglide-js compiles your.json translation files into typed message functions. Wire them into FlowDrop’s messages prop:
paraglide-js is one option — sveltekit-i18n, typesafe-i18n, or any reactive store will work. The contract is just: a callback returning a partial tree.
Why the callback re-runs on locale change
Why the callback re-runs on locale change
Passing
messages as a callback (not a plain object) is what makes locale
switching reactive. Paraglide’s reactive locale store causes Svelte to
re-evaluate the expression; FlowDrop’s root then re-derives the merged message
tree and re-renders.The Messages shape
The full default tree lives atlibs/flowdrop/src/lib/messages/defaults.ts and is exported as defaultMessages from @flowdrop/flowdrop/core. The shape is grouped by domain, not by component — file paths churn, domains don’t.
| Branch | What it covers |
|---|---|
common | Generic verbs reused everywhere: save, cancel, confirm, close, delete, yes, no. |
form | All form components — array.* (move/delete/empty/limits), markdown.* (toolbar, status bar, placeholder), autocomplete.*, field.required, toggle.{enabled,disabled}, schema.{save,cancel,empty}, code.editor (JSON), template.editor (Mustache). |
interrupt | Inline interrupt prompts — confirmation.*, choice.* (with parameterised counter), review.* (accept/reject/diff/summary), text.* (placeholder, min, submit), form.*, bubble.* (per-kind required/submitted labels, retry, cancel). Plus shared responseSubmitted / responseSubmittedBy({ name }). |
chat | AI Assistant panel: aiAssistant, placeholder, send, autoRetry({ attempt, max }), plus commandPreview.* (apply / cancel / status). |
playground | Playground chat: chat.{placeholder, predefinedRun}, states.* (welcome screens), actions.* (run/stop/send), roles.* (you/assistant/system/log/message), messageTooltips.*, sessions.* (list, empty, delete confirm, relative timestamps). |
nodes.notes | NotesNode placeholder, type names (info/warning/success/error/note), processing/error indicators, configure tooltip. |
nodes.graph | SvelteFlow node and port aria-labels — workflowNode({ name }), gatewayNode({ title }), ideaNode({ title }), connectInputPort({ name }), connectOutputPort({ name }), connectBranch({ name }). |
navigation | Navbar branding (appName, tagline), connection indicator, settings button, default primary action labels (save, export, import, workflowSettings), right-sidebar panel titles (workflowSettingsPanelTitle, workflowSettingsPanelSubtitle, nodeConfigDescription), close affordances (closeSettings, closeConfigModal, copyId), and bottom-panel tab labels (bottomPanel.console, bottomPanel.chat). |
layout | Sidebar/canvas landmarks (componentsSidebar, workflowCanvas, executionLogs, settingsCategories), search input (searchComponents), command console (commandConsole, closeConsole), resize handles (resizeLeftSidebar, resizeRightSidebar, resizeBottomPanel), sidebar toggle (expandSidebar, collapseSidebar), modal close affordances, swap workflow (swapNode, backToConfiguration, backToNodeSelection), and loadSession({ name }). |
status | pipeline.* (refresh/view-logs/breadcrumbs) and overlay.* (NodeStatusOverlay tooltip and detail labels). |
({ n: _n }) => 'Move up'.
Removed label props
Several components used to accept individual*Label props that duplicated the messages tree. These duplicates are removed — use the corresponding messages key instead:
| Component | Removed prop | Replace with |
|---|---|---|
<SchemaForm> | saveLabel | messages.form.schema.save |
<SchemaForm> | cancelLabel | messages.form.schema.cancel |
<AIChatPanel> | placeholder | messages.chat.placeholder |
<FormToggle>’s onLabel/offLabel and <FormArray>’s addLabel are not removed. They express per-instance labels the global messages system cannot (a toggle’s “Hidden”/“Visible”, a schema-derived “Add Header” button) and are documented overrides.
Workflow-level overrides on interrupt configs (config.confirmLabel, config.acceptAllLabel, etc.) are not removed either — those are runtime data from the workflow author, not component-prop API. They keep their priority over the messages defaults.
Components used outside the <App> provider
If you mount a flowdrop component (e.g. <SchemaForm> standalone, or a Storybook story) outside the root <App>, it falls back silently to the English defaultMessages. There is no error. The trade-off: a missing provider always renders English regardless of locale. To get translations in standalone usage, set up the messages context yourself:
setMessages accepts a getter so reactive overrides propagate the same way they do under <App>.
Reference
- Defaults:
libs/flowdrop/src/lib/messages/defaults.ts - Public types:
Messages,MessagesOverride(re-exported from@flowdrop/flowdrop) - Source:
libs/flowdrop/src/lib/messages/