Резюме
При включённой локализации контента и переводе с помощью ИИ 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
Причина
- При событии
:post_createdплагин discourse-ai ставит в очередьJobs::DetectTranslatePost(plugins/discourse-ai/lib/translation/entry_point.rb). Задача определяет язык одним вызовом модели, а затем переводит текст на каждую другую поддерживаемую локаль по очереди. PostJobsEnqueuerставит в очередь:post_alertв тот же момент.PostAlerter.push_notificationнемедленно ставит в очередьJobs::DeliverPushNotification. Задержка происходит только в том случае, если получатель был активен в течениеpush_notification_time_window_mins(по умолчанию 1 минута), и тогда лишь на остаток этого временного окна.DeliverPushNotification#localize_content!один раз, при выполнении задачи, ищетTopicLocalizationиPostLocalizationдляuser.effective_locale. Не найдя их, он отправляет исходный заголовок и отрывок. Ничего не ожидает и не повторяет попытку.- Уведомительные электронные письма проходят через
NotificationEmailerс задержкой вemail_time_window_mins(по умолчанию 10 минут), поэтому к моменту формирования письма перевод уже существует.
app/jobs/regular/deliver_push_notification.rb идентичен в v2026.7.3 и в main на b5548f76 (2026-10-05).
Запрос
- Удерживать push-уведомление о новом посте до сохранения его перевода. Один из вариантов: когда локализация контента включена, а у поста ещё нет определённой локали, или нет локализации для локали получателя, хотя она ожидается, переставить
DeliverPushNotificationв очередь один раз после короткой задержки, а затем отправить то, что доступно. Несколько секунд покроют случаи, измеренные выше. - Выбирать контент по общему правилу. Задача push-уведомлений выполняет собственный поиск по
effective_locale. Изменение для электронной почты в #44240 проходит черезContentLocalization.show_translated_post?и сравниваетpost_version. Использование того же пути для push-уведомлений позволит учитыватьautomatically_translateиunderstood_languages, пропускать устаревшие переводы и сохранять согласованность с электронными письмами и отображением темы. - Применить то же самое к живым уведомлениям. Полезная нагрузка, публикуемая в
/notification-alert/:user_idвPostAlerter.create_notification_alert, содержит исходный заголовок и отрывок. Модификаторpost_alerter_live_notification_payloadсуществует, но ядро не локализует полезную нагрузку.