ローカライズ/翻訳された投稿コンテンツでは、アフィリエイトリンクの書き換え(および post_process_cooked フック)がスキップされます

まとめ

コンテンツローカライズが有効な場合、アフィリエイトプラグインのAmazonタグ(およびより一般的に、post_process_cooked イベントを通じて処理済みHTMLを書き換えるすべてのプラグイン)は、投稿の元の処理済みHTMLには適用されますが、翻訳された PostLocalization の処理済みHTMLには適用されません。そのため、翻訳されたロケールで投稿を表示する読者は、タグ付けされていない生のリンクを見てしまい、翻訳されたインプレッションごとにアフィリエイト手数料が失われることになります。

根本的な原因は、翻訳されたコンテンツが別の独立したプロセッサ(LocalizedCookedPostProcessor)によって処理され、post_process_cooked イベントが決してトリガーされないことです。

環境

  • Discourse: コア main @ 978e9b2e5dc (2026-07-15); 2026.7.0 ライン @ 7c06c1528 (2026-07-10) でも確認済み。両者の間に関連する変更はありません。
  • プラグイン: discourse-affiliate(コアの plugins/ ディレクトリに同梱)、affiliate_amazon_de(または任意の affiliate_amazon_*)が有効なタグに設定されています。
  • 設定: content_localization_enabled = truecontent_localization_supported_locales に投稿の元のロケール以外の少なくとも1つのロケールが含まれています。
  • 範囲: サーバー側(投稿の処理)。デバイス/OS/ブラウザに依存せず、フロントエンドではなく処理パイプライン内で発生するため、セーフモードやテーマなしでも再現します。

再現手順

  1. content_localization_enabled を有効化し、2つ目のサポート対象ロケールを追加します(例:元の投稿を de で、en に翻訳)。
  2. discourse-affiliate を設定します:関連するマーケットプレイスのAmazonタグを設定します(例:affiliate_amazon_de = mytag-21)。
  3. Amazon製品リンクを含む生データを有する投稿を作成します。例:https://www.amazon.de/-/en/…/dp/B0C3WGSSWC
  4. 投稿を元のロケールで表示し、Amazonアンカーの href を確認します。
  5. 同じ投稿の翻訳されたバージョンを生成/提供します(言語切り替え器を使用するか、翻訳が作成されるのを待ち)、同じアンカーの href を確認します。

実際の結果

  • 元の処理済み: …/dp/B0C3WGSSWC?tag=mytag-21 — アフィリエイトタグが存在します。:white_check_mark:
  • PostLocalization 処理済み(翻訳): …/dp/B0C3WGSSWCtag がなく、アフィリエイト書き換えが一切行われていません。:cross_mark:

(DBで直接確認済み:影響を受けた投稿では、posts.cooked にタグ付きURLが含まれていますが、その投稿のすべての post_localizations.cooked 行にはタグなしのURLが含まれています。)

期待される結果

翻訳された処理済みHTMLには元のものと同じリンク書き換えが適用され、読者が表示できるすべてのロケールでアフィリエイトタグ(およびその他の post_process_cooked 変換)が存在すること。

根本原因

アフィリエイトプラグインは post_process_cooked イベント内でのみリンクを書き換えます:

# plugins/discourse-affiliate/plugin.rb
on(:post_process_cooked) do |doc, post|
  doc.css("a[href]").each { |a| a["href"] = AffiliateProcessor.apply(a["href"]) }
  true
end

このイベントは、元の言語の処理から1箇所のみでトリガーされます:

# lib/cooked_post_processor.rb:50
DiscourseEvent.trigger(:post_process_cooked, @doc, @post)

一方、翻訳されたコンテンツは PostLocalizationCreator/PostLocalizationUpdater から Jobs::ProcessLocalizedCooked としてキューに入れられた別のプロセッサによって処理されます:

# lib/localized_cooked_post_processor.rb
def post_process
  post_process_oneboxes
  post_process_images
  @post_localization.link_post_uploads(fragments: @doc)
end

LocalizedCookedPostProcessor#post_processpost_process_cooked をトリガーせず、ローカライズの処理パスにはどこにも DiscourseEvent.trigger が存在しません — そのため、そのイベントに依存するプラグインは翻訳されたコンテンツに関与しません。これは一般的なギャップであり、現在アフィリエイトタグ付けに影響していますが、同様に post_process_cooked を通じて処理済みHTMLを操作するすべてのプラグイン(リンクデコレーター、バッジ/メンション書き換えなど)にも影響します。

提案される修正

ローカライズされた処理が、元の処理と同じリンク/DOM書き換えに参加するようにします。以下のいずれかのオプションで解決できます:

  1. ローカライズされたプロセッサからフック可能なイベントを発行するLocalizedCookedPostProcessor#post_process 内で post_process_cooked(または専用の post_process_localized_cooked)をトリガーし、既存のプラグインがプラグイン個別の変更なしに翻訳で動作するようにします。(二重処理の副作用を避けるために新しいイベントを優先する場合、プラグインはオプトインできます。)
  2. ローカライズされたパスでアフィリエイト書き換えを実行する — 例:ワンボックス/画像パスの後に、LocalizedCookedPostProcessor#post_process@doc.css("a[href]") に対して AffiliateProcessor.apply を再利用します。

オプション1はより一般的な修正です。同じギャップがアフィリエイトだけでなく、すべての post_process_cooked 消費者に影響するためです。

追加の注記

  • すでに影響を受けた翻訳を持つサイトは、修正後に既存の PostLocalization 行を再処理する必要があります(例:recook: trueJobs::ProcessLocalizedCooked を再キューイングし、すでに翻訳された投稿にタグをバックフィル)。
  • アフィリエイト対象のリンクを含む投稿が翻訳されたロケールで提供されるたびに、一貫して再現します(断続的ではありません)。