# General Translation Knowledge Base: Как перевести Markdown и MDX, не нарушив синтаксис?
URL: https://generaltranslation.com/ru/kb/translate-markdown-files.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Переводите текст, alt-текст изображений, заголовки и описания во frontmatter, а также пропсы компонентов с отображаемым текстом. Блоки кода, встроенный код, импорты, имена JSX-компонентов, ключи frontmatter и URL ссылок оставляйте без изменений, если только их не переписывает сопоставление локалей. Заключайте переведённые значения YAML в кавычки, а затем запустите сборку сайта.
Category: Перевод
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

В файле Markdown обычный текст перемежается с техническим синтаксисом. MDX добавляет к этому JavaScript: строки `import`, JSX-компоненты и `{expressions}`, которые компилятор должен корректно разобрать и после перевода. Прежде чем переводить, определите, какие поля содержат отображаемый текст: `title` компонента может требовать перевода, тогда как его `id` должен оставаться неизменным.

## Что ломается, когда Markdown проходит через универсальный переводчик

Переводчик, который воспринимает файл как обычный текст, считает языком всё его содержимое. Вот на какие сбои стоит проверить результат:

* **Блоки кода и встроенный код.** Команды и идентификаторы могут оказаться переведены: например, `npm install` может превратиться в `npm installer`.
* **URL ссылок и якоря.** Если слаг или `#fragment` в ссылке переведён, ссылка будет вести в никуда. Кроме того, переведённые заголовки получают новые сгенерированные ID, и все ссылки `#anchor` на них перестают работать; именно поэтому Docusaurus рекомендует задавать [явные ID заголовков](https://docusaurus.io/docs/i18n/tutorial#translate-markdown-files).
* **Frontmatter.** Ключи вроде `title` могут оказаться переведены, значения `slug` — изменены, а переведённое значение может сломать YAML. Во французском перед двоеточием ставится пробел, поэтому `title: Installer la CLI : guide rapide` — невалидный YAML (парсер `yaml` сообщает о вложенном сопоставлении). Такое значение нужно заключить в кавычки.
* **HTML-атрибуты.** Текст в `alt` и `title` нужно переводить. `class` и другие идентификаторы следует сохранять, а `src` или `href` менять только через явное сопоставление локализованных ресурсов или URL.
* **Импорты MDX и JSX.** Если `import Tabs from '@theme/Tabs'` переведён как обычное предложение или `<Tabs>` превратился в `<Onglets>`, сборка завершится с ошибкой. [Руководство Docusaurus по Crowdin](https://docusaurus.io/docs/i18n/crowdin#mdx) предупреждает, что инструменты, читающие JSX как HTML, могут выдавать невалидный JSX, причём чаще всего ломаются пропсы со значениями-объектами или массивами.
* **Блоки-предупреждения.** Docusaurus распознаёт `:::note`, `:::tip`, `:::info`, `:::warning` и `:::danger` как [ключевые слова](https://docusaurus.io/docs/markdown-features/admonitions). Переведённое `:::astuce` к ним не относится, поэтому блок-выноска отображается как обычный текст.
* **Таблицы.** Таблица GFM распознаётся, только если в строке заголовка столько же ячеек, сколько в строке-разделителе, а вертикальную черту внутри ячейки нужно экранировать как `\|` ([спецификация GFM](https://github.github.com/gfm/#tables-extension-)). Если переводчик добавит в ячейку вертикальную черту или перенос строки, строка таблицы сломается.

Ниже приведены исходный файл и пример результата, в котором встречаются все эти сбои. Пример искусственно собирает все проблемы в одном месте и не является выводом какого-то конкретного инструмента.

```mdx
---
title: Install the CLI
slug: /install
---

import Tabs from '@theme/Tabs';

## Install the CLI {/* #install */}

Run `npm install my-cli`, then read the [setup guide](/docs/setup#api-keys).

:::tip
Use <Tabs groupId="pm">a package manager</Tabs> you already have.
:::
```

```mdx
---
titre: Installer la CLI : guide rapide
slug: /installer
---

importer Tabs depuis '@theme/Tabs';

## Installer la CLI {/* #installer */}

Exécutez `npm installer my-cli`, puis lisez le [guide](/docs/configuration#cles-api).

:::astuce
Utilisez <Onglets groupId="gp">un gestionnaire de paquets</Onglets> que vous avez déjà.
:::
```

Во втором файле переведён ключ во frontmatter, YAML стал невалидным, изменился слаг, появился импорт, который MDX не может разобрать, сменился ID заголовка, сломалась команда, ссылка ведёт в никуда, а ещё в нём есть неизвестный блок-предупреждение и несуществующий компонент.

## Способы перевода Markdown и MDX

### a) Перевод документов через Google или DeepL

Перевод документов в [Google Cloud Translation](https://docs.cloud.google.com/translate/docs/supported-formats) (редакция Advanced) поддерживает файлы Word, PDF, PowerPoint и Excel, но не Markdown, а перевод текста работает с обычным текстом или HTML. В [DeepL API](https://developers.deepl.com/docs/api-reference/document) перевод документов Markdown (`.md`) указан как бета-функция, а MDX не упоминается вовсе. В любом случае проверьте результат на собственных файлах, прежде чем доверять сервису блоки кода и frontmatter.

### b) Используйте AST, чтобы отделить текст от синтаксиса

[remark](https://github.com/remarkjs/remark) преобразует Markdown в дерево [mdast](https://github.com/syntax-tree/mdast). Приведённый ниже пример извлечения обходит узлы `text`, пропуская код, атрибуты и frontmatter. Он хорошо подходит как отправная точка для анализа контента, но не является полноценным конвейером перевода:

```js
// extract.mjs: npm i unified remark-parse remark-stringify remark-mdx
//   remark-frontmatter remark-gfm remark-directive unist-util-visit
import { readFileSync } from 'node:fs';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkFrontmatter from 'remark-frontmatter';
import remarkGfm from 'remark-gfm';
import remarkMdx from 'remark-mdx';
import remarkDirective from 'remark-directive';
import remarkStringify from 'remark-stringify';
import { visit } from 'unist-util-visit';

const processor = unified()
  .use(remarkParse)
  .use(remarkFrontmatter, ['yaml']) // frontmatter становится одним узлом `yaml`
  .use(remarkGfm)                   // таблицы
  .use(remarkMdx)                   // import/export и JSX
  .use(remarkDirective)             // блоки-предупреждения :::tip
  .use(remarkStringify);

const tree = processor.parse(readFileSync(process.argv[2], 'utf8'));

// Этот пример извлекает только текстовые узлы. Отображаемый текст в атрибутах
// и frontmatter в рабочем переводчике нужно обрабатывать отдельно.
const segments = [];
visit(tree, 'text', (node) => {
  if (node.value.trim()) segments.push(node);
});

console.log(segments.map((n) => JSON.stringify(n.value)).join('\n'));

// Заглушка вместо вызова перевода: заменяем каждый сегмент на месте.
for (const node of segments) node.value = node.value.toUpperCase();
console.log('\n' + processor.stringify(tree));
```

Запущенная на приведённом выше исходном файле, к которому добавлены блок кода `bash` и таблица из двух столбцов, команда `node extract.mjs guide.mdx` вывела следующие сегменты (фрагмент):

```text
"Install the CLI "
"Run "
", then read the "
"setup guide"
"."
"Use "
"a package manager"
" you already have."
```

Повторно сериализованный файл сохранил содержимое frontmatter, импорт, ID заголовка, встроенный код, адрес ссылки, имя блока-предупреждения, атрибуты JSX и содержимое блока кода, а текстовые узлы были переведены в верхний регистр. Однако форматирование сохранилось не байт в байт. Обнаружились три ограничения:

* **Предложения приходят по частям.** «Run … then read the … setup guide» — это пять сегментов, поэтому переводчик не может переставить слова вокруг кода и ссылки. Скрипты для рабочей среды переводят абзац целиком, заменяя встроенные узлы плейсхолдерами.
* **Часть текста находится вне узлов `text`.** Текст `alt` у изображений, значения атрибутов JSX (например, проп `title`) и значения frontmatter, такие как `title`, требуют отдельной обработки.
* **Вывод переформатируется.** `remark-stringify` заново выровнял столбцы таблицы, поэтому в различии появляются строки, которые вы не меняли.

Кроме того, разбор помогает обнаружить синтаксические ошибки на раннем этапе. Из-за суффикса заголовка `{#install}` в стиле Mintlify `remark-mdx` завершался с ошибкой «Could not parse expression with acorn», поскольку в MDX фигурные скобки открывают выражение JavaScript. Docusaurus также поддерживает вариант в виде комментария `{/* #install */}`, который может проставить за вас команда `docusaurus write-heading-ids --syntax mdx-comment`.

Замена на верхний регистр показывает, какой текст выбирает парсер, но ничего не говорит о качестве перевода. Прежде чем запускать конвейер перевода, сравните защищённые поля с источником, проверьте синтаксис YAML и MDX и выполните реальную сборку сайта, чтобы выявить сломанные импорты, ссылки или компоненты, специфичные для фреймворка.

### c) Система управления переводами

Система управления переводами (TMS) разбирает файл за вас. Crowdin поддерживает [Markdown](https://store.crowdin.com/md) и [MDX](https://store.crowdin.com/mdx) «из коробки», а его [конфигурация парсера](https://support.crowdin.com/parsers-configuration/) позволяет исключать блоки кода и выбранные элементы frontmatter. По умолчанию MDX-файлы загружаются как MDX v1, а для v2 нужно указать тип `mdx_v2`. При этом вам всё равно придётся сопоставлять пути к исходным и выходным файлам, синхронизировать файлы в CI и искать обходные пути для JSX, который парсер обрабатывает некорректно.

### d) Промпт для LLM с правилами

Модель, получившая файл целиком, может учитывать контекст абзацев. Укажите поля с отображаемым текстом, которые нужно перевести: основной текст, alt-текст изображений, `title` и `description` во frontmatter, а также конкретные пропсы компонентов. Запретите изменять код, структурные ключи, импорты, имена JSX-компонентов и ключевые слова `:::`; разрешите менять URL только в соответствии с вашим сопоставлением локалей и потребуйте корректно расставлять кавычки в YAML. Соблюдение правил из промпта ничем не гарантируется, поэтому разберите результат, скомпилируйте MDX и сравните защищённое содержимое с источником.

### Сравнение

| Подход                                | Понимает структуру Markdown             | MDX и JSX                                                         | Frontmatter                             | Синхронизация переводов                                         | Ваши усилия                                                                   |
| ------------------------------------- | --------------------------------------- | ----------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Перевод документов в Google или DeepL | DeepL: `.md` в бета-версии; Google: нет | Не указано                                                        | Не проверялось; уточните                | Повторный запуск для каждого файла                              | Низкие, плюс проверка                                                         |
| Скрипт на remark                      | Да, вы сами выбираете узлы              | Да, с `remark-mdx`                                                | Обрабатываете сами                      | Отслеживание изменений пишете сами                              | Высокие                                                                       |
| TMS (Crowdin)                         | Да                                      | Встроенная поддержка с задокументированными ограничениями для JSX | Можно исключить выбранные ключи         | Синхронизация через CLI в CI                                    | Средние                                                                       |
| LLM с правилами                       | Только по инструкции                    | Только по инструкции                                              | Только по инструкции                    | Автоматизируете сами                                            | Средние, плюс проверка                                                        |
| General Translation CLI               | Специализированная обработка Markdown   | Специализированная обработка MDX                                  | Переводит заголовки и описания Mintlify | При повторных запусках повторно использует совпадающие переводы | Настроить пути к исходным файлам, проверить результат, запустить сборку сайта |

Для разового файла `.md`, который вы проверите вручную, подойдёт бета-поддержка Markdown в DeepL. Если нужен полный контроль над небольшим стабильным набором файлов, напишите скрипт на remark. Если переводчики работают в редакторе TMS, используйте TMS. Для быстрых черновиков, изменения в которых вы затем просмотрите через различия, хватит промпта для LLM. Для документации, которая меняется с каждым релизом, выбирайте General Translation: он берёт на себя генерацию и повторное использование переводов, а переведённые файлы остаются в вашем репозитории.

## Как переводить Markdown и MDX с помощью General Translation

Если файлы Markdown и MDX хранятся в часто изменяющемся репозитории, CLI от General Translation — `gt` — может переводить их при каждом запуске. Он переводит [файлы MDX и Markdown](/docs/cli/reference/formats/mdx-md-files), сохраняя их синтаксис и форматирование. Выполнив [`npx gt init`](/docs/cli/reference/commands/init) по инструкции из раздела [Быстрый старт с CLI](/docs/cli/quickstart), добавьте запись `mdx` или `md` в раздел `files` файла `gt.config.json`:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["fr", "ja"],
  "files": {
    "mdx": { "include": ["docs/[locale]/**/*.mdx"] },
    "md": { "include": ["docs/[locale]/**/*.md"] }
  }
}
```

Затем выполните [`npx gt translate`](/docs/cli/reference/commands/translate). CLI считывает исходные файлы из `docs/en/` и записывает переводы в `docs/fr/` и `docs/ja/`. Для документации важно учитывать несколько моментов:

* **ID заголовков.** Суффиксы `{#id}` в стиле Mintlify остаются привязанными к своим заголовкам (`gt` версии 2.17.3 или новее).
* **Frontmatter.** Для сайтов на Mintlify заголовки и описания во frontmatter тоже переводятся.
* **Инкрементальные запуски.** Совпадающие переводы из предыдущих запусков используются повторно, а переводится и оплачивается только новый или изменённый контент. Флаг `--force` заново переводит всё и перезаписывает локальные изменения.
* **Ручные правки.** Обратная синхронизация правок требует явного включения: используйте [`npx gt translate --save-local`](/docs/cli/reference/commands/translate) или [`npx gt save-local`](/docs/cli/reference/commands/save-local).
* **Ссылки и импорты.** Перезапись URL, импортов и путей к ресурсам для каждой локали — экспериментальная функция, которая включается флагами, например `--experimental-localize-static-urls`.

Запускайте команду [в CI](/docs/cli/guides/generating-translations) перед сборкой, храните продуктовые термины в [Glossary](/docs/platform/dashboard/guides/defining-context-for-translations), общем с приложением, и проверяйте формулировки в [редакторе панели управления](/docs/platform/dashboard/guides/reviewing-translations). Перед публикацией выполните сборку и проверку ссылок для каждой локали. (Подробнее о преимуществах и недостатках см. в статьях [General Translation vs. Google Translate](/kb/general-translation-vs-google-translate) и [General Translation vs. Crowdin](/kb/general-translation-vs-crowdin).)

## Основные выводы

* Переводите предложения целиком, а также выбранные поля с отображаемым текстом, включая alt-текст, значения frontmatter и соответствующие пропсы. Сохраняйте технический синтаксис и идентификаторы; изменяйте URL только через настроенное сопоставление.
* Французская пунктуация `" : "` может сломать YAML frontmatter без кавычек, а суффиксы заголовков `{#id}` приводят к ошибке в обычном парсере MDX.
* Сервис перевода документов Google не принимает Markdown; DeepL поддерживает `.md` в бета-режиме, а MDX в списке форматов вообще нет.
* Демонстрация с remark показывает текстовые узлы, но полноценный конвейер должен сохранять контекст предложений и обрабатывать отображаемый текст за пределами этих узлов.
* CLI General Translation переводит файлы `md` и `mdx` с сохранением синтаксиса и при последующих запусках повторно использует совпадающие переводы.

## Related questions

- [Как перевести JSON-файлы i18n?](https://generaltranslation.com/ru/kb/translate-json-files.mdx): Переводите только строковые значения в JSON-файле локали. Ключи, не связанные с множественным числом, заполнители вроде {{name}} и теги оставляйте без изменений, но учтите, что ключи для форм множественного числа зависят от языка: например, для польского нужны inbox_few и inbox_many. Используйте инструмент или API с поддержкой формата, а затем разберите и проверьте результат перед вычиткой.
- [Как сделать сайт многоязычным?](https://generaltranslation.com/ru/kb/make-website-multilingual.mdx): Выберите, где будут храниться переводы — в прокси, плагине CMS, конструкторе сайтов или в вашем собственном коде, — а затем выделите каждому языку собственный URL, как рекомендует Google. Переводите страницы целиком, включая заголовки и метаописания, связывайте языковые версии с помощью hreflang и предлагайте переключатель языка вместо автоматического перенаправления посетителей.
- [Альтернативы Google Translate: General Translation и Google Translate](https://generaltranslation.com/ru/kb/general-translation-vs-google-translate.mdx): Google Translate — быстрый способ перевести разовый текст, но чтобы выпустить продукт на другом языке, нужно переводить каждую строку с учётом контекста, соблюдать единую терминологию, правильно обрабатывать переменные и формы множественного числа, проводить ревью и выстроить процесс релизов. General Translation понимает контекст каждой строки в вашем коде и автоматизирует весь рабочий процесс локализации — от кода до ревью и каждого релиза.
- [Альтернативы Crowdin: General Translation или Crowdin](https://generaltranslation.com/ru/kb/general-translation-vs-crowdin.mdx): Выбирайте General Translation, если хотите хранить тексты прямо в компонентах и создавать переводы во время сборки. Crowdin управляет проектами перевода, выстроенными вокруг файлов ресурсов, переводчиков и процессов проверки, — инженерам приходится подключать всё это к приложению и поддерживать по мере развития продукта. При этом Crowdin по-прежнему хорошо подходит для перевода силами open-source-сообщества и для программ, которые ведут подрядчики.

## Previous and next questions

- Previous question: [Как перевести JSON-файлы i18n?](https://generaltranslation.com/ru/kb/translate-json-files.mdx)
- Next question: [Как перевести субтитры SRT, не нарушив тайминг?](https://generaltranslation.com/ru/kb/translate-srt-subtitles.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ru/kb/sitemap.md) for every article.
