摘要
当启用内容本地化时,联盟插件的 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/目录中),并设置了有效的 Amazon 标签(如affiliate_amazon_de或任何affiliate_amazon_*)。 - 设置:
content_localization_enabled = true,content_localization_supported_locales至少包含一个不同于帖子原始语言的语言环境。 - 范围: 服务器端(帖子烘焙)。与设备/操作系统/浏览器无关;在安全模式下且无主题时也能复现,因为它发生在烹饪管道中,而非前端。
复现步骤
- 启用
content_localization_enabled并添加第二个支持的语言环境(例如,原始帖子为de,翻译为en)。 - 配置
discourse-affiliate:为相关市场设置 Amazon 标签(例如affiliate_amazon_de = mytag-21)。 - 创建一个原始内容包含 Amazon 产品链接的帖子,例如
https://www.amazon.de/-/en/…/dp/B0C3WGSSWC。 - 以原始语言环境查看该帖子,并检查 Amazon 锚点的
href。 - 生成/提供同一帖子的翻译版本(通过语言切换器,或等待翻译创建),并检查相同锚点的
href。
实际结果
- 原始已处理内容:
…/dp/B0C3WGSSWC?tag=mytag-21— 包含联盟标签。
PostLocalization已处理内容(翻译):…/dp/B0C3WGSSWC— 无tag,完全未进行联盟重写。
(直接在数据库中确认:对于受影响的帖子,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
该事件仅从原始语言烹饪的一个位置触发:
# 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_process 从未触发 post_process_cooked,并且在本地化烘焙路径中没有任何地方存在 DiscourseEvent.trigger — 因此任何依赖该事件的插件都不参与翻译内容。这是一个普遍存在的缺陷:目前影响联盟标记,但同样影响任何通过 post_process_cooked 修改已处理 HTML 的插件(链接装饰器、徽章/提及重写等)。
建议的修复方案
让本地化烘焙参与与原始烹饪相同的链接/DOM 重写。以下任一选项均可解决此问题:
- 从本地化处理器发出可挂钩的事件 — 在
LocalizedCookedPostProcessor#post_process内部触发post_process_cooked(或专用的post_process_localized_cooked),以便现有插件无需针对每个插件进行修改即可在翻译上工作。(如果为了双重处理副作用而首选新事件,插件可以选择加入。) - 在本地化路径中运行联盟重写,例如在
LocalizedCookedPostProcessor#post_process中,在 onebox/图片处理之后,对@doc.css("a[href]")重用AffiliateProcessor.apply。
选项 1 是更通用的修复方案,因为同样的缺陷影响每一个 post_process_cooked 消费者,而不仅仅是联盟插件。
补充说明
- 已经拥有受影响翻译的网站需要在修复后重新烘焙现有的
PostLocalization行(例如,重新入队Jobs::ProcessLocalizedCooked并设置recook: true),以便将标签回填到已翻译的帖子中。 - 只要以翻译语言环境提供包含联盟资格链接的帖子,该问题就会一致复现(非间歇性)。