Mudanças entre as edições de "Widget:Character.Translator"
Ir para navegação
Ir para pesquisar
m (add flag icons) |
m |
||
| (2 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
| Linha 1: | Linha 1: | ||
<!-- CHARACTER TRANSLATOR SYSTEM --> | |||
<script> | <script> | ||
(() => { | (() => { | ||
| Linha 20: | Linha 21: | ||
const map = { en: 'Skills', pt: 'Habilidades', es: 'Habilidades', pl: 'Umiejętności' }; | const map = { en: 'Skills', pt: 'Habilidades', es: 'Habilidades', pl: 'Umiejętności' }; | ||
const btn = document.querySelector('.character-tabs .tab-btn[data-tab="skills"]') | const btn = document.querySelector('.character-tabs .tab-btn[data-tab="skills"]') | ||
|| Array.from(document.querySelectorAll('.character-tabs .tab-btn')) | || 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; | if (btn) btn.textContent = map[norm] || map.pt; | ||
}; | }; | ||
| Linha 40: | Linha 40: | ||
icon.dataset.desc = pickDescFor(icon, norm); | icon.dataset.desc = pickDescFor(icon, norm); | ||
}); | }); | ||
}; | }; | ||
| Linha 48: | Linha 47: | ||
if (!cont) return; | if (!cont) return; | ||
const tier = cont.querySelector('.class-tag.tier'); | const tier = cont.querySelector('.class-tag.tier'); | ||
if (tier) { | if (tier) { | ||
| Linha 59: | Linha 57: | ||
} | } | ||
let tags = []; | let tags = []; | ||
const pack = cont.getAttribute('data-tags-i18n'); | const pack = cont.getAttribute('data-tags-i18n'); | ||
if (pack) { | if (pack) { | ||
| Linha 72: | Linha 67: | ||
} | } | ||
if (!tags.length) { | if (!tags.length) { | ||
const raw = cont.getAttribute('data-tags-' + norm) | const raw = cont.getAttribute('data-tags-' + norm) | ||
| Linha 81: | Linha 75: | ||
|| ''; | || ''; | ||
if (raw) { | if (raw) { | ||
try { const maybe = JSON.parse(raw); if (Array.isArray(maybe)) tags = maybe; } catch (e) { } | try { | ||
const maybe = JSON.parse(raw); | |||
if (Array.isArray(maybe)) tags = maybe; | |||
} catch (e) { } | |||
if (!tags.length && typeof raw === 'string') { | if (!tags.length && typeof raw === 'string') { | ||
tags = raw.split(',').map(s => s.trim()).filter(Boolean); | tags = raw.split(',').map(s => s.trim()).filter(Boolean); | ||
| Linha 88: | Linha 85: | ||
} | } | ||
if (!tags.length) return; | if (!tags.length) return; | ||
cont.querySelectorAll('.class-tag:not(.tier)').forEach(el => el.remove()); | cont.querySelectorAll('.class-tag:not(.tier)').forEach(el => el.remove()); | ||
tags.forEach(t => { | tags.forEach(t => { | ||
| Linha 106: | Linha 101: | ||
if (!skillsRoot) return; | if (!skillsRoot) return; | ||
let pack = {}; | let pack = {}; | ||
try { | try { pack = JSON.parse(skillsRoot.dataset.i18nFlags || '{}'); } catch (e) { } | ||
const dict = pack[norm] || pack.pt || {}; | const dict = pack[norm] || pack.pt || {}; | ||
const tooltip = window.__globalSkillTooltip; | |||
if (!tooltip) return; | |||
document.querySelectorAll('.skill-flags .skill-flag[data-flag]').forEach(el => { | document.querySelectorAll('.skill-flags .skill-flag[data-flag]').forEach(el => { | ||
const key = el.getAttribute('data-flag'); | 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'; | |||
}); | |||
} | } | ||
}); | }); | ||
| Linha 124: | Linha 151: | ||
const root = document.querySelector('#skins'); | const root = document.querySelector('#skins'); | ||
if (!root) return; | if (!root) return; | ||
const cards = root.querySelectorAll('.skin-card'); | const cards = root.querySelectorAll('.skin-card'); | ||
if (!cards.length) return; | if (!cards.length) return; | ||
| Linha 131: | Linha 157: | ||
const title = card.getAttribute('data-skin-title') || ''; | const title = card.getAttribute('data-skin-title') || ''; | ||
const pack = card.getAttribute('data-skin-tooltip-i18n'); | const pack = card.getAttribute('data-skin-tooltip-i18n'); | ||
const titleHtml = title ? ('<div class="skin-tooltip-title" style="margin:0">' + title + '</div>') : ''; | const titleHtml = title ? ('<div class="skin-tooltip-title" style="margin:0">' + title + '</div>') : ''; | ||
| Linha 141: | Linha 165: | ||
chosen = (obj[norm] || obj.pt || obj.en || obj.es || obj.pl || '').trim(); | chosen = (obj[norm] || obj.pt || obj.en || obj.es || obj.pl || '').trim(); | ||
} catch (e) { } | } catch (e) { } | ||
if (chosen) { | if (chosen) { | ||
let bodyHtml = chosen.replace(/'''([^']+)'''/g, '<b>$1</b>').replace(/\n/g, '<br>'); | let bodyHtml = chosen.replace(/'''([^']+)'''/g, '<b>$1</b>').replace(/\n/g, '<br>'); | ||
bodyHtml = '<b>' + bodyHtml + '</b>'; | bodyHtml = '<b>' + bodyHtml + '</b>'; | ||
card.setAttribute('data-skin-tooltip', titleHtml + bodyHtml); | card.setAttribute('data-skin-tooltip', titleHtml + bodyHtml); | ||
} | } | ||
| Linha 150: | Linha 173: | ||
} | } | ||
if (title) { | if (title) { | ||
const current = card.getAttribute('data-skin-tooltip') || ''; | const current = card.getAttribute('data-skin-tooltip') || ''; | ||
if (!/skin-tooltip-title/.test(current)) { | if (!/skin-tooltip-title/.test(current)) { | ||
let bodyHtml = current; | let bodyHtml = current; | ||
| Linha 164: | Linha 185: | ||
}); | }); | ||
const hovered = root.querySelector('.skin-card.hovered'); | const hovered = root.querySelector('.skin-card.hovered'); | ||
const liveTip = root.querySelector('.skin-tooltip[aria-hidden="false"], .skin-tooltip.show'); | const liveTip = root.querySelector('.skin-tooltip[aria-hidden="false"], .skin-tooltip.show'); | ||
| Linha 185: | Linha 205: | ||
updateAllSkillDescs(norm); | updateAllSkillDescs(norm); | ||
updateTierAndTags(norm); | updateTierAndTags(norm); | ||
updateSkinTooltips(norm); | updateSkinTooltips(norm); | ||
updateFlagTooltips(norm); | updateFlagTooltips(norm); | ||
try { window.dispatchEvent(new CustomEvent('gla:langChanged', { detail: { norm } })); } catch (e) { } | try { | ||
window.dispatchEvent(new CustomEvent('gla:langChanged', { detail: { norm } })); | |||
} catch (e) { } | |||
document.body.dataset.suppressSkillPlay = '1'; | document.body.dataset.suppressSkillPlay = '1'; | ||
requestAnimationFrame(() => { | requestAnimationFrame(() => { | ||
if (myReq !== __langReqSeq) { delete document.body.dataset.suppressSkillPlay; return; } | if (myReq !== __langReqSeq) { | ||
delete document.body.dataset.suppressSkillPlay; | |||
return; | |||
} | |||
const lastIcon = window.__lastActiveSkillIcon; | const lastIcon = window.__lastActiveSkillIcon; | ||
if (lastIcon && typeof lastIcon.click === 'function') { | if (lastIcon && typeof lastIcon.click === 'function') { | ||
lastIcon.click(); | lastIcon.click(); | ||
} | } | ||
setTimeout(() => { if (myReq === __langReqSeq) delete document.body.dataset.suppressSkillPlay; }, 120); | setTimeout(() => { | ||
if (myReq === __langReqSeq) delete document.body.dataset.suppressSkillPlay; | |||
}, 120); | |||
}); | }); | ||
}; | }; | ||
| Linha 204: | Linha 230: | ||
// ---------- BOOT ---------- | // ---------- BOOT ---------- | ||
const boot = () => { | const boot = () => { | ||
document.addEventListener('click', (ev) => { | document.addEventListener('click', (ev) => { | ||
const btn = ev.target.closest('.char-flag[data-lang]'); | const btn = ev.target.closest('.char-flag[data-lang]'); | ||
| Linha 212: | Linha 237: | ||
}); | }); | ||
let start = 'pt-br'; | let start = 'pt-br'; | ||
try { | try { | ||
| Linha 228: | Linha 252: | ||
})(); | })(); | ||
</script> | </script> | ||
<div id="char-translator" class="char-translator" role="group" aria-label="Language switch"> | <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)"> | <button class="char-flag" data-lang="pt-br" title="Português (Brasil)" aria-label="Português (Brasil)"> | ||
| Linha 244: | Linha 266: | ||
</button> | </button> | ||
</div> | </div> | ||
<style> | <style> | ||
:root { | :root { | ||
| Linha 250: | Linha 271: | ||
--ct-bd: rgba(255, 255, 255, .15); | --ct-bd: rgba(255, 255, 255, .15); | ||
--ct-active: #3b82f6; | --ct-active: #3b82f6; | ||
--ct-active-bg: rgba(59, 130, 246, .14); | --ct-active-bg: rgba(59, 130, 246, .14); | ||
--ct-active-bd: rgba(59, 130, 246, .45); | --ct-active-bd: rgba(59, 130, 246, .45); | ||
| Linha 271: | Linha 291: | ||
border-radius: 8px; | border-radius: 8px; | ||
border: 1px solid var(--ct-bd); | border: 1px solid var(--ct-bd); | ||
-webkit-backdrop-filter: blur(2px); | |||
backdrop-filter: blur(2px); | backdrop-filter: blur(2px); | ||
box-shadow: 0 4px 12px rgba(0, 0, 0, .25); | box-shadow: 0 4px 12px rgba(0, 0, 0, .25); | ||
} | } | ||
| Linha 310: | Linha 330: | ||
} | } | ||
.char-flag.active { | .char-flag.active { | ||
outline-color: var(--ct-active); | outline-color: var(--ct-active); | ||
Edição atual tal como às 17h10min de 30 de novembro de 2025
<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;
cont.querySelectorAll('.class-tag:not(.tier)').forEach(el => el.remove());
tags.forEach(t => {
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 cards = root.querySelectorAll('.skin-card');
if (!cards.length) return;
cards.forEach(card => {
const title = card.getAttribute('data-skin-title') || ;
const pack = card.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 + '';
card.setAttribute('data-skin-tooltip', titleHtml + bodyHtml);
}
return;
}
if (title) {
const current = card.getAttribute('data-skin-tooltip') || ;
if (!/skin-tooltip-title/.test(current)) {
let bodyHtml = current;
if (!/^[\s\S]*<\/b>$/.test(bodyHtml)) {
bodyHtml = '' + bodyHtml + '';
}
card.setAttribute('data-skin-tooltip', titleHtml + bodyHtml);
}
}
});
const hovered = root.querySelector('.skin-card.hovered');
const liveTip = root.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 boot = () => {
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, .35);
--ct-bd: rgba(255, 255, 255, .15);
--ct-active: #3b82f6;
--ct-active-bg: rgba(59, 130, 246, .14);
--ct-active-bd: rgba(59, 130, 246, .45);
--ct-hover-bd: rgba(255, 255, 255, .30);
}
.character-box .character-header {
position: relative;
}
.char-translator {
position: absolute;
top: 8px;
right: 8px;
display: flex;
gap: 6px;
z-index: 10;
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, .25);
}
.char-flag {
width: 32px;
height: 24px;
padding: 0;
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, .18);
background: rgba(255, 255, 255, .06);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
overflow: hidden;
transition: transform .08s ease, border-color .15s ease, background .15s ease, outline-color .15s ease;
outline: 2px solid transparent;
}
.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) {
.char-translator {
top: 6px;
right: 6px;
gap: 4px;
padding: 3px;
}
.char-flag {
width: 28px;
height: 20px;
border-radius: 5px;
}
}
</style>