Greasy Fork

来自缓存

Greasy Fork is available in English.

Journal3 多语言编辑助手

为 Journal3 和 OpenCart 后台提供多语言内容同步、批量翻译功能,支持分行同步、一键同步和自动翻译

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Journal3 多语言编辑助手
// @namespace    http://www.webidea.top/
// @version      1.0.2
// @description  为 Journal3 和 OpenCart 后台提供多语言内容同步、批量翻译功能,支持分行同步、一键同步和自动翻译
// @author       TamsChan
// @license      GPLv3
// @match        *://*/*
// @match        *://*/admin/index.php?route=journal3/journal3&user_token=*
// @match        *://*/admin/index.php?route=catalog/information/edit&user_token=*&information_id=*
// @match        *://*/admin/index.php?route=catalog/information/add&user_token=*&information_id=*
// @icon         https://wiki.greasespot.net/favicon.ico
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_log
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';
    // 进度监控管理器
    const progressManager = {
        activeTasks: 0,

        // 确保只有一个遮罩层
        ensureMask: function () {
            if ($('#translate-progress-mask').length === 0) {
                const maskHtml = '<div id="translate-progress-mask" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 9998;"></div>';
                const containerHtml = '<div id="translate-progress-container" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 9999; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.2); min-width: 300px; max-height: 70vh; overflow-y: auto;"><h3 style="margin-top: 0; margin-bottom: 15px; text-align: center;">正在翻译中...</h3><div id="translate-progress-bars"></div></div>';
                $('body').append(maskHtml + containerHtml);
            }
        },

        // 添加一个进度条
        addProgress: function (taskId, total, label) {
            this.ensureMask();
            this.activeTasks++;
            const progressHtml = `
                <div id="progress-${taskId}" style="margin-bottom: 15px;">
                    <div style="font-size: 14px; margin-bottom: 5px; color: #333;">${label}</div>
                    <div style="height: 15px; background: #f0f0f0; border-radius: 8px; overflow: hidden;">
                        <div id="progress-${taskId}-bar" style="height: 100%; background: #4CAF50; width: 0%; transition: width 0.3s ease;"></div>
                    </div>
                    <div id="progress-${taskId}-info" style="font-size: 12px; margin-top: 5px; color: #666;">0/${total} (0%)</div>
                </div>
            `;
            $('#translate-progress-bars').append(progressHtml);
        },

        // 更新进度
        updateProgress: function (taskId, current, total, status) {
            const percentage = Math.round((current / total) * 100);
            $(`#progress-${taskId}-bar`).css('width', `${percentage}%`);
            $(`#progress-${taskId}-info`).text(`${current}/${total} (${percentage}%) - ${status}`);
        },

        // 移除一个进度条
        removeProgress: function (taskId) {
            $(`#progress-${taskId}`).remove();
            this.activeTasks--;
            // 如果所有任务都完成了,移除遮罩层
            if (this.activeTasks <= 0) {
                setTimeout(() => {
                    $('#translate-progress-mask').remove();
                    $('#translate-progress-container').remove();
                    this.activeTasks = 0;
                }, 300);
            }
        }
    };

    // 并发请求所有语言的翻译(带进度监控)
    function translateToMultipleLanguages(text, originalLang, languages, label = '翻译') {
        const total = languages.length;
        let completed = 0;
        const taskId = `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

        // 添加进度条
        progressManager.addProgress(taskId, total, label);

        const promises = languages.map(lang => {
            return new Promise((resolve, reject) => {
                const maxRetries = 3;
                let attempt = 0;

                function doRequest() {
                    attempt++;
                    const url = `https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=${originalLang}&tl=${lang}&q=${encodeURIComponent(text)}`;
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: url,
                        onload: function (res) {
                            if (res.status === 200) {
                                const result = JSON.parse(res.responseText);
                                const translated = result[0][0][0];
                                completed++;
                                progressManager.updateProgress(taskId, completed, total, `${lang} 完成`);
                                resolve({ language: lang, result: translated });
                            } else {
                                if (attempt < maxRetries) {
                                    setTimeout(doRequest, 1000 * attempt);
                                } else {
                                    completed++;
                                    progressManager.updateProgress(taskId, completed, total, `${lang} 失败`);
                                    reject({ language: lang, error: res.status });
                                }
                            }
                        },
                        onerror: function () {
                            if (attempt < maxRetries) {
                                setTimeout(doRequest, 1000 * attempt);
                            } else {
                                completed++;
                                progressManager.updateProgress(taskId, completed, total, `${lang} 网络错误`);
                                reject({ language: lang, error: 'network error' });
                            }
                        }
                    });
                }

                doRequest();
            });
        });

        return Promise.allSettled(promises).then(results => {
            progressManager.removeProgress(taskId);
            return results.map(r => r.status === 'fulfilled' ? r.value : r.reason);
        });
    }

    if (location.href.indexOf('route=journal3/journal3') != -1) {
        GM_addStyle('.ui-input-lang-container{position:relative}.ui-input-lang-container textarea{min-height:100px;width:100%;border:1px solid #007fff;outline:none;padding:8px}.ui-input-lang-container .ui-input-lang-button{position:absolute;right:5px;bottom:5px;z-index:9;display:flex;align-items:center;gap:5px}.ui-input-lang-container .ui-input-lang-button input,.ui-input-lang-container .ui-input-lang-button button,.ui-input-lang-container .ui-input-lang-button select{height:25px}')

        function journal3Init() {
            observer.disconnect();
            if ($('.ui-input-lang').length > 0) {
                let optionHtml = '';
                $('.ui-input-lang').eq(0).find('>div:not(.ui-input-lang-container) img').each(function () {
                    const src = $(this).attr('src');
                    const label = $(this).attr('alt');
                    const lang = src.split('/')[1];
                    optionHtml += `<option value="${lang}">${label}</option>`;
                })
                const placeholder = '分行同步:一行对于一个语言,按顺序,如遇空行则跳过空行语言。\n同步:所有语言内容同步当前输入框内容。\n翻译:将当前输入框内容翻译到其他语言。';
                $('.ui-input-lang').each(function () {
                    if ($(this).find('.ui-input-lang-container').length == 0) {
                        let input = ''
                        if ($(this).find('>div:not(.ui-input-lang-container) textarea').length > 0) {
                            input = '<input type="text" placeholder="请输入内容的换行符" value="\\n">';
                        }
                        $(this).prepend(`<div class="ui-input-lang-container"><textarea placeholder="${placeholder}"></textarea><div class="ui-input-lang-button">${input}<button class="ui-input-lang-button-sync-line">分行同步</button><button class="ui-input-lang-button-sync">同步</button> <button class="ui-input-lang-button-translate">翻译</button><select class="ui-input-lang-select" value="auto"><option value="auto">自动</option>${optionHtml}</select></div></div>`);
                    }
                });
            }
            startObserve();
        }

        // 创建观察器实例,防抖执行 init 方法
        let debounceTimer = null;

        const observer = new MutationObserver(() => {
            // 清除之前的定时器
            if (debounceTimer) {
                clearTimeout(debounceTimer);
            }
            // 设置新的防抖定时器
            debounceTimer = setTimeout(() => {
                journal3Init();
            }, 1000);
        });

        function startObserve() {
            // 配置观察选项(监听所有可能的变化)
            const config = {
                childList: true,     // 观察子节点的添加/删除
                subtree: true,       // 观察所有后代节点
                attributes: true,    // 观察属性变化
                characterData: true  // 观察文本内容变化
            };

            // 开始观察
            const appContainer = document.querySelector('#content') || document.body;
            observer.observe(appContainer, config);
        }
        startObserve()

        var _GM_registerMenuCommand;
        if (typeof GM_registerMenuCommand != 'undefined') {
            _GM_registerMenuCommand = GM_registerMenuCommand;
        } else if (typeof GM != 'undefined' && typeof GM.registerMenuCommand != 'undefined') {
            _GM_registerMenuCommand = GM.registerMenuCommand;
        } else {
            _GM_registerMenuCommand = (s, f) => { };
        }
        _GM_registerMenuCommand("插入", () => {
            journal3Init();
        });

        // 直接同步按钮点击事件
        $(document).on('click', '.ui-input-lang-button-sync', function () {
            const textarea = $(this).closest('.ui-input-lang-container').find('textarea');
            if (textarea.val().trim() === '') {
                return;
            }
            const value = textarea.val();

            const langTag = $(this).parents('.ui-input-lang');
            if (langTag.find('.tabs').length > 0) {
                if (langTag.find('.ui-editor').length > 0) {
                    langTag.find('.tab-items li').each(function () {
                        $(this).click();
                        langTag.find('.ui-editor .note-editor').prev('div').summernote('code', value);
                    })
                } else {
                    langTag.find('.tab-items li').each(function () {
                        $(this).click();
                        const input = langTag.find('>div:not(.ui-input-lang-container) textarea').eq(0)[0];
                        const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                        if (key) {
                            input[key].onChange({ target: { value: value } });
                        }
                    })
                }
            } else {
                langTag.find('>div:not(.ui-input-lang-container) input').each(function () {
                    const input = this;
                    const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                    console.log(input);
                    if (key) {
                        input[key].onChange({ target: { value: value } });
                    }
                });
            }
        })

        // 分行同步按钮点击事件
        $(document).on('click', '.ui-input-lang-button-sync-line', function () {
            const textarea = $(this).closest('.ui-input-lang-container').find('textarea');
            if (textarea.val().trim() === '') {
                return;
            }
            const value = textarea.val().trim().split('\n');
            for (let i = 0; i < value.length; i++) {
                const line = value[i];
                if (line.trim() === '') {
                    continue;
                }
                const langTag = $(this).parents('.ui-input-lang');
                if (langTag.find('.tabs').length > 0) {
                    let lineFormat = $(this).siblings('input').val()
                    if (langTag.find('.ui-editor').length > 0) {
                        langTag.find('.tab-items li').eq(i).click();
                        langTag.find('.ui-editor .note-editor').prev('div').summernote('code', line.replaceAll(lineFormat, '\n'));
                    } else {
                        langTag.find('.tab-items li').eq(i).click();
                        const input = langTag.find('>div:not(.ui-input-lang-container) textarea').eq(0)[0];
                        const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                        if (key) {
                            input[key].onChange({ target: { value: line.replaceAll(lineFormat, '\n') } });
                        }
                    }
                } else {
                    const input = langTag.find('>div:not(.ui-input-lang-container) input').eq(i)[0];
                    const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                    if (key) {
                        input[key].onChange({ target: { value: line } });
                    }
                }
            }
        })
        $(document).on('click', '.ui-input-lang-button-translate', function () {
            const textarea = $(this).closest('.ui-input-lang-container').find('textarea');
            if (textarea.val().trim() === '') {
                return;
            }
            const value = textarea.val();
            const languages = [];
            $(this).parents('.ui-input-lang').find('>div:not(.ui-input-lang-container) .lang-flag img').each(function () {
                const img = this;
                const src = $(img).attr('src');
                languages.push(src.split('/')[1]);
            });
            const originalLang = $(this).closest('.ui-input-lang').find('.ui-input-lang-select').val();
            translateToMultipleLanguages(value, originalLang, languages).then(results => {
                results.forEach(r => {
                    if (r.result) {
                        const langTag = $(this).parents('.ui-input-lang');
                        if (langTag.find('.tabs').length > 0) {
                            let lineFormat = $(this).siblings('input').val()
                            if (langTag.find('.ui-editor').length > 0) {
                                langTag.find('.tab-items li').eq(languages.indexOf(r.language)).click();
                                langTag.find('.ui-editor .note-editor').prev('div').summernote('code', r.result.replaceAll(lineFormat, '\n'));
                            } else {
                                langTag.find('.tab-items li').eq(languages.indexOf(r.language)).click();
                                const input = langTag.find('>div:not(.ui-input-lang-container) textarea').eq(0)[0];
                                const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                                if (key) {
                                    input[key].onChange({ target: { value: r.result.replaceAll(lineFormat, '\n') } });
                                }
                            }
                        } else {
                            const input = langTag.find('>div:not(.ui-input-lang-container) input').eq(languages.indexOf(r.language))[0];
                            const key = Object.keys(input).find(key => key.startsWith('__reactEventHandlers'));
                            if (key) {
                                input[key].onChange({ target: { value: r.result } });
                            }
                        }
                    }
                });
            });
        })
    } else if (location.href.indexOf('route=catalog/information/edit') != -1 || location.href.indexOf('route=catalog/information/add') != -1) {
        function informationInit() {
            let optionHtml = '';
            $('#tab-general #language li img').each(function () {
                const src = $(this).attr('src');
                const label = $(this).attr('title');
                const lang = src.split('/')[1];
                optionHtml += `<option value="${lang}">${label}</option>`;
            })
            $('#tab-seo .table-responsive').before('<div class="form-group"><label class="col-sm-2 control-label" for="all-seo">Seo</label><div class="col-sm-10" style="display: flex;"><input type="text" class="form-control" id="all-seo" placeholder="seo"><button type="button" id="sync-seo" class="btn btn-default">同步</button></div></div>');

            $('#tab-general #language').append('<li><a href="#sync-line" data-toggle="tab">一键同步</a></li>');
            $('#tab-general .tab-content').append(`<div class="tab-pane" id="sync-line">
                <div class="form-group required">
                    <label class="col-sm-2 control-label" for="input-sync-line">Information Title</label>
                    <div class="col-sm-10">
                        <input type="text" placeholder="Information Title" id="input-sync-line" class="form-control">
                    </div>
                </div>
                <div class="form-group required">
                    <label class="col-sm-2 control-label" for="input-description-sync-line">Description</label>
                    <div class="col-sm-10">
                        <textarea rows="10" placeholder="Information Description" id="input-description-sync-line" class="form-control"></textarea>
                    </div>
                </div>
                <div class="form-group required">
                    <label class="col-sm-2 control-label" for="input-meta-sync-line">Meta Tag Title</label>
                    <div class="col-sm-10">
                        <input type="text" placeholder="Meta Tag Title" id="input-meta-sync-line" class="form-control">
                    </div>
                </div>
                <div class="form-group">
                    <label class="col-sm-2 control-label" for="input-meta-description-sync-line">Meta Tag Description</label>
                    <div class="col-sm-10">
                        <textarea rows="5" placeholder="Meta Tag Description" id="input-meta-description-sync-line" class="form-control"></textarea>
                    </div>
                </div>
                <div class="form-group">
                    <label class="col-sm-2 control-label" for="input-meta-keywords-sync-line">Meta Tag Keywords</label>
                    <div class="col-sm-10">
                        <textarea rows="5" placeholder="Meta Tag Keywords" id="input-meta-keywords-sync-line" class="form-control"></textarea>
                    </div>
                </div>
                <div class="form-group">
                    <label class="col-sm-2 control-label">操作</label>
                    <div class="col-sm-10">
                        <div class="row">
                            <div class="col-sm-9">
                                <div class="row">
                                    <div class="col-sm-6">
                                    </div>
                                    <label class="col-sm-1 control-label">原语言</label>
                                    <div class="col-sm-5">
                                        <select class="form-control" id="input-original-language" value="auto">
                                            <option value="auto">auto</option>
                                            ${optionHtml}
                                        </select>
                                    </div>
                                </div>
                            </div>
                            <div class="col-sm-3">
                                <button type="button" class="btn btn-primary" id="sync-line-btn">一键同步</button>
                                <button type="button" class="btn btn-primary" id="translate-btn">翻译同步</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>`);
        }
        informationInit();
        $(document).on('click', '#sync-seo', function () {
            const seo = $("#all-seo").val().trim();
            if (seo !== '') {
                $('input[name^="information_seo_url["]').each(function () {
                    const src = $(this).siblings('.input-group-addon').find('img').attr('src');
                    const lang = src.split('/')[1].toLocaleLowerCase();
                    const langL = lang.split('-');
                    let langCode = '-' + langL[0];
                    switch (lang) {
                        case 'en-gb':
                            langCode = '';
                            break;
                        case 'pt-br':
                            langCode = '-pt-br';
                            break;
                        case 'ko-kr':
                            langCode = '-kr';
                            break;
                        case 'el-gr':
                            langCode = '-gr';
                            break;
                        case 'pt-pt':
                            langCode = '-pt-pt';
                            break;
                        default:
                            langCode = '-' + langL[0];
                            break;
                    }
                    $(this).val(seo + langCode);
                })
                $('input[name^="information_seo_url["]').each(function () {
                    const src = $(this).siblings('.input-group-addon').find('img').attr('src');
                    const _lang = src.split('/')[1].toLocaleLowerCase();
                    const _this = this
                    $('input[name^="information_seo_url["]').each(function () {
                        const src = $(this).siblings('.input-group-addon').find('img').attr('src');
                        const lang = src.split('/')[1].toLocaleLowerCase();
                        if (this !== _this && $(this).val() === $(_this).val()) {
                            $(this).val(seo + '-' + lang);
                            $(_this).val(seo + '-' + _lang);
                        }
                    })
                })
                const seoErr = []
                $('input[name^="information_seo_url["]').parents('.input-group').removeClass('has-error');
                $('input[name^="information_seo_url["]').each(function () {
                    const _this = this
                    $('input[name^="information_seo_url["]').each(function () {
                        if (this !== _this && $(this).val() === $(_this).val()) {
                            $(this).parents('.input-group').addClass('has-error');
                            $(_this).parents('.input-group').addClass('has-error');
                            seoErr.push(true);
                        }
                    })
                })
                if (seoErr.includes(true)) {
                    alert('SEO URL 重复,请检查');
                }
            }
        })
        $(document).on('click', '#sync-line-btn', function () {
            const title = $("#input-sync-line").val().trim();
            const description = $("#input-description-sync-line").val().trim();
            const metaTitle = $("#input-meta-sync-line").val().trim();
            const metaDescription = $("#input-meta-description-sync-line").val().trim();
            const metaKeywords = $("#input-meta-keywords-sync-line").val().trim();

            if (title.trim() !== '') {
                $('input[name^="information_description["][name$="][title]"]').val(title);
            }
            if (description.trim() !== '') {
                $('textarea[name^="information_description["][name$="][description]"]').each(function () {
                    $(this).summernote('code', description);
                })
            }
            if (metaTitle.trim() !== '') {
                $('input[name^="information_description["][name$="][meta_title]"]').val(metaTitle);
            }
            if (metaDescription.trim() !== '') {
                $('textarea[name^="information_description["][name$="][meta_description]"]').val(metaDescription);
            }
            if (metaKeywords.trim() !== '') {
                $('textarea[name^="information_description["][name$="][meta_keyword]"]').val(metaKeywords);
            }
        })
        $(document).on('click', '#translate-btn', function () {
            const languages = []
            $('#tab-general #language li img').each(function () {
                const src = $(this).attr('src');
                const lang = src.split('/')[1];
                languages.push(lang);
            })
            const originalLanguage = $("#input-original-language").val();

            const title = $("#input-sync-line").val().trim();
            const description = $("#input-description-sync-line").val().trim();
            const metaTitle = $("#input-meta-sync-line").val().trim();
            const metaDescription = $("#input-meta-description-sync-line").val().trim();
            const metaKeywords = $("#input-meta-keywords-sync-line").val().trim();

            if (title !== '') {
                $('input[name^="information_description["][name$="][title]"]').val(title);
                translateToMultipleLanguages(title, originalLanguage, languages, '标题').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('.tab-content .tab-pane').eq(langIndex + 1).find('input[name^="information_description["][name$="][title]"]').val(result);
                        }
                    })
                })
            }
            if (description !== '' && description.length < 5000) {
                translateToMultipleLanguages(description, originalLanguage, languages, '描述').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('.tab-content .tab-pane').eq(langIndex + 1).find('textarea[name^="information_description["][name$="][description]"]').eq(0).summernote('code', result);
                        }
                    })
                })
            }
            if (metaTitle !== '') {
                translateToMultipleLanguages(metaTitle, originalLanguage, languages, 'meta标题').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('.tab-content .tab-pane').eq(langIndex + 1).find('input[name^="information_description["][name$="][meta_title]"]').val(result);
                        }
                    })
                })
            }
            if (metaDescription !== '') {
                translateToMultipleLanguages(metaDescription, originalLanguage, languages, 'meta描述').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('.tab-content .tab-pane').eq(langIndex + 1).find('textarea[name^="information_description["][name$="][meta_description]"]').val(result);
                        }
                    })
                })
            }
            if (metaKeywords !== '') {
                translateToMultipleLanguages(metaKeywords, originalLanguage, languages, 'meta关键词').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('.tab-content .tab-pane').eq(langIndex + 1).find('textarea[name^="information_description["][name$="][meta_keyword]"]').val(result);
                        }
                    })
                })
            }
        })
    } else if (location.href.indexOf('route=catalog/new_product/edit') != -1 || location.href.indexOf('route=catalog/new_product/add') != -1) {
        function initProductDescription() {
            let optionHtml = '';
            $('#tab-general img').each(function () {
                const src = $(this).attr('src');
                const label = $(this).attr('title');
                const lang = src.split('/')[1];
                optionHtml += `<option value="${lang}">${label}</option>`;
            })

            $('#tab-general').prepend(`<div class="form-group"><label class="col-sm-2 control-label" for="input-sync-line">产品名称</label><div class="col-sm-10" style="display: flex;"><input type="text" class="form-control" id="input-sync-line" placeholder="产品名称"><select class="form-control" id="input-original-language" value="auto" style="width: 160px;"><option value="auto">auto</option>${optionHtml}</select><button type="button" id="sync-title" class="btn btn-default">同步</button><button type="button" id="translate-btn" class="btn btn-default">翻译</button></div></div>`)
        }
        initProductDescription();

        $(document).on('click', '#sync-title', function () {
            // 同步产品名称
            const title = $("#input-sync-line").val().trim();
            if (title !== '') {
                $('input[name^="product_description["][name$="][name]"]').val(title);
            }
        })
        $(document).on('click', '#translate-btn', function () {
            // 翻译产品名称
            const title = $("#input-sync-line").val().trim();
            const originalLanguage = $("#input-original-language").val();
            const languages = [];
            $('#tab-general img').each(function () {
                const src = $(this).attr('src');
                const lang = src.split('/')[1];
                languages.push(lang);
            })
            if (title !== '') {
                translateToMultipleLanguages(title, originalLanguage, languages, '产品名称').then(function (results) {
                    results.forEach(r => {
                        if (r.result) {
                            const language = r.language;
                            const result = r.result;
                            const langIndex = languages.indexOf(language);
                            $('input[name^="product_description["][name$="][name]"]').eq(langIndex).val(result);
                        }
                    })
                })
            }
        })
    }
})();