【vue】网页项目嵌入Google Translate小部件

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱因斯坦乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值