Skip to content

Commit 20afead

Browse files
feat: Introduce translation page with new CSS, JavaScript, and a GitHub Actions compile workflow.
1 parent 74b0a2f commit 20afead

File tree

3 files changed

+207
-1
lines changed

3 files changed

+207
-1
lines changed

.github/workflows/compile-on-merge.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,7 @@ jobs:
134134
135135
Glossário usado: rodrigomiquilino/wwm_brasileiro/docs/glossary.json
136136
Compilado automaticamente via GitHub Actions"
137-
git push
137+
138+
# Pull com rebase para evitar conflitos de race condition
139+
git pull --rebase origin main || true
140+
git push origin main

docs/assets/css/translate.css

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,3 +2799,141 @@ footer a {
27992799
from { opacity: 0; transform: translateY(-5px); }
28002800
to { opacity: 1; transform: translateY(0); }
28012801
}
2802+
2803+
/* ========== ADMIN MODAL GLOSSARY HINTS ========== */
2804+
.admin-glossary-hints {
2805+
background: rgba(124, 58, 237, 0.08);
2806+
border: 1px solid rgba(124, 58, 237, 0.2);
2807+
border-radius: 10px;
2808+
padding: 0.75rem;
2809+
margin: 0.75rem 0;
2810+
}
2811+
2812+
.admin-glossary-header {
2813+
display: flex;
2814+
align-items: center;
2815+
gap: 0.5rem;
2816+
font-size: 0.8rem;
2817+
font-weight: 600;
2818+
color: #a78bfa;
2819+
margin-bottom: 0.5rem;
2820+
}
2821+
2822+
.admin-glossary-header i {
2823+
font-size: 0.9rem;
2824+
}
2825+
2826+
.admin-glossary-terms {
2827+
display: flex;
2828+
flex-direction: column;
2829+
gap: 0.5rem;
2830+
}
2831+
2832+
.admin-glossary-term {
2833+
background: rgba(0, 0, 0, 0.2);
2834+
border-left: 3px solid var(--term-color, #c9a227);
2835+
border-radius: 6px;
2836+
padding: 0.5rem 0.75rem;
2837+
}
2838+
2839+
.admin-glossary-term-header {
2840+
display: flex;
2841+
align-items: center;
2842+
gap: 0.5rem;
2843+
margin-bottom: 0.25rem;
2844+
}
2845+
2846+
.admin-glossary-original {
2847+
font-weight: 600;
2848+
color: var(--text-primary);
2849+
font-size: 0.85rem;
2850+
}
2851+
2852+
.admin-glossary-chinese {
2853+
font-size: 0.75rem;
2854+
color: var(--text-muted);
2855+
opacity: 0.8;
2856+
}
2857+
2858+
.admin-glossary-translation {
2859+
display: flex;
2860+
align-items: center;
2861+
gap: 0.4rem;
2862+
font-size: 0.8rem;
2863+
color: var(--text-secondary);
2864+
margin-bottom: 0.25rem;
2865+
}
2866+
2867+
.admin-glossary-translation i.translate {
2868+
color: var(--success);
2869+
}
2870+
2871+
.admin-glossary-translation i.no-translate {
2872+
color: #ef4444;
2873+
}
2874+
2875+
.admin-glossary-variable {
2876+
display: flex;
2877+
align-items: center;
2878+
gap: 0.4rem;
2879+
}
2880+
2881+
.admin-var-code {
2882+
font-family: 'JetBrains Mono', monospace;
2883+
font-size: 0.7rem;
2884+
background: rgba(201, 162, 39, 0.15);
2885+
padding: 0.2rem 0.4rem;
2886+
border-radius: 4px;
2887+
color: var(--gold-primary);
2888+
}
2889+
2890+
.admin-copy-var-btn {
2891+
display: inline-flex;
2892+
align-items: center;
2893+
justify-content: center;
2894+
width: 22px;
2895+
height: 22px;
2896+
padding: 0;
2897+
background: transparent;
2898+
border: 1px solid rgba(255, 255, 255, 0.1);
2899+
border-radius: 4px;
2900+
color: var(--text-muted);
2901+
font-size: 0.65rem;
2902+
cursor: pointer;
2903+
transition: all 0.2s ease;
2904+
}
2905+
2906+
.admin-copy-var-btn:hover {
2907+
background: rgba(201, 162, 39, 0.15);
2908+
border-color: var(--gold-primary);
2909+
color: var(--gold-primary);
2910+
}
2911+
2912+
.admin-glossary-link {
2913+
display: inline-flex;
2914+
align-items: center;
2915+
justify-content: center;
2916+
width: 22px;
2917+
height: 22px;
2918+
background: transparent;
2919+
border: 1px solid rgba(255, 255, 255, 0.1);
2920+
border-radius: 4px;
2921+
color: var(--text-muted);
2922+
font-size: 0.6rem;
2923+
text-decoration: none;
2924+
transition: all 0.2s ease;
2925+
}
2926+
2927+
.admin-glossary-link:hover {
2928+
background: rgba(124, 58, 237, 0.15);
2929+
border-color: #a78bfa;
2930+
color: #a78bfa;
2931+
}
2932+
2933+
.admin-glossary-context {
2934+
font-size: 0.7rem;
2935+
color: var(--text-muted);
2936+
font-style: italic;
2937+
margin-top: 0.25rem;
2938+
opacity: 0.8;
2939+
}

docs/assets/js/translate.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,70 @@ function findGlossaryTerms(text) {
580580
return found;
581581
}
582582

583+
// Renderiza hints do glossário para o modal de revisão do admin
584+
// Versão compacta similar ao modal de tradução
585+
function renderAdminGlossaryHints(originalText) {
586+
if (!glossaryData || !originalText) return '';
587+
588+
const terms = findGlossaryTerms(originalText);
589+
if (terms.length === 0) return '';
590+
591+
const termsHtml = terms.map(term => {
592+
const category = glossaryData?.categories?.[term.category];
593+
const categoryColor = category?.color || '#c9a227';
594+
const statusClass = term.doNotTranslate ? 'no-translate' : 'translate';
595+
const statusIcon = term.doNotTranslate ? 'fa-ban' : 'fa-check';
596+
const varName = `{{${term.id.toUpperCase().replace(/-/g, '_')}}}`;
597+
598+
return `
599+
<div class="admin-glossary-term" style="--term-color: ${categoryColor}">
600+
<div class="admin-glossary-term-header">
601+
<span class="admin-glossary-original">${escapeHtml(term.original)}</span>
602+
${term.chinese ? `<span class="admin-glossary-chinese">${escapeHtml(term.chinese)}</span>` : ''}
603+
</div>
604+
<div class="admin-glossary-translation">
605+
<i class="fas ${statusIcon} ${statusClass}"></i>
606+
${escapeHtml(term.translation)}
607+
</div>
608+
<div class="admin-glossary-variable">
609+
<code class="admin-var-code">${varName}</code>
610+
<button type="button" class="admin-copy-var-btn" onclick="copyVarToClipboard('${varName}', this)" title="Copiar variável">
611+
<i class="fas fa-copy"></i>
612+
</button>
613+
<a href="glossary#${encodeURIComponent(term.id)}" class="admin-glossary-link" target="_blank" title="Ver no Glossário">
614+
<i class="fas fa-external-link-alt"></i>
615+
</a>
616+
</div>
617+
${term.context ? `<div class="admin-glossary-context">${escapeHtml(term.context)}</div>` : ''}
618+
</div>
619+
`;
620+
}).join('');
621+
622+
return `
623+
<div class="admin-glossary-hints">
624+
<div class="admin-glossary-header">
625+
<i class="fas fa-book"></i> Glossário (${terms.length} termo${terms.length !== 1 ? 's' : ''})
626+
</div>
627+
<div class="admin-glossary-terms">
628+
${termsHtml}
629+
</div>
630+
</div>
631+
`;
632+
}
633+
634+
// Copia variável para clipboard no modal admin
635+
function copyVarToClipboard(varName, btn) {
636+
navigator.clipboard.writeText(varName).then(() => {
637+
const originalIcon = btn.innerHTML;
638+
btn.innerHTML = '<i class="fas fa-check"></i>';
639+
btn.style.color = 'var(--success)';
640+
setTimeout(() => {
641+
btn.innerHTML = originalIcon;
642+
btn.style.color = '';
643+
}, 1000);
644+
});
645+
}
646+
583647
// ========== NPC DETECTION ==========
584648
// Lista de NPCs do glossário (category='npcs' com doNotTranslate=true)
585649
let npcNames = new Set();
@@ -2642,6 +2706,7 @@ async function openAdminIssueModal(issueNumber) {
26422706
<div class="admin-text-label"><i class="fas fa-globe"></i> Original (EN)</div>
26432707
<div class="admin-text-content original">${escapeHtml(originalText)}</div>
26442708
</div>
2709+
${renderAdminGlossaryHints(originalText)}
26452710
${hasCurrentTranslation ? `
26462711
<div class="admin-text-row">
26472712
<div class="admin-text-label"><i class="fas fa-check-circle" style="color: var(--success);"></i> Já Traduzido (PT-BR)</div>

0 commit comments

Comments
 (0)