Support for localization of Dashboard extensions was added in v3.5.1
The Dashboard uses Lingui, which provides a powerful i18n solution for React:
First you'll need to wrap any strings that need to be localized:
You will mainly make use of the Trans component and the useLingui hook.
Create a lingui.config.js file in your project root, with references to any plugins that need to be localized:
Then extract the translations:
This will output the given locale files in the directories specified in the config file above. In this case:
src/
└── plugins/
└── reviews/
└── dashboard/
└── i18n/
├── en.po
└── de.po
Since we set the "sourceLocale" to be "en", the en.po file will already be complete. You'll then need to
open up the de.po file and add German translations for each of the strings, by filling out the empty msgstr values:
The #: comment above each message records where the string was found, down to the line number. Those
line numbers are recalculated on every extraction, so any edit that shifts code up or down rewrites
them — adding one import at the top of a file changes the recorded line of every string below it, even
though none of the strings themselves changed.
If several people work on the same plugin, this can make the .po files a recurring source of merge
conflicts that have nothing to do with the translations. You can turn the line numbers off by passing an
explicit PO formatter to your config:
The references then keep the file path and drop the line number, which is usually enough context for a translator to find the string:
The next npx lingui extract rewrites every reference in your catalogs, so expect one large diff when
you first make this change. After that the references only change when a string genuinely moves to a
different file.
formatter comes from @lingui/format-po, which is installed as part of the Lingui CLI. If your package
manager enforces strict dependency resolution (pnpm, or Yarn PnP), add it to your project explicitly with
npm install --save-dev @lingui/format-po.
The sections above cover localizing your own extensions. If instead you want to translate the built-in Dashboard UI into a new language — or improve an existing translation — those catalogs live in the Vendure repository and the change is contributed via a pull request.
This is for the React Dashboard (@vendure/dashboard). The legacy Angular Admin UI has its own
separate translation workflow.
The Dashboard's own message catalogs live at packages/dashboard/src/i18n/locales/{locale}.po, one
.po file per supported language. The English catalog (en.po) is the source and is always complete;
the others are translations of it.
Open the catalog for the language you want to improve — for example de.po for German — and fill in
or correct the msgstr values. An empty msgstr means that string is not yet translated and falls
back to English at runtime.
Add the locale code to the locales array in packages/dashboard/lingui.config.js. It must be a
valid LanguageCode
value, which uses underscores for region variants (zh_Hans, pt_BR).
Add the same locale to defaultAvailableLanguages in packages/dashboard/vite/constants.ts. The
Display language selector is built from this list, so a catalog missing from it can never be
selected.
From packages/dashboard, generate the catalog:
This creates src/i18n/locales/{locale}.po with every UI string and empty msgstr values. Use
npx lingui extract rather than npm run i18n:extract, which also runs an LLM helper that writes
an untracked missing-translations.txt.
Fill in the msgstr values. The Dashboard globs that directory, so nothing else needs registering.
Run the development server so you can see your translations in the running Dashboard:
bun run dev prints the Dashboard URL when it starts — open that. It serves from Vite, so .po edits
are picked up on reload (the static build served by DashboardPlugin would need a rebuild). Then switch
the UI language from the user menu at the bottom of the sidebar → Display language, and choose your
locale. The interface re-renders with your catalog; any string you left untranslated shows the English source.
Commit the changed .po file(s) (and, for a new language, the lingui.config.js and
vite/constants.ts changes) and open a PR against master. A translation change is a fix, so title
it accordingly, e.g. fix(dashboard): Add Ukrainian UI translations. Translations are always welcome,
including partial ones — you don't have to translate every string to contribute.
Two CI checks gate a translation PR: dashboard i18n sync (runs lingui extract and fails if the
committed catalogs are out of date) and i18n:check (per-locale catalog validation). Run
npx lingui extract from packages/dashboard and commit the result so the sync check stays green.