Skip to content

Translate the control panels like @plone/plate - #353

Open
sneridagh wants to merge 4 commits into
feat/controlpanels-restapi-driverfrom
feat/controlpanels-i18n
Open

sneridagh wants to merge 4 commits into
feat/controlpanels-restapi-driverfrom
feat/controlpanels-i18n

Conversation

@sneridagh

@sneridagh sneridagh commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Part of #269. Stacked on #351.

The control panels are translated the way @plone/plate is, so they work the same in Plone Aurora and in Volto, and they ship translations: English, German, Spanish, Italian, Catalan and Brazilian Portuguese. A new conceptual guide documents the pattern both packages follow.

@plone/controlpanels

  • Plate's i18n contract: ControlPanelsProvider takes a t function in react-i18next's shape, t(key, { defaultValue, ...values }), instead of translate. Aurora passes react-i18next's t as is. Apps on react-intl, such as Volto, pass translationFromIntl(intl), which turns the placeholders into ICU's. The screens keep using useTranslate() with their messages, so they don't change.
  • Placeholders use i18next's double braces, {{count}}, in all 258 messages.
  • No double escaping: the screens ask i18next not to escape the values (interpolation: { escapeValue: false }), since React escapes what it renders. Without it, "Intranet/Extranet" showed as Intranet/Extranet in the workflow dialog; the acceptance tests caught it.
  • Catalogs in src/locales/<language>/common.json, i18next's common namespace, next to the package's main, where the registry looks:
    • en is generated from the messages in the code: pnpm i18n.
    • de, es, it, ca and pt-BR translate every message, with the terms of Volto's catalog for each language (Content type, Workflow, Fieldset, Short name…).
    • src/locales.test.ts fails when en is outdated, or when a translation has unknown keys or other placeholders.
  • An add-on entry point: a default-exported applyConfig that returns the config, so Aurora can register the package and load its translations.
  • A badge message: "Not globally addable" on the type page gets its own message. It shared one with the list's sentence about new types, which needs a plural in Spanish, Italian and Catalan.

Aurora

  • apps/aurora depends on @plone/controlpanels and lists it in registry.config.ts, so the registry merges its catalogs into public/locales.
  • cmsui's ContentTypesProviders passes react-i18next's t, and no longer fills in the placeholders itself.

Documentation

  • New conceptual guide, docs/conceptual-guides/packages-for-volto-and-aurora.md, on what makes a package run in both apps:
    • no framework imports
    • a provider for app services, and a driver with capabilities for data
    • translations
    • scoped styles for Volto
    • shipping TypeScript source
    • @plone/registry as a peer dependency
  • AGENTS.md: the root file summarizes the pattern and points to the guide; @plone/plate's and @plone/controlpanels' files point to it too.

Not in this PR

  • Volto: Add the content types control panel from @plone/controlpanels volto#8500 will pass translationFromIntl(intl), and bring the messages into Volto's catalogs from these JSON files, as volto-plate does for Plate.
  • Aurora's language choice doesn't apply: with more than English in supportedLanguages, choosing German in the personal preferences still renders English everywhere. app/i18n.ts reads the supported languages when it's first imported, probably before the configuration has run. That's a separate fix. Here I checked that Aurora serves the control panel's catalogs, for example /locales/de/common.json with "Inhaltstypen".

Checks

  • @plone/controlpanels: 128 unit tests, including the contract, translationFromIntl and the catalogs. check:ts, lint and Prettier pass.
  • @plone/cmsui: 451 unit tests; check:ts passes.
  • Acceptance, content-types.test.ts against plone.restapi issue-2061-workflows: 23 passed, 2 skipped (the known gaps on that backend).
  • Docs: make docs-html builds without warnings from the new guide.

See #269 for how to review and merge the stack.

ControlPanelsProvider takes a t function in react-i18next's shape, as
PlateEditor does, instead of translate. Aurora passes react-i18next's t,
and apps on react-intl pass translationFromIntl(intl). The messages use
{{placeholder}}s, and i18next doesn't escape the values, as React
renders them.

The translations ship in src/locales, in English, German, Spanish,
Italian and Catalan. The English catalog is generated from the code
(pnpm i18n), and a test checks the others. Aurora registers
@plone/controlpanels as an add-on, so they load.

The not globally addable badge gets its own message, since the list's
sentence about new types needs a plural in some languages.
A conceptual guide on the pattern @plone/plate and @plone/controlpanels
follow, and a pointer to it in the root and package AGENTS.md files.

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