Skip to content

feat: add a labels prop to localize the widget's built-in UI strings - #38

Open
blaab2 wants to merge 1 commit into
VapiAI:mainfrom
blaab2:feat/localizable-widget-labels
Open

blaab2 wants to merge 1 commit into
VapiAI:mainfrom
blaab2:feat/localizable-widget-labels

Conversation

@blaab2

@blaab2 blaab2 commented Sep 22, 2026

Copy link
Copy Markdown

Problem

Most of the widget's text can be set from props, but about twenty UI strings are hard-coded in English with no way to change them, so a non-English site always shows them in English:

  • the header status line: Type a message below, Chat active, Assistant is typing..., Connecting..., Listening..., Assistant Speaking..., Ready to assist, Connected, Click the microphone to start, Choose voice or text
  • header controls: End Chat (label + tooltip), Reset conversation (tooltip)
  • after a chat has ended: Start new chat, Close
  • the consent form buttons: Accept, Cancel
  • tooltips: Send message, Mute microphone, Unmute microphone, Start voice call, Stop voice call

We ship the widget on a German/French/English site and currently have to rewrite these strings in the DOM with a MutationObserver, which is fragile. This PR adds the missing API.

Change

A labels prop — Partial<WidgetLabels> — that overrides any subset of those strings. Keys left out keep their English default, so existing integrations render exactly as before.

  • WidgetLabels (exported type) and defaultLabels (English defaults, src/components/constants.ts); VapiWidget merges { ...defaultLabels, ...labels } and passes the result to WidgetHeader, ConsentForm, ChatControls, HybridControls, VoiceControls and the chat-ended screen.
  • Embed support: <vapi-widget labels='{"consentAccept":"Akzeptieren",…}'> and data-labels='{…}' are parsed as JSON, the same way assistant-overrides already is (a small JSON_PROPS list replaces the two inline assistantOverrides || assistant checks).
  • Two small accessibility side effects while touching these buttons, both using the new labels: the chat-mode send button gets the same title the hybrid one already had, and the header's close button gets a title (it had no accessible name at all).
  • README: a labels row in the props table and a Localization section listing every key with its default and where it shows, plus React, custom-element and data-attribute examples.

No behaviour changes without the prop. I went with one object rather than ~20 individual props to keep the props table readable and so a translation table can be typed with WidgetLabels; happy to switch to individual …Text props if you prefer that style for attribute users.

Tests

tests/widget-labels.spec.ts on a new fixture page (test-widget-labels.html) — one <vapi-widget> with a labels JSON attribute and one data-attribute embed with data-labels:

  • consent buttons, status line and End Chat render the given labels,
  • keys that were not overridden keep their English default (reset / send tooltips),
  • and, on the existing fixture without labels, the English defaults are unchanged (control group).

Locally: npm run lint, npm run type-check, npm run format:check, npm run build, npm run build:widget and npm run test:ci all pass.

About twenty UI strings were hard-coded in English with no prop to set
them: the header status line ("Type a message below", "Chat active",
"Assistant is typing...", ...), the End Chat and Reset controls, the
buttons after a chat has ended, the consent form's Accept / Cancel and
the control tooltips. A non-English site could not change them.

`labels?: Partial<WidgetLabels>` overrides any subset; keys left out keep
their English default (`defaultLabels`), so existing integrations render
exactly as before. The embed parses `labels` / `data-labels` as JSON like
`assistant-overrides`. While touching these buttons, the chat-mode send
button gets the tooltip the hybrid one already had, and the header's
close button gets an accessible title.

Covered by tests/widget-labels.spec.ts on a new fixture page with both
embed mechanisms, plus a control test on the existing fixture asserting
the English defaults are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
blaab2 added a commit to blaab2/client-sdk-react that referenced this pull request Sep 25, 2026
Adds the chat-end-message attribute mapping (VapiAI#40)
on top of VapiAI#38 and VapiAI#39; dist/ rebuilt and committed as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant