GoogleTranslateWidget.vue
<template>
<div class="translate-container">
<div
v-if="showTranslate"
id="google-translate-element"
class="custom-translate-dropdown"
></div>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
translateInstance: null,
googleScriptLoaded: false,
showTranslate: true,
isInitialized: false, // 新增初始化状态标志
};
},
computed: {
...mapGetters("translate", ["shouldReload", "currentLang"]),
},
watch: {
shouldReload(newVal) {
if (newVal) {
this.resetTranslateComponent();
this.$store.dispatch("translate/resetReload");
}
},
currentLang(newLang) {
this.setLanguage(newLang);
},
},
mounted() {
console.log("翻译组件挂载开始");
// 确保全局回调函数设置正确
window.googleTranslateElementInit = () => {
console.log("Google翻译API回调触发");
this.isInitialized = true;
setTimeout(() => {
this.initGoogleTranslate();
}, 800);
};
// 初始加载翻译
this.loadGoogleTranslate();
// 添加DOM检查机制
this.domCheckInterval = setInterval(() => {
this.checkAndFixDom();
}, 1000);
},
methods: {
...mapActions("translate", ["changeLanguage"]),
checkAndFixDom() {
// 检查Google翻译生成的元素是否存在
const googleElement = document.getElementById("google-translate-element");
const googleWidget = document.querySelector(".goog-te-combo");
if (googleElement && !googleWidget && this.isInitialized) {
console.log("检测到翻译组件DOM异常,重新初始化");
this.forceReinitialize();
}
},
forceReinitialize() {
// 完全重新初始化翻译组件
this.showTranslate = false;
this.$nextTick(() => {
this.showTranslate = true;
this.$nextTick(() => {
// 完全移除旧实例
if (this.translateInstance) {
try {
// 尝试清理Google翻译的DOM
const element = document.getElementById(
"google-translate-element"
);
if (element) element.innerHTML = "";
} catch (e) {
console.warn("清理翻译实例时出错:", e);
}
}
// 重新加载脚本
this.loadGoogleTranslate();
});
});
},
cleanUpGoogleScripts() {
// 移除所有Google翻译相关的脚本
const scripts = document.querySelectorAll(
'script[src*="translate.google.com"], script[id^="google"], script[id^="gapi"]'
);
scripts.forEach((script) => {
console.log("移除脚本:", script.id || script.src);
script.remove();
});
// 清理Google翻译生成的iframe
const frames = document.querySelectorAll(
'iframe[src*="translate.google.com"]'
);
frames.forEach((frame) => {
console.log("移除iframe:", frame.src);
frame.remove();
});
},
initGoogleTranslate() {
if (
!window.google ||
!window.google.translate ||
!window.google.translate.TranslateElement
) {
console.warn("Google Translate API not fully loaded yet");
setTimeout(() => this.initGoogleTranslate(), 100);
return;
}
const layout = window.google.translate.TranslateElement.InlineLayout
? window.google.translate.TranslateElement.InlineLayout.HORIZONTAL
: null;
const element = document.getElementById("google-translate-element");
if (element) element.innerHTML = "";
this.translateInstance = new window.google.translate.TranslateElement(
{
pageLanguage: "en",
includedLanguages: "en,zh-CN,es,pt",
layout: layout,
autoDisplay: false,
},
"google-translate-element"
);
this.$nextTick(() => {
this.customizeDropdown();
this.setLanguage(this.currentLang);
});
},
// 重置方法
resetTranslateComponent() {
console.log("执行重置翻译组件");
this.showTranslate = false;
this.$nextTick(() => {
// 确保DOM完全更新
setTimeout(() => {
this.showTranslate = true;
this.$nextTick(() => {
// 完全重新加载脚本
console.log("开始重新加载脚本");
this.loadGoogleTranslate();
});
}, 300);
});
},
// 加载方法
loadGoogleTranslate() {
console.log("开始加载Google翻译脚本");
// 更彻底的脚本清理
this.cleanUpGoogleScripts();
// 检查是否已加载
if (window.google && window.google.translate) {
console.log("Google翻译已加载,直接初始化");
this.initGoogleTranslate();
return;
}
// 创建新的脚本元素
const script = document.createElement("script");
script.src =
"https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
script.async = true;
script.defer = true;
script.id = "google-translate-loader";
script.onload = () => {
console.log("Google翻译脚本加载完成");
this.googleScriptLoaded = true;
};
script.onerror = (error) => {
console.error("Google翻译脚本加载失败:", error);
setTimeout(() => this.loadGoogleTranslate(), 1000);
};
document.head.appendChild(script);
},
// 美化翻译下拉框并移除Google品牌
customizeDropdown() {
// 完全移除Google标识
this.removeGoogleBranding();
// 获取语言选择器并应用自定义样式
const select = document.querySelector(".goog-te-combo");
if (select) {
// 添加新class应用自定义样式
select.classList.add("custom-language-select");
// 设置默认选中英语
select.value = "en";
// 重新设置字体
select.style.fontFamily =
'"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
select.style.fontSize = "14px";
select.style.color = "#2d3748";
// 触发一次初始翻译
const event = new Event("change");
select.dispatchEvent(event);
}
// 添加自定义下拉箭头
const wrapper = document.querySelector(".goog-te-combo-wrapper");
if (wrapper && !document.querySelector(".custom-dropdown-arrow")) {
const customArrow = document.createElement("div");
customArrow.className = "custom-dropdown-arrow";
wrapper.appendChild(customArrow);
}
},
// 移除所有Google品牌标识
removeGoogleBranding() {
// 移除"Powered by"文本
const brandings = document.querySelectorAll(
".gapps-branding, .goog-logo-link"
);
brandings.forEach((branding) => branding.remove());
// 移除品牌文本
const brandText = document.querySelector(
".goog-te-gadget-simple .goog-te-combo + span"
);
if (brandText) {
brandText.textContent = "";
brandText.style.display = "none";
}
// 移除品牌图标
const googleLogo = document.querySelector(".goog-te-gadget-icon");
if (googleLogo) googleLogo.remove();
// 移除下拉框图标
const dropDownIcon = document.querySelector(".goog-te-arrow");
if (dropDownIcon) dropDownIcon.remove();
// 移除"Select Language"中的Google关联文本
const selectText = document.querySelector(".goog-te-menu-value");
if (selectText) {
const spans = selectText.querySelectorAll("span");
if (spans.length > 2) {
// 移除多余的Google品牌文本
for (let i = 1; i < spans.length; i++) {
spans[i].remove();
}
}
}
},
// 切换语言
changeLanguage(lang) {
localStorage.setItem("lang", lang);
this.setLanguage(lang);
},
// 设置当前语言
setLanguage(lang) {
const select = document.querySelector(".goog-te-combo");
if (select) {
select.value = lang;
const event = new Event("change");
select.dispatchEvent(event);
}
},
},
beforeDestroy() {
clearInterval(this.domCheckInterval);
this.cleanUpGoogleScripts();
},
};
</script>
<style scoped>
.translate-container {
position: relative;
z-index: 1000;
display: inline-block;
margin: 0 10px;
height: 40px;
width: 180px; /* 固定宽度避免内容变化 */
}
/* 高度固定以避免布局跳动 */
.custom-translate-dropdown {
height: 40px;
overflow: hidden;
}
</style>
<style>
/* 全局样式覆盖 - 保留顶部工具栏 */
body {
top: 0 !important;
}
/* 自定义语言选择框样式 - 更加简洁专业 */
.custom-language-select {
padding: 8px 32px 8px 15px !important;
border: 1px solid #e6a23c !important;
border-radius: 6px !important;
background-color: #ffffff !important;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05) !important;
color: #ffffff !important;
font-size: 14px !important;
font-weight: 500 !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif !important;
appearance: none !important;
cursor: pointer !important;
transition: all 0.25s ease !important;
width: 100% !important;
height: 38px !important;
background: #e6a23c
url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a5568' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e")
no-repeat right 12px center / 18px 18px !important;
}
.custom-language-select:hover {
border-color: #cbd5e0 !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important;
}
.custom-language-select:focus {
outline: none !important;
border-color: #d66a05 !important;
box-shadow: 0 0 0 2px rgba(128, 72, 0, 0.849) !important;
}
/* 下拉菜单样式调整 - 专业UI */
.goog-te-menu2 {
padding: 8px 0 !important;
border: 1px solid #d66a05 !important;
border-radius: 6px !important;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.08) !important;
background: #ffffff !important; /* 白色背景 */
z-index: 10000 !important;
margin-top: 6px !important;
}
.goog-te-menu2-item {
padding: 10px 20px !important;
font-size: 14px !important;
color: #2d3748 !important; /* 深灰色文字 */
transition: all 0.15s ease !important;
border-bottom: 1px solid #f0f2f5 !important; /* 浅灰色分隔线 */
}
.goog-te-menu2-item:last-child {
border-bottom: none !important;
}
/* === 关键修复:Hover颜色改为橙色主题 === */
.goog-te-menu2-item:hover {
background-color: #fef6e7 !important; /* 浅橙色背景 */
color: #d66a05 !important; /* 深橙色文字 */
}
/* 隐藏所有品牌元素 */
.gapps-branding,
.goog-logo-link,
.goog-te-gadget-simple .goog-te-combo + span {
display: none !important;
}
/* 自定义下拉箭头 */
.custom-dropdown-arrow {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
width: 16px;
height: 16px;
/* 箭头颜色改为白色 */
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
}
/* 隐藏移动端顶部栏 */
[id=":1.container"].skiptranslate {
display: none;
}
/* 隐藏 PC 端顶部栏 */
[id=":2.container"].skiptranslate {
display: none;
}
.goog-te-menu2[dir="rtl"] .goog-te-menu2-item {
text-align: right !important;
padding-right: 20px !important;
}
/* 确保下拉框在移动端正常显示 */
@media (max-width: 768px) {
.translate-container {
width: 160px;
}
.custom-language-select {
font-size: 13px !important;
padding: 8px 28px 8px 12px !important;
}
}
</style>
这是谷歌多语言插件实现方式,但是中国大陆需要vpn