Резюме
Когда включена локализация контента, партнерский тег Amazon плагина (и, в более общем смысле, любой плагин, который переписывает готовый HTML через событие post_process_cooked) применяется к исходному готовому HTML поста, но не к его переведенному готовому HTML PostLocalization. Поэтому читатели, просматривающие пост в переведенной локали, видят «сырую» ссылку без тега, что приводит к потере партнерского вознаграждения при каждом просмотре переведенной версии.
Корень проблемы заключается в том, что переведенный контент обрабатывается вторым, отдельным процессором (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 = true,content_localization_supported_localesвключает хотя бы одну локаль, отличную от исходной. - Область: серверная часть (обработка поста). Независимо от устройства/ОС/браузера; воспроизводится в Safe Mode и без тем, поскольку происходит в конвейере обработки, а не на стороне клиента.
Шаги для воспроизведения
- Включите
content_localization_enabledи добавьте вторую поддерживаемую локаль (например, исходные посты наde, перевод наen). - Настройте
discourse-affiliate: установите тег Amazon для соответствующего маркетплейса (например,affiliate_amazon_de = mytag-21). - Создайте пост, исходный текст которого содержит ссылку на товар Amazon, например
https://www.amazon.de/-/en/…/dp/B0C3WGSSWC. - Просмотрите пост в его исходной локали и проверьте атрибут
hrefякоря Amazon. - Сгенерируйте/отобразите переведенную версию того же поста (через переключатель языка или путем создания перевода) и проверьте атрибут
hrefтого же якоря.
Фактический результат
- Исходный готовый HTML:
…/dp/B0C3WGSSWC?tag=mytag-21— партнерский тег присутствует.
- Готовый HTML
PostLocalization(переведенный):…/dp/B0C3WGSSWC— нетtag, вообще нет переписывания ссылок.
(Подтверждено напрямую в БД: для затронутого поста поле posts.cooked содержит URL с тегом, тогда как каждая строка post_localizations.cooked для этого поста содержит «голый» URL.)
Ожидаемый результат
Переведенный готовый HTML должен получать то же самое переписывание ссылок, что и исходный, чтобы партнерский тег (и любые другие преобразования post_process_cooked) присутствовал в каждой локали, доступной для чтения.
Корень проблемы
Плагин affiliate переписывает ссылки только внутри события 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 в пути локализации — поэтому ни один плагин, зависящий от этого события, не участвует в обработке переведенного контента. Это общая проблема: сегодня она затрагивает партнерские теги, но в равной степени влияет на любой плагин, который изменяет готовый HTML через post_process_cooked (декораторы ссылок, переписывание значков/упоминаний и т.д.).
Предлагаемое решение
Заставьте локализацию участвовать в том же переписывании ссылок/DOM, что и исходная обработка. Любой из вариантов решает проблему:
- Генерация хукаемого события из локализационного процессора — вызовите
post_process_cooked(или выделенноеpost_process_localized_cooked) внутриLocalizedCookedPostProcessor#post_process, чтобы существующие плагины работали с переводами без изменений в каждом плагине. (Если предпочтительнее новое событие для избежания побочных эффектов двойной обработки, плагины могут подключиться к нему.) - Запуск переписывания affiliate в пути локализации, например, повторно используйте
AffiliateProcessor.applyдля@doc.css("a[href]")вLocalizedCookedPostProcessor#post_processпосле прохода onebox/изображений.
Вариант 1 является более общим решением, поскольку та же проблема затрагивает каждого потребителя post_process_cooked, а не только affiliate.
Дополнительные примечания
- Сайтам, у которых уже есть затронутые переводы, потребуется повторная обработка существующих строк
PostLocalizationпосле исправления (например, повторная постановка в очередьJobs::ProcessLocalizedCookedс флагомrecook: true), чтобы добавить теги в уже переведенные посты. - Воспроизводится стабильно (не прерывисто) каждый раз, когда пост со ссылкой, подходящей для партнерской программы, отображается в переведенной локали.