facebook/docusaurus · error · Error

Translation file path at "${translationFilePath}" does not n

Error message

Translation file path at "${translationFilePath}" does not need to end with ".json", we add the extension automatically.

What it means

Thrown by `addTranslationFileExtension` when a plugin declares a translation file path that already ends in `.json`. Docusaurus appends the extension itself (the comment explains it reserves room for future formats like yaml/toml), so a user-supplied `.json` suffix would double it. This is a configuration contract enforced for plugin authors.

Source

Thrown at packages/docusaurus/src/server/translations/translations.ts:171

}
export async function writeCodeTranslations(
  context: TranslationContext,
  content: TranslationFileContent,
  options: WriteTranslationsOptions,
): Promise<void> {
  return writeTranslationFileContent({
    filePath: getCodeTranslationsFilePath(context),
    content,
    options,
  });
}

// We ask users to not provide any extension on purpose:
// maybe some day we'll want to support multiple FS formats?
// (json/yaml/toml/xml...)
function addTranslationFileExtension(translationFilePath: string) {
  if (translationFilePath.endsWith('.json')) {
    throw new Error(
      `Translation file path at "${translationFilePath}" does not need to end with ".json", we add the extension automatically.`,
    );
  }
  return `${translationFilePath}.json`;
}

function getPluginTranslationFilePath({
  localizationDir,
  plugin,
  translationFilePath,
}: TranslationContext & {
  plugin: InitializedPlugin;
  translationFilePath: string;
}): string {
  const dirPath = getPluginI18nPath({
    localizationDir,
    pluginName: plugin.name,
    pluginId: plugin.options.id,

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Remove the `.json` suffix from the translation file path your plugin returns.
  2. Use the path without extension consistently in `getTranslationFiles` and `translate`.
  3. If you control the format and want `.json` literally, you cannot — rely on Docusaurus to append it.

Example fix

// before
getTranslationFiles: () => [{path: 'fr/messages.json', content: {}}],
// after
getTranslationFiles: () => [{path: 'fr/messages', content: {}}],
Defensive patterns

Strategy: validation

Validate before calling

function assertNoJsonExt(path: string) {
  if (path.endsWith('.json')) throw new Error(`Remove .json from translation path: ${path}`);
}

Prevention

When it happens

Trigger: A plugin's `getTranslationFiles` / `translate` hook returns a path like `'i18n/fr/messages.json'`. The check at translations.ts:171-176 fires before the internal `.json` append.

Common situations: Third-party plugin authors copying example code that included the extension; refactoring a plugin and adding `.json` for clarity; migrating content where source files used `.json`.

Related errors


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/0aeeb74cddd95a34. Report an issue: GitHub.