Skip to content

Language Support internals

Overview

Runtime language switching for the bpmn-js / dmn-js modeler UI is implemented as a standalone library (libs/bpmn-i18n/) exposing a bpmn-js DI module (TranslateModule) and a translation service (CustomTranslator). The extension host pushes the active locale; the webview re-imports the current diagram to force bpmn-js to re-evaluate every translate() call.

See the user-facing Language Support page for the list of supported locales and how to switch at runtime.

System overview

ComponentRole
libs/bpmn-i18n/Translation library — dictionaries, CustomTranslator, TranslateModule
libs/bpmn-i18n/src/languages/{locale}/Per-locale dictionary files (bpmn-js, dmn-js, properties-panel, other)
apps/modeler-plugin/src/infrastructure/VsCodeSettings.tsReads the miragon.bpmnModeler.language setting
apps/bpmn-webview/src/main.tsHandles LanguageQuery, triggers refreshDiagram()

CustomTranslator looks up UI strings in per-locale dictionaries and supports {param} placeholder substitution (e.g. "Append {type}""Ajouter {type}"). The active locale is switched at runtime via setLanguage(locale).

TranslateModule registers CustomTranslator as an __init__ service and exposes it under the customTranslator and translate DI keys.

Entry points

  • Host sideBpmnEditorController subscribes to configuration changes for miragon.bpmnModeler.language. On change, it pushes a LanguageQuery to each open BPMN webview via BpmnModelerService.setLanguage().
  • Webview sideapps/bpmn-webview/src/main.ts handles LanguageQuery, calls CustomTranslator.setLanguage(locale), and triggers refreshDiagram().

Key files

FilePurpose
libs/bpmn-i18n/src/TranslateModule.tsCustomTranslator class and DI module
libs/bpmn-i18n/src/languages/index.tsLocale registry, supportedLanguages array, dictionaries map
libs/bpmn-i18n/src/languages/{locale}/Per-locale translation dictionaries (four files each)
libs/shared/src/lib/modeler.tsLanguageQuery message type
apps/modeler-plugin/package.jsonSetting and command definitions
apps/modeler-plugin/src/infrastructure/VsCodeSettings.tsgetLanguage() setting reader
apps/modeler-plugin/src/controller/BpmnEditorController.tsSetting change subscription, initial language push
apps/modeler-plugin/src/controller/CommandController.tschangeLanguage command handler (QuickPick)
apps/modeler-plugin/src/service/BpmnModelerService.tssetLanguage() sends LanguageQuery to webview
apps/bpmn-webview/src/main.tsLanguageQuery handler, refreshDiagram()
apps/bpmn-webview/src/app/modeler.tsBpmnModeler.create() accepts TranslateModule

Message protocol

MessageDirectionPayload
LanguageQueryhost → webview{ locale: SupportedLocale }

There is no webview → host message — the host always pushes the current locale.

Interaction flow

Dictionary structure

Each locale has its own directory under libs/bpmn-i18n/src/languages/{locale}/ with four translation files:

FileScope
bpmn-js.tsbpmn-js modeler UI (palette, context pad, labels)
dmn-js.tsdmn-js modeler UI
properties-panel.tsProperties panel labels and descriptions
other.tsMiscellaneous UI strings

Each file exports a Record<string, string> mapping English source text to translated text. The locale's index.ts merges all four into a single dictionary. All dictionaries are cached in a dictionaries map for fast lookup.

Adding a new language

  1. Create a new directory under libs/bpmn-i18n/src/languages/{locale}/ with the four translation files. Copy an existing locale (e.g. en/) as a template.
  2. Export the merged dictionary from libs/bpmn-i18n/src/languages/{locale}/index.ts.
  3. Register the new locale in libs/bpmn-i18n/src/languages/index.ts:
    • Add it to the SupportedLocale union type.
    • Add an entry to the supportedLanguages array with the locale code and display label.
    • Add it to the dictionaries map.
  4. Add the locale to the enum and enumItemLabels arrays in apps/modeler-plugin/package.json under the miragon.bpmnModeler.language setting definition.

Gotchas

  • Diagram re-import is required on language change. Already-rendered UI elements (palette entries, context pad items) retain their original text — re-importing forces bpmn-js to call translate() again for every label.
  • Four files per locale, four places to register. If you add a string to bpmn-js.ts for one locale and forget the others, that string falls through to the English source (the identity mapping) — silent divergence.
  • Viewport must be saved and restored around the re-import, otherwise the user is scrolled back to the diagram origin on every language change.