payloadcms / payloadcms/payload

bug: plugin-ecommerce overwrites user i18n overrides in plugin-ecommerce namespace

Open
#16,502 0 comments 0 reactions 1 assignee View on GitHub

@paulpopus is already working on this.

Since May 6, 2026.

created-by: Contributor plugin: ecommerce
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

When a user supplies translations for the plugin-ecommerce namespace via Payload's top-level i18n.translations config (e.g. to localise a label like cart), the ecommerce plugin silently discards them at config-build time.

The plugin first deep-merges the user's translations into the plugin defaults (good), but then immediately overwrites the entire plugin-ecommerce namespace per locale with only its own defaults (bad), losing every user override.

In node_modules/@payloadcms/plugin-ecommerce/dist/index.js (v3.84.1), lines 208 and 214–230:

// line 208 — first this is fine: user overrides survive deepMerge
incomingConfig.i18n.translations = deepMergeSimple(translations, incomingConfig.i18n?.translations);

// lines 214-230 — then this loop wipes them out
Object.entries(translations).forEach(([locale, pluginI18nObject]) => {
  const typedLocale = locale;
  if (!incomingConfig.i18n.translations) {
    incomingConfig.i18n.translations = {};
  }
  if (!(typedLocale in incomingConfig.i18n.translations)) {
    incomingConfig.i18n.translations[typedLocale] = {};
  }
  if (!('plugin-ecommerce' in incomingConfig.i18n.translations[typedLocale])) {
    incomingConfig.i18n.translations[typedLocale]['plugin-ecommerce'] = {};
  }
  // wholesale assignment — discards anything merged in above
  incomingConfig.i18n.translations[typedLocale]['plugin-ecommerce'] = {
    ...pluginI18nObject.translations['plugin-ecommerce'],
  };
});

The result is that incomingConfig.i18n.translations[locale]['plugin-ecommerce'] always equals the plugin's bundled defaults, regardless of what the user passed in.

Plugin source on GitHub: https://github.com/payloadcms/payload/blob/main/packages/plugin-ecommerce/src/index.ts (the equivalent of dist/index.js:227-229 in the published 3.84.1 build).

Suggested Fix

Replace the wholesale assignment with a merge that lets user overrides win, e.g.:

incomingConfig.i18n.translations[typedLocale]['plugin-ecommerce'] = {
  ...pluginI18nObject.translations['plugin-ecommerce'],
  ...incomingConfig.i18n.translations[typedLocale]['plugin-ecommerce'],
};

…or simply remove the second loop entirely, since the deepMergeSimple call on line 208 already correctly merges plugin defaults with user overrides (with user overrides winning).

Link to the code that reproduces this issue

https://github.com/jhb-dev/payload-ecommerce-i18n-overwrite

Reproduction Steps
  1. Clone the reproduction repository and run the development server.
  2. The reproduction's payload.config.ts passes a top-level i18n with translations.de['plugin-ecommerce'].cart = 'MEIN KORB (user override)'.
  3. The onInit hook reads back payload.config.i18n.translations.de['plugin-ecommerce'].cart and logs the resolved value.
  4. Hit any API route to trigger initialisation: curl http://localhost:3000/api/users.
  5. Expected: the log prints MEIN KORB (user override).
  6. Actual: the log prints Warenkorb (the plugin default), proving the user override was overwritten.

Captured server output:

[i18n-repro] de.plugin-ecommerce.cart resolved to: "Warenkorb"
[i18n-repro] expected: "MEIN KORB (user override)"
[i18n-repro] BUG REPRODUCED — user i18n override for plugin-ecommerce was overwritten by plugin defaults
Which area(s) are affected?

plugin: ecommerce

Environment Info
Binaries:
  Node: 24.3.0
  npm: 11.4.2
  pnpm: 10.33.0
Relevant Packages:
  payload: 3.84.1
  next: 15.4.11
  @payloadcms/db-mongodb: 3.84.1
  @payloadcms/plugin-ecommerce: 3.84.1
  @payloadcms/translations: 3.84.1
  react: 19.2.1
  react-dom: 19.2.1
Operating System:
  Platform: darwin
  Arch: arm64

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.