Mudanças entre as edições de "Widget:C.Translator"

De Wiki Gla
Ir para navegação Ir para pesquisar
(Criou página com '<!-- TRANSLATOR SYSTEM --> <script> (() => { 'use strict'; const normalizeLang = (s) => { s = (s || '').toLowerCase(); if (s === 'p...')
 
m
 
(3 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
<!-- TRANSLATOR SYSTEM -->
<!-- CHARACTER TRANSLATOR SYSTEM -->
<script>
<script>
    (() => {
  (() => {
        'use strict';
    let __langReqSeq = 0;
        const normalizeLang = (s) => {
            s = (s || '').toLowerCase();
            if (s === 'pt-br' || s === 'pt_br' || s === 'ptbr') return 'pt';
            return (s.split('-')[0] || 'pt');
        };


        const updateSkillsTabLabel = (norm) => {
    // ---------- helpers ----------
            const map = { en: 'Skills', pt: 'Habilidades', es: 'Habilidades', pl: 'Umiejętności' };
    const normalizeLang = (s) => {
            const btn = document.querySelector('.character-tabs .tab-btn[data-tab="skills"]');
      s = (s || "").toLowerCase();
            if (btn) btn.textContent = map[norm] || map.pt;
      if (s === "pt-br" || s === "pt_br" || s === "ptbr") return "pt";
        };
      return s.split("-")[0] || "pt";
    };


         const pickDescFor = (icon, norm) => {
    const markActive = (langFull) => {
            const keyMap = { pt: 'descPt', en: 'descEn', es: 'descEs', pl: 'descPl' };
      const lang = (langFull || "pt-br").toLowerCase();
            const order = [keyMap[norm], 'descPt', 'descEn', 'descEs', 'descPl'].filter(Boolean);
      document.querySelectorAll(".char-flag[data-lang]").forEach((b) => {
            for (const k of order) {
        b.classList.toggle("active", b.dataset.lang === lang);
                const v = (icon.dataset[k] || '').trim();
      });
                if (v) return v;
    };
             }
 
             return '';
    const updateSkillsTabLabel = (norm) => {
         };
      const map = {
        en: "Skills",
        pt: "Habilidades",
        es: "Habilidades",
        pl: "Umiejętności",
      };
      const btn =
        document.querySelector('.character-tabs .tab-btn[data-tab="skills"]') ||
         Array.from(document.querySelectorAll(".character-tabs .tab-btn")).find(
          (b) => /skill|habil|umiej/i.test(b.textContent || "")
        );
      if (btn) btn.textContent = map[norm] || map.pt;
    };
 
    // ---------- skills ----------
    const pickDescFor = (icon, norm) => {
      const keyMap = { pt: "descPt", en: "descEn", es: "descEs", pl: "descPl" };
      const order = [
        keyMap[norm],
        "descPt",
        "descEn",
        "descEs",
        "descPl",
      ].filter(Boolean);
      for (const k of order) {
        const v = (icon.dataset[k] || "").trim();
        if (v) return v;
      }
      return "";
    };
 
    const updateAllSkillDescs = (norm) => {
      document.querySelectorAll(".icon-bar .skill-icon").forEach((icon) => {
        icon.dataset.desc = pickDescFor(icon, norm);
      });
    };
 
    // ---------- tier & tags ----------
    const updateTierAndTags = (norm) => {
      const cont = document.querySelector(".class-tags");
      if (!cont) return;
 
      const tier = cont.querySelector(".class-tag.tier");
      if (tier) {
        const t =
          tier.getAttribute("data-tier-" + norm) ||
          tier.getAttribute("data-tier-pt") ||
          tier.getAttribute("data-tier-en") ||
          tier.getAttribute("data-tier-es") ||
          tier.getAttribute("data-tier-pl") ||
          "";
        if (t) tier.textContent = t;
      }
 
      let tags = [];
      const pack = cont.getAttribute("data-tags-i18n");
      if (pack) {
        try {
          const obj = JSON.parse(pack);
          const arr =
            obj?.[norm] || obj?.pt || obj?.en || obj?.es || obj?.pl || [];
          if (Array.isArray(arr)) tags = arr;
        } catch (e) { }
      }
 
      if (!tags.length) {
        const raw =
          cont.getAttribute("data-tags-" + norm) ||
          cont.getAttribute("data-tags-pt") ||
          cont.getAttribute("data-tags-en") ||
          cont.getAttribute("data-tags-es") ||
          cont.getAttribute("data-tags-pl") ||
          "";
        if (raw) {
          try {
             const maybe = JSON.parse(raw);
            if (Array.isArray(maybe)) tags = maybe;
          } catch (e) { }
          if (!tags.length && typeof raw === "string") {
             tags = raw
              .split(",")
              .map((s) => s.trim())
              .filter(Boolean);
          }
        }
      }
 
      if (!tags.length) return;
 
      // Tags invisíveis (não devem ser exibidas na wiki)
      const HIDDEN_TAGS = {
        mulher: true,
        woman: true,
        mujer: true,
        kobieta: true,
      };
 
      cont
        .querySelectorAll(".class-tag:not(.tier)")
        .forEach((el) => el.remove());
      tags.forEach((t) => {
        // Filtra tags invisíveis
        const normalized = (t || "").toLowerCase().trim();
        if (HIDDEN_TAGS[normalized]) return;
 
        const chip = document.createElement("span");
        chip.className = "class-tag";
        chip.textContent = t;
        cont.appendChild(chip);
      });
    };
 
    // ---------- FLAGS: tooltips i18n ----------
    const updateFlagTooltips = (norm) => {
      const skillsRoot = document.querySelector("#skills");
      if (!skillsRoot) return;
      let pack = {};
      try {
        pack = JSON.parse(skillsRoot.dataset.i18nFlags || "{}");
      } catch (e) { }
      const dict = pack[norm] || pack.pt || {};
      const tooltip = window.__globalSkillTooltip;
      if (!tooltip) return;
 
      document
        .querySelectorAll(".skill-flags .skill-flag[data-flag]")
        .forEach((el) => {
          delete el.dataset.flagTipWired;
         });
 
      const descBoxes = document.querySelectorAll(".desc-box");
      descBoxes.forEach((box) => {
        if (box.querySelector(".skill-flags")) {
          const flags = box.querySelectorAll(
            ".skill-flags .skill-flag[data-flag]"
          );
          flags.forEach((el) => {
            const key = el.getAttribute("data-flag");
            const tip = (dict && dict[key]) || "";
            if (!tip) return;
            delete el.dataset.flagTipWired;
            el.setAttribute("aria-label", tip);
            if (el.hasAttribute("title")) el.removeAttribute("title");


        const updateAllSkillDescs = (norm) => {
            el.addEventListener("mouseenter", () => {
            document.querySelectorAll('.icon-bar .skill-icon').forEach(icon => {
              const tipEl = document.querySelector(".skill-tooltip");
                 icon.dataset.desc = pickDescFor(icon, norm);
              if (tipEl) tipEl.classList.add("flag-tooltip");
              tooltip.show(el, tip);
            });
            el.addEventListener("mousemove", () => {
              if (performance.now() >= tooltip.lockUntil.value) {
                 tooltip.measureAndPos(el);
              }
             });
             });
         };
            el.addEventListener("click", () => {
              tooltip.lockUntil.value = performance.now() + 240;
              tooltip.measureAndPos(el);
            });
            el.addEventListener("mouseleave", () => {
              const tipEl = document.querySelector(".skill-tooltip");
              if (tipEl) tipEl.classList.remove("flag-tooltip");
              tooltip.hide();
            });
            el.dataset.flagTipWired = "1";
          });
         }
      });
    };
 
    // ---------- SKINS: tooltips i18n ----------
    const updateSkinTooltips = (norm) => {
      const root = document.querySelector("#skins");
      if (!root) return;
      const slots = root.querySelectorAll(".podium-slot");
      if (!slots.length) return;
 
      slots.forEach((slot) => {
        const title = slot.getAttribute("data-skin-title") || "";
        const pack = slot.getAttribute("data-skin-tooltip-i18n");
        const titleHtml = title
          ? '<div class="skin-tooltip-title" style="margin:0">' +
          title +
          "</div>"
          : "";


         const updateTierAndTags = (norm) => {
         if (pack) {
             const cont = document.querySelector('.class-tags');
          let chosen = "";
             if (!cont) return;
          try {
            const obj = JSON.parse(pack);
            chosen = (
              obj[norm] ||
              obj.pt ||
              obj.en ||
              obj.es ||
              obj.pl ||
              ""
            ).trim();
          } catch (e) { }
          if (chosen) {
             let bodyHtml = chosen
              .replace(/'''([^']+)'''/g, "<b>$1</b>")
              .replace(/\n/g, "<br>");
             bodyHtml = "<b>" + bodyHtml + "</b>";
            slot.setAttribute("data-skin-tooltip", titleHtml + bodyHtml);
          }
          return;
        }


            const tier = cont.querySelector('.class-tag.tier');
        if (title) {
            if (tier) {
          const current = slot.getAttribute("data-skin-tooltip") || "";
                const t = tier.getAttribute('data-tier-' + norm)
          if (!/skin-tooltip-title/.test(current)) {
                    || tier.getAttribute('data-tier-pt')
            let bodyHtml = current;
                    || tier.getAttribute('data-tier-en')
            if (!/^<b>[\s\S]*<\/b>$/.test(bodyHtml)) {
                    || tier.getAttribute('data-tier-es')
              bodyHtml = "<b>" + bodyHtml + "</b>";
                    || tier.getAttribute('data-tier-pl') || '';
                if (t) tier.textContent = t;
             }
             }
            slot.setAttribute("data-skin-tooltip", titleHtml + bodyHtml);
          }
        }
      });
      const hovered = root.querySelector(".podium-slot.hovered");
      const liveTip = document.querySelector(
        '.skin-tooltip[aria-hidden="false"], .skin-tooltip.show'
      );
      if (hovered && liveTip) {
        liveTip.innerHTML = hovered.getAttribute("data-skin-tooltip") || "";
      }
    };
    // ---------- APPLY ----------
    const applyLang = (langFull) => {
      const myReq = ++__langReqSeq;
      const norm = normalizeLang(langFull);
      const langTag = (langFull || "pt-br").toLowerCase();
      markActive(langFull);
      document.documentElement.lang = langTag;
      try {
        localStorage.setItem("glaLang", langTag);
      } catch (e) { }
      updateSkillsTabLabel(norm);
      updateAllSkillDescs(norm);
      updateTierAndTags(norm);
      updateSkinTooltips(norm);
      updateFlagTooltips(norm);


            let tags = [];
      try {
            const pack = cont.getAttribute('data-tags-i18n');
        window.dispatchEvent(
            if (pack) {
          new CustomEvent("gla:langChanged", { detail: { norm } })
                try {
        );
                    const obj = JSON.parse(pack);
      } catch (e) { }
                    const arr = obj?.[norm] || obj?.pt || obj?.en || obj?.es || obj?.pl || [];
 
                    if (Array.isArray(arr)) tags = arr;
      document.body.dataset.suppressSkillPlay = "1";
                } catch (e) { }
      requestAnimationFrame(() => {
            }
        if (myReq !== __langReqSeq) {
          delete document.body.dataset.suppressSkillPlay;
          return;
        }
        const lastIcon = window.__lastActiveSkillIcon;
        if (lastIcon && typeof lastIcon.click === "function") {
          lastIcon.click();
        }
        setTimeout(() => {
          if (myReq === __langReqSeq)
            delete document.body.dataset.suppressSkillPlay;
        }, 120);
      });
    };


            if (!tags.length) return;
    // ---------- BOOT ----------
    const ensureControlsPosition = () => {
      const controls = document.querySelector(".character-header-controls");
      const header = document.querySelector(".character-header");
      if (controls && header && !header.contains(controls)) {
        header.appendChild(controls);
        return true;
      }
      return false;
    };


            cont.querySelectorAll('.class-tag:not(.tier)').forEach(el => el.remove());
    const boot = () => {
            tags.forEach(t => {
      // Tenta mover o character-header-controls para dentro do character-header
                const chip = document.createElement('span');
      // Se não conseguir, tenta novamente após um delay
                chip.className = 'class-tag';
      const tryMove = () => {
                chip.textContent = t;
        const controls = document.querySelector(".character-header-controls");
                cont.appendChild(chip);
        const header = document.querySelector(".character-header");
            });
        if (controls && header) {
         };
          if (!header.contains(controls)) {
            header.appendChild(controls);
          }
          return true;
         }
        return false;
      };


        const updateFlagTooltips = (norm) => {
      if (!tryMove()) {
            const skillsRoot = document.querySelector('#skills');
        let attempts = 0;
            if (!skillsRoot) return;
        const maxAttempts = 20;
            let pack = {};
        const checkInterval = setInterval(() => {
            try {
          attempts++;
                pack = JSON.parse(skillsRoot.dataset.i18nFlags || '{}');
          if (tryMove() || attempts >= maxAttempts) {
            } catch (e) { }
            clearInterval(checkInterval);
            const dict = pack[norm] || pack.pt || {};
          }
            document.querySelectorAll('.skill-flags .skill-flag[data-flag]').forEach(el => {
        }, 100);
                const key = el.getAttribute('data-flag');
      }
                const tip = (dict && dict[key]) || '';
                if (tip) el.setAttribute('aria-label', tip);
            });
        };


        const updateAll = (langFull) => {
      document.addEventListener("click", (ev) => {
            const norm = normalizeLang(langFull);
        const btn = ev.target.closest(".char-flag[data-lang]");
            updateSkillsTabLabel(norm);
        if (!btn) return;
            updateAllSkillDescs(norm);
        ev.preventDefault();
            updateTierAndTags(norm);
        applyLang(btn.dataset.lang || "pt-br");
            updateFlagTooltips(norm);
      });
        };


        // Listen to language changes
      let start = "pt-br";
        document.querySelectorAll('.char-flag[data-lang]').forEach(btn => {
      try {
            btn.addEventListener('click', () => {
        const saved = localStorage.getItem("glaLang");
                const lang = btn.getAttribute('data-lang');
        if (saved) start = saved;
                updateAll(lang);
      } catch (e) { }
            });
      applyLang(start);
        });
    };


        // Initial update
    if (document.readyState === "loading") {
        const currentLang = document.documentElement.lang || 'pt-br';
      document.addEventListener("DOMContentLoaded", boot);
        updateAll(currentLang);
    } else {
     })();
      boot();
     }
  })();
</script>
</script>
<div class="character-header-controls">
  <div id="char-translator" class="char-translator" role="group" aria-label="Language switch">
    <button class="char-flag" data-lang="pt-br" title="Português (Brasil)" aria-label="Português (Brasil)">
      <img src="https://wiki.gla.com.br/images/8/8c/Brazil.png" alt="Português (Brasil)" />
    </button>
    <button class="char-flag" data-lang="en" title="English" aria-label="English">
      <img src="https://wiki.gla.com.br/images/0/0a/Usa.png" alt="English" />
    </button>
    <button class="char-flag" data-lang="es" title="Español" aria-label="Español">
      <img src="https://wiki.gla.com.br/images/5/58/Spain.png" alt="Español" />
    </button>
    <button class="char-flag" data-lang="pl" title="Polski" aria-label="Polski">
      <img src="https://wiki.gla.com.br/images/9/99/Poland.png" alt="Polski" />
    </button>
  </div>
</div>
<style>
  :root {
    --ct-bg: rgba(0, 0, 0, 0.35);
    --ct-bd: rgba(255, 255, 255, 0.15);
    --ct-active: #3b82f6;
    --ct-active-bg: rgba(59, 130, 246, 0.14);
    --ct-active-bd: rgba(59, 130, 246, 0.45);
    --ct-hover-bd: rgba(255, 255, 255, 0.3);
  }
  .character-box .character-header {
    position: relative;
  }
  /* Container para organizar translator e weapon toggle em blocos separados */
  .character-header-controls {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 10;
    align-items: flex-end;
  }
  .char-translator {
    display: flex;
    gap: 6px;
    background: var(--ct-bg);
    padding: 4px;
    border-radius: 8px;
    border: 1px solid var(--ct-bd);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
  }
  .char-flag {
    width: 32px;
    height: 24px;
    padding: 0;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.06);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    overflow: hidden;
    transition: transform 0.08s ease, border-color 0.15s ease,
      background 0.15s ease, outline-color 0.15s ease;
    outline: 2px solid transparent;
    box-sizing: border-box;
  }
  .char-flag:hover {
    border-color: var(--ct-hover-bd);
    transform: translateY(-1px);
  }
  .char-flag:focus-visible {
    outline-color: var(--ct-active);
    outline-offset: 2px;
  }
  .char-flag img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    pointer-events: none;
  }
  .char-flag.active {
    outline-color: var(--ct-active);
    background: var(--ct-active-bg);
    border-color: var(--ct-active-bd);
  }
  @media (max-width: 600px) {
    .character-header-controls {
      top: 6px;
      right: 6px;
      gap: 6px;
    }
    .char-translator {
      gap: 4px;
      padding: 3px;
    }
    .char-flag {
      width: 28px;
      height: 20px;
      padding: 0;
      border-radius: 5px;
    }
  }
</style>

Edição atual tal como às 14h18min de 22 de janeiro de 2026

<script>

 (() => {
   let __langReqSeq = 0;
   // ---------- helpers ----------
   const normalizeLang = (s) => {
     s = (s || "").toLowerCase();
     if (s === "pt-br" || s === "pt_br" || s === "ptbr") return "pt";
     return s.split("-")[0] || "pt";
   };
   const markActive = (langFull) => {
     const lang = (langFull || "pt-br").toLowerCase();
     document.querySelectorAll(".char-flag[data-lang]").forEach((b) => {
       b.classList.toggle("active", b.dataset.lang === lang);
     });
   };
   const updateSkillsTabLabel = (norm) => {
     const map = {
       en: "Skills",
       pt: "Habilidades",
       es: "Habilidades",
       pl: "Umiejętności",
     };
     const btn =
       document.querySelector('.character-tabs .tab-btn[data-tab="skills"]') ||
       Array.from(document.querySelectorAll(".character-tabs .tab-btn")).find(
         (b) => /skill|habil|umiej/i.test(b.textContent || "")
       );
     if (btn) btn.textContent = map[norm] || map.pt;
   };
   // ---------- skills ----------
   const pickDescFor = (icon, norm) => {
     const keyMap = { pt: "descPt", en: "descEn", es: "descEs", pl: "descPl" };
     const order = [
       keyMap[norm],
       "descPt",
       "descEn",
       "descEs",
       "descPl",
     ].filter(Boolean);
     for (const k of order) {
       const v = (icon.dataset[k] || "").trim();
       if (v) return v;
     }
     return "";
   };
   const updateAllSkillDescs = (norm) => {
     document.querySelectorAll(".icon-bar .skill-icon").forEach((icon) => {
       icon.dataset.desc = pickDescFor(icon, norm);
     });
   };
   // ---------- tier & tags ----------
   const updateTierAndTags = (norm) => {
     const cont = document.querySelector(".class-tags");
     if (!cont) return;
     const tier = cont.querySelector(".class-tag.tier");
     if (tier) {
       const t =
         tier.getAttribute("data-tier-" + norm) ||
         tier.getAttribute("data-tier-pt") ||
         tier.getAttribute("data-tier-en") ||
         tier.getAttribute("data-tier-es") ||
         tier.getAttribute("data-tier-pl") ||
         "";
       if (t) tier.textContent = t;
     }
     let tags = [];
     const pack = cont.getAttribute("data-tags-i18n");
     if (pack) {
       try {
         const obj = JSON.parse(pack);
         const arr =
           obj?.[norm] || obj?.pt || obj?.en || obj?.es || obj?.pl || [];
         if (Array.isArray(arr)) tags = arr;
       } catch (e) { }
     }
     if (!tags.length) {
       const raw =
         cont.getAttribute("data-tags-" + norm) ||
         cont.getAttribute("data-tags-pt") ||
         cont.getAttribute("data-tags-en") ||
         cont.getAttribute("data-tags-es") ||
         cont.getAttribute("data-tags-pl") ||
         "";
       if (raw) {
         try {
           const maybe = JSON.parse(raw);
           if (Array.isArray(maybe)) tags = maybe;
         } catch (e) { }
         if (!tags.length && typeof raw === "string") {
           tags = raw
             .split(",")
             .map((s) => s.trim())
             .filter(Boolean);
         }
       }
     }
     if (!tags.length) return;
     // Tags invisíveis (não devem ser exibidas na wiki)
     const HIDDEN_TAGS = {
       mulher: true,
       woman: true,
       mujer: true,
       kobieta: true,
     };
     cont
       .querySelectorAll(".class-tag:not(.tier)")
       .forEach((el) => el.remove());
     tags.forEach((t) => {
       // Filtra tags invisíveis
       const normalized = (t || "").toLowerCase().trim();
       if (HIDDEN_TAGS[normalized]) return;
       const chip = document.createElement("span");
       chip.className = "class-tag";
       chip.textContent = t;
       cont.appendChild(chip);
     });
   };
   // ---------- FLAGS: tooltips i18n ----------
   const updateFlagTooltips = (norm) => {
     const skillsRoot = document.querySelector("#skills");
     if (!skillsRoot) return;
     let pack = {};
     try {
       pack = JSON.parse(skillsRoot.dataset.i18nFlags || "{}");
     } catch (e) { }
     const dict = pack[norm] || pack.pt || {};
     const tooltip = window.__globalSkillTooltip;
     if (!tooltip) return;
     document
       .querySelectorAll(".skill-flags .skill-flag[data-flag]")
       .forEach((el) => {
         delete el.dataset.flagTipWired;
       });
     const descBoxes = document.querySelectorAll(".desc-box");
     descBoxes.forEach((box) => {
       if (box.querySelector(".skill-flags")) {
         const flags = box.querySelectorAll(
           ".skill-flags .skill-flag[data-flag]"
         );
         flags.forEach((el) => {
           const key = el.getAttribute("data-flag");
           const tip = (dict && dict[key]) || "";
           if (!tip) return;
           delete el.dataset.flagTipWired;
           el.setAttribute("aria-label", tip);
           if (el.hasAttribute("title")) el.removeAttribute("title");
           el.addEventListener("mouseenter", () => {
             const tipEl = document.querySelector(".skill-tooltip");
             if (tipEl) tipEl.classList.add("flag-tooltip");
             tooltip.show(el, tip);
           });
           el.addEventListener("mousemove", () => {
             if (performance.now() >= tooltip.lockUntil.value) {
               tooltip.measureAndPos(el);
             }
           });
           el.addEventListener("click", () => {
             tooltip.lockUntil.value = performance.now() + 240;
             tooltip.measureAndPos(el);
           });
           el.addEventListener("mouseleave", () => {
             const tipEl = document.querySelector(".skill-tooltip");
             if (tipEl) tipEl.classList.remove("flag-tooltip");
             tooltip.hide();
           });
           el.dataset.flagTipWired = "1";
         });
       }
     });
   };
   // ---------- SKINS: tooltips i18n ----------
   const updateSkinTooltips = (norm) => {
     const root = document.querySelector("#skins");
     if (!root) return;
     const slots = root.querySelectorAll(".podium-slot");
     if (!slots.length) return;
     slots.forEach((slot) => {
       const title = slot.getAttribute("data-skin-title") || "";
       const pack = slot.getAttribute("data-skin-tooltip-i18n");
       const titleHtml = title

 ? '

' +
         title +
"

"

         : "";
       if (pack) {
         let chosen = "";
         try {
           const obj = JSON.parse(pack);
           chosen = (
             obj[norm] ||
             obj.pt ||
             obj.en ||
             obj.es ||
             obj.pl ||
             ""
           ).trim();
         } catch (e) { }
         if (chosen) {
           let bodyHtml = chosen
             .replace(/([^']+)/g, "$1")
             .replace(/\n/g, "
"); bodyHtml = "" + bodyHtml + ""; slot.setAttribute("data-skin-tooltip", titleHtml + bodyHtml); } return; }
       if (title) {
         const current = slot.getAttribute("data-skin-tooltip") || "";
         if (!/skin-tooltip-title/.test(current)) {
           let bodyHtml = current;
           if (!/^[\s\S]*<\/b>$/.test(bodyHtml)) {
             bodyHtml = "" + bodyHtml + "";
           }
           slot.setAttribute("data-skin-tooltip", titleHtml + bodyHtml);
         }
       }
     });
     const hovered = root.querySelector(".podium-slot.hovered");
     const liveTip = document.querySelector(
       '.skin-tooltip[aria-hidden="false"], .skin-tooltip.show'
     );
     if (hovered && liveTip) {
       liveTip.innerHTML = hovered.getAttribute("data-skin-tooltip") || "";
     }
   };
   // ---------- APPLY ----------
   const applyLang = (langFull) => {
     const myReq = ++__langReqSeq;
     const norm = normalizeLang(langFull);
     const langTag = (langFull || "pt-br").toLowerCase();
     markActive(langFull);
     document.documentElement.lang = langTag;
     try {
       localStorage.setItem("glaLang", langTag);
     } catch (e) { }
     updateSkillsTabLabel(norm);
     updateAllSkillDescs(norm);
     updateTierAndTags(norm);
     updateSkinTooltips(norm);
     updateFlagTooltips(norm);
     try {
       window.dispatchEvent(
         new CustomEvent("gla:langChanged", { detail: { norm } })
       );
     } catch (e) { }
     document.body.dataset.suppressSkillPlay = "1";
     requestAnimationFrame(() => {
       if (myReq !== __langReqSeq) {
         delete document.body.dataset.suppressSkillPlay;
         return;
       }
       const lastIcon = window.__lastActiveSkillIcon;
       if (lastIcon && typeof lastIcon.click === "function") {
         lastIcon.click();
       }
       setTimeout(() => {
         if (myReq === __langReqSeq)
           delete document.body.dataset.suppressSkillPlay;
       }, 120);
     });
   };
   // ---------- BOOT ----------
   const ensureControlsPosition = () => {
     const controls = document.querySelector(".character-header-controls");
     const header = document.querySelector(".character-header");
     if (controls && header && !header.contains(controls)) {
       header.appendChild(controls);
       return true;
     }
     return false;
   };
   const boot = () => {
     // Tenta mover o character-header-controls para dentro do character-header
     // Se não conseguir, tenta novamente após um delay
     const tryMove = () => {
       const controls = document.querySelector(".character-header-controls");
       const header = document.querySelector(".character-header");
       if (controls && header) {
         if (!header.contains(controls)) {
           header.appendChild(controls);
         }
         return true;
       }
       return false;
     };
     if (!tryMove()) {
       let attempts = 0;
       const maxAttempts = 20;
       const checkInterval = setInterval(() => {
         attempts++;
         if (tryMove() || attempts >= maxAttempts) {
           clearInterval(checkInterval);
         }
       }, 100);
     }
     document.addEventListener("click", (ev) => {
       const btn = ev.target.closest(".char-flag[data-lang]");
       if (!btn) return;
       ev.preventDefault();
       applyLang(btn.dataset.lang || "pt-br");
     });
     let start = "pt-br";
     try {
       const saved = localStorage.getItem("glaLang");
       if (saved) start = saved;
     } catch (e) { }
     applyLang(start);
   };
   if (document.readyState === "loading") {
     document.addEventListener("DOMContentLoaded", boot);
   } else {
     boot();
   }
 })();

</script>

   <button class="char-flag" data-lang="pt-br" title="Português (Brasil)" aria-label="Português (Brasil)">
     <img src="https://wiki.gla.com.br/images/8/8c/Brazil.png" alt="Português (Brasil)" />
   </button>
   <button class="char-flag" data-lang="en" title="English" aria-label="English">
     <img src="https://wiki.gla.com.br/images/0/0a/Usa.png" alt="English" />
   </button>
   <button class="char-flag" data-lang="es" title="Español" aria-label="Español">
     <img src="https://wiki.gla.com.br/images/5/58/Spain.png" alt="Español" />
   </button>
   <button class="char-flag" data-lang="pl" title="Polski" aria-label="Polski">
     <img src="https://wiki.gla.com.br/images/9/99/Poland.png" alt="Polski" />
   </button>

<style>

 :root {
   --ct-bg: rgba(0, 0, 0, 0.35);
   --ct-bd: rgba(255, 255, 255, 0.15);
   --ct-active: #3b82f6;
   --ct-active-bg: rgba(59, 130, 246, 0.14);
   --ct-active-bd: rgba(59, 130, 246, 0.45);
   --ct-hover-bd: rgba(255, 255, 255, 0.3);
 }
 .character-box .character-header {
   position: relative;
 }
 /* Container para organizar translator e weapon toggle em blocos separados */
 .character-header-controls {
   position: absolute;
   top: 8px;
   right: 8px;
   display: flex;
   flex-direction: column;
   gap: 8px;
   z-index: 10;
   align-items: flex-end;
 }
 .char-translator {
   display: flex;
   gap: 6px;
   background: var(--ct-bg);
   padding: 4px;
   border-radius: 8px;
   border: 1px solid var(--ct-bd);
   -webkit-backdrop-filter: blur(2px);
   backdrop-filter: blur(2px);
   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
 }
 .char-flag {
   width: 32px;
   height: 24px;
   padding: 0;
   border-radius: 6px;
   border: 1px solid rgba(255, 255, 255, 0.18);
   background: rgba(255, 255, 255, 0.06);
   display: flex;
   align-items: center;
   justify-content: center;
   cursor: pointer;
   overflow: hidden;
   transition: transform 0.08s ease, border-color 0.15s ease,
     background 0.15s ease, outline-color 0.15s ease;
   outline: 2px solid transparent;
   box-sizing: border-box;
 }
 .char-flag:hover {
   border-color: var(--ct-hover-bd);
   transform: translateY(-1px);
 }
 .char-flag:focus-visible {
   outline-color: var(--ct-active);
   outline-offset: 2px;
 }
 .char-flag img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
   pointer-events: none;
 }
 .char-flag.active {
   outline-color: var(--ct-active);
   background: var(--ct-active-bg);
   border-color: var(--ct-active-bd);
 }
 @media (max-width: 600px) {
   .character-header-controls {
     top: 6px;
     right: 6px;
     gap: 6px;
   }
   .char-translator {
     gap: 4px;
     padding: 3px;
   }
   .char-flag {
     width: 28px;
     height: 20px;
     padding: 0;
     border-radius: 5px;
   }
 }

</style>