Перейти к содержанию

Изменение оригинала и устаревший перевод

Оригинал статьи «Постоянные адреса» обновился: мы добавили объяснение серверного перенаправления. Английская версия пока описывает старое состояние. Обе страницы существуют и доступны, но их содержание уже не полностью согласовано. Наличие ссылки в переключателе и правильного hreflang не обнаруживает такую проблему.

Введём редакционный договор ревизий. Он позволит понять, от какой версии оригинала подготовлен перевод, какие материалы требуют внимания и кто должен принять решение о готовности. Это не автоматическая оценка качества перевода: номер и хеш описывают происхождение текста, а смысл проверяет человек.

Ревизия оригинала

У статьи stable-urls уже есть source_revision: 3. У каждого перевода записано translated_from: 3. Пока значения равны, перевод подготовлен на основе указанной текущей ревизии. После содержательной правки оригинала увеличим ревизию до 4, сохранив translated_from английского текста прежним.

Изменённый фрагмент articles.json выглядит так:

{
  "id": "stable-urls",
  "source_revision": 4,
  "variants": {
    "ru": {"status": "published", "translated_from": 4},
    "en": {"status": "published", "translated_from": 3}
  }
}

Это сокращённый фрагмент: title, file и url сохраняются из прежней записи. Мы не меняем адреса и не создаём статью с ID stable-urls-v4. Версия содержания и идентичность документа решают разные задачи. В противном случае каждая правка породила бы новый публичный URL и усложнила внешние ссылки.

Опечатку в запятой можно учитывать отдельной политикой. В учебной библиотеке увеличиваем смысловую ревизию, когда меняются объяснение, поведение примера или важное ограничение. Не следует объявлять каждый перевод устаревшим из-за изменения общей оболочки страницы, которое вообще не затронуло текст.

Отчёт об отставших версиях

Добавим самостоятельный редакционный сценарий translation_report.py. Он читает реестр, но не изменяет статусы и не публикует страницы. Основной цикл полный:

import json
from pathlib import Path

root = Path(__file__).resolve().parent
articles = json.loads((root / "articles.json").read_text(encoding="utf-8"))

for article in articles:
    current = article["source_revision"]
    for language, variant in article["variants"].items():
        if language == "ru":
            continue
        based_on = variant.get("translated_from")
        if based_on != current:
            print(f'{article["id"]}\t{language}\t'
                  f'{based_on} -> {current}\t{variant["status"]}')

Для нашего изменённого примера ожидаем строку stable-urls, язык en и переход 3 -> 4. Отчёт не утверждает, что английская статья неверна целиком. Он показывает, что её происхождение требует новой редакционной оценки. Переводчик сможет сравнить конкретную правку, вместо повторного перевода всего материала.

У черновой английской версии reading-list тоже может отсутствовать актуальная ревизия. Состояние draft и отставание — независимые свойства. Первое отвечает за возможность выдачи, второе — за согласованность происхождения. Один сложный статус вроде published-but-old-and-under-review быстро становится неудобным для фильтрации.

Хеш для обнаружения незаписанной правки

Ревизию редактор меняет явно, поэтому можно забыть увеличить число. Дополнительно сохраним SHA-256 исходного Markdown. Он обнаружит изменение файла, даже если оно не оформлено в реестре. Для вычисления используем стандартную библиотеку Python:

from hashlib import sha256

def content_digest(path):
    return sha256(path.read_bytes()).hexdigest()

Хеш сравнивает байты. Замена окончания строки или пробела тоже изменит его, поэтому он не является номером смысловой ревизии. Не пытайтесь автоматически объявить любой новый хеш новым учебным результатом. Удобнее показать редактору расхождение и предложить подтвердить характер изменения.

В полном примере рядом с реестром предусмотрен файл source-lock.json, который читатель создаст после первоначальной редакционной проверки. Мы не записываем выдуманные контрольные суммы в статью. При подготовке уроков сценарий не выполнялся; в архиве даны исходники механизма, а не свидетельство проведённой сверки.

Для переводов также полезно хранить собственный хеш принятого текста. Он помогает заметить правку уже после одобрения. Но подпись редактора, время решения и исходная ревизия должны оставаться отдельными полями: контрольная сумма не объясняет, кто проверил терминологию и код.

Публикация при частичном отставании

Не всякое отставание требует немедленного снятия страницы. Если оригинал получил дополнительный пример, старый перевод может всё ещё быть полезен. Если исправлена опасная инструкция или неверная версия API, решение другое. Такая оценка зависит от содержания, а не только от разницы чисел.

В «Параллели» отчёт создаёт задачу редактору и не меняет published автоматически. При существенном расхождении редактор может добавить видимую заметку, обновить перевод или временно перевести его в draft. Тогда общий механизм сборки уберёт публичные ссылки. Для уже опубликованного URL также нужно отдельно решить поведение сервера; простой пропуск файла не описывает нужный HTTP-ответ.

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

Передача работы следующему редактору

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

В репозитории сохраняем оригинал, перевод и изменение реестра вместе. Такой набор удобно рассматривать как одну редакционную правку. Автоматический перевод может подготовить черновик, но он не отменяет проверки смысла, ссылок и одинакового поведения примеров. Особенно важно сверять команды и имена файлов: их случайный перевод способен сделать инструкцию невыполнимой.

Одновременная работа двух редакторов

Пока переводчик обновляет английский текст с ревизии 3 на 4, автор может внести в оригинал следующую правку и создать ревизию 5. Нельзя после завершения перевода автоматически поставить текущую пятёрку только потому, что она уже находится в реестре. Переводчик работал с конкретным источником — четвёртой ревизией.

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

Система контроля версий помогает сохранить оба изменения, но сама не разрешает смысловой конфликт. Успешное объединение файлов означает отсутствие текстового конфликта, а не согласованность перевода. Решение о принятии следует записывать вместе с исходной ревизией и коротким описанием проверенной правки.

Теперь готовность языковых версий описана явно и отделена от их адресов. В следующем уроке рассмотрим интерфейс для языков с другим направлением письма и смешанные фрагменты текста, которые встречаются даже на обычной русской странице.

Оглавление серии