コンテンツのローカライズ:新投稿のプッシュ通知が翻訳保存前に送信される

概要

コンテンツローカライズとAI翻訳を有効にすると、新しい投稿のプッシュ通知は、受信者が別の言語で閲覧しており、翻訳が数秒後に保存される場合であっても、ほぼ常に著者の原文を保持します。プッシュは投稿作成時にキューイングされ、翻訳ジョブが完了する前に一度だけ翻訳を検索します。

翻訳されたメールは本日、この返信(#44240)で発表されました。メールはこのタイミングの問題に晒されませんが、プッシュ通知は晒されるため、その変更がデプロイされると、同じ投稿のメールとプッシュ通知が同じメンバーに異なる言語で届くことになります。

メンバーが見るもの

インターフェース言語が英語のメンバーが、フランス語で書かれた新しいトピックのプッシュ通知を、ブラウザおよびモバイルで受信します。通知の本文はフランス語です。通知を開くと、投稿は英語で表示されます。

測定

release/2026.7(2026.7.3)のサイト、バンドルされた discourse-ai プラグイン、サポートされるロケール en、fr、de、it、翻訳は gemini-3.8-flash、言語検出は gemini-3.5-flash-lite を使用。

11件の翻訳済み投稿について、最初の翻訳は投稿作成後2〜3秒で保存され、3件中最後のものは4〜7秒後に保存されました。観察されたケースでは、受信者の言語への翻訳は投稿後2秒で保存されましたが、プッシュ通知はすでに原文とともに送信されていました。

この遅延は、以下のSQLで任意のサイトで確認できます:

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)。このジョブは1回のモデル呼び出しで言語を検出し、その後、サポートされている他の各ロケールへ順番に翻訳します。
  2. PostJobsEnqueuer は同じタイミングで :post_alert をキューイングします。PostAlerter.push_notification は即座に Jobs::DeliverPushNotification をキューイングします。これは、受信者が push_notification_time_window_mins(デフォルト1分)以内に確認した場合にのみ遅延し、その場合でもそのウィンドウの残り時間分だけです。
  3. DeliverPushNotification#localize_content! は、ジョブ実行時に user.effective_locale に対して TopicLocalization と PostLocalization を一度だけ検索します。見つからない場合、元のタイトルと抜粋を送信します。待機や再試行は行われません。
  4. 通知メールは NotificationEmailer を通じ、email_time_window_mins(デフォルト10分)の遅延があるため、メールが構築される時点で翻訳が存在します。

app/jobs/regular/deliver_push_notification.rb は、v2026.7.3 と main の b5548f76(2026-10-05)で同一です。

要望

  1. 新しい投稿のプッシュ通知を、その翻訳が保存されるまで保留する。 1つの選択肢として:コンテンツローカライズが有効で、かつ投稿にまだ検出されたロケールがない場合、または受信者のロケールへのローカライズが存在しないが期待されている場合、短い遅延後に DeliverPushNotification を一度だけ再キューイングし、その後利用可能なものを送信する。数秒の遅延で、上記で測定されたケースをカバーできます。
  2. 共有ルールでコンテンツを選択する。 プッシュジョブは effective_locale による独自の検索を行っています。#44240 のメール変更は ContentLocalization.show_translated_post? を通じ、post_version を比較します。プッシュにも同じパスを使用することで、automatically_translate と understood_languages を尊重し、古い翻訳をスキップし、メールおよびトピックビューと整合性を保つことができます。
  3. ライブアラートにも同じことを適用する。 PostAlerter.create_notification_alert で /notification-alert/:user_id に公開されるペイロードには、元のタイトルと抜粋が含まれています。モディファイア post_alerter_live_notification_payload は存在しますが、コアではペイロードがローカライズされていません。

関連項目

「いいね!」 2