Please bookmark this page to avoid losing your image tool!

Image Translation 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.
async function processImage(originalImg, sourceLang = 'eng', targetLang = 'rus') {

    /**
     * Dynamically loads a UMD script from a URL and resolves with its global variable.
     * Caches the result to avoid re-loading.
     * @param {string} url The URL of the script to load.
     * @param {string} globalName The name of the global variable the script exposes.
     * @returns {Promise<any>} A promise that resolves with the library's global object.
     */
    const loadScript = (url, globalName) => {
        return new Promise((resolve, reject) => {
            if (window[globalName]) {
                return resolve(window[globalName]);
            }
            const script = document.createElement('script');
            script.src = url;
            script.onload = () => {
                if (window[globalName]) {
                    resolve(window[globalName]);
                } else {
                    reject(new Error(`Global ${globalName} not found after loading ${url}`));
                }
            };
            script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
            document.head.appendChild(script);
        });
    };

    // 1. DYNAMICALLY IMPORT LIBRARIES
    // Load Tesseract.js for OCR
    const Tesseract = await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js', 'Tesseract');
    // Load Transformers.js for translation (as an ES module)
    const { pipeline, env } = await import('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.1');
    
    // Configure Transformers.js environment
    env.allowLocalModels = false; // For security and to ensure models are fetched from HuggingFace
    
    // 2. LANGUAGE MAPPING
    // Maps simple language codes to the specific codes required by Tesseract and the translation model.
    const langMap = {
        'eng': { tesseract: 'eng', nllb: 'eng_Latn' },
        'rus': { tesseract: 'rus', nllb: 'rus_Cyrl' },
        'deu': { tesseract: 'deu', nllb: 'deu_Latn' }, // German
        'fra': { tesseract: 'fra', nllb: 'fra_Latn' }, // French
        'spa': { tesseract: 'spa', nllb: 'spa_Latn' }, // Spanish
        'jpn': { tesseract: 'jpn', nllb: 'jpn_Jpan' }, // Japanese
        'chi_sim': { tesseract: 'chi_sim', nllb: 'zho_Hans' }, // Chinese (Simplified)
    };

    if (!langMap[sourceLang] || !langMap[targetLang]) {
        throw new Error(`Unsupported language. Supported codes: ${Object.keys(langMap).join(', ')}`);
    }
    const tesseractLang = langMap[sourceLang].tesseract;
    const nllbSourceLang = langMap[sourceLang].nllb;
    const nllbTargetLang = langMap[targetLang].nllb;

    // 3. SETUP CANVAS AND UI CONTAINER
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    ctx.drawImage(originalImg, 0, 0);

    // Create a container to hold the canvas and a status overlay
    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.display = 'inline-block';
    
    const statusDiv = document.createElement('div');
    statusDiv.style.position = 'absolute';
    statusDiv.style.top = '0';
    statusDiv.style.left = '0';
    statusDiv.style.width = '100%';
    statusDiv.style.height = '100%';
    statusDiv.style.display = 'flex';
    statusDiv.style.alignItems = 'center';
    statusDiv.style.justifyContent = 'center';
    statusDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
    statusDiv.style.color = 'white';
    statusDiv.style.fontFamily = 'sans-serif';
    statusDiv.style.fontSize = '16px';
    statusDiv.style.textAlign = 'center';
    statusDiv.style.padding = '20px';
    statusDiv.style.boxSizing = 'border-box';
    statusDiv.textContent = 'Initializing...';

    container.appendChild(canvas);
    container.appendChild(statusDiv);

    const updateStatus = (text) => {
        console.log(text);
        statusDiv.innerHTML = text.replace(/\n/g, '<br>');
    };

    try {
        // 4. PERFORM OCR
        updateStatus('Initializing OCR engine...');
        const worker = await Tesseract.createWorker(tesseractLang, 1, {
            logger: m => updateStatus(`OCR: ${m.status}\n(${(m.progress * 100).toFixed(0)}%)`)
        });
        const { data: { paragraphs } } = await worker.recognize(canvas);
        await worker.terminate();
        
        const validParagraphs = paragraphs.filter(p => p.text.trim().length > 1);
        if (validParagraphs.length === 0) {
            updateStatus("No readable text detected.");
            setTimeout(() => { statusDiv.style.display = 'none'; }, 3000);
            return container;
        }
        const textsToTranslate = validParagraphs.map(p => p.text.replace(/\n/g, ' ').trim());

        // 5. PERFORM TRANSLATION
        updateStatus('Loading translation model...\n(This may take a moment on first use)');
        const translator = await pipeline('translation', 'Xenova/nllb-200-distilled-600M', {
            progress_callback: p => {
                if (p.status === 'progress') {
                    const progress = (p.progress || 0).toFixed(2);
                    updateStatus(`Downloading model...\n${p.file}\n${progress}%`);
                } else {
                    updateStatus(`Translation model: ${p.status}`);
                }
            }
        });

        updateStatus('Translating detected text...');
        const translatedTexts = await translator(textsToTranslate, {
            src_lang: nllbSourceLang,
            tgt_lang: nllbTargetLang,
        });

        // 6. RENDER RESULTS
        updateStatus('Rendering translation...');
        validParagraphs.forEach((p, i) => {
            const translatedText = translatedTexts[i].translation_text;
            const bbox = p.bbox;

            // Erase the original text by drawing a white box over it
            ctx.fillStyle = 'white';
            ctx.fillRect(bbox.x0, bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);

            // Prepare to draw the translated text
            ctx.fillStyle = 'black';
            ctx.textAlign = 'left';
            ctx.textBaseline = 'middle';
            const boxWidth = bbox.x1 - bbox.x0;
            const boxHeight = bbox.y1 - bbox.y0;

            // Auto-adjust font size to fit the bounding box
            let fontSize = boxHeight * 0.9;
            do {
                ctx.font = `bold ${fontSize--}px sans-serif`;
            } while (ctx.measureText(translatedText).width > boxWidth && fontSize > 8);

            // Draw the text vertically centered in the box
            ctx.fillText(translatedText, bbox.x0, bbox.y0 + boxHeight / 2);
        });

        updateStatus('Done!');
        setTimeout(() => { statusDiv.style.display = 'none'; }, 2000);

    } catch (error) {
        console.error('An error occurred during image processing:', error);
        updateStatus(`Error: ${error.message}\nCheck console for details.`);
        // Don't hide the status div on error
    }

    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

The Image Translation Tool is designed to extract text from images and translate it from one language to another. Users can upload an image containing text in a source language, and the tool will perform optical character recognition (OCR) to identify the text. The identified text is then translated into a target language. This tool is useful for translating signs, documents, and other visual content, making it beneficial for travelers, language learners, and anyone needing to comprehend foreign text in images.

Leave a Reply

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