ВозможностиПлагинЦеныРесурсы
Изменить язык
РесурсыИспользование msgctxt: Добавление контекста к переводам Gettext

Использование msgctxt: Добавление контекста к переводам Gettext

SimplePoTranslate Team15 мая 2026 г.
Использование msgctxt: Добавление контекста к переводам Gettext

Вы переводите английское слово «Book» на немецкий, и ваш переводчик уверенно выдает «Buch». Три недели спустя поступает сообщение об ошибке: кнопка «Book a table» на вашей форме бронирования теперь гласит «Buch a table» — существительное, а не глагол. Слово было правильным. Контекст отсутствовал. Это одна из наиболее распространенных скрытых проблем в локализации программного обеспечения, и решение для нее существует в Gettext десятилетиями: msgctxt.

Если вы когда-либо выпускали перевод, где одна и та же английская строка была правильной в одном месте и бессмысленной в другом, вы столкнулись с проблемой неоднозначности. Одно и то же исходное слово соответствует разным переводам в зависимости от того, где оно появляется. Без msgctxt переводчик (человек или ИИ) не может различить эти случаи, потому что все, что он видит, это простую строку msgid "Book". Это руководство объясняет, как msgctxt работает в Gettext, как размечать ваш исходный код с помощью _x() и _ex(), как он отображается в ваших файлах .po, и почему контентно-ориентированный конвейер перевода является единственным надежным способом правильно переводить эти строки в больших масштабах.

Проблема неоднозначности: одно слово, много значений

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

Слова, распадающиеся на разные языки

Рассмотрим три классических примера:

  • «Book» — существительное (объект на полке) против глагола («Book a flight»). Немецкий: Buch против buchen.
  • «Post» — публиковать контент против отправлять почту. Французский: publier против courrier.
  • «Order» — последовательность/сортировка против покупки. Испанский: orden против pedido.

В английском ваш код использует одну и ту же буквальную строку в обоих местах:

// Somewhere in a library catalog screen
echo __( 'Book', 'mytextdomain' );

// Somewhere in a reservation form button
echo __( 'Book', 'mytextdomain' );

Как идентичные строки сводятся к одной записи

Когда вы запускаете wp i18n make-pot или xgettext, оба вызова сводятся к одной записи .po:

#: catalog.php:42 reservation-form.php:88
msgid "Book"
msgstr ""

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

Что такое msgctxt и как он устраняет неоднозначность?

msgctxt — это контекстная строка, прикрепленная к записи перевода. Краткий ответ: она добавляет второй ключ к msgid, поэтому Gettext рассматривает (context, msgid) как уникальную пару. Две записи с одинаковым msgid, но разными msgctxt становятся двумя отдельными, независимо переводимыми строками.

В модели поиска Gettext перевод обычно индексируется только исходной строкой. С msgctxt ключ становится комбинацией контекста и источника. Это весь механизм, и именно поэтому он работает так чисто: вы не меняете отображаемый текст, а только внутренний ключ поиска.

Строка msgctxt в файле .po

В файле .po контекст появляется на отдельной строке непосредственно над msgid:

#: catalog.php:42
msgctxt "noun"
msgid "Book"
msgstr "Buch"

#: reservation-form.php:88
msgctxt "verb"
msgid "Book"
msgstr "Reservieren"

Теперь есть две записи. У них одинаковые значения msgid, но разные значения msgctxt, поэтому каждая получает свою собственную msgstr. Каталог отображает Buch; кнопка бронирования отображает Reservieren. Среда выполнения выбирает правильную, потому что ваш код указал, какой контекст использовать.

Сравните это с неработающей версией с одной записью выше. Разница не в качестве перевода — а в том, позволяет ли модель данных вообще существовать правильному ответу.

Разметка кода: _x() и _ex()

Чтобы вывести msgctxt в ваш шаблон .po, вы вызываете функцию перевода, учитывающую контекст, вместо обычной. В WordPress это _x() и его дублирующий аналог _ex(); в чистом Gettext они соответствуют pgettext().

Выбор между _x() и _ex()

Обычная функция __() принимает строку и текстовый домен. Вариант с контекстом вставляет контекст в качестве второго аргумента:

// Without context - ambiguous
__( 'Book', 'mytextdomain' );

// With context - the second argument is the msgctxt
_x( 'Book', 'noun', 'mytextdomain' );        // returns the translated string
_ex( 'Book', 'verb', 'mytextdomain' );       // echoes it directly

// Real-world disambiguation
_x( 'Post', 'verb: publish content', 'mytextdomain' );
_x( 'Post', 'noun: mail item', 'mytextdomain' );
_x( 'Order', 'sequence or sorting', 'mytextdomain' );
_x( 'Order', 'customer purchase', 'mytextdomain' );

Второй аргумент — это метка контекста. Она никогда не показывается вашим пользователям — она существует исключительно для устранения неоднозначности, как для поиска Gettext, так и для того, кто (или что) выполняет перевод. Пишите контексты как короткие, описательные подсказки: 'существительное', 'глагол', 'метка кнопки', 'меню администратора'. Нечеткий контекст, такой как '1', технически допустим, но бесполезен для переводчика.

Когда вы заново генерируете шаблон, экстрактор распознает эти вызовы и выдает строку msgctxt. Такие инструменты, как Poedit и другие PO-редакторы, затем группируют записи видимым образом по контексту, так что человек-переводчик сразу видит, что «Book (существительное)» и «Book (глагол)» — это две разные задачи. Если вы все еще настраиваете свою цепочку инструментов для извлечения или боретесь с тем, как переменные взаимодействуют с этими строками, наше руководство по переводу PO-файлов без нарушения переменных кода подробно описывает окружающий рабочий процесс.

Почему наивные переводчики — и многие инструменты ИИ — ошибаются в этом

Вот неудобная часть. Добавление msgctxt в ваш исходный код необходимо, но недостаточно. Контекст помогает только в том случае, если то, что выполняет перевод, действительно его читает.

Режим отказа из-за отброшенного контекста

Наивный скрипт пакетного перевода делает следующее: он перебирает записи, берет каждую msgid, отправляет ее в API перевода и записывает результат в msgstr. Он никогда не смотрит на строку msgctxt. Таким образом, хотя вы тщательно написали _x( 'Book', 'noun' ) и _x( 'Book', 'verb' ), скрипт отправляет два идентичных запроса — «перевести Book» — и вставляет один и тот же ответ в оба. Все ваши усилия по разметке отбрасываются на последнем шаге.

Многие универсальные инструменты ИИ-перевода имеют то же самое «слепое пятно». Они созданы для перевода текста, а msgctxt — это метаданные, а не текст. Если инструмент «сплющивает» ваш .po в список строк перед отправкой модели, контекст никогда не достигает запроса модели. Модель, не имея никакого сигнала, по умолчанию использует наиболее статистически распространенное значение слова — обычно существительное для «Book», значение «публиковать» для «Post» — и молча неправильно переводит меньшинство случаев. Вы не увидите ошибки. Вы увидите отчет об ошибке от немецкого пользователя через несколько недель.

Контекст и множественное число имеют одну и ту же первопричину

Здесь же пересекаются обработка множественного числа и контекст, поскольку оба зависят от того, понимает ли инструмент структуру Gettext, а не рассматривает файл как плоский текст. Если ваши строки также включают формы, основанные на количестве, то такое же структурное понимание имеет значение — мы подробно разбираем это в понимании множественного числа Gettext.

Как конвейер, учитывающий контекст, использует msgctxt

Конвейер перевода, который учитывает msgctxt, делает противоположное наивному скрипту. Он анализирует файл .po как структурированные данные, сохраняет контекст каждой записи, прикрепленный к ее исходной строке, и передает этот контекст ИИ как часть запроса — так модель знает, что она переводит «Book» именно как глагол, а не абстрактно.

Контекст как первоклассный сигнал

Именно так SimplePoTranslate подходит к этой проблеме. Его ИИ, учитывающий контекст, считывает строку msgctxt как первоклассный сигнал: когда две записи имеют общий msgid, но отличаются по контексту, они переводятся как отдельные строки, которыми они фактически являются, а подсказка контекста влияет на выбор слова моделью. В результате «Book (существительное)» возвращается как Buch, а «Book (глагол)» — как buchen или reservieren — автоматически, без необходимости вручную исправлять каждый неоднозначный термин.

Не менее важно, что конвейер сохраняет строку msgctxt в выходных данных. Менее мощный инструмент может удалить контекст во время циклической обработки, незаметно свернув ваши две записи обратно в одну и вновь введя неоднозначность при следующем слиянии. Полная поддержка Gettext означает, что контекст сохраняется при переводе, компиляции .mo и любых последующих повторных импортах — так что ваше устранение неоднозначности является долговечным, а не одноразовой ручной правкой. В сочетании с Syntax Locking для заполнителей внутри этих строк вы получаете переводы, которые являются как контекстуально правильными, так и структурно целостными.

Вы по-прежнему принимаете решение о разметке — только вы знаете, что данное «Book» является глаголом. Но как только вы аннотировали свой исходный код с помощью _x() и _ex(), конвейер, учитывающий контекст, превращает эту аннотацию в правильные переводы на всех целевых языках без необходимости контролировать каждую строку.

Заключение

Проблема неоднозначности — одно английское слово, множество значений — это не причуда, которую можно игнорировать; это структурная особенность того, как Gettext хранит строки. Решение — msgctxt: аннотируйте неоднозначные строки в вашем источнике с помощью _x() и _ex(), дайте каждому вхождению четкую метку контекста и позвольте Gettext индексировать перевод по паре (context, msgid). Эта часть зависит от вас и занимает минуты.

Более сложная часть — убедиться, что ваш шаг перевода действительно учитывает этот контекст, а не отбрасывает его. Наивные скрипты и текстовые ИИ-инструменты игнорируют msgctxt и вновь вводят ту самую ошибку, которую вы пытались предотвратить. Конвейер, учитывающий контекст, считывает контекст, правильно переводит каждую однозначную запись и сохраняет ее при компиляции и повторном импорте.

Готовы перестать выпускать контекстно-слепые ошибочные переводы? Попробуйте SimplePoTranslate бесплатно — кредитная карта не требуется. Бесплатный тариф обрабатывает реальные файлы .po и .pot с полной поддержкой контекста msgctxt, поэтому ваши однозначные строки переводятся правильно с первого раза.

Поделиться этой статьёй