Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Real-Time Website Translation Using jQuery and Baidu Translate API

Tech May 16 2

Front-end Structure

To enable dynamic translation, markup elements that require localization with a specific class and store their unique identifiers in data attributes. A dropdown menu allows users to switch between languages.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dynamic Localization Demo</title>
</head>
<body>
    <!-- Localizable Content -->
    <h1 class="translate-node" data-msg-id="header">Hello, welcome to our service!</h1>
    <p class="translate-node" data-msg-id="description">This content can be translated dynamically using the Baidu API.</p>
    
    <button class="translate-node" data-msg-id="actionBtn">Learn More</button>

    <!-- Language Selection Dropdown -->
    <div style="margin-top: 20px;">
        <label for="langSelector">Select Language: </label>
        <select id="langSelector">
            <option value="en">English</option>
            <option value="zh">Chinese (Simplified)</option>
            <option value="jp">Japanese</option>
            <option value="kor">Korean</option>
        </select>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="./hash-utils.js"></script>
    <script src="./app-translator.js"></script>
</body>
</html>

Translation Logic with jQuery

The following script listens for changes in the dropdown menu, iterates through all element marked for translation, and updates their text content by calling the Baidu Translate service.

$(document).ready(function () {
    const $selector = $('#langSelector');

    $selector.on('change', function () {
        const targetLang = $(this).val();
        processTranslation(targetLang);
    });
});

/**
 * Scans the DOM for translatable elements and updates them.
 * @param {string} langCode - The target language code (e.g., 'zh', 'en').
 */
function processTranslation(langCode) {
    $('.translate-node').each(function () {
        const $element = $(this);
        const rawText = $element.text();

        fetchBaiduTranslation(rawText, langCode)
            .then(translated => {
                $element.text(translated);
            })
            .catch(err => {
                console.error("Translation Error:", err);
            });
    });
}

/**
 * Handles the API request to Baidu Translate.
 * @param {string} query - The text to translate.
 * @param {string} destLang - The target language.
 */
function fetchBaiduTranslation(query, destLang) {
    return new Promise((resolve, reject) => {
        const config = {
            appId: 'YOUR_APP_ID',
            secretKey: 'YOUR_SECRET_KEY',
            endpoint: 'http://api.fanyi.baidu.com/api/trans/vip/translate'
        };

        const salt = Date.now();
        const fromLang = 'auto';
        
        // Construct signature: appId + query + salt + secretKey
        const signature = CryptoUtils.md5(config.appId + query + salt + config.secretKey);

        $.ajax({
            url: config.endpoint,
            type: 'GET',
            dataType: 'jsonp',
            data: {
                q: query,
                appid: config.appId,
                salt: salt,
                from: fromLang,
                to: destLang,
                sign: signature
            },
            success: (response) => {
                if (response.trans_result && response.trans_result.length > 0) {
                    resolve(response.trans_result[0].dst);
                } else {
                    reject(response.error_msg || 'Unknown error');
                }
            },
            error: (xhr, status, error) => {
                reject(error);
            }
        });
    });
}

MD5 Utility Implementation

Baidu's API security requires an MD5 signtaure. Below is a encapsulated utility to handle string hashing and UTF-8 encoding.

const CryptoUtils = (function () {
    function rotateLeft(lValue, iShiftBits) {
        return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
    }

    function addUnsigned(lX, lY) {
        const lX8 = (lX & 0x80000000);
        const lY8 = (lY & 0x80000000);
        const lX4 = (lX & 0x40000000);
        const lY4 = (lY & 0x40000000);
        const lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        if (lX4 | lY4) {
            return (lResult & 0x40000000) ? (lResult ^ 0xC0000000 ^ lX8 ^ lY8) : (lResult ^ 0x40000000 ^ lX8 ^ lY8);
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }

    function md5(string) {
        let x = [];
        let k, AA, BB, CC, DD, a, b, c, d;
        const S11 = 7, S12 = 12, S13 = 17, S14 = 22;
        const S21 = 5, S22 = 9, S23 = 14, S24 = 20;
        const S31 = 4, S32 = 11, S33 = 16, S34 = 23;
        const S41 = 6, S42 = 10, S43 = 15, S44 = 21;

        function F(x, y, z) { return (x & y) | ((~x) & z); }
        function G(x, y, z) { return (x & z) | (y & (~z)); }
        function H(x, y, z) { return (x ^ y ^ z); }
        function I(x, y, z) { return (y ^ (x | (~z))); }

        function FF(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }

        function GG(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }

        function HH(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }

        function II(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }

        const utf8String = unescape(encodeURIComponent(string));
        const lMessageLength = utf8String.length;
        const lNumberOfWords_temp1 = lMessageLength + 8;
        const lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
        const lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
        let lWordArray = Array(lNumberOfWords - 1);
        let lBytePosition = 0;
        let lByteCount = 0;
        while (lByteCount < lMessageLength) {
            const lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (utf8String.charCodeAt(lByteCount) << lBytePosition));
            lByteCount++;
        }
        const lWordCountFinal = (lByteCount - (lByteCount % 4)) / 4;
        lBytePosition = (lByteCount % 4) * 8;
        lWordArray[lWordCountFinal] = lWordArray[lWordCountFinal] | (0x80 << lBytePosition);
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;

        x = lWordArray;
        a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

        for (k = 0; k < x.length; k += 16) {
            AA = a; BB = b; CC = c; DD = d;
            a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
            d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
            c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
            b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
            // ... (rest of MD5 rounds omitted for brevity but required for full logic)
            a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD);
        }

        const wordToHex = (lValue) => {
            let hex = "";
            for (let i = 0; i <= 3; i++) {
                let byte = (lValue >>> (i * 8)) & 255;
                hex += ("0" + byte.toString(16)).slice(-2);
            }
            return hex;
        };

        return (wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d)).toLowerCase();
    }

    return { md5 };
})();
```",
  "tags": ["jQuery", "JavaScript", "Baidu Translate API", "Front-end Development", "MD5", "Localization"]
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.