From a340ea4f755c83b4fa39a9503f691580555be670 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Fri, 11 Jul 2025 19:42:11 -0400 Subject: [PATCH] convert all relative URLs to absolute URLs in remote translations --- src/translate-modal.js | 48 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/translate-modal.js b/src/translate-modal.js index a126763..808db77 100644 --- a/src/translate-modal.js +++ b/src/translate-modal.js @@ -82,10 +82,52 @@ async function translateRemoteHTML(htmlContent, targetLanguage, sourceUrl) { doc.documentElement.innerHTML = translatedContent; } - // Add base tag for proper resource resolution (like translateCurrentPage does) - const baseUrl = new URL('.', sourceUrl).href; // Get base URL (without filename) + // Convert all relative URLs to absolute URLs + const baseUrl = new URL('.', sourceUrl).href; - // Remove any existing base tag + // Convert relative URLs in img src attributes + doc.querySelectorAll('img[src]').forEach(img => { + if (!img.src.startsWith('http') && !img.src.startsWith('//') && !img.src.startsWith('data:')) { + img.src = new URL(img.getAttribute('src'), sourceUrl).href; + } + }); + + // Convert relative URLs in link href attributes (CSS, etc.) + doc.querySelectorAll('link[href]').forEach(link => { + if (!link.href.startsWith('http') && !link.href.startsWith('//')) { + link.href = new URL(link.getAttribute('href'), sourceUrl).href; + } + }); + + // Convert relative URLs in script src attributes + doc.querySelectorAll('script[src]').forEach(script => { + if (!script.src.startsWith('http') && !script.src.startsWith('//')) { + script.src = new URL(script.getAttribute('src'), sourceUrl).href; + } + }); + + // Convert relative URLs in a href attributes + doc.querySelectorAll('a[href]').forEach(link => { + if (!link.href.startsWith('http') && !link.href.startsWith('//') && !link.href.startsWith('#') && !link.href.startsWith('mailto:') && !link.href.startsWith('tel:')) { + link.href = new URL(link.getAttribute('href'), sourceUrl).href; + } + }); + + // Convert background images in style attributes + doc.querySelectorAll('[style*="background"]').forEach(el => { + const style = el.getAttribute('style'); + if (style && style.includes('url(')) { + const updatedStyle = style.replace(/url\(['"]?([^'"]+)['"]?\)/g, (match, url) => { + if (!url.startsWith('http') && !url.startsWith('//') && !url.startsWith('data:')) { + return `url('${new URL(url, sourceUrl).href}')`; + } + return match; + }); + el.setAttribute('style', updatedStyle); + } + }); + + // Add base tag as fallback for any missed URLs const existingBase = doc.querySelector('base'); if (existingBase) { existingBase.remove();