Локализация контента: уведомления о новых постах отправляются до сохранения перевода

Резюме

При включённой локализации контента и переводе с помощью ИИ push-уведомление о новом посте почти всегда содержит исходный текст автора, даже если получатель читает на другом языке, а перевод сохраняется через несколько секунд. Уведомление ставится в очередь в момент создания поста и ищет перевод один раз, до завершения задачи по переводу.

Сегодня были объявлены переводы для электронных писем в этом ответе (#44240). Электронные письма не подвержены этой задержке во времени, в отличие от push-уведомлений, поэтому после развёртывания этого изменения электронное письмо и push-уведомление об одном и том же посте дойдут до одного и того же участника на разных языках.

Что видит участник

Участник, у которого язык интерфейса — английский, получает push-уведомление (в браузере и на мобильном устройстве) о новой теме, написанной на французском языке. Текст уведомления на французском. При открытии уведомления пост отображается на английском.

Измерения

Сайт на release/2026.7 (2026.7.3) с включенным плагинном discourse-ai, поддерживаемые локали en, fr, de и it, перевод на gemini-3.8-flash и определение языка на gemini-3.5-flash-lite.

Для 11 переведённых постов первый перевод сохранялся через 2–3 секунды после создания поста, а последний из трёх — через 4–7 секунд. В наблюдаемом случае перевод на язык получателя сохранялся через 2 секунды после создания поста, а push-уведомление уже было отправлено с исходным текстом.

Задержку можно проверить на любом сайте с помощью:

SELECT p.id,
       p.locale AS post_locale,
       pl.locale AS translation_locale,
       ROUND(EXTRACT(EPOCH FROM (pl.created_at - p.created_at))) AS seconds_after_post
FROM posts p
JOIN post_localizations pl ON pl.post_id = p.id
WHERE p.created_at > NOW() - INTERVAL '2 days'
ORDER BY p.id, pl.created_at

Причина

  1. При событии :post_created плагин discourse-ai ставит в очередь Jobs::DetectTranslatePost (plugins/discourse-ai/lib/translation/entry_point.rb). Задача определяет язык одним вызовом модели, а затем переводит текст на каждую другую поддерживаемую локаль по очереди.
  2. PostJobsEnqueuer ставит в очередь :post_alert в тот же момент. PostAlerter.push_notification немедленно ставит в очередь Jobs::DeliverPushNotification. Задержка происходит только в том случае, если получатель был активен в течение push_notification_time_window_mins (по умолчанию 1 минута), и тогда лишь на остаток этого временного окна.
  3. DeliverPushNotification#localize_content! один раз, при выполнении задачи, ищет TopicLocalization и PostLocalization для user.effective_locale. Не найдя их, он отправляет исходный заголовок и отрывок. Ничего не ожидает и не повторяет попытку.
  4. Уведомительные электронные письма проходят через NotificationEmailer с задержкой в email_time_window_mins (по умолчанию 10 минут), поэтому к моменту формирования письма перевод уже существует.

app/jobs/regular/deliver_push_notification.rb идентичен в v2026.7.3 и в main на b5548f76 (2026-10-05).

Запрос

  1. Удерживать push-уведомление о новом посте до сохранения его перевода. Один из вариантов: когда локализация контента включена, а у поста ещё нет определённой локали, или нет локализации для локали получателя, хотя она ожидается, переставить DeliverPushNotification в очередь один раз после короткой задержки, а затем отправить то, что доступно. Несколько секунд покроют случаи, измеренные выше.
  2. Выбирать контент по общему правилу. Задача push-уведомлений выполняет собственный поиск по effective_locale. Изменение для электронной почты в #44240 проходит через ContentLocalization.show_translated_post? и сравнивает post_version. Использование того же пути для push-уведомлений позволит учитывать automatically_translate и understood_languages, пропускать устаревшие переводы и сохранять согласованность с электронными письмами и отображением темы.
  3. Применить то же самое к живым уведомлениям. Полезная нагрузка, публикуемая в /notification-alert/:user_id в PostAlerter.create_notification_alert, содержит исходный заголовок и отрывок. Модификатор post_alerter_live_notification_payload существует, но ядро не локализует полезную нагрузку.

Связанные материалы

2 лайка