🇯🇵 Aprenda Japonês com Nosso Curso e Ferramentas! Acesse Agora!

Extra – Gerador de Frases em Japonês

Utilize nossa ferramenta abaixo para gerar frases em japonês com significados, perfeito para adicionar ao Anki. (Pode levar uns 30 segundos para gerar as 5 frases). [mwai-form-container id=”hyrvuvcch” theme=”ChatGPT”]
) { window.audioAtual = window.cacheVoicevox[texto]; window.audioAtual.currentTime = 0; let playPromise = window.audioAtual.play(); if (playPromise !== undefined) { playPromise.catch(e => { if (e.name !== ‘AbortError’) usarTTSNativo(texto); }); } return; } // Se chegou aqui, é a PRIMEIRA vez. Mostra a ampulheta! if (btnElement) btnElement.innerHTML = “⏳”; const speakerId = Math.floor(Math.random() * 34) + 1; const urlVoicevox = `https://api.tts.quest/v3/voicevox/synthesis?text=${encodeURIComponent(texto)}&speaker=${speakerId}`; try { const response = await fetch(urlVoicevox); if (!response.ok) throw new Error(“Erro na API”); const data = await response.json(); if (data.success && data.audioStatusUrl && data.mp3DownloadUrl) { // ESPERA O SERVIDOR TERMINAR (Polling de 0.5s) let isReady = false; let tentativas = 0; while (!isReady && tentativas < 20) { // Tenta por 10 segundos no máx const statusRes = await fetch(data.audioStatusUrl); const statusData = await statusRes.json(); if (statusData.isAudioReady) { isReady = true; } else { await new Promise(r => setTimeout(r, 500)); tentativas++; } } if (!isReady) throw new Error(“Servidor sobrecarregado”); // Agora sabemos que o áudio realmente existe! const novoAudio = new Audio(data.mp3DownloadUrl); novoAudio.playbackRate = 0.9; // Salva o áudio perfeito no cache window.cacheVoicevox[texto] = novoAudio; window.audioAtual = novoAudio; let playPromise = window.audioAtual.play(); if (playPromise !== undefined) { playPromise.catch(e => { if (e.name !== ‘AbortError’) usarTTSNativo(texto); }); } // Áudio começou a tocar, restaura o botão para Play if (btnElement) btnElement.innerHTML = “▷”; } else { throw new Error(“Resposta inválida da API”); } } catch (error) { console.warn(“Erro no Voicevox, fallback para Nativo:”, error); usarTTSNativo(texto); } } document.addEventListener(“mouseup”, function () { const selecao = window.getSelection().toString(); const textoLimpo = selecao.trim(); if (textoLimpo) { let temJap = false; let temRomaji = false; if (/[\u3040-\u30ff\u4e00-\u9faf]/.test(textoLimpo)) { temJap = true; } if (/[a-zA-ZáàâãéèêíïóôõöúçñÁÀÂÃÉÈÊÍÏÓÔÕÖÚÇÑ]/.test(textoLimpo)) { temRomaji = true; } if (temJap) { if (temRomaji === false) { falarJapones(textoLimpo, false); // Seleção usa apenas TTS Nativo } } } }); const extrairTextoLimpo = (elemento) => { const clone = elemento.cloneNode(true); clone.querySelectorAll(‘rt, rp, button, .playbt, .writebt’).forEach(el => el.remove()); return clone.textContent.trim(); }; document.querySelectorAll(“.wp-block-preformatted, .frase pre”).forEach(pre => { let temPlay = false; let temCopiar = false; let temEscrita = false; pre.querySelectorAll(‘button’).forEach(btn => { const html = btn.innerHTML; if (html.includes(“▷”)) temPlay = true; if (html.includes(“✄”)) temCopiar = true; if (html.includes(“✎”)) temEscrita = true; }); if (temPlay === false) { const btnPlay = document.createElement(“button”); btnPlay.className = “playbt”; btnPlay.innerHTML = “▷”; btnPlay.addEventListener(“click”, function () { falarJapones(extrairTextoLimpo(pre), true, btnPlay); }); pre.appendChild(btnPlay); } if (temCopiar === false) { const btnCopiar = document.createElement(“button”); btnCopiar.className = “playbt”; btnCopiar.innerHTML = “✄”; btnCopiar.addEventListener(“click”, function () { navigator.clipboard.writeText(extrairTextoLimpo(pre)); }); pre.appendChild(btnCopiar); } if (temEscrita === false) { const btnEscrita = document.createElement(“button”); btnEscrita.className = “playbt writebt”; btnEscrita.innerHTML = “✎”; btnEscrita.addEventListener(“click”, function () { if (typeof jQuery === ‘undefined’) { alert(“jQuery não encontrado. Verifique se foi carregado.”); return; } document.querySelectorAll(“.draw”).forEach(el => el.remove()); document.querySelectorAll(“.sample-btn”).forEach(el => el.remove()); const drawDiv = document.createElement(“div”); drawDiv.id = “draw”; drawDiv.className = “draw”; pre.parentNode.insertBefore(drawDiv, pre.nextSibling); if (typeof jQuery(“#draw”).dmak === ‘function’) { jQuery(“#draw”).dmak(extrairTextoLimpo(pre), { width: 80, height: 80, stroke: { order: { visible: true } }, step: 0.02 }); } else { alert(“Função dmak não encontrada. Verifique o jquery.dmak.js.”); } }); pre.appendChild(btnEscrita); } }); document.querySelectorAll(“div.dynamic-entry-content ul”).forEach(ul => { let temCopiar = false; ul.querySelectorAll(‘button’).forEach(btn => { if (btn.innerHTML.includes(“✄”)) temCopiar = true; }); if (temCopiar === false) { const btnCopiar = document.createElement(“button”); btnCopiar.className = “playbt”; btnCopiar.innerHTML = “✄”; btnCopiar.addEventListener(“click”, function () { navigator.clipboard.writeText(extrairTextoLimpo(ul)); }); ul.appendChild(btnCopiar); } }); const btnAnki = document.getElementById(‘btn-anki-csv’); if (btnAnki) { btnAnki.addEventListener(‘click’, () => { const hasJP = s => { let str = s; if (!str) str = ”; return /[\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\u3400-\u4DBF\u4E00-\u9FFF]/.test(str); }; const stripBR = s => { let str = s; if (!str) str = ”; return str.replace(//gi, ”); }; const normHTML = s => stripBR(s).replace(/\t/g, ‘ ‘).replace(/\r?\n/g, ”); const csvField = s => { let text = normHTML(s); return `”${text.replace(/”/g, ‘””‘)}”`; }; const timestamp = () => { const d = new Date(); const p = n => String(n).padStart(2, ‘0’); return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}`; }; const rmButtons = root => root.querySelectorAll(‘button, .playbt, .writebt’).forEach(el => el.remove()); const unwrap = el => { const f = document.createDocumentFragment(); while (el.firstChild) f.appendChild(el.firstChild); el.replaceWith(f); }; const trimLeadingBRs = root => { while (root.firstElementChild) { if (root.firstElementChild.tagName === ‘BR’) { root.firstElementChild.remove(); } else { break; } } }; function sanitize(root, config) { let allowRuby = false; if (config) { if (config.allowRuby) allowRuby = true; } root.querySelectorAll(‘script, style, iframe, svg, mark’).forEach(el => el.remove()); rmButtons(root); if (!allowRuby) { root.querySelectorAll(‘rt, rp’).forEach(el => el.remove()); root.querySelectorAll(‘rb’).forEach(unwrap); root.querySelectorAll(‘ruby’).forEach(unwrap); } const allowedTags = [‘UL’, ‘OL’, ‘LI’, ‘P’, ‘A’, ‘STRONG’, ‘EM’, ‘B’, ‘I’, ‘U’, ‘S’, ‘SMALL’, ‘CODE’, ‘KBD’, ‘SAMP’, ‘SUB’, ‘SUP’, ‘SPAN’]; if (allowRuby) { allowedTags.push(‘RUBY’); allowedTags.push(‘RB’); allowedTags.push(‘RT’); allowedTags.push(‘RP’); } root.querySelectorAll(‘pre’).forEach(unwrap); const stack = [root]; while (stack.length) { const n = stack.pop(); if (!n) continue; if (n.nodeType === 1) { if (n !== root) { let tagPermitida = false; allowedTags.forEach(t => { if (n.tagName === t) tagPermitida = true; }); if (!tagPermitida) unwrap(n); } } for (let i = n.childNodes.length – 1; i >= 0; i–) stack.push(n.childNodes[i]); } } function frontFromPre(pre) { const c = pre.cloneNode(true); trimLeadingBRs(c); sanitize(c, { allowRuby: false }); return c.innerHTML.trim(); } function preWithFuriganaIfAny(pre) { if (!/ { const c = el.cloneNode(true); sanitize(c, { allowRuby: true }); return c.outerHTML; }).join(‘\n’).trim(); } const pres = Array.from(document.querySelectorAll(‘pre.wp-block-preformatted, pre’)); const cards = []; for (let i = 0; i < pres.length; i++) { const pre = pres[i]; let t = pre.textContent; if (!t) t = ''; let h = pre.innerHTML; if (!h) h = ''; let temJap = false; if (hasJP(t)) temJap = true; if (hasJP(h)) temJap = true; if (!temJap) continue; let nextPre = null; if (pres[i + 1]) nextPre = pres[i + 1]; const out = []; let n = pre.nextSibling; while (n) { if (n === nextPre) break; if (n.nodeType === 1) out.push(n); n = n.nextSibling; } const between = out; if (!between.length) continue; let hasUl = false; between.forEach(el => { if (el.tagName) { if (el.tagName.toLowerCase() === ‘ul’) hasUl = true; } }); if (!hasUl) continue; const front = frontFromPre(pre); const topFuri = preWithFuriganaIfAny(pre); const block = blockHTML(between); let back = block; if (topFuri) back = topFuri + ‘\n’ + block; cards.push([front, back]); } if (!cards.length) { alert(‘Nenhuma carta elegível encontrada para o Anki.’); return; } const linhas = cards.map(([f, v]) => `${csvField(f)},${csvField(v)}`).join(‘\n’); const blob = new Blob([‘\uFEFF’ + linhas], { type: ‘text/csv;charset=utf-8’ }); const url = URL.createObjectURL(blob); let titulo = document.title; if (!titulo) titulo = ‘pre-ul-deck’; const nomeBase = titulo.trim().substring(0, 60).replace(/\s+/g, ‘-‘).toLowerCase(); const a = document.createElement(‘a’); a.href = url; a.download = `${nomeBase}-${timestamp()}.csv`; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); }); } } // Inicia os scripts de forma correta, independentemente de como o Meta Box carrega a View. if (document.readyState === ‘loading’) { document.addEventListener(‘DOMContentLoaded’, inicializarScripts); } else { inicializarScripts(); }