La reescritura de enlaces de afiliados (y cualquier hook post_process_cooked) se omite para el contenido de publicaciones localizado/traducido

Resumen

Cuando la localización de contenido está habilitada, la etiqueta de Amazon del plugin de afiliados (y, en general, cualquier plugin que reescriba HTML procesado mediante el evento post_process_cooked) se aplica al HTML procesado original de una publicación, pero no a su HTML procesado PostLocalization traducido. Por lo tanto, los lectores que ven una publicación en un idioma traducido observan el enlace sin procesar y sin etiqueta, lo que significa que se pierde la comisión de afiliado en cada visualización traducida.

La causa raíz es que el contenido traducido se procesa a través de un segundo procesador separado (LocalizedCookedPostProcessor) que nunca activa el evento post_process_cooked.

Entorno

  • Discourse: rama principal main @ 978e9b2e5dc (2026-07-15); también confirmado en la rama 2026.7.0 @ 7c06c1528 (2026-07-10). No hay cambios relevantes entre ambas.
  • Plugin: discourse-affiliate (incluido en el directorio plugins/ del núcleo), con affiliate_amazon_de (o cualquier affiliate_amazon_*) configurado con una etiqueta válida.
  • Configuración: content_localization_enabled = true, content_localization_supported_locales incluye al menos un idioma diferente al original de la publicación.
  • Alcance: lado del servidor (procesamiento de publicaciones). Independiente del dispositivo/SO/navegador; se reproduce en Modo Seguro y sin temas, ya que ocurre en la pipeline de procesamiento, no en el front end.

Pasos para reproducir

  1. Habilita content_localization_enabled y añade un segundo idioma compatible (por ejemplo, publicaciones originales en de, traducción a en).
  2. Configura discourse-affiliate: establece la etiqueta de Amazon para el mercado relevante (por ejemplo, affiliate_amazon_de = mytag-21).
  3. Crea una publicación cuyo contenido sin procesar contenga un enlace de producto de Amazon, por ejemplo, https://www.amazon.de/-/en/…/dp/B0C3WGSSWC.
  4. Visualiza la publicación en su idioma original e inspecciona el atributo href del enlace de Amazon.
  5. Genera/sirve la versión traducida de la misma publicación (mediante el selector de idioma, o dejando que se cree la traducción) e inspecciona el atributo href del mismo enlace.

Resultado actual

  • HTML procesado original: …/dp/B0C3WGSSWC?tag=mytag-21 — etiqueta de afiliado presente. :white_check_mark:
  • HTML procesado PostLocalization (traducido): …/dp/B0C3WGSSWC — sin tag, sin reescritura de afiliado en absoluto. :cross_mark:

(Confirmado directamente en la base de datos: para una publicación afectada, posts.cooked contiene la URL con etiqueta, mientras que cada fila post_localizations.cooked para esa publicación contiene la URL sin etiqueta.)

Resultado esperado

El HTML procesado traducido debería recibir la misma reescritura de enlaces que el original, de modo que la etiqueta de afiliado (y cualquier otra transformación de post_process_cooked) esté presente en cada idioma que pueda ver un lector.

Causa raíz

El plugin de afiliados reescribe enlaces únicamente dentro del evento 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

Dicho evento se activa desde un único lugar, el procesamiento del idioma original:

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

Sin embargo, el contenido traducido se procesa mediante un procesador diferente, encolado desde PostLocalizationCreator/PostLocalizationUpdater como 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 nunca activa post_process_cooked, y no hay ningún DiscourseEvent.trigger en ninguna parte de la ruta de procesamiento de localización; por lo tanto, ningún plugin que dependa de ese evento participa en el contenido traducido. Esta es una brecha general: afecta a la etiquetado de afiliados hoy, pero también a cualquier plugin que modifique HTML procesado a través de post_process_cooked (decoradores de enlaces, reescritura de insignias/menciones, etc.).

Corrección sugerida

Hacer que el procesamiento de localización participe en la misma reescritura de enlaces/DOM que el procesamiento original. Cualquiera de las siguientes opciones lo resuelve:

  1. Emitir un evento accionable desde el procesador de localización — activar post_process_cooked (o un post_process_localized_cooked dedicado) dentro de LocalizedCookedPostProcessor#post_process, para que los plugins existentes funcionen en traducciones sin cambios específicos por plugin. (Si se prefiere un nuevo evento para evitar efectos secundarios de procesamiento doble, los plugins pueden optar por incorporarse.)
  2. Ejecutar la reescritura de afiliados en la ruta de localización, por ejemplo, reutilizar AffiliateProcessor.apply sobre @doc.css("a[href]") en LocalizedCookedPostProcessor#post_process después de los pasos de onebox/imágenes.

La opción 1 es la corrección más general, ya que la misma brecha afecta a cada consumidor de post_process_cooked, no solo a afiliados.

Notas adicionales

  • Un sitio que ya tenga traducciones afectadas necesitará reprocesar las filas existentes de PostLocalization después de la corrección (por ejemplo, reencolar Jobs::ProcessLocalizedCooked con recook: true) para rellenar etiquetas en publicaciones ya traducidas.
  • Se reproduce de manera consistente (no intermitente) siempre que se sirva una publicación con un enlace elegible para afiliado en un idioma traducido.