Hello,
When using content Localization with Discourse AI translations and Cloudflare R2 as S3-compatible storage, the translated post content stores the raw R2 bucket endpoint URL instead of the configured s3_cdn_url (custom domain). Images render broken for all users viewing translations.
Environment
- Discourse: latest
- Cloudflare R2 configured via S3 compatible storage
s3_cdn_url:https://files.mydomain.coms3_use_cdn_url_for_all_uploads: enabled- Content Localization + Discourse AI translation: enabled
Steps to Reproduce
- Configure Cloudflare R2 with a custom domain (
s3_cdn_url) - Enable Content Localization and AI translation
- Create a post with an image
- Wait for the AI translation to generate the localized version
- Switch language — images in the translated version are broken
Observed behavior
The translated content contains URLs like:
//files.myendpoint.r2.cloudflarestorage.com/original/1X/ instead of https://files.mydomain.com/original/1X/
Related bug: Chat thumbnails bypass s3_cdn_url & use raw S3 bucket URLs
a temporary fix is to do a remap or use this tc:
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("1.8.0", (api) => {
const badDomain = "files.myendpoint.r2.cloudflarestorage.com";
const goodDomain = "files.mydomain.com";
function fixImages() {
document.querySelectorAll(`img[src*="${badDomain}"]`).forEach(img => {
img.src = img.src.replace(badDomain, goodDomain);
});
document.querySelectorAll(`img[data-src*="${badDomain}"]`).forEach(img => {
img.dataset.src = img.dataset.src.replace(badDomain, goodDomain);
});
document.querySelectorAll(`img[data-large-src*="${badDomain}"]`).forEach(img => {
img.dataset.largeSrc = img.dataset.largeSrc.replace(badDomain, goodDomain);
});
}
api.decorateCooked(() => fixImages(), { id: "fix-r2-translated-images" });
api.onPageChange(() => fixImages());
});