Prueba ingles

Introduce un texto aquí...

import { useState, useRef, useEffect } from "react"; /* ══════════════════════════════════════════════════════════ TTS + KARAOKE ENGINE ══════════════════════════════════════════════════════════ */ let _voice = null; function _loadVoice() { const vv = window.speechSynthesis?.getVoices() || []; for (const n of ["Samantha","Alex","Karen","Google US English","Microsoft Zira","Microsoft David"]) { const v = vv.find(x => x.name.includes(n)); if (v) { _voice = v; return; } } _voice = vv.find(v => v.lang === "en-US") || vv.find(v => v.lang?.startsWith("en")) || null; } if (typeof window !== "undefined") { _loadVoice(); if (window.speechSynthesis?.onvoiceschanged !== undefined) window.speechSynthesis.onvoiceschanged = _loadVoice; } function tts(text, rate = 0.82, onEnd = null) { if (!window.speechSynthesis) return; window.speechSynthesis.cancel(); setTimeout(() => { const u = new SpeechSynthesisUtterance(text); u.lang = "en-US"; u.rate = rate; u.pitch = 1; if (_voice) u.voice = _voice; if (onEnd) u.onend = onEnd; window.speechSynthesis.speak(u); }, 100); } function wrapSpans(el) { if (el.dataset.ws) return; el.dataset.ws = "1"; const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); const nodes = []; let n; while ((n = walker.nextNode())) nodes.push(n); nodes.forEach(node => { const parts = node.textContent.split(/(\s+)/); const frag = document.createDocumentFragment(); parts.forEach(p => { if (!p) return; if (/^\s+$/.test(p)) { frag.appendChild(document.createTextNode(p)); return; } const s = document.createElement("span"); s.className = "ks"; s.textContent = p; frag.appendChild(s); }); node.parentNode.replaceChild(frag, node); }); } function playKaraoke(el, rate, onDone) { if (!el) return; wrapSpans(el); const spans = Array.from(el.querySelectorAll(".ks")); const full = el.textContent; const offsets = []; let pos = 0; spans.forEach(s => { const idx = full.indexOf(s.textContent, pos); offsets.push(idx >= 0 ? idx : pos); pos = idx >= 0 ? idx + s.textContent.length : pos; }); spans.forEach(s => s.classList.remove("ks-on","ks-done")); let last = -1; window.speechSynthesis.cancel(); setTimeout(() => { const u = new SpeechSynthesisUtterance(full); u.lang = "en-US"; u.rate = rate; u.pitch = 1; if (_voice) u.voice = _voice; u.onboundary = ev => { if (ev.name !== "word") return; let lo = 0, hi = offsets.length - 1, best = 0; while (lo <= hi) { const m = (lo+hi)>>1; if (offsets[m]<=ev.charIndex){best=m;lo=m+1;}else hi=m-1; } if (best === last) return; if (last >= 0) { spans[last].classList.remove("ks-on"); spans[last].classList.add("ks-done"); } for (let i = last+1; i < best; i++) { spans[i].classList.remove("ks-on"); spans[i].classList.add("ks-done"); } spans[best].classList.remove("ks-done"); spans[best].classList.add("ks-on"); spans[best].scrollIntoView({ behavior:"smooth", block:"nearest" }); last = best; }; u.onend = () => { spans.forEach(s => { s.classList.remove("ks-on"); s.classList.add("ks-done"); }); if (onDone) onDone(); }; u.onerror = () => { if (onDone) onDone(); }; window.speechSynthesis.speak(u); }, 150); } function stopKaraoke(el) { window.speechSynthesis.cancel(); if (el) el.querySelectorAll(".ks").forEach(s => s.classList.remove("ks-on","ks-done")); } /* ══════════════════════════════════════════════════════════ CONTENT DATA ══════════════════════════════════════════════════════════ */ const VOCAB = [ { id:"v1", en:"Occupational asthma", ph:"/ˌɒkjʊˈpeɪʃənl ˈæzmə/", es:"Asma ocupacional / laboral", def:"Asthma caused or worsened by exposure to substances in the workplace.", ex:"He was diagnosed with occupational asthma after five years in the bakery." }, { id:"v2", en:"Sensitizer", ph:"/ˈsɛnsɪtaɪzər/", es:"Sensibilizante", def:"A substance that causes the immune system to become hypersensitive after repeated exposure.", ex:"Flour is a high-molecular-weight sensitizer common in bakeries." }, { id:"v3", en:"Irritant", ph:"/ˈɪrɪtənt/", es:"Irritante", def:"A substance causing direct airway inflammation without an allergic mechanism.", ex:"Chlorine gas is a potent respiratory irritant in cleaning industries." }, { id:"v4", en:"Bronchospasm", ph:"/ˈbrɒŋkəʊˌspæzəm/", es:"Broncoespasmo", def:"Sudden constriction of bronchial smooth muscle causing airway narrowing.", ex:"The patient developed bronchospasm within minutes of isocyanate exposure." }, { id:"v5", en:"Workplace exposure", ph:"/ˈwɜːkpleɪs ɪkˈspoʊʒər/", es:"Exposición laboral", def:"Contact with a harmful agent during the course of professional work.", ex:"Workplace exposure to isocyanates is the leading cause of occupational asthma." }, { id:"v6", en:"Peak expiratory flow", ph:"/piːk ɪkˈspaɪrətɔːri floʊ/", es:"Flujo espiratorio máximo", def:"Maximum speed of expiration, measured with a peak flow meter.", ex:"Serial peak expiratory flow recordings are essential for occupational asthma diagnosis." }, { id:"v7", en:"Airway hyperresponsiveness", ph:"/ˈɛərweɪ ˌhaɪpərɪˈspɒnsɪvnəs/", es:"Hiperreactividad bronquial", def:"Exaggerated airway narrowing in response to nonspecific stimuli such as cold air or exercise.", ex:"Airway hyperresponsiveness confirmed bronchial sensitivity to methacholine." }, { id:"v8", en:"Latency period", ph:"/ˈleɪtənsi ˈpɪəriəd/", es:"Período de latencia", def:"Time from first exposure to an agent to the onset of sensitization and symptoms.", ex:"The latency period for isocyanate sensitization ranges from months to years." }, { id:"v9", en:"Specific inhalation challenge",ph:"/spɪˈsɪfɪk ɪnhəˈleɪʃən ˈtʃælɪndʒ/",es:"Prueba de provocación bronquial", def:"Gold-standard test where the patient inhales the suspected occupational agent.", ex:"The specific inhalation challenge confirmed the flour sensitization." }, { id:"v10", en:"Isocyanate", ph:"/ˌaɪsəˈsaɪəneɪt/", es:"Isocianato", def:"A reactive chemical group used in spray paints and polyurethane production.", ex:"Isocyanates are the most common chemical cause of occupational asthma worldwide." }, { id:"v11", en:"Spirometry", ph:"/spaɪˈrɒmɪtri/", es:"Espirometría", def:"A test measuring the volume and speed of air that can be exhaled from the lungs.", ex:"Spirometry before and after the work shift is standard for diagnosis." }, { id:"v12", en:"FEV₁", ph:"/ˌef iː ˈviː wʌn/", es:"VEF₁", def:"Forced expiratory volume in one second — the key spirometry measurement.", ex:"A fall in FEV₁ of more than 20% after exposure confirms bronchial obstruction." }, { id:"v13", en:"Removal from exposure", ph:"/rɪˈmuːvəl frəm ɪkˈspoʊʒər/", es:"Retirada de la exposición", def:"Permanent or temporary removal of the worker from contact with the causal agent.", ex:"Early removal from exposure leads to significantly better clinical outcomes." }, { id:"v14", en:"High-molecular-weight agent", ph:"/haɪ məˈlɛkjʊlər weɪt ˈeɪdʒənt/", es:"Agente de alto peso molecular",def:"Large organic molecules that cause IgE-mediated sensitization — flour, latex, animal proteins.", ex:"High-molecular-weight agents are the most common cause in food industry workers." }, { id:"v15", en:"Low-molecular-weight agent", ph:"/loʊ məˈlɛkjʊlər weɪt ˈeɪdʒənt/", es:"Agente de bajo peso molecular",def:"Small chemicals such as isocyanates that cause sensitization through non-IgE mechanisms.", ex:"Low-molecular-weight agents include isocyanates, anhydrides, and wood dust." }, { id:"v16", en:"Reactive airways dysfunction", ph:"/riˈæktɪv ˈɛərweɪz dɪsˈfʌŋkʃən/", es:"Síndrome de disfunción reactiva de vías aéreas",def:"Asthma-like syndrome after a single massive irritant exposure.", ex:"She developed reactive airways dysfunction after a chlorine gas spill at work." }, { id:"v17", en:"Methacholine challenge", ph:"/ˌmɛθəˈkoʊliːn ˈtʃælɪndʒ/", es:"Prueba de metacolina", def:"A bronchial provocation test using methacholine to measure airway hyperresponsiveness.", ex:"A positive methacholine challenge supports a diagnosis of bronchial hyperreactivity." }, { id:"v18", en:"Work-related asthma", ph:"/wɜːk rɪˈleɪtɪd ˈæzmə/", es:"Asma relacionada con el trabajo",def:"Broad term including both occupational asthma and work-aggravated asthma.", ex:"Work-related asthma accounts for 15 to 20 percent of adult-onset asthma cases." }, { id:"v19", en:"Allergen", ph:"/ˈælərdʒən/", es:"Alérgeno", def:"A substance triggering an allergic response in a sensitized individual.", ex:"Wheat flour is the most common airborne allergen in bakeries." }, { id:"v20", en:"Occupational history", ph:"/ˌɒkjʊˈpeɪʃənl ˈhɪstəri/", es:"Historia ocupacional", def:"A detailed account of all jobs held and the substances encountered during work.", ex:"A thorough occupational history is the first step in diagnosing work-related asthma." }, ]; const LINES = [ { r:"D", sp:"Dr. Williams", text:"Good morning, Mr. Reyes. Please, come in and have a seat. What brings you in today?", es:"Buenos días, Sr. Reyes. Pase y siéntese. ¿Qué le trae por aquí hoy?", note:"Apertura estándar de consulta — chief complaint." }, { r:"P", sp:"Mr. Reyes", text:"Good morning, doctor. I've been having a lot of trouble breathing for about six months now. It seems to get much worse when I'm at work.", es:"Buenos días, doctor. He tenido mucho problema para respirar durante los últimos seis meses. Parece empeorar mucho cuando estoy en el trabajo.", note:"El paciente conecta los síntomas con el trabajo — clave diagnóstica." }, { r:"D", sp:"Dr. Williams", text:"I see. Can you describe the breathing problem for me? Is it wheezing, shortness of breath, or chest tightness — or all three?", es:"Entiendo. ¿Puede describirme el problema respiratorio? ¿Son sibilancias, falta de aire, o presión en el pecho — o los tres?", note:"Pregunta de tres opciones — estructura A1." }, { r:"P", sp:"Mr. Reyes", text:"All three, doctor. And I also have a dry cough that usually starts right when I begin my shift.", es:"Los tres, doctor. Y también tengo una tos seca que generalmente empieza justo cuando comienzo mi turno.", note:"Inicio al comienzo del turno — latencia corta muy sugestiva." }, { r:"D", sp:"Dr. Williams", text:"That is very important information. What is your job? What substances do you work with on a daily basis?", es:"Esa es información muy importante. ¿Cuál es su trabajo? ¿Con qué sustancias trabaja a diario?", note:"Historia ocupacional — la pregunta más importante en asma laboral." }, { r:"P", sp:"Mr. Reyes", text:"I spray paint cars at an auto body shop. I've been doing it for about three years now.", es:"Pinto coches con pistola en un taller de carrocería. Llevo haciéndolo unos tres años.", note:"Pintura en aerosol = exposición a isocianatos — agente más frecuente." }, { r:"D", sp:"Dr. Williams", text:"Do your symptoms improve on weekends or when you are on vacation and away from work for several days?", es:"¿Sus síntomas mejoran los fines de semana o cuando está de vacaciones y alejado del trabajo varios días?", note:"Criterio de relación laboral — mejora fuera del trabajo." }, { r:"P", sp:"Mr. Reyes", text:"Yes, definitely. By Sunday I feel much better. But on Monday morning, as soon as I get to work, they come back.", es:"Sí, definitivamente. El domingo me siento mucho mejor. Pero el lunes por la mañana, en cuanto llego al trabajo, vuelven.", note:"Patrón clásico: mejoría en fin de semana, reaparición el lunes." }, { r:"D", sp:"Dr. Williams", text:"Are you allergic to any medications? And are you currently taking any medications?", es:"¿Es alérgico a algún medicamento? ¿Y está tomando algún medicamento actualmente?", note:"Preguntas de seguridad — siempre antes de prescribir." }, { r:"P", sp:"Mr. Reyes", text:"No known allergies, doctor. I use a rescue inhaler sometimes when the breathing gets really bad at work.", es:"Sin alergias conocidas, doctor. A veces uso un inhalador de rescate cuando la respiración se pone muy mal en el trabajo.", note:"Uso de rescate en el trabajo — confirmación de broncoespasmo laboral." }, { r:"D", sp:"Dr. Williams", text:"Based on your symptoms and your work history, I think you may have occupational asthma caused by the chemicals in the spray paint, most likely isocyanates.", es:"Según sus síntomas e historia laboral, creo que puede tener asma ocupacional causada por los químicos de la pintura en aerosol, probablemente isocianatos.", note:"Diagnóstico probable — usa 'may have' para expresar posibilidad." }, { r:"D", sp:"Dr. Williams", text:"I am going to order spirometry and a peak expiratory flow diary. I will also refer you to a pulmonologist and an occupational medicine specialist.", es:"Voy a ordenar una espirometría y un diario de flujo espiratorio máximo. También lo voy a derivar a un neumólogo y a un especialista en medicina ocupacional.", note:"Plan clínico: pruebas + derivación especializada." }, { r:"P", sp:"Mr. Reyes", text:"Should I stop working in the meantime, doctor?", es:"¿Debo dejar de trabajar mientras tanto, doctor?", note:"El paciente pregunta lo más importante — respuesta crítica." }, { r:"D", sp:"Dr. Williams", text:"You should try to avoid direct exposure as much as possible. Always use your respirator and work in a well-ventilated area. Early removal from exposure significantly improves your prognosis.", es:"Debe intentar evitar la exposición directa tanto como sea posible. Use siempre su respirador y trabaje en un área bien ventilada. La retirada temprana de la exposición mejora significativamente su pronóstico.", note:"Consejo práctico + pronóstico — cierre clínico de la consulta." }, ]; const GRAMMAR = [ { pat:"When you are at work, do your symptoms get worse?", es:"Cuando está en el trabajo, ¿sus síntomas empeoran?", use:"Explorar la relación entre el trabajo y los síntomas.", rule:"When + presente simple, → presente simple?" }, { pat:"If you use a respirator, does the coughing improve?", es:"Si usa un respirador, ¿la tos mejora?", use:"Evaluar el efecto de las medidas de protección.", rule:"If + presente simple, → presente simple?" }, { pat:"When you leave work on Friday, how do you feel by Sunday?", es:"Cuando sale del trabajo el viernes, ¿cómo se siente el domingo?",use:"Patrón clásico de mejoría en período no laboral.", rule:"When + presente simple, → presente simple?" }, { pat:"If you are exposed to paint fumes, does your chest feel tight?",es:"Si se expone a humos de pintura, ¿siente presión en el pecho?", use:"Confirmar la relación síntoma-agente específico.", rule:"If + presente simple, → presente simple?" }, { pat:"When you are on vacation, do your symptoms disappear completely?",es:"Cuando está de vacaciones, ¿sus síntomas desaparecen completamente?",use:"Distinción entre asma laboral y asma agravada por el trabajo.", rule:"When + presente simple, → presente simple?" }, ]; const PRON = [ { word:"asthma", ph:"/ˈæzmə/", tip:"La 'th' es completamente silenciosa. Pronuncia: AZ-muh. Nunca 'AST-ma'." }, { word:"wheezing", ph:"/ˈwiːzɪŋ/", tip:"'Wh' suena /w/. Labios redondeados: WHEE-zing. Alargada la ee." }, { word:"bronchospasm", ph:"/ˈbrɒŋkəʊˌspæzəm/", tip:"4 sílabas: BRONK-oh-SPAZ-um. Acento principal en la primera." }, { word:"spirometry", ph:"/spaɪˈrɒmɪtri/", tip:"Acento en la 2ª sílaba: spy-ROM-ih-tree. No 'es-pi-ro-MET-ría'." }, { word:"isocyanate", ph:"/ˌaɪsəˈsaɪəneɪt/", tip:"5 sílabas: eye-so-SY-uh-nayt. Acento en la 3ª sílaba." }, { word:"hyperresponsiveness", ph:"/ˌhaɪpərɪˈspɒnsɪvnəs/",tip:"6 sílabas. Acento en '-spon-': hi-per-ih-SPON-siv-ness." }, { word:"expiratory", ph:"/ɪkˈspaɪrətɔːri/", tip:"Acento en 2ª sílaba: ex-PIE-ruh-tor-ee. No 'expi-ra-TO-rio'." }, { word:"occupational", ph:"/ˌɒkjʊˈpeɪʃənl/", tip:"5 sílabas: ok-yuh-PAY-shun-ul. Acento principal en '-pay-'." }, ]; /* ══════════════════════════════════════════════════════════ MICRO COMPONENTS ══════════════════════════════════════════════════════════ */ function Btn({ onClick, active, children, style = {} }) { return ( ); } function PlayCircle({ onClick, playing, size = 36, bg = "#C1272D" }) { return ( ); } function Wave({ color = "#C1272D", n = 7 }) { const heights = [6,14,20,10,18,8,14]; const bars = heights.slice(0, n); return (
{bars.map((h, i) => (
))}
); } function Pill({ text, ok }) { return {ok?"✓ ":""}{text}; } /* ══════════════════════════════════════════════════════════ ARTICLE 1 — VOCABULARY ══════════════════════════════════════════════════════════ */ function A1Vocab() { const [playing, setPlaying] = useState(null); const [flipped, setFlipped] = useState({}); return (
{/* Section intro */}
ARTÍCULO 1 · VOCABULARIO · VOCABULARY
20 términos esenciales
del asma laboral
The language of occupational asthma is specific, precise, and entirely learnable. Master these 20 clinical terms and you will be equipped to understand any consultation, any specialist report, and any patient conversation on work-related respiratory disease.
Domina estas 20 palabras clínicas y estarás equipado para entender cualquier consulta de asma laboral.
{/* Instruction strip */}
Presiona el botón rojo para oír la pronunciación americana · Haz clic en la tarjeta para ver la traducción
{VOCAB.map((v, i) => (
setFlipped(f => ({ ...f, [v.id]: !f[v.id] }))} className="vc" style={{ animationDelay:`${i*.035}s`, background:"#FEFCF8", border:"1px solid #E0D8CC", borderLeft:`4px solid ${flipped[v.id]?"#B8892A":"#0D2B45"}`, borderRadius:3, padding:"14px 16px", cursor:"pointer", transition:"border-color .2s" }}>
{v.en}
{v.ph}
{flipped[v.id] &&
— {v.es}
}
{ e.stopPropagation(); setPlaying(v.id); tts(v.en,0.76,()=>setPlaying(null)); }} playing={playing===v.id} size={32}/>
{v.def}
"{v.ex}"
))}
); } /* ══════════════════════════════════════════════════════════ ARTICLE 2 — DIALOGUE ══════════════════════════════════════════════════════════ */ function A2Dialogue() { const [rate, setRate] = useState(0.82); const [kLine, setKLine] = useState(null); const [kPlay, setKPlay] = useState(false); const [lPlay, setLPlay] = useState(null); const [showEs, setShowEs] = useState({}); const [showNote, setShowNote] = useState({}); const elRefs = useRef({}); function playAll() { if (kPlay) { stopKaraoke(elRefs.current[kLine]); setKPlay(false); setKLine(null); return; } setKPlay(true); setKLine(null); setLPlay(null); let i = 0; function next() { if (i >= LINES.length) { setKPlay(false); setKLine(null); return; } const el = elRefs.current[i]; setKLine(i); if (el) el.closest(".db")?.scrollIntoView({ behavior:"smooth", block:"center" }); playKaraoke(el, rate, () => { i++; next(); }); } next(); } function playOne(i) { if (lPlay === i) { window.speechSynthesis.cancel(); setLPlay(null); return; } setLPlay(i); setKPlay(false); setKLine(null); tts(LINES[i].text, rate, () => setLPlay(null)); } return (
ARTÍCULO 2 · DIÁLOGO CLÍNICO · CLINICAL DIALOGUE
En la consulta:
An Occupational Asthma Encounter
A spray painter presents with six months of work-related respiratory symptoms. Follow the complete consultation — from opening to diagnosis and clinical plan. Every line is bilingual, with audio, karaoke highlighting, and clinical notes.
{/* Controls */}
{kPlay ? <> DETENER : <>▶ LEER DIÁLOGO COMPLETO}
{[["🐇 Normal", 0.82], ["🐢 Lento", 0.58]].map(([l,r]) => ( ))}
🌐 Traducción · 💡 Nota clínica · ▶ Línea individual
{LINES.map((ln, i) => { const isD = ln.r === "D"; const isK = kLine === i && kPlay; return (
{isD?"Dr":"Px"}
{ln.sp}
{[["🌐","ES",showEs,setShowEs],["💡","TIP",showNote,setShowNote]].map(([ico,lbl,st,setSt])=>( ))} playOne(i)} playing={lPlay===i} size={26} bg={isD?"#0D2B45":"#C1272D"}/>
elRefs.current[i]=el} style={{ fontFamily:"'Lora',serif", fontSize:16, color:"#1A1A1A", lineHeight:1.68 }}>{ln.text}
{showEs[i] &&
{ln.es}
} {showNote[i] &&
📋 {ln.note}
}
); })}
); } /* ══════════════════════════════════════════════════════════ ARTICLE 3 — GRAMMAR ══════════════════════════════════════════════════════════ */ function A3Grammar() { const [playing, setPlaying] = useState(null); return (
ARTÍCULO 3 · GRAMÁTICA · GRAMMAR
When you work with chemicals,
do your symptoms get worse?
Real conditional sentences are the grammatical backbone of occupational medicine. They let you explore the relationship between exposure and symptoms — the central diagnostic question in work-related asthma.
Las condicionales reales son la estructura gramatical central del diagnóstico de asma laboral.
{/* Rule box */}
LA REGLA · THE RULE
{[["CONDICIÓN / CONDITION","When / If + presente simple","When you are at work…"],["","→",""],["RESULTADO / RESULT","Presente simple","…do your symptoms get worse?"]].map(([lbl,main,ex],i)=>( i===1 ?
:
{lbl}
{main}
{ex}
))}
Use the real conditional to ask whether symptoms change in relation to workplace exposure. This is how you establish work-relatedness in your clinical history.
{/* Patterns */}
{GRAMMAR.map((g,i) => (
PATRÓN {i+1} · PATTERN {i+1}
{ setPlaying(i); tts(g.pat,0.78,()=>setPlaying(null)); }} playing={playing===i} size={28}/>
"{g.pat}"
"{g.es}"
USO CLÍNICO
{g.use}
FÓRMULA
{g.rule}
))}
{/* Exercise box */}
EJERCICIO · EXERCISE
Transforma cada afirmación en una condicional real adecuada para el interrogatorio clínico:
{["The patient wears a respirator → the coughing reduces.","The patient stays away from work → the FEV₁ normalizes.","The patient is exposed to spray paint → chest tightness appears."].map((e,i) => (
{i+1}. {e}
))}
); } /* ══════════════════════════════════════════════════════════ ARTICLE 4 — PRONUNCIATION ══════════════════════════════════════════════════════════ */ function A4Pron() { const [modPlay, setModPlay] = useState(null); const [recSt, setRecSt] = useState({}); const [heard, setHeard] = useState({}); const [audURL, setAudURL] = useState({}); const [myPlay, setMyPlay] = useState(null); const srRef = useRef({}); const mrRef = useRef({}); const runRef = useRef({}); const finRef = useRef({}); const auRef = useRef({}); function playMod(w) { setModPlay(w); tts(w, 0.7, () => setModPlay(null)); } async function startRec(w) { finRef.current[w] = ""; setHeard(h => ({...h,[w]:""})); setRecSt(s=>({...s,[w]:"rec"})); try { const stream = await navigator.mediaDevices.getUserMedia({ audio:true }); const mr = new MediaRecorder(stream, { mimeType:MediaRecorder.isTypeSupported("audio/webm")?"audio/webm":"" }); const chunks = []; mr.ondataavailable = e => { if(e.data?.size>0) chunks.push(e.data); }; mr.onstop = () => { const blob = new Blob(chunks,{type:"audio/webm"}); setAudURL(u=>({...u,[w]:URL.createObjectURL(blob)})); stream.getTracks().forEach(t=>t.stop()); }; mr.start(100); mrRef.current[w] = mr; } catch(e){} const SR = window.SpeechRecognition||window.webkitSpeechRecognition; if (!SR) return; runRef.current[w] = true; const rec = new SR(); rec.lang="en-US"; rec.continuous=true; rec.interimResults=true; srRef.current[w] = rec; rec.onresult = e => { let it=""; for(let i=e.resultIndex;i({...h,[w]:(finRef.current[w]+it).trim()})); }; rec.onend = () => { if(runRef.current[w]) try{rec.start();}catch(e){} }; rec.onerror = ()=>{}; try{rec.start();}catch(e){} } function stopRec(w) { runRef.current[w]=false; try{srRef.current[w]?.stop();}catch(e){} try{if(mrRef.current[w]?.state==="recording") mrRef.current[w].stop();}catch(e){} setRecSt(s=>({...s,[w]:"done"})); } function playMy(w) { const url=audURL[w]; if(!url||myPlay) return; setMyPlay(w); const a=new Audio(url); auRef.current[w]=a; a.play().catch(()=>setMyPlay(null)); a.onended=()=>setMyPlay(null); a.onerror=()=>setMyPlay(null); } function reset(w) { if(audURL[w]) URL.revokeObjectURL(audURL[w]); setRecSt(s=>({...s,[w]:"idle"})); setHeard(h=>({...h,[w]:""})); setAudURL(u=>({...u,[w]:null})); } function evalMatch(w, tr) { if(!tr) return null; const tw = w.toLowerCase().replace(/[^a-z\s]/g,"").split(/\s+/); const hw = tr.toLowerCase().replace(/[^a-z\s]/g,"").split(/\s+/); const ok = tw.filter(t=>hw.some(h=>h.includes(t)||t.includes(h))); const p = ok.length/tw.length; return p>=.75?"excellent":p>=.4?"good":"retry"; } const RM = { excellent:{ bg:"#EBF7F2", bdr:"#1A6B44", clr:"#1A6B44", lbl:"✅ Excelente / Excellent!" }, good: { bg:"#FDF6E3", bdr:"#B8892A", clr:"#B8892A", lbl:"👍 Bien / Good!" }, retry: { bg:"#FEF0EE", bdr:"#C1272D", clr:"#C1272D", lbl:"🎙 Intenta de nuevo / Try again" }, }; return (
ARTÍCULO 4 · PRONUNCIACIÓN · PRONUNCIATION
Di lo correcto:
8 términos respiratorios
These 8 occupational asthma terms are systematically mispronounced by Spanish-speaking physicians. For each word: listen to the American model, record yourself, play back your own voice, and compare. The difference will be immediate.
▶ MODELO → ● GRABAR → ■ DETENER → 🔊 MY VOICE (escucha tu voz) → ↺ REINTENTAR
{PRON.map((item, i) => { const st = recSt[item.word] || "idle"; const hr = heard[item.word] || ""; const ev = st==="done" ? evalMatch(item.word,hr) : null; const rm = ev ? RM[ev] : null; const aok = !!audURL[item.word]; const tw = item.word.toLowerCase().replace(/[^a-z\s]/g,"").split(/\s+/); const hw = hr.toLowerCase().replace(/[^a-z\s]/g,"").split(/\s+/); return (
{/* Word header */}
{item.word}
{item.ph}
playMod(item.word)} playing={modPlay===item.word} size={34} bg="#C1272D"/>
{/* Tip */}
CONSEJO DE PRONUNCIACIÓN
{item.tip}
{/* Recording zone */}
{st==="idle"?"TU TURNO · YOUR TURN":st==="rec"?"● GRABANDO · RECORDING":"COMPARA · COMPARE"}
{st==="rec" && } {hr &&
"{hr}"
}
{st !== "rec" ? : } {st==="done" && aok && ( )} {st==="done" && }
{/* Feedback */} {rm && (
{rm.lbl}
{tw.map((t,j) => h.includes(t)||t.includes(h))}/>)}
{ev==="excellent"?"Pronunciation detected correctly. Well done!":ev==="good"?"Almost there — listen again and retry.":"Press ▶ to hear the model pronunciation, then try again."}
{hr &&
Detected: "{hr}"
}
)}
); })}
); } /* ══════════════════════════════════════════════════════════ COVER ══════════════════════════════════════════════════════════ */ function Cover({ onOpen }) { const [hov, setHov] = useState(false); return (
{/* Grid background texture */}
{/* ── MASTHEAD ── */}
{/* Logo block */}
MedEnglish
ASOGESTION · CLINICAL ENGLISH
{[["NIVEL","A1 · Medical English"],["FORMATO","Quincenal · Biweekly"],["SECCIÓN","Medicina Ocupacional"],["AÑO","2025"]].map(([l,v])=>(
{l}
{v}
))}
{/* ── COVER BODY ── */}
{/* Kicker */}
MEDICINA OCUPACIONAL · OCCUPATIONAL MEDICINE
{/* Main title */}
Occupational
Asthma
at Work — Asma Laboral
{/* Deck */}
The language of work-related asthma: vocabulary, clinical dialogue, grammar for diagnosis, and pronunciation training for the American medical context.
El lenguaje del asma laboral: vocabulario, diálogo, gramática diagnóstica y pronunciación.
{/* Contents preview */}
{[ ["📖","VOCABULARIO","20 Términos Esenciales del Asma Laboral","pp. 2–11"], ["💬","DIÁLOGO CLÍNICO","An Occupational Asthma Encounter","pp. 12–19"], ["🔤","GRAMÁTICA","When You Work With Chemicals…","pp. 20–25"], ["🎙️","PRONUNCIACIÓN","8 Términos Respiratorios — Graba y Compara","pp. 26–31"], ].map(([ic,ty,ti,pp])=>(
{ic}
{ty} {ti}
{pp}
))}
{/* Right decorative column — abstract lung shape */}
{[120,140,160,155,145,150,148,140,130,120,105,95,80,70,58,46,36,24].map((w,i)=>(
))}
{/* Footer bar */}
© 2025 MEDENGLISH · ASOGESTION · TODOS LOS DERECHOS RESERVADOS AMERICAN MEDICAL ENGLISH · A1 LEVEL
); } /* ══════════════════════════════════════════════════════════ SIDEBAR TOC ══════════════════════════════════════════════════════════ */ const ARTS = [ { n:1, ic:"📖", type:"VOCABULARIO", title:"20 Términos del Asma Laboral", color:"#0D2B45", pp:"pp. 2–11" }, { n:2, ic:"💬", type:"DIÁLOGO", title:"An Occupational Asthma Encounter", color:"#C1272D", pp:"pp. 12–19" }, { n:3, ic:"🔤", type:"GRAMÁTICA", title:"Condicionales para el Diagnóstico", color:"#1C5C8A", pp:"pp. 20–25" }, { n:4, ic:"🎙️", type:"PRONUNCIACIÓN", title:"8 Términos Respiratorios — MY VOICE", color:"#7A4A00", pp:"pp. 26–31" }, ]; function Sidebar({ active, onSelect }) { return (
{/* Mini cover */}
MedEnglish
ASOGESTION
ASMA LABORAL
Occupational Asthma
ÍNDICE · CONTENTS
{ARTS.map(a => ( ))}
{[["NIVEL","A1 · Medical English"],["PUBLICACIÓN","Quincenal · Biweekly"],["ISSN","2025-MED-OA"]].map(([l,v])=>(
{l}
{v}
))}
); } /* ══════════════════════════════════════════════════════════ ROOT ══════════════════════════════════════════════════════════ */ export default function App() { const [view, setView] = useState("cover"); // cover | mag const [art, setArt] = useState(1); const AC = ARTS.find(a=>a.n===art); return (
{view === "cover" && setView("mag")}/>} {view === "mag" && (
{/* Top nav */}
MedEnglish · ASMA LABORAL · Occupational Asthma
{/* Article tabs */}
{ARTS.map(a => ( ))}
{/* Content area */}
{/* Folio / breadcrumb */}
{AC?.type} · {AC?.title} {AC?.pp}
{art===1 && } {art===2 && } {art===3 && } {art===4 && } {/* Bottom pagination */}
{art} / 4
)}
); }