From a2e705aa30c1fd0f539c1c42df8649b773f09cde Mon Sep 17 00:00:00 2001 From: guoqingshan Date: Sat, 1 Aug 2026 17:13:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=B8=AD=E8=AF=91?= =?UTF-8?q?=E8=A5=BF=E8=BE=85=E5=8A=A9=E3=80=81=E5=9C=A8=E7=BA=BF=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E3=80=81B1=E8=AF=8D=E5=BA=93=E4=B8=8E=E4=B8=89?= =?UTF-8?q?=E8=AF=AD=E8=AF=AD=E9=9F=B3=E5=AF=B9=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 104 +++++ b1-vocab.js | 617 ++++++++++++++++++++++++++++ index.html | 20 + knowledge.html | 10 + knowledge/b1-vocabulario.html | 69 ++++ knowledge/comparacion-fonetica.html | 358 ++++++++++++++++ knowledge/style.css | 4 + style.css | 53 +++ translate.js | 296 ++++++++++++- 9 files changed, 1530 insertions(+), 1 deletion(-) create mode 100644 b1-vocab.js create mode 100644 knowledge/b1-vocabulario.html create mode 100644 knowledge/comparacion-fonetica.html diff --git a/app.js b/app.js index 9966cbf..5facaeb 100644 --- a/app.js +++ b/app.js @@ -229,6 +229,106 @@ function saveTextareaSelection() { savedSelEnd = ta.selectionEnd; } +// ----- Chinese to Spanish helper ----- + +var helperDebounceTimer = null; +var helperRequestSeq = 0; +var helperOnlineResult = ''; + +function openHelperModal() { + var ta = document.getElementById('entry-text'); + savedSelStart = ta.selectionStart; + savedSelEnd = ta.selectionEnd; + helperOnlineResult = ''; + if (helperDebounceTimer) clearTimeout(helperDebounceTimer); + document.getElementById('helper-input').value = ''; + document.getElementById('helper-result').textContent = ''; + document.getElementById('helper-confirm').disabled = true; + document.getElementById('helper-modal-overlay').classList.add('show'); + setTimeout(function() { document.getElementById('helper-input').focus(); }, 0); +} + +function closeHelperModal() { + if (helperDebounceTimer) clearTimeout(helperDebounceTimer); + helperRequestSeq++; + document.getElementById('helper-modal-overlay').classList.remove('show'); +} + +function updateHelperPreview() { + var zh = document.getElementById('helper-input').value; + helperOnlineResult = ''; + if (helperDebounceTimer) clearTimeout(helperDebounceTimer); + if (!zh.trim()) { + document.getElementById('helper-result').textContent = ''; + document.getElementById('helper-confirm').disabled = true; + return; + } + var local = translateZhToEs(zh); + document.getElementById('helper-result').textContent = local || '本地词典未收录,正在尝试在线翻译...'; + document.getElementById('helper-confirm').disabled = !local; + helperDebounceTimer = setTimeout(function() { + translateZhOnline(zh); + }, 600); +} + +function translateZhOnline(zh) { + var seq = ++helperRequestSeq; + var url = 'https://api.mymemory.translated.net/get?q=' + + encodeURIComponent(zh) + '&langpair=zh-CN|es'; + fetch(url) + .then(function(res) { return res.json(); }) + .then(function(data) { + if (seq !== helperRequestSeq) return; + var text = data && data.responseData && data.responseData.translatedText; + if (text && !data.quotaFinished) { + helperOnlineResult = text.trim(); + document.getElementById('helper-result').textContent = helperOnlineResult; + document.getElementById('helper-confirm').disabled = false; + } + }) + .catch(function() { + if (seq !== helperRequestSeq) return; + var local = translateZhToEs(zh); + if (local) { + document.getElementById('helper-result').textContent = local; + document.getElementById('helper-confirm').disabled = false; + } else { + document.getElementById('helper-result').textContent = '在线翻译暂不可用,且本地词典未收录'; + } + }); +} + +function getHelperResult() { + if (helperOnlineResult) return helperOnlineResult; + return translateZhToEs(document.getElementById('helper-input').value); +} + +function insertSpanishAtCursor(es) { + var ta = document.getElementById('entry-text'); + var start = savedSelStart || ta.selectionStart; + var end = savedSelEnd || ta.selectionEnd; + var before = ta.value.slice(0, start); + var after = ta.value.slice(end); + var prefix = ''; + var suffix = ''; + if (before.length > 0 && !/\s$/.test(before)) prefix = ' '; + if (after.length > 0 && !/^\s/.test(after)) suffix = ' '; + var insert = prefix + es + suffix; + var newPos = start + insert.length; + ta.value = before + insert + after; + ta.focus(); + ta.setSelectionRange(newPos, newPos); + savedSelStart = savedSelEnd = newPos; + updateLiveTranslation(); +} + +function confirmHelperInsert() { + var es = getHelperResult(); + if (!es) return; + insertSpanishAtCursor(es); + closeHelperModal(); +} + // ----- Speech handler ----- function handleSpeech(lang) { @@ -260,6 +360,10 @@ function init() { document.getElementById('btn-new').addEventListener('click', newEntry); document.getElementById('btn-save').addEventListener('click', saveCurrentEntry); + document.getElementById('btn-helper').addEventListener('click', openHelperModal); + document.getElementById('helper-cancel').addEventListener('click', closeHelperModal); + document.getElementById('helper-confirm').addEventListener('click', confirmHelperInsert); + document.getElementById('helper-input').addEventListener('input', updateHelperPreview); document.querySelectorAll('.btn-speech').forEach(function(btn) { btn.addEventListener('click', function() { handleSpeech(btn.dataset.lang); }); diff --git a/b1-vocab.js b/b1-vocab.js new file mode 100644 index 0000000..7f403fa --- /dev/null +++ b/b1-vocab.js @@ -0,0 +1,617 @@ +// B1 核心词汇与表达(按主题整理) +// 格式: [西班牙语, 英语, 中文, 主题] +const B1_VOCAB = [ + // 日常生活 + ['levantarse', 'to get up', '起床', '日常生活'], + ['ducharse', 'to shower', '洗澡', '日常生活'], + ['vestirse', 'to get dressed', '穿衣服', '日常生活'], + ['desayunar', 'to have breakfast', '吃早餐', '日常生活'], + ['almorzar', 'to have lunch', '吃午餐', '日常生活'], + ['cenar', 'to have dinner', '吃晚餐', '日常生活'], + ['dormir', 'to sleep', '睡觉', '日常生活'], + ['acostarse', 'to go to bed', '上床睡觉', '日常生活'], + ['despertarse', 'to wake up', '醒来', '日常生活'], + ['bañarse', 'to bathe', '洗澡', '日常生活'], + ['afeitarse', 'to shave', '刮胡子', '日常生活'], + ['peinarse', 'to comb hair', '梳头', '日常生活'], + ['maquillarse', 'to put on makeup', '化妆', '日常生活'], + ['lavarse los dientes', 'to brush teeth', '刷牙', '日常生活'], + ['cepillarse', 'to brush', '刷', '日常生活'], + ['preparar', 'to prepare', '准备', '日常生活'], + ['cocinar', 'to cook', '做饭', '日常生活'], + ['limpiar', 'to clean', '打扫', '日常生活'], + ['fregar', 'to wash dishes', '洗碗', '日常生活'], + ['lavar', 'to wash', '洗', '日常生活'], + ['planchar', 'to iron', '熨衣服', '日常生活'], + ['ordenar', 'to tidy', '整理', '日常生活'], + ['arreglar', 'to fix', '修理', '日常生活'], + ['comprar', 'to buy', '买', '日常生活'], + ['vender', 'to sell', '卖', '日常生活'], + ['pagar', 'to pay', '付钱', '日常生活'], + ['cobrar', 'to charge', '收款', '日常生活'], + ['devolver', 'to return', '退还', '日常生活'], + ['prestar', 'to lend', '借出', '日常生活'], + ['pedir', 'to ask/order', '请求;点餐', '日常生活'], + // 家庭与人际 + ['abuelo', 'grandfather', '爷爷;外公', '家庭与人际'], + ['abuela', 'grandmother', '奶奶;外婆', '家庭与人际'], + ['padre', 'father', '父亲', '家庭与人际'], + ['madre', 'mother', '母亲', '家庭与人际'], + ['padres', 'parents', '父母', '家庭与人际'], + ['hijo', 'son', '儿子', '家庭与人际'], + ['hija', 'daughter', '女儿', '家庭与人际'], + ['hermano', 'brother', '兄弟', '家庭与人际'], + ['hermana', 'sister', '姐妹', '家庭与人际'], + ['marido', 'husband', '丈夫', '家庭与人际'], + ['esposa', 'wife', '妻子', '家庭与人际'], + ['tío', 'uncle', '叔叔;舅舅', '家庭与人际'], + ['tía', 'aunt', '阿姨;姑姑', '家庭与人际'], + ['primo', 'cousin (male)', '表兄弟', '家庭与人际'], + ['prima', 'cousin (female)', '表姐妹', '家庭与人际'], + ['sobrino', 'nephew', '侄子;外甥', '家庭与人际'], + ['sobrina', 'niece', '侄女;外甥女', '家庭与人际'], + ['novio', 'boyfriend', '男朋友', '家庭与人际'], + ['novia', 'girlfriend', '女朋友', '家庭与人际'], + ['vecino', 'neighbor', '邻居', '家庭与人际'], + ['amigo', 'friend', '朋友', '家庭与人际'], + ['compañero', 'companion/classmate', '同伴;同学', '家庭与人际'], + ['conocido', 'acquaintance', '熟人', '家庭与人际'], + ['invitado', 'guest', '客人', '家庭与人际'], + ['jefe', 'boss', '老板', '家庭与人际'], + ['colega', 'colleague', '同事', '家庭与人际'], + ['cita', 'appointment/date', '约会;预约', '家庭与人际'], + ['boda', 'wedding', '婚礼', '家庭与人际'], + ['cumpleaños', 'birthday', '生日', '家庭与人际'], + ['aniversario', 'anniversary', '纪念日', '家庭与人际'], + // 食物与餐饮 + ['desayuno', 'breakfast', '早餐', '食物与餐饮'], + ['almuerzo', 'lunch', '午餐', '食物与餐饮'], + ['cena', 'dinner', '晚餐', '食物与餐饮'], + ['plato', 'dish/plate', '菜;盘子', '食物与餐饮'], + ['menú', 'menu', '菜单', '食物与餐饮'], + ['entrante', 'starter', '前菜', '食物与餐饮'], + ['postre', 'dessert', '甜点', '食物与餐饮'], + ['bebida', 'drink', '饮料', '食物与餐饮'], + ['carne', 'meat', '肉', '食物与餐饮'], + ['pescado', 'fish', '鱼', '食物与餐饮'], + ['pollo', 'chicken', '鸡肉', '食物与餐饮'], + ['cerdo', 'pork', '猪肉', '食物与餐饮'], + ['ternera', 'veal/beef', '牛肉', '食物与餐饮'], + ['verduras', 'vegetables', '蔬菜', '食物与餐饮'], + ['fruta', 'fruit', '水果', '食物与餐饮'], + ['pan', 'bread', '面包', '食物与餐饮'], + ['arroz', 'rice', '米饭', '食物与餐饮'], + ['pasta', 'pasta', '意大利面', '食物与餐饮'], + ['huevo', 'egg', '鸡蛋', '食物与餐饮'], + ['queso', 'cheese', '奶酪', '食物与餐饮'], + ['leche', 'milk', '牛奶', '食物与餐饮'], + ['mantequilla', 'butter', '黄油', '食物与餐饮'], + ['aceite', 'oil', '油', '食物与餐饮'], + ['sal', 'salt', '盐', '食物与餐饮'], + ['azúcar', 'sugar', '糖', '食物与餐饮'], + ['sopa', 'soup', '汤', '食物与餐饮'], + ['ensalada', 'salad', '沙拉', '食物与餐饮'], + ['torta', 'cake', '蛋糕', '食物与餐饮'], + ['galleta', 'cookie', '饼干', '食物与餐饮'], + ['helado', 'ice cream', '冰淇淋', '食物与餐饮'], + // 居住与城市 + ['apartamento', 'apartment', '公寓', '居住与城市'], + ['piso', 'flat', '楼层;公寓', '居住与城市'], + ['edificio', 'building', '楼房', '居住与城市'], + ['habitación', 'room', '房间', '居住与城市'], + ['dormitorio', 'bedroom', '卧室', '居住与城市'], + ['baño', 'bathroom', '浴室', '居住与城市'], + ['cocina', 'kitchen', '厨房', '居住与城市'], + ['salón', 'living room', '客厅', '居住与城市'], + ['comedor', 'dining room', '餐厅;饭厅', '居住与城市'], + ['balcón', 'balcony', '阳台', '居住与城市'], + ['garaje', 'garage', '车库', '居住与城市'], + ['jardín', 'garden', '花园', '居住与城市'], + ['patio', 'courtyard', '院子', '居住与城市'], + ['escalera', 'stairs', '楼梯', '居住与城市'], + ['ascensor', 'elevator', '电梯', '居住与城市'], + ['puerta', 'door', '门', '居住与城市'], + ['ventana', 'window', '窗户', '居住与城市'], + ['pared', 'wall', '墙', '居住与城市'], + ['suelo', 'floor', '地面', '居住与城市'], + ['techo', 'ceiling', '天花板', '居住与城市'], + ['mueble', 'furniture', '家具', '居住与城市'], + ['cama', 'bed', '床', '居住与城市'], + ['mesa', 'table', '桌子', '居住与城市'], + ['silla', 'chair', '椅子', '居住与城市'], + ['sofá', 'sofa', '沙发', '居住与城市'], + ['lámpara', 'lamp', '台灯', '居住与城市'], + ['nevera', 'refrigerator', '冰箱', '居住与城市'], + ['lavadora', 'washing machine', '洗衣机', '居住与城市'], + ['calle', 'street', '街道', '居住与城市'], + ['barrio', 'neighborhood', '街区', '居住与城市'], + // 交通出行 + ['coche', 'car', '汽车', '交通出行'], + ['autobús', 'bus', '公交车', '交通出行'], + ['tren', 'train', '火车', '交通出行'], + ['metro', 'subway', '地铁', '交通出行'], + ['tranvía', 'tram', '有轨电车', '交通出行'], + ['bicicleta', 'bicycle', '自行车', '交通出行'], + ['moto', 'motorcycle', '摩托车', '交通出行'], + ['avión', 'airplane', '飞机', '交通出行'], + ['barco', 'boat', '船', '交通出行'], + ['taxi', 'taxi', '出租车', '交通出行'], + ['billete', 'ticket', '车票', '交通出行'], + ['estación', 'station', '车站', '交通出行'], + ['parada', 'stop', '公交站', '交通出行'], + ['andén', 'platform', '站台', '交通出行'], + ['carretera', 'road', '公路', '交通出行'], + ['autopista', 'highway', '高速公路', '交通出行'], + ['semáforo', 'traffic light', '红绿灯', '交通出行'], + ['conductor', 'driver', '司机', '交通出行'], + ['pasajero', 'passenger', '乘客', '交通出行'], + ['equipaje', 'luggage', '行李', '交通出行'], + ['maleta', 'suitcase', '行李箱', '交通出行'], + ['mapa', 'map', '地图', '交通出行'], + ['dirección', 'direction/address', '方向;地址', '交通出行'], + ['cruzar', 'to cross', '穿过', '交通出行'], + ['conducir', 'to drive', '驾驶', '交通出行'], + ['viajar', 'to travel', '旅行', '交通出行'], + ['llegar', 'to arrive', '到达', '交通出行'], + ['salir', 'to leave', '离开;出去', '交通出行'], + ['esperar', 'to wait', '等待', '交通出行'], + ['reservar', 'to reserve', '预订', '交通出行'], + // 工作与职业 + ['trabajo', 'work', '工作', '工作与职业'], + ['oficina', 'office', '办公室', '工作与职业'], + ['empresa', 'company', '公司', '工作与职业'], + ['empleo', 'job', '工作;职位', '工作与职业'], + ['empleado', 'employee', '雇员', '工作与职业'], + ['salario', 'salary', '工资', '工作与职业'], + ['sueldo', 'salary', '薪水', '工作与职业'], + ['contrato', 'contract', '合同', '工作与职业'], + ['entrevista', 'interview', '面试', '工作与职业'], + ['currículum', 'resume', '简历', '工作与职业'], + ['horario', 'schedule', '时间表', '工作与职业'], + ['jornada', 'working day', '工作日', '工作与职业'], + ['reunión', 'meeting', '会议', '工作与职业'], + ['informe', 'report', '报告', '工作与职业'], + ['proyecto', 'project', '项目', '工作与职业'], + ['cliente', 'client', '客户', '工作与职业'], + ['proveedor', 'supplier', '供应商', '工作与职业'], + ['medico', 'doctor', '医生', '工作与职业'], + ['enfermera', 'nurse', '护士', '工作与职业'], + ['profesor', 'teacher', '老师', '工作与职业'], + ['ingeniero', 'engineer', '工程师', '工作与职业'], + ['abogado', 'lawyer', '律师', '工作与职业'], + ['contable', 'accountant', '会计', '工作与职业'], + ['camarero', 'waiter', '服务员', '工作与职业'], + ['vendedor', 'salesperson', '销售员', '工作与职业'], + ['dependiente', 'shop assistant', '店员', '工作与职业'], + ['policía', 'police', '警察', '工作与职业'], + ['jubilado', 'retired person', '退休人员', '工作与职业'], + ['desempleado', 'unemployed', '失业的', '工作与职业'], + ['contratar', 'to hire', '雇用', '工作与职业'], + // 教育与学习 + ['asignatura', 'subject', '课程;科目', '教育与学习'], + ['clase', 'class', '课;班级', '教育与学习'], + ['lección', 'lesson', '课;功课', '教育与学习'], + ['deberes', 'homework', '作业', '教育与学习'], + ['examen', 'exam', '考试', '教育与学习'], + ['nota', 'grade/note', '分数;笔记', '教育与学习'], + ['aprobado', 'passed', '及格', '教育与学习'], + ['suspenso', 'failed', '不及格', '教育与学习'], + ['libro', 'book', '书', '教育与学习'], + ['cuaderno', 'notebook', '笔记本', '教育与学习'], + ['bolígrafo', 'pen', '圆珠笔', '教育与学习'], + ['lápiz', 'pencil', '铅笔', '教育与学习'], + ['borrador', 'eraser', '橡皮', '教育与学习'], + ['diccionario', 'dictionary', '词典', '教育与学习'], + ['biblioteca', 'library', '图书馆', '教育与学习'], + ['universidad', 'university', '大学', '教育与学习'], + ['facultad', 'faculty', '学院;系', '教育与学习'], + ['beca', 'scholarship', '奖学金', '教育与学习'], + ['investigación', 'research', '研究', '教育与学习'], + ['título', 'degree/title', '学位;标题', '教育与学习'], + ['aprender', 'to learn', '学习;学会', '教育与学习'], + ['estudiar', 'to study', '学习', '教育与学习'], + ['enseñar', 'to teach', '教', '教育与学习'], + ['entender', 'to understand', '理解', '教育与学习'], + ['explicar', 'to explain', '解释', '教育与学习'], + ['repetir', 'to repeat', '重复', '教育与学习'], + ['recordar', 'to remember', '记得', '教育与学习'], + ['olvidar', 'to forget', '忘记', '教育与学习'], + ['practicar', 'to practice', '练习', '教育与学习'], + ['repasar', 'to review', '复习', '教育与学习'], + // 健康与身体 + ['salud', 'health', '健康', '健康与身体'], + ['enfermedad', 'illness', '疾病', '健康与身体'], + ['dolor', 'pain', '疼痛', '健康与身体'], + ['fiebre', 'fever', '发烧', '健康与身体'], + ['tos', 'cough', '咳嗽', '健康与身体'], + ['gripe', 'flu', '流感', '健康与身体'], + ['resfriado', 'cold', '感冒', '健康与身体'], + ['cita médica', 'medical appointment', '医疗预约', '健康与身体'], + ['medicina', 'medicine', '药', '健康与身体'], + ['pastilla', 'pill', '药片', '健康与身体'], + ['receta', 'prescription', '处方', '健康与身体'], + ['hospital', 'hospital', '医院', '健康与身体'], + ['farmacia', 'pharmacy', '药店', '健康与身体'], + ['urgencias', 'emergency room', '急诊', '健康与身体'], + ['análisis', 'test/analysis', '检查;化验', '健康与身体'], + ['operación', 'operation', '手术', '健康与身体'], + ['dieta', 'diet', '饮食;节食', '健康与身体'], + ['ejercicio', 'exercise', '锻炼', '健康与身体'], + ['descanso', 'rest', '休息', '健康与身体'], + ['cansancio', 'tiredness', '疲惫', '健康与身体'], + ['herida', 'wound', '伤口', '健康与身体'], + ['sangre', 'blood', '血', '健康与身体'], + ['presión', 'pressure', '压力;血压', '健康与身体'], + ['cabeza', 'head', '头', '健康与身体'], + ['estómago', 'stomach', '胃', '健康与身体'], + ['espalda', 'back', '背', '健康与身体'], + ['pierna', 'leg', '腿', '健康与身体'], + ['brazo', 'arm', '手臂', '健康与身体'], + ['corazón', 'heart', '心脏', '健康与身体'], + ['curarse', 'to heal', '痊愈', '健康与身体'], + // 休闲娱乐 + ['afición', 'hobby', '爱好', '休闲娱乐'], + ['pasatiempo', 'pastime', '消遣', '休闲娱乐'], + ['deporte', 'sport', '运动', '休闲娱乐'], + ['fútbol', 'football/soccer', '足球', '休闲娱乐'], + ['baloncesto', 'basketball', '篮球', '休闲娱乐'], + ['tenis', 'tennis', '网球', '休闲娱乐'], + ['natación', 'swimming', '游泳', '休闲娱乐'], + ['correr', 'to run', '跑步', '休闲娱乐'], + ['cine', 'cinema', '电影院', '休闲娱乐'], + ['película', 'movie', '电影', '休闲娱乐'], + ['teatro', 'theater', '剧院', '休闲娱乐'], + ['concierto', 'concert', '音乐会', '休闲娱乐'], + ['música', 'music', '音乐', '休闲娱乐'], + ['canción', 'song', '歌曲', '休闲娱乐'], + ['baile', 'dance', '舞蹈', '休闲娱乐'], + ['dibujo', 'drawing', '绘画', '休闲娱乐'], + ['pintura', 'painting', '绘画;油漆', '休闲娱乐'], + ['fotografía', 'photography', '摄影', '休闲娱乐'], + ['juego', 'game', '游戏', '休闲娱乐'], + ['ajedrez', 'chess', '国际象棋', '休闲娱乐'], + ['excursión', 'excursion', '远足', '休闲娱乐'], + ['picnic', 'picnic', '野餐', '休闲娱乐'], + ['partido', 'match/game', '比赛', '休闲娱乐'], + ['equipo', 'team', '队伍', '休闲娱乐'], + ['ganador', 'winner', '赢家', '休闲娱乐'], + ['perdedor', 'loser', '输家', '休闲娱乐'], + ['tocar', 'to play (instrument)', '演奏;触摸', '休闲娱乐'], + ['cantar', 'to sing', '唱歌', '休闲娱乐'], + ['bailar', 'to dance', '跳舞', '休闲娱乐'], + ['dibujar', 'to draw', '画画', '休闲娱乐'], + // 自然与环境 + ['naturaleza', 'nature', '大自然', '自然与环境'], + ['campo', 'countryside/field', '田野;乡村', '自然与环境'], + ['montaña', 'mountain', '山', '自然与环境'], + ['mar', 'sea', '海', '自然与环境'], + ['playa', 'beach', '海滩', '自然与环境'], + ['río', 'river', '河', '自然与环境'], + ['lago', 'lake', '湖', '自然与环境'], + ['bosque', 'forest', '森林', '自然与环境'], + ['árbol', 'tree', '树', '自然与环境'], + ['flor', 'flower', '花', '自然与环境'], + ['animal', 'animal', '动物', '自然与环境'], + ['pájaro', 'bird', '鸟', '自然与环境'], + ['perro', 'dog', '狗', '自然与环境'], + ['gato', 'cat', '猫', '自然与环境'], + ['caballo', 'horse', '马', '自然与环境'], + ['vaca', 'cow', '牛', '自然与环境'], + ['tierra', 'earth/land', '土地;地球', '自然与环境'], + ['cielo', 'sky', '天空', '自然与环境'], + ['sol', 'sun', '太阳', '自然与环境'], + ['luna', 'moon', '月亮', '自然与环境'], + ['estrella', 'star', '星星', '自然与环境'], + ['lluvia', 'rain', '雨', '自然与环境'], + ['nieve', 'snow', '雪', '自然与环境'], + ['viento', 'wind', '风', '自然与环境'], + ['tormenta', 'storm', '暴风雨', '自然与环境'], + ['clima', 'climate', '气候', '自然与环境'], + ['ambiente', 'environment', '环境', '自然与环境'], + ['contaminación', 'pollution', '污染', '自然与环境'], + ['reciclar', 'to recycle', '回收利用', '自然与环境'], + ['cuidar', 'to take care of', '照顾;爱护', '自然与环境'], + // 购物 + ['tienda', 'shop', '商店', '购物'], + ['supermercado', 'supermarket', '超市', '购物'], + ['mercado', 'market', '市场', '购物'], + ['precio', 'price', '价格', '购物'], + ['rebajas', 'sales', '打折', '购物'], + ['descuento', 'discount', '折扣', '购物'], + ['oferta', 'offer', '特价', '购物'], + ['factura', 'invoice/receipt', '发票', '购物'], + ['recibo', 'receipt', '收据', '购物'], + ['dinero', 'money', '钱', '购物'], + ['tarjeta', 'card', '卡片', '购物'], + ['efectivo', 'cash', '现金', '购物'], + ['moneda', 'coin', '硬币', '购物'], + ['bolsa', 'bag', '袋子', '购物'], + ['cesta', 'basket', '篮子', '购物'], + ['ropa', 'clothes', '衣服', '购物'], + ['talla', 'size', '尺码', '购物'], + ['color', 'color', '颜色', '购物'], + ['probarse', 'to try on', '试穿', '购物'], + ['cambiar', 'to change', '换;改变', '购物'], + ['devolución', 'return/refund', '退货', '购物'], + ['barato', 'cheap', '便宜的', '购物'], + ['caro', 'expensive', '贵的', '购物'], + ['gratis', 'free', '免费', '购物'], + ['regatear', 'to bargain', '讨价还价', '购物'], + // 旅行 + ['viaje', 'trip', '旅行', '旅行'], + ['turista', 'tourist', '游客', '旅行'], + ['hotel', 'hotel', '旅馆', '旅行'], + ['hostal', 'hostel', '青年旅舍', '旅行'], + ['reserva', 'reservation', '预订', '旅行'], + ['habitación doble', 'double room', '双人间', '旅行'], + ['habitación individual', 'single room', '单人间', '旅行'], + ['recepción', 'reception', '前台', '旅行'], + ['llave', 'key', '钥匙', '旅行'], + ['pasaporte', 'passport', '护照', '旅行'], + ['visado', 'visa', '签证', '旅行'], + ['aduanas', 'customs', '海关', '旅行'], + ['guía', 'guide', '导游;指南', '旅行'], + ['visita', 'visit/tour', '参观', '旅行'], + ['monumento', 'monument', '古迹', '旅行'], + ['museo', 'museum', '博物馆', '旅行'], + ['iglesia', 'church', '教堂', '旅行'], + ['catedral', 'cathedral', '大教堂', '旅行'], + ['playa', 'beach', '海滩', '旅行'], + ['piscina', 'pool', '游泳池', '旅行'], + ['cámara', 'camera', '相机', '旅行'], + ['souvenir', 'souvenir', '纪念品', '旅行'], + ['hacer la maleta', 'to pack', '收拾行李', '旅行'], + ['perderse', 'to get lost', '迷路', '旅行'], + ['preguntar', 'to ask', '询问', '旅行'], + // 情感 + ['amor', 'love', '爱', '情感'], + ['alegría', 'joy', '快乐', '情感'], + ['tristeza', 'sadness', '悲伤', '情感'], + ['miedo', 'fear', '害怕', '情感'], + ['sorpresa', 'surprise', '惊讶', '情感'], + ['preocupación', 'worry', '担心', '情感'], + ['vergüenza', 'shame', '害羞;羞愧', '情感'], + ['orgullo', 'pride', '骄傲', '情感'], + ['calma', 'calm', '平静', '情感'], + ['enfado', 'anger', '生气', '情感'], + ['paciencia', 'patience', '耐心', '情感'], + ['confianza', 'confidence/trust', '信任', '情感'], + ['esperanza', 'hope', '希望', '情感'], + ['nostalgia', 'nostalgia', '怀旧', '情感'], + ['aburrimiento', 'boredom', '无聊', '情感'], + ['interés', 'interest', '兴趣', '情感'], + ['ilusionado', 'excited/hopeful', '满怀期待的', '情感'], + ['preocupado', 'worried', '担心的', '情感'], + ['nervioso', 'nervous', '紧张的', '情感'], + ['tranquilo', 'calm', '平静的', '情感'], + // 科技与媒体 + ['ordenador', 'computer', '电脑', '科技与媒体'], + ['portátil', 'laptop', '笔记本电脑', '科技与媒体'], + ['móvil', 'mobile phone', '手机', '科技与媒体'], + ['pantalla', 'screen', '屏幕', '科技与媒体'], + ['teclado', 'keyboard', '键盘', '科技与媒体'], + ['ratón', 'mouse', '鼠标', '科技与媒体'], + ['aplicación', 'app', '应用程序', '科技与媒体'], + ['programa', 'program', '程序;节目', '科技与媒体'], + ['archivo', 'file', '文件', '科技与媒体'], + ['documento', 'document', '文档', '科技与媒体'], + ['correo electrónico', 'email', '电子邮件', '科技与媒体'], + ['contraseña', 'password', '密码', '科技与媒体'], + ['usuario', 'user', '用户', '科技与媒体'], + ['red', 'network', '网络', '科技与媒体'], + ['internet', 'internet', '互联网', '科技与媒体'], + ['página web', 'web page', '网页', '科技与媒体'], + ['noticia', 'news', '新闻', '科技与媒体'], + ['periódico', 'newspaper', '报纸', '科技与媒体'], + ['revista', 'magazine', '杂志', '科技与媒体'], + ['redes sociales', 'social media', '社交媒体', '科技与媒体'], + // 描述与评价 + ['bonito', 'pretty', '漂亮的', '描述与评价'], + ['feo', 'ugly', '丑的', '描述与评价'], + ['grande', 'big', '大的', '描述与评价'], + ['pequeño', 'small', '小的', '描述与评价'], + ['alto', 'tall/high', '高的', '描述与评价'], + ['bajo', 'low/short', '矮的;低的', '描述与评价'], + ['largo', 'long', '长的', '描述与评价'], + ['corto', 'short', '短的', '描述与评价'], + ['nuevo', 'new', '新的', '描述与评价'], + ['viejo', 'old', '旧的', '描述与评价'], + ['joven', 'young', '年轻的', '描述与评价'], + ['mayor', 'older', '年长的;较大的', '描述与评价'], + ['menor', 'younger/smaller', '较小的;年幼的', '描述与评价'], + ['fácil', 'easy', '容易的', '描述与评价'], + ['difícil', 'difficult', '困难的', '描述与评价'], + ['interesante', 'interesting', '有趣的', '描述与评价'], + ['aburrido', 'boring', '无聊的', '描述与评价'], + ['importante', 'important', '重要的', '描述与评价'], + ['necesario', 'necessary', '必要的', '描述与评价'], + ['posible', 'possible', '可能的', '描述与评价'], + ['imposible', 'impossible', '不可能的', '描述与评价'], + ['seguro', 'safe/certain', '安全的;确定的', '描述与评价'], + ['peligroso', 'dangerous', '危险的', '描述与评价'], + ['limpio', 'clean', '干净的', '描述与评价'], + ['sucio', 'dirty', '脏的', '描述与评价'], + ['rápido', 'fast', '快的', '描述与评价'], + ['lento', 'slow', '慢的', '描述与评价'], + ['fuerte', 'strong', '强壮的;强烈的', '描述与评价'], + ['débil', 'weak', '虚弱的', '描述与评价'], + ['lleno', 'full', '满的', '描述与评价'], + // 常用动词 + ['ser', 'to be', '是', '常用动词'], + ['estar', 'to be (state)', '在;处于', '常用动词'], + ['haber', 'to have (there is)', '有', '常用动词'], + ['tener', 'to have', '有', '常用动词'], + ['hacer', 'to do/make', '做', '常用动词'], + ['ir', 'to go', '去', '常用动词'], + ['venir', 'to come', '来', '常用动词'], + ['volver', 'to return', '回来', '常用动词'], + ['entrar', 'to enter', '进入', '常用动词'], + ['subir', 'to go up', '上去', '常用动词'], + ['bajar', 'to go down', '下去', '常用动词'], + ['abrir', 'to open', '打开', '常用动词'], + ['cerrar', 'to close', '关闭', '常用动词'], + ['empezar', 'to begin', '开始', '常用动词'], + ['terminar', 'to finish', '结束', '常用动词'], + ['continuar', 'to continue', '继续', '常用动词'], + ['quedar', 'to remain/stay', '留下;约定', '常用动词'], + ['encontrar', 'to find', '找到', '常用动词'], + ['buscar', 'to look for', '寻找', '常用动词'], + ['dar', 'to give', '给', '常用动词'], + ['recibir', 'to receive', '收到', '常用动词'], + ['enviar', 'to send', '发送', '常用动词'], + ['dejar', 'to leave/allow', '留下;允许', '常用动词'], + ['poner', 'to put', '放置', '常用动词'], + ['quitar', 'to remove', '拿走', '常用动词'], + ['tomar', 'to take/drink', '拿;喝', '常用动词'], + ['beber', 'to drink', '喝', '常用动词'], + ['comer', 'to eat', '吃', '常用动词'], + ['vivir', 'to live', '居住', '常用动词'], + ['morir', 'to die', '死', '常用动词'], + ['nacer', 'to be born', '出生', '常用动词'], + ['crecer', 'to grow', '长大;增长', '常用动词'], + ['cambiar', 'to change', '改变;换', '常用动词'], + ['mejorar', 'to improve', '改善', '常用动词'], + ['empeorar', 'to worsen', '恶化', '常用动词'], + ['aumentar', 'to increase', '增加', '常用动词'], + ['disminuir', 'to decrease', '减少', '常用动词'], + ['necesitar', 'to need', '需要', '常用动词'], + ['querer', 'to want', '想要', '常用动词'], + ['desear', 'to wish', '希望', '常用动词'], + ['preferir', 'to prefer', '更喜欢', '常用动词'], + ['elegir', 'to choose', '选择', '常用动词'], + ['decidir', 'to decide', '决定', '常用动词'], + ['probar', 'to try', '尝试', '常用动词'], + ['intentar', 'to attempt', '尝试', '常用动词'], + ['lograr', 'to achieve', '实现', '常用动词'], + ['conseguir', 'to get/obtain', '获得', '常用动词'], + ['pensar', 'to think', '思考', '常用动词'], + ['creer', 'to believe', '相信', '常用动词'], + ['opinar', 'to have an opinion', '认为', '常用动词'], + ['suponer', 'to suppose', '假设', '常用动词'], + ['conocer', 'to know', '认识;了解', '常用动词'], + ['saber', 'to know', '知道', '常用动词'], + ['hablar', 'to speak', '说话', '常用动词'], + ['decir', 'to say', '说', '常用动词'], + ['contar', 'to tell/count', '讲述;数', '常用动词'], + ['escuchar', 'to listen', '听', '常用动词'], + ['oir', 'to hear', '听见', '常用动词'], + ['mirar', 'to look', '看', '常用动词'], + ['ver', 'to see', '看见', '常用动词'], + ['leer', 'to read', '阅读', '常用动词'], + ['escribir', 'to write', '写', '常用动词'], + ['ayudar', 'to help', '帮助', '常用动词'], + ['acompañar', 'to accompany', '陪伴', '常用动词'], + ['apoyar', 'to support', '支持', '常用动词'], + ['invitar', 'to invite', '邀请', '常用动词'], + ['visitar', 'to visit', '拜访', '常用动词'], + ['llamar', 'to call', '打电话;称呼', '常用动词'], + ['preguntar', 'to ask', '询问', '常用动词'], + ['responder', 'to answer', '回答', '常用动词'], + ['contestar', 'to answer', '答复', '常用动词'], + ['aceptar', 'to accept', '接受', '常用动词'], + ['rechazar', 'to reject', '拒绝', '常用动词'], + ['permitir', 'to allow', '允许', '常用动词'], + ['prohibir', 'to prohibit', '禁止', '常用动词'], + ['obligar', 'to oblige', '迫使', '常用动词'], + ['cumplir', 'to fulfill', '履行;完成', '常用动词'], + ['romper', 'to break', '打破', '常用动词'], + ['perder', 'to lose', '丢失;输', '常用动词'], + ['ganar', 'to win', '赢', '常用动词'], + ['parecer', 'to seem', '看起来', '常用动词'], + ['resultar', 'to turn out', '结果是', '常用动词'], + ['depender', 'to depend', '取决于', '常用动词'], + ['tratar', 'to treat/deal with', '对待;处理', '常用动词'], + ['funcionar', 'to work/function', '运转', '常用动词'], + ['usar', 'to use', '使用', '常用动词'], + ['utilizar', 'to utilize', '利用', '常用动词'], + ['guardar', 'to keep/store', '保存', '常用动词'], + ['recoger', 'to pick up', '拾起;接', '常用动词'], + ['sacar', 'to take out', '取出', '常用动词'], + ['meter', 'to put in', '放入', '常用动词'], + ['colgar', 'to hang', '挂', '常用动词'], + ['apagar', 'to turn off', '关闭', '常用动词'], + ['encender', 'to turn on', '打开', '常用动词'], + ['conectar', 'to connect', '连接', '常用动词'], + ['descargar', 'to download', '下载', '常用动词'], + ['compartir', 'to share', '分享', '常用动词'], + ['publicar', 'to publish', '发布', '常用动词'], + ['acordarse de', 'to remember', '记得', '常用动词'], + ['darse cuenta de', 'to realize', '意识到', '常用动词'], + ['tener que', 'to have to', '必须', '常用动词'], + ['poder', 'to be able to', '能够', '常用动词'], + ['soler', 'to usually do', '经常', '常用动词'], + ['costar', 'to cost', '花费;困难', '常用动词'], + // 时间与频率 + ['vez', 'time/occasion', '次', '时间与频率'], + ['momento', 'moment', '时刻', '时间与频率'], + ['época', 'era/period', '时代', '时间与频率'], + ['siglo', 'century', '世纪', '时间与频率'], + ['año', 'year', '年', '时间与频率'], + ['mes', 'month', '月', '时间与频率'], + ['semana', 'week', '星期', '时间与频率'], + ['fin de semana', 'weekend', '周末', '时间与频率'], + ['día laborable', 'working day', '工作日', '时间与频率'], + ['tarde', 'afternoon/late', '下午;晚', '时间与频率'], + ['mañana', 'morning/tomorrow', '早晨;明天', '时间与频率'], + ['noche', 'night', '夜晚', '时间与频率'], + ['madrugada', 'early morning', '凌晨', '时间与频率'], + ['minuto', 'minute', '分钟', '时间与频率'], + ['hora', 'hour', '小时', '时间与频率'], + ['segundo', 'second', '秒', '时间与频率'], + ['temporada', 'season', '季节;时节', '时间与频率'], + ['frecuente', 'frequent', '频繁的', '时间与频率'], + ['diario', 'daily', '每天的', '时间与频率'], + ['semanal', 'weekly', '每周的', '时间与频率'], + ['mensual', 'monthly', '每月的', '时间与频率'], + ['anual', 'annual', '每年的', '时间与频率'], + ['pronto', 'soon', '很快', '时间与频率'], + ['tarde', 'late', '迟到', '时间与频率'], + ['temprano', 'early', '早', '时间与频率'], + ['durante', 'during', '在……期间', '时间与频率'], + ['mientras', 'while', '当……时候', '时间与频率'], + ['hasta', 'until', '直到', '时间与频率'], + ['desde', 'since/from', '自从;从', '时间与频率'], + ['al final', 'at the end', '最后', '时间与频率'], + // 连接词与常用表达 + ['aunque', 'although', '虽然', '连接词与常用表达'], + ['además', 'besides', '此外', '连接词与常用表达'], + ['también', 'also', '也', '连接词与常用表达'], + ['tampoco', 'neither', '也不', '连接词与常用表达'], + ['sin embargo', 'however', '然而', '连接词与常用表达'], + ['por eso', 'therefore', '因此', '连接词与常用表达'], + ['por tanto', 'therefore', '所以', '连接词与常用表达'], + ['entonces', 'then', '那么', '连接词与常用表达'], + ['después', 'afterwards', '之后', '连接词与常用表达'], + ['luego', 'then', '然后', '连接词与常用表达'], + ['antes', 'before', '之前', '连接词与常用表达'], + ['primero', 'first', '首先', '连接词与常用表达'], + ['finalmente', 'finally', '最后', '连接词与常用表达'], + ['es decir', 'that is', '也就是说', '连接词与常用表达'], + ['por ejemplo', 'for example', '例如', '连接词与常用表达'], + ['en general', 'in general', '总的来说', '连接词与常用表达'], + ['en resumen', 'in summary', '总之', '连接词与常用表达'], + ['por un lado', 'on one hand', '一方面', '连接词与常用表达'], + ['por otro lado', 'on the other hand', '另一方面', '连接词与常用表达'], + ['a pesar de', 'despite', '尽管', '连接词与常用表达'], + ['en lugar de', 'instead of', '代替', '连接词与常用表达'], + ['a través de', 'through', '通过', '连接词与常用表达'], + ['de acuerdo', 'agreed', '同意', '连接词与常用表达'], + ['por supuesto', 'of course', '当然', '连接词与常用表达'], + ['claro que sí', 'of course yes', '当然可以', '连接词与常用表达'], + ['no sé', 'I do not know', '我不知道', '连接词与常用表达'], + ['me parece bien', 'that seems fine', '我觉得可以', '连接词与常用表达'], + ['qué pena', 'what a pity', '真遗憾', '连接词与常用表达'], + ['qué bien', 'how great', '太好了', '连接词与常用表达'], + ['qué mal', 'how bad', '太糟糕了', '连接词与常用表达'], + ['buena idea', 'good idea', '好主意', '连接词与常用表达'], + ['mala idea', 'bad idea', '坏主意', '连接词与常用表达'], + ['tener razón', 'to be right', '说得对', '连接词与常用表达'], + ['estar de acuerdo', 'to agree', '同意', '连接词与常用表达'], + ['depende', 'it depends', '看情况', '连接词与常用表达'], + ['por fin', 'at last', '终于', '连接词与常用表达'], + ['de repente', 'suddenly', '突然', '连接词与常用表达'], + ['al principio', 'at the beginning', '一开始', '连接词与常用表达'], + ['más o menos', 'more or less', '差不多', '连接词与常用表达'], + ['todo el mundo', 'everyone', '每个人', '连接词与常用表达'], + ['algo', 'something', '某事;一些', '连接词与常用表达'], +]; diff --git a/index.html b/index.html index 59f850f..30dc04e 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,8 @@
  • 重音规则
  • 时间表达
  • 常用动词短语
  • +
  • B1 核心词汇
  • +
  • 三语语音对照
  • @@ -35,6 +37,7 @@
    +
    @@ -92,7 +95,24 @@ + +
    +
    +

    中文 → 西班牙语

    + +
    + 翻译结果: + +
    + +
    +
    + + diff --git a/knowledge.html b/knowledge.html index 0ad71db..b8b96b2 100644 --- a/knowledge.html +++ b/knowledge.html @@ -46,6 +46,16 @@

    副词、介词、数词、常用句型

    12 个知识点 + +

    📚 B1 核心词汇

    +

    按主题整理的约 600 个 B1 常用词与表达

    + 18 类 · 595 词 +
    + +

    🔤 三语语音对照

    +

    汉语拼音 / 英语字母 / 西班牙语音标异同对比

    + 拼音 · 英语 · 西语 +
    diff --git a/knowledge/b1-vocabulario.html b/knowledge/b1-vocabulario.html new file mode 100644 index 0000000..a382989 --- /dev/null +++ b/knowledge/b1-vocabulario.html @@ -0,0 +1,69 @@ + + + + + + B1 核心词汇 — 西班牙语知识库 + + + + + +

    B1 核心词汇与表达

    +

    按主题整理的 B1 常用词汇,约 600 个核心词与表达。点击 🔊 听发音。

    + +
    +
    + + + + + + diff --git a/knowledge/comparacion-fonetica.html b/knowledge/comparacion-fonetica.html new file mode 100644 index 0000000..6f037ba --- /dev/null +++ b/knowledge/comparacion-fonetica.html @@ -0,0 +1,358 @@ + + + + + + 语音对照:汉语拼音 / 英语 / 西班牙语 — 西班牙语知识库 + + + + + +

    汉语拼音 · 英语字母 · 西班牙语发音对照

    +

    比较三套语音系统的异同,点击 🔊 听发音,重点区分最容易混淆的音。

    + +
    +

    0. 三套语音系统概览

    +
    Sistemas de pronunciación
    + + + + + + + + +
    项目汉语拼音英语西班牙语
    文字系统汉字 + 拼音字母26 个拉丁字母27 个拉丁字母
    发音单位声母 + 韵母 + 声调字母名 + 音素(元音/辅音)字母名 + 固定拼读规则
    元音数量6 个单韵母(含 ü)约 20 个元音音素5 个固定元音
    声调/重音4 个声调,决定词义重音影响词义,拼写不标记重音规则固定,可写重音符号
    字母音对应拼读较规则拼写与读音不一致多拼读非常规则
    最易混淆zh/ch/sh/j/q/x/cth / v / r / 长短元音b/v、r/rr、ll、ñ、j
    +
    + +
    +

    1. 汉语拼音

    +
    Pinyin chino
    + +

    声母

    +
    + +

    韵母

    +
    + +

    四个声调

    +
    +
    易错提醒:汉语声调决定词义,如 mā(妈)、má(麻)、mǎ(马)、mà(骂);西班牙语没有声调,只有固定重音。
    +
    + +
    +

    2. 英语字母与常见音素

    +
    English letters and sounds
    + +

    26 个字母名称

    +
    + +

    常见元音音素

    +
    + +

    常见辅音音素

    +
    +
    易错提醒:英语同一个字母有多种读音,如 a 在 apple /æ/、cake /eɪ/、about /ə/ 中不同;字母名与单词中的实际发音也不同。
    +
    + +
    +

    3. 西班牙语字母与拼读

    +
    Alfabeto y sonidos españoles
    + +

    元音

    +
    + +

    易混辅音

    +
    +
    易错提醒:西班牙语拼读基本固定:h 不发音,ll 常发“衣”或“日”,ñ 是 ni 的鼻音,r 和 rr 会区分词义(pero 但是 / perro 狗)。
    +
    + +
    +

    4. 三语易混淆音对照

    +
    Puntos de confusión
    +
    +
    + + + + + diff --git a/knowledge/style.css b/knowledge/style.css index 2953641..a046a93 100644 --- a/knowledge/style.css +++ b/knowledge/style.css @@ -185,6 +185,10 @@ th { background: var(--code-bg); font-weight: 600; } +.vocab-word-cell { + font-family: var(--font-mono); + white-space: nowrap; +} .badge { display: inline-block; diff --git a/style.css b/style.css index 8c33fe6..663ae5c 100644 --- a/style.css +++ b/style.css @@ -150,6 +150,12 @@ body { font-size: 0.85rem; cursor: pointer; white-space: nowrap; } #btn-save:hover { background: var(--accent-hover); } +#btn-helper { + background: none; border: 1px solid var(--accent); color: var(--accent); + padding: 0.35rem 0.75rem; border-radius: 6px; + font-size: 0.85rem; cursor: pointer; white-space: nowrap; +} +#btn-helper:hover { background: var(--accent); color: #fff; } #entry-text { flex: 1; resize: none; border: none; padding: 1rem; font-size: 1.05rem; line-height: 1.7; @@ -219,6 +225,53 @@ body { #modal-box .btn-cancel { background: var(--panel-bg); color: var(--text); } #modal-box .btn-confirm { background: var(--danger); color: #fff; border-color: var(--danger); } +/* Chinese to Spanish helper modal */ +#helper-modal-overlay { + display: none; + position: fixed; inset: 0; + background: rgba(0,0,0,0.4); + align-items: center; justify-content: center; + z-index: 110; +} +#helper-modal-overlay.show { display: flex; } +#helper-modal-box { + background: var(--panel-bg); border-radius: var(--radius); + padding: 1.5rem; max-width: 520px; width: 90%; + box-shadow: 0 8px 24px rgba(0,0,0,0.15); +} +#helper-modal-box h3 { + font-size: 1rem; margin-bottom: 0.75rem; +} +#helper-input { + width: 100%; min-height: 90px; resize: vertical; + border: 1px solid var(--border); border-radius: 6px; + padding: 0.6rem; font-size: 0.95rem; line-height: 1.6; + background: var(--bg); color: var(--text); outline: none; +} +#helper-input:focus { border-color: var(--accent); } +#helper-preview { + margin: 0.75rem 0 1rem; + padding: 0.6rem 0.75rem; + background: var(--code-bg, var(--bg)); + border-radius: 6px; + font-size: 0.9rem; + min-height: 2.5rem; +} +.helper-preview-label { color: var(--text-muted); font-weight: 600; } +#helper-result { font-family: var(--font-mono); color: var(--accent); } +#helper-modal-box .modal-actions { display: flex; gap: 0.5rem; justify-content: flex-end; } +#helper-modal-box .modal-actions button { + padding: 0.4rem 1rem; border-radius: 6px; border: 1px solid var(--border); + cursor: pointer; font-size: 0.85rem; +} +#helper-modal-box .btn-cancel { background: var(--panel-bg); color: var(--text); } +#helper-modal-box .btn-confirm { + background: var(--accent); color: #fff; border-color: var(--accent); +} +#helper-modal-box .btn-confirm:disabled { + opacity: 0.45; cursor: not-allowed; +} + @media (max-width: 768px) { body { padding: 0.5rem; } #app { grid-template-columns: 1fr; } diff --git a/translate.js b/translate.js index 793daaf..d3a28c5 100644 --- a/translate.js +++ b/translate.js @@ -127,7 +127,7 @@ const MOCK_TRANSLATIONS = { 'estar bien': { en: 'be fine', zh: '没问题' } }; -const SORTED_KEYS = Object.keys(MOCK_TRANSLATIONS).sort(function(a, b) { +var SORTED_KEYS = Object.keys(MOCK_TRANSLATIONS).sort(function(a, b) { return b.length - a.length; }); @@ -197,3 +197,297 @@ function getVocabForWord(word) { var entry = MOCK_TRANSLATIONS[w]; return entry || null; } + +// Chinese -> Spanish helper dictionary +const ZH_TO_ES = { + '你好': 'Hola', + '早上好': 'Buenos días', + '下午好': 'Buenas tardes', + '晚上好': 'Buenas noches', + '晚安': 'Buenas noches', + '再见': 'Adiós', + '谢谢': 'Gracias', + '请': 'Por favor', + '对不起': 'Lo siento', + '很高兴认识你': 'Mucho gusto', + '祝你好运': 'Buena suerte', + '是的': 'Sí', + '不是': 'No', + '今天': 'Hoy', + '昨天': 'Ayer', + '明天': 'Mañana', + '现在': 'ahora', + '已经': 'ya', + '总是': 'siempre', + '从不': 'nunca', + '我': 'yo', + '你': 'tú', + '他': 'él', + '她': 'ella', + '我们': 'nosotros', + '你们': 'vosotros', + '他们': 'ellos', + '我的': 'mi', + '你的': 'tu', + '和': 'y', + '或者': 'o', + '但是': 'pero', + '因为': 'porque', + '也': 'también', + '非常': 'muy', + '很': 'muy', + '一点': 'un poco', + '很多': 'mucho', + '好的': 'bien', + '朋友': 'amigo', + '家': 'casa', + '学校': 'escuela', + '工作': 'trabajo', + '公园': 'parque', + '餐厅': 'restaurante', + '图书馆': 'biblioteca', + '超市': 'supermercado', + '医院': 'hospital', + '书': 'libro', + '篮球': 'baloncesto', + '足球': 'fútbol', + '羽毛球': 'bádminton', + '游泳': 'nadar', + '跑步': 'correr', + '咖啡': 'café', + '茶': 'té', + '水': 'agua', + '电影': 'película', + '音乐': 'música', + '天气': 'tiempo', + '时间': 'tiempo', + '星期一': 'lunes', + '星期二': 'martes', + '星期三': 'miércoles', + '星期四': 'jueves', + '星期五': 'viernes', + '星期六': 'sábado', + '星期日': 'domingo', + '一月': 'enero', + '二月': 'febrero', + '三月': 'marzo', + '四月': 'abril', + '五月': 'mayo', + '六月': 'junio', + '七月': 'julio', + '八月': 'agosto', + '九月': 'septiembre', + '十月': 'octubre', + '十一月': 'noviembre', + '十二月': 'diciembre', + '去': 'ir', + '我去了': 'fui', + '我去': 'voy', + '我要': 'voy a', + '我想': 'quiero', + '我想要': 'quiero', + '我有': 'tengo', + '我学习': 'estudio', + '我学习了': 'estudié', + '我读书': 'leo', + '我读了一本书': 'leí un libro', + '我吃饭': 'como', + '我吃了': 'comí', + '我喝水': 'bebo agua', + '我喝了': 'bebí', + '我喜欢': 'me gusta', + '我爱': 'me encanta', + '我累了': 'Estoy cansado', + '我很累': 'Estoy muy cansado', + '我很开心': 'Estoy muy feliz', + '我生病了': 'Estoy enfermo', + '我正在学习': 'Estoy estudiando', + '我必须工作': 'Tengo que trabajar', + '我喜欢读书': 'Me gusta leer', + '我喜欢听音乐': 'Me gusta escuchar música', + '我想去旅行': 'Quiero viajar', + '我有一个朋友': 'Tengo un amigo', + '我没有钱': 'No tengo dinero', + '今天我去公园': 'Hoy fui al parque', + '今天我去学校': 'Hoy fui a la escuela', + '今天我去工作': 'Hoy fui al trabajo', + '昨天我去了公园': 'Ayer fui al parque', + '明天我要去公园': 'Mañana voy al parque', + '我和朋友去了公园': 'Fui al parque con mi amigo', + '今天我和朋友去了公园': 'Hoy fui al parque con mi amigo', + '今天天气很好': 'Hoy hace buen tiempo', + '今天天气热': 'Hoy hace calor', + '今天天气冷': 'Hoy hace frío', + '我学习西班牙语': 'Estudio español', + '我喜欢篮球': 'Me gusta el baloncesto', + '我喜欢足球': 'Me gusta el fútbol', + '我喜欢游泳': 'Me gusta nadar', + '我喜欢跑步': 'Me gusta correr', + '我喜欢打篮球': 'Me gusta jugar al baloncesto', + '我喜欢打足球': 'Me gusta jugar al fútbol', + '打篮球': 'jugar al baloncesto', + '打足球': 'jugar al fútbol', + '我喜欢篮球今天天气真好': 'Me gusta el baloncesto. Hoy hace muy buen tiempo.', + '我喜欢篮球今天天气很好': 'Me gusta el baloncesto. Hoy hace buen tiempo.', + '我要去打篮球': 'Voy a jugar al baloncesto', + '我要去打篮球了': 'Voy a jugar al baloncesto', + '我去打篮球': 'Voy a jugar al baloncesto', + '我去打篮球了': 'Fui a jugar al baloncesto', + '我要去踢足球': 'Voy a jugar al fútbol', + '我要去踢足球了': 'Voy a jugar al fútbol', + '我要去游泳': 'Voy a nadar', + '我要去游泳了': 'Voy a nadar', + '我去游泳了': 'Fui a nadar', + '我要去跑步': 'Voy a correr', + '我要去跑步了': 'Voy a correr', + '我去跑步了': 'Fui a correr', + '我要去图书馆': 'Voy a la biblioteca', + '我去图书馆了': 'Fui a la biblioteca', + '我要去学校': 'Voy a la escuela', + '我去学校了': 'Fui a la escuela', + '我要去工作': 'Voy al trabajo', + '我去工作了': 'Fui al trabajo', + '我想去公园': 'Quiero ir al parque', + '我想去学校': 'Quiero ir a la escuela', + '我想去图书馆': 'Quiero ir a la biblioteca', + '我想去工作': 'Quiero ir al trabajo', + '去公园': 'ir al parque', + '去学校': 'ir a la escuela', + '去图书馆': 'ir a la biblioteca', + '去工作': 'ir al trabajo', + '今天天气很好': 'Hoy hace buen tiempo', + '今天天气真好': 'Hoy hace muy buen tiempo', + '今天天气非常好': 'Hoy hace muy buen tiempo', + '天气很好': 'hace buen tiempo', + '天气真好': 'hace muy buen tiempo', + '真好': 'muy bien', + '很好': 'muy bien', + '今天我去公园和我的朋友': 'Hoy fui al parque con mi amigo', + '我去了公园和我的朋友': 'Fui al parque con mi amigo', + '公园和我的朋友': 'el parque con mi amigo', + '公园': 'el parque', + '我的朋友': 'mi amigo', + '妈妈': 'mamá', + '爸爸': 'papá', + '爷爷': 'abuelo', + '奶奶': 'abuela', + '外公': 'abuelo', + '外婆': 'abuela', + '哥哥': 'hermano mayor', + '姐姐': 'hermana mayor', + '弟弟': 'hermano menor', + '妹妹': 'hermana menor', + '儿子': 'hijo', + '女儿': 'hija', + '丈夫': 'marido', + '妻子': 'esposa', + '男朋友': 'novio', + '女朋友': 'novia', + '同事': 'colega', + '邻居': 'vecino', + '为什么': 'por qué', + '什么': 'qué', + '哪里': 'dónde', + '什么时候': 'cuándo', + '多少': 'cuánto', + '谁': 'quién', + '怎么': 'cómo', + '星期': 'semana', +}; + +var ZH_SORTED_KEYS = Object.keys(ZH_TO_ES).sort(function(a, b) { + return b.length - a.length; +}); + +function translateZhSegment(segment) { + if (!segment || !segment.trim()) return ''; + var input = segment.replace(/[\s,。!?、,.!?;;::""''()()]/g, ''); + var result = ''; + var matched = false; + var i = 0; + while (i < input.length) { + var found = false; + for (var k = 0; k < ZH_SORTED_KEYS.length; k++) { + var key = ZH_SORTED_KEYS[k]; + if (input.indexOf(key, i) === i) { + result += ZH_TO_ES[key] + ' '; + i += key.length; + matched = true; + found = true; + break; + } + } + if (!found) i++; + } + return matched ? result.trim() : ''; +} + +function translateZhToEs(text) { + if (!text || !text.trim()) return ''; + var clauses = []; + var seps = []; + var cur = ''; + for (var i = 0; i < text.length; i++) { + var ch = text[i]; + if (ch === '。' || ch === '!' || ch === '?' || ch === '!' || ch === '?' || ch === ';' || ch === ';') { + clauses.push(cur.trim()); + seps.push('.'); + cur = ''; + } else if (ch === ',' || ch === ',') { + clauses.push(cur.trim()); + seps.push(','); + cur = ''; + } else { + cur += ch; + } + } + clauses.push(cur.trim()); + seps.push(''); + + var parts = []; + for (var j = 0; j < clauses.length; j++) { + if (!clauses[j]) continue; + var translated = translateZhSegment(clauses[j]); + if (translated) { + parts.push(translated.replace(/[.。]+$/g, '')); + } + } + if (parts.length === 0) return ''; + + function capitalizeFirst(s) { + return s.charAt(0).toUpperCase() + s.slice(1); + } + function lowercaseFirst(s) { + return s.charAt(0).toLowerCase() + s.slice(1); + } + + var out = capitalizeFirst(parts[0]); + var k = 1; + for (var m = 0; m < seps.length && k < parts.length; m++) { + if (seps[m] && k < parts.length) { + out += (seps[m] === ',' ? ', ' + lowercaseFirst(parts[k]) : '. ' + capitalizeFirst(parts[k])); + k++; + } + } + while (k < parts.length) { + out += '. ' + capitalizeFirst(parts[k]); + k++; + } + if (!/[.!?]$/.test(out)) out += '.'; + return out; +} + +// Merge B1 vocabulary into translation dictionaries +if (typeof B1_VOCAB !== 'undefined') { + B1_VOCAB.forEach(function(item) { + var es = item[0].toLowerCase(); + MOCK_TRANSLATIONS[es] = { en: item[1], zh: item[2] }; + if (item[2]) ZH_TO_ES[item[2]] = item[0]; + }); + SORTED_KEYS = Object.keys(MOCK_TRANSLATIONS).sort(function(a, b) { + return b.length - a.length; + }); + ZH_SORTED_KEYS = Object.keys(ZH_TO_ES).sort(function(a, b) { + return b.length - a.length; + }); +}