Please bookmark this page to avoid losing your image tool!

Image Translation To World Languages Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, sourceLang = "eng", targetLanguages = "ru,es,fr,zh-CN", textColor = "auto", bgColor = "auto") {
    // Create the container element that will be returned immediately
    const container = document.createElement('div');
    container.style.width = '100%';
    container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.alignItems = 'center';

    const statusDiv = document.createElement('div');
    statusDiv.style.width = '100%';
    statusDiv.style.padding = '15px';
    statusDiv.style.backgroundColor = '#f8f9fa';
    statusDiv.style.border = '1px solid #dee2e6';
    statusDiv.style.borderRadius = '5px';
    statusDiv.style.marginBottom = '15px';
    statusDiv.style.color = '#495057';
    statusDiv.style.boxSizing = 'border-box';
    statusDiv.style.textAlign = 'center';
    statusDiv.innerText = 'Initializing OCR and translation engine... please wait.';
    container.appendChild(statusDiv);

    // Run async workflow so we don't block returning the container DOM element
    (async () => {
        try {
            const langs = targetLanguages.split(',').map(s => s.trim()).filter(Boolean);
            if (langs.length === 0) langs.push("ru"); // Default to Russian if empty

            // Scale image if it's too large to prevent out-of-memory errors and speed up processing
            let imgW = originalImg.width || originalImg.naturalWidth;
            let imgH = originalImg.height || originalImg.naturalHeight;
            const maxDimension = 1200;
            if (imgW > maxDimension || imgH > maxDimension) {
                const scale = Math.min(maxDimension / imgW, maxDimension / imgH);
                imgW = Math.round(imgW * scale);
                imgH = Math.round(imgH * scale);
            }

            const ocrCanvas = document.createElement('canvas');
            ocrCanvas.width = imgW;
            ocrCanvas.height = imgH;
            const ocrCtx = ocrCanvas.getContext('2d');
            ocrCtx.drawImage(originalImg, 0, 0, imgW, imgH);

            // 1. Dynamically Load Tesseract
            statusDiv.innerText = 'Loading text recognition models...';
            if (typeof Tesseract === 'undefined') {
                const script = document.createElement('script');
                script.src = 'https://unpkg.com/tesseract.js@4.1.1/dist/tesseract.min.js';
                document.head.appendChild(script);
                await new Promise((resolve, reject) => {
                    script.onload = resolve;
                    script.onerror = reject;
                });
            }

            // 2. OCR Original Image
            statusDiv.innerText = 'Extracting text from image (this may take a few moments)...';
            
            const worker = await Tesseract.createWorker(sourceLang);
            const ret = await worker.recognize(ocrCanvas);
            await worker.terminate();
            const lines = ret.data.lines;

            if (!lines || lines.length === 0) {
                statusDiv.innerText = 'No readable text was detected in the image.';
                container.appendChild(ocrCanvas);
                return;
            }

            const imgData = ocrCtx.getImageData(0, 0, ocrCanvas.width, ocrCanvas.height);
            
            // 3. Create Final Stacked Canvas
            const headerHeight = 60;
            const outCanvas = document.createElement('canvas');
            outCanvas.width = ocrCanvas.width;
            outCanvas.height = (ocrCanvas.height + headerHeight) * langs.length;
            const outCtx = outCanvas.getContext('2d');
            
            outCanvas.style.maxWidth = '100%';
            outCanvas.style.height = 'auto';
            outCanvas.style.border = '1px solid #ccc';
            outCanvas.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';

            const langNames = {
                "ru": "Русский (Russian)", "es": "Español (Spanish)", "fr": "Français (French)", 
                "de": "Deutsch (German)", "zh-CN": "中文 (Chinese)", "ar": "العربية (Arabic)", 
                "hi": "हिन्दी (Hindi)", "ja": "日本語 (Japanese)", "pt": "Português (Portuguese)", 
                "it": "Italiano (Italian)", "ko": "한국어 (Korean)", "en": "English"
            };

            let pY = 0;

            // Render translated version per requested language
            for (let i = 0; i < langs.length; i++) {
                const lang = langs[i];
                statusDiv.innerText = `Translating to ${langNames[lang] || lang} (${i + 1}/${langs.length})...`;
                
                // Draw Target Language Banner
                outCtx.fillStyle = '#2c3e50';
                outCtx.fillRect(0, pY, outCanvas.width, headerHeight);
                outCtx.fillStyle = '#ecf0f1';
                outCtx.textBaseline = 'middle';
                outCtx.textAlign = 'center';
                
                let headerFontSize = 24;
                const headerText = `World Language: ${langNames[lang] || lang.toUpperCase()}`;
                
                outCtx.font = `bold ${headerFontSize}px sans-serif`;
                while(headerFontSize > 12 && outCtx.measureText(headerText).width > outCanvas.width - 20) {
                    headerFontSize--;
                    outCtx.font = `bold ${headerFontSize}px sans-serif`;
                }
                outCtx.fillText(headerText, outCanvas.width / 2, pY + headerHeight / 2);
                pY += headerHeight;

                // Draw Initial Frame Image
                outCtx.drawImage(ocrCanvas, 0, pY, imgW, imgH);

                // Translate & Overlay text onto the frame
                for (const line of lines) {
                    const text = line.text.trim();
                    if (!text) continue;

                    const bbox = line.bbox;
                    let translated = text;

                    // Fetch Free Google Translate
                    try {
                        const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${lang}&dt=t&q=${encodeURIComponent(text)}`;
                        const res = await fetch(url);
                        if (res.ok) {
                            const data = await res.json();
                            translated = data[0].map(item => item[0]).join("");
                        }
                    } catch (err) {
                        console.error("Translation blocked or failed:", err);
                    }

                    // Erase original text bounds with boundary average color or user selection
                    let boxBg = bgColor;
                    if (bgColor === 'auto') {
                        const margin = 2;
                        let r = 0, g = 0, b = 0, count = 0;
                        const d = imgData.data;

                        const addSample = (px, py) => {
                            px = Math.floor(px); py = Math.floor(py);
                            if (px >= 0 && px < imgW && py >= 0 && py < imgH) {
                                const i = (py * imgW + px) * 4;
                                r += d[i]; g += d[i+1]; b += d[i+2]; count++;
                            }
                        };
                        
                        for(let x = bbox.x0; x <= bbox.x1; x += 4) {
                            addSample(x, bbox.y0 - margin);
                            addSample(x, bbox.y1 + margin);
                        }
                        for(let y = bbox.y0; y <= bbox.y1; y += 4) {
                            addSample(bbox.x0 - margin, y);
                            addSample(bbox.x1 + margin, y);
                        }
                        
                        if (count > 0) boxBg = `rgb(${Math.round(r/count)}, ${Math.round(g/count)}, ${Math.round(b/count)})`;
                        else boxBg = '#ffffff';
                    }

                    outCtx.fillStyle = boxBg;
                    outCtx.fillRect(bbox.x0, pY + bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);

                    // Compute text styling based on boundary contrast
                    const boxWidth = bbox.x1 - bbox.x0;
                    const boxHeight = bbox.y1 - bbox.y0;
                    
                    let contrastColor = '#000000';
                    const match = boxBg.match(/\d+/g);
                    if (match && match.length >= 3) {
                        const yiq = ((parseInt(match[0])*299)+(parseInt(match[1])*587)+(parseInt(match[2])*114))/1000;
                        contrastColor = (yiq >= 128) ? '#000000' : '#ffffff';
                    }

                    // Render readable translated text inside erased boundary box
                    outCtx.fillStyle = textColor === 'auto' ? contrastColor : textColor;
                    outCtx.textBaseline = 'middle';
                    outCtx.textAlign = 'center';
                    
                    let fontSize = boxHeight * 0.75;
                    outCtx.font = `bold ${fontSize}px sans-serif`;
                    let textWidth = outCtx.measureText(translated).width;
                    
                    while (textWidth > boxWidth * 0.95 && fontSize > 8) {
                        fontSize -= 1;
                        outCtx.font = `bold ${fontSize}px sans-serif`;
                        textWidth = outCtx.measureText(translated).width;
                    }
                    
                    const x = bbox.x0 + boxWidth / 2;
                    const y = pY + bbox.y0 + boxHeight / 2 + (fontSize * 0.05);
                    outCtx.fillText(translated, x, y);
                }
                pY += imgH;
            }

            statusDiv.innerText = 'Translation dynamically completed!';
            statusDiv.style.backgroundColor = '#d4edda';
            statusDiv.style.color = '#155724';
            statusDiv.style.borderColor = '#c3e6cb';
            
            container.appendChild(outCanvas);
            setTimeout(() => { statusDiv.style.display = 'none'; }, 3500);

        } catch (err) {
            console.error(err);
            statusDiv.innerText = 'An error occurred processing the image: ' + err.message;
            statusDiv.style.backgroundColor = '#f8d7da';
            statusDiv.style.color = '#721c24';
            statusDiv.style.borderColor = '#f5c6cb';
        }
    })();

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool extracts text from images using Optical Character Recognition (OCR) and translates it into multiple world languages. It processes the image by identifying text locations, erasing the original text with a color-matched background, and overlaying the translated text directly onto the image. This tool is useful for translating signs, documents, or menus in foreign languages, making it a great resource for travelers, educators, or anyone needing to quickly understand visual information in different languages.

Leave a Reply

Your email address will not be published. Required fields are marked *

Other Image Tools:

Image World Languages Translator Identifier

Image Language and Text Identifier Translator

Image Text Scanner Language Identifier and Translator Tool

Image Search Using API Key Translator

Image To TMDb Metadata Fetcher

TMDB Movie and TV Show Image Search Tool

Image To IMDb Rating Fetcher

IMDb Movie Database Settings Name Tool

Undead Image Filter

Website Interface Address Image Extractor

Image Text Field Creator Studio

Image Project Creation Icon and Text Field Tool

Image Text Underneath Adder

Image Language Editor

AI Image Project Creator Tool

Image Language Scanner Identifier

Image Scanner Identifier and Language Translator

Movie Studio Name and Year Image Scanner Identifier

Image Based Audio Song Lyric Identifier and MP3 Downloader

Image Scanner Interface Address Identifier Tool

3D Printer Scanner Identifier Tool

3D Model Printer and Scanner Identifier Tool

Image Scanner City Identifier Tool

Image Scanner Movie Identifier Tool

Scanner Identifier for Studio Company and Year from Image

Image Scanner Language Identifier and Dub Translator Tool

Image Scanner Software and Mediateka Topic Search Identifier

Image Scanner Identifier and Mediateka Search Topic Picker

Image Scanner Identifier Picker

Mediateka Image Scanner and Identifier Tool

Image Based Movie Scanner and Identifier

Image Address Icon Generator Tool

Image Company Year Identifier Scanner Tool

AI Company Year Generator From Image

Movie Studio Of The Year Photo Remover

AI Studio Company Year Image Identifier Generator

See All →