docusaurus icon indicating copy to clipboard operation
docusaurus copied to clipboard

Labels do not have unique translation keys

Open mike-solomon opened this issue 10 months ago • 2 comments

Have you read the Contributing Guidelines on issues?

Prerequisites

  • [x] I'm using the latest version of Docusaurus.
  • [x] I have tried the npm run clear or yarn clear command.
  • [x] I have tried rm -rf node_modules yarn.lock package-lock.json and re-installing packages.
  • [x] I have tried creating a repro with https://new.docusaurus.io.
  • [x] I have read the console error message carefully (if applicable).

Description

In the sidebars.ts file, if you give multiple objects the same label (e.g., "How-to guides"), they will not generate unique translation keys. This means that the description field on those objects will not work as one of the objects will clobber all of the other ones.

As an example, let's say I want my site to look like this:

Topic A
  Getting Started
    ...
  How to guides
    ...
  References
    ...
Topic B
  Getting Started
    ...
  How to guides
    ...
  References
    ...

In my sidebars.ts file, I figured I could do something like this:

type: 'category',
label: 'References',
link: {
  type: 'generated-index',
  title: 'References',
  description: 'Moderne DX reference docs.',
  slug: '/administrator-documentation/moderne-dx/references',
  keywords: ['reference'],
},

and

type: 'category',
label: 'References',
link: {
  type: 'generated-index',
  title: 'References',
  description: 'Moderne Platform reference docs.',
  slug: '/administrator-documentation/moderne-platform/references',
  keywords: ['reference'],
},

However, that will result in one of the categories not having the correct description:

Image

Image

Related information here: https://github.com/facebook/docusaurus/discussions/10906#discussioncomment-12079496

Reproducible demo

https://github.com/mike-solomon/docusaurus-testing/tree/main/website

Steps to reproduce

  1. Launch the side.
  2. Navigate to foo/how-to.
  3. Notice that it has the description for the bar/how-to page.

Expected behavior

I would expect the descriptions on the category pages to match what I wrote in the sidebars.ts file.

Actual behavior

One or more of my pages descriptions gets clobbered with the incorrect description.

Your environment

  • Public source code: https://github.com/moderneinc/moderne-docs
  • Public site URL: https://docs.moderne.io/
  • Docusaurus version used: 3.7.0
  • Operating system and version (e.g. Ubuntu 20.04.2 LTS): Mac OS 15.3

Self-service

  • [ ] I'd be willing to fix this bug myself.

mike-solomon avatar Feb 06 '25 16:02 mike-solomon

Hi! I ran into the same issue with the sidebar translation generation when working with duplicate labels, I'd like to share the details and a possible solution.

In the getTranslationsFiles method, an object is constructed using sidebar data. The problem arises when two sidebar categories share the same label for example, both labeled "Guides". In such cases, the generated object keys become identical. Since JavaScript objects cannot have duplicate keys within the same level, this leads to conflicts.

Here's an example of the issue

{
  path: "current",
    content: {
      "sidebar.docs.category.Guides.link.generated-index.description": {
        message: "Let's learn about the most important Docusaurus concepts!",
        description: "First Description",
      },
      "sidebar.docs.category.Guides.link.generated-index.description": {
        message: "Docusaurus Guides",
        description: "Second Description",
      }
  }
}

As you can see, the key "sidebar.docs.category.Guides.link.generated-index.description" appears twice, which is not valid in JavaScript.

This object is constructed in packages/docusaurus-plugin-content-docs/src/translations.ts specifically between line 63 - 72, as shown in the screenshot below:

Image

Proposed Solution

To address this, I initially modified the structure to use an array of objects instead of a single object. Here’s the new format I propose

{
  path: "current",
    content: [
    {
      "sidebar.docs.category.Guides.link.generated-index.description": {
        message: "Let's learn about the most important Docusaurus concepts!",
        description: "First Description",
      }
    },
    {
      "sidebar.docs.category.Guides.link.generated-index.description": {
        message: "Docusaurus Guides",
        description: "Second Description",
      }
    }
  ]
}

This avoids the duplicate key issue, but it does introduce some side effects in the docusaurus-plugin-content-docs logic. Fortunately, the impact is limited since the methods in that file are mostly self contained and don't affect each other directly.

My next idea was to adjust the logic that assigns the description key by comparing both the key and the value. For example, in the same file translations.ts, line 137 is where the description is assigned:

packages/docusaurus-plugin-content-docs/src/translations.ts 137 is where the description assignment happens refer to the screenshot below

Image

When mapping the descriptions from the JSON back to the sidebar structure, we have access to the current category’s description via category.link.description. So with the array-based format, we could update the transformation logic accordingly to handle it properly.

However, I later discovered that this change would interfere with the writeTranslations method, which is responsible for handling localizations. Unfortunately, this means my proposed format could lead to further side effects and may not be a viable solution without deeper refactoring.

0xlakshan avatar Jun 03 '25 18:06 0xlakshan

I'm exploring how we could fix those issues in https://github.com/facebook/docusaurus/pull/11228

The problem is that the fix is likely to be a breaking change, and we need to figure out how to roll it out, possibly using v4 future flags.


Do not localize for the default locale?

One way to mitigate this easily is to disable the localization process for the current locale. For unlocalized sites, it's not really useful to try to localize strings.

Most sites with a single locale don't use the i18n folder to override the labels we provide, so making it opt-in would help mitigate the problem.

It's unusual to have conclifts, and it's also unusual to have localized sites, so having both at the same time is even more unusual, which saves us time to design and fix the underlying issue.

Keep translation keys short, but report conflicts?

We have conflicts because it's difficult to generate unique translation keys.

At the same time, we want the translation keys to be relatively short, easy to understand, and do not to change whenever we refactor the sidebar.

We could add the parent/breadcrumb labels, sidebar position index or other fancy things, but this is likely to be annoying in practice since this will lead to the keys to change whenever you change anything in the sidebar.

Instead of using more complex labels, my solution would rather to fail fast (or warn) when such conflict happen, and for the rare cases where this happen, let the user provide explicit translation keys (for example, using a dedicated sidebar item attribute).

Does it make sense?


The idea for me would be that:

  • Common case: unlocalized sites should be allowed to have label conflicts without any visual glitch
  • Edge case: localized sites with label conflicts would have to provide explicit translation keys for conflicting items

slorber avatar Jun 04 '25 10:06 slorber

Docusaurus v3.9 will throw a clear error when it encounters i18n translation key conflicts: https://github.com/facebook/docusaurus/pull/11228

And you can resolve those conflicts by adding a unique key attribute to sidebar items that share the same label.

Now I'll try to follow up and see if we can avoid all this for sites that do not even use i18n: https://github.com/facebook/docusaurus/pull/11304

slorber avatar Jul 03 '25 11:07 slorber

In v3.9, unlocalized sites shouldn't need to worry about translation key conflicts anymore: https://github.com/facebook/docusaurus/pull/11304

slorber avatar Jul 07 '25 12:07 slorber

For Docusaurus v3.9.2 we are also fixing/completing the support with the sidebar_key front matter: https://github.com/facebook/docusaurus/pull/11490

If you have Feature1/API/index.md, you can pass a unique key such as feature1.api instead of having to create a _category_.json with a "key": "feature1.api" attribute.

slorber avatar Oct 17 '25 10:10 slorber