Library
🎬 Video B1 Easy Cantonese 2 — What Makes You Happy?
Easy Cantonese 2 — What Makes You Happy?
咩令你快樂?
About this video Easy Languages hits the streets of Hong Kong to ask locals: what makes you happy? Listen to real Cantonese speakers give short, natural answers — perfect for intermediate learners.
Transcript
00:00
Ngo5dei6 ji4gaa1 ceot1faat3 laa3! Gam1jat6 soeng2 man6 haa5 nei5 ne1, jau5 di1 me1 ling6dou3 nei5 hoi1sam1 gaa3?
Let's get started! Today we want to ask you: what makes you happy?
00:35
Ngo5 lam2 hai6 ngo5 uk1kei2jan4 laa1, ngo5 siu2pang4jau5 lo1, waak6ze2 jau5zan2si4 tung4 aa3zai2 jat1cai4 waan2. Zi3siu2 ho2ji5 hai5 uk1kei2 hing1sung1 haa2.
I think it's my family, my child. Sometimes playing with my son. At least I can stay home and relax.
01:18
……
Gaan2 heoi3 bin1dou6 aa2? Ngo5 mei6 heoi3gwo3 ge1 dei6fong1 lo1. Pei3jyu4... jat6bun2 lo1, jyun5 di1 ge3 dei6fong1.
Where would I go? Places I've never been. For example... Japan. Somewhere farther away.
01:40
……
Sang1wut6 leoi5min6 ling6dou3 ngo5 hoi1sam1 aa3? Ng6... mou5 me1 hing3ceoi3 ge2. Hou2 naan4 gong2.
Things in life that make me happy? Um... I don't really have any hobbies. It's hard to say.
02:18
Gam2 keoi5 jau4 sai3 dou3 daai6 dou1 ziu3gu3 ngo5 laa1, keoi5 zi1 ngo5 ng4 zung1ji3 sik6 di1 pei4 aa1 maa3.
He's been taking care of me since I was little. He knows I don't like eating the skin.
03:12
……
Pei3jyu4 se6gik1 aa1? Ding6hai6 go2di1... Gei2 fan1zung1 dou1 mou5, zau6 bei3 ngo5 aa3maa1 sau1zo2 laa3.
For example archery? Or those... Not even a few minutes and my mum confiscates it.
03:50
Mou5, zau6 hai6 sik6 je5. Ng6! Ngo5 dou1 hai6.
No, just eating. Yes! Me too.
04:15
Do1ze6 nei5dei6 zip3sau6 ngo5dei6 ge3 fong3man6!
Thank you all for taking part in our interview!
/** * Cantonese.hk — Audio Helper * Uses POST to /api/audio.php to bypass Cloudflare CDN cache. * Converts response to Blob URL for playback. * * Exposes: * window.cantoAudio — the shared Audio element (set once created) * window.cantoSpeak(text, btn, rate) * window.cantoSpeakWord(wordId, fallbackText, btn) * window.cantoStop() * * Dispatches on document: * 'cantoplaystart' — when audio.play() is called ({ detail: { text } }) * 'cantoplayend' — when audio ends or errors */ (function() { 'use strict'; var audioEl = null; var currentBtn = null; var currentBlob = null; function getAudio() { if (!audioEl) { audioEl = new Audio(); window.cantoAudio = audioEl; // expose for external karaoke hooks } return audioEl; } function revokeBlob() { if (currentBlob) { URL.revokeObjectURL(currentBlob); currentBlob = null; } } function clearPlaying() { if (currentBtn) { currentBtn.classList.remove('playing'); currentBtn = null; } } function dispatchEnd() { document.dispatchEvent(new CustomEvent('cantoplayend')); } window.cantoStop = function() { clearPlaying(); if (audioEl) { audioEl.pause(); audioEl.src = ''; } revokeBlob(); if ('speechSynthesis' in window) window.speechSynthesis.cancel(); dispatchEnd(); }; // POST text to audio.php, play response as blob window.cantoSpeak = function(text, btn, rate) { if (!text) return; clearPlaying(); if (audioEl) { audioEl.pause(); audioEl.src = ''; } revokeBlob(); if ('speechSynthesis' in window) window.speechSynthesis.cancel(); if (btn) { currentBtn = btn; btn.classList.add('playing'); } var fd = new FormData(); fd.append('action', 'speak'); fd.append('text', text); fetch('/api/audio.php', {method: 'POST', body: fd}) .then(function(r) { if (r.status === 204 || !r.ok) throw new Error('no audio'); return r.blob(); }) .then(function(blob) { var url = URL.createObjectURL(blob); currentBlob = url; var audio = getAudio(); audio.onended = function() { clearPlaying(); revokeBlob(); dispatchEnd(); }; audio.onerror = function() { clearPlaying(); revokeBlob(); dispatchEnd(); }; audio.src = url; // Fire cantoplaystart so readers can attach timeupdate karaoke document.dispatchEvent(new CustomEvent('cantoplaystart', { detail: { text: text, audio: audio } })); return audio.play(); }) .catch(function() { fallbackWebSpeech(text, rate); }); }; function fallbackWebSpeech(text, rate) { if (!('speechSynthesis' in window)) { clearPlaying(); return; } var u = new SpeechSynthesisUtterance(text); u.lang = 'zh-HK'; u.rate = rate || 0.8; var voices = window.speechSynthesis.getVoices(); for (var i = 0; i < voices.length; i++) { var vl = voices[i].lang.toLowerCase(); if (vl === 'zh-hk' || vl === 'yue-hk' || vl.indexOf('yue') !== -1 || vl === 'zh-tw') { u.voice = voices[i]; break; } } u.onend = function() { clearPlaying(); dispatchEnd(); }; u.onerror = function() { clearPlaying(); dispatchEnd(); }; window.speechSynthesis.speak(u); } if ('speechSynthesis' in window) { window.speechSynthesis.getVoices(); window.speechSynthesis.onvoiceschanged = function() { window.speechSynthesis.getVoices(); }; } window.cantoSpeakWord = function(wordId, fallbackText, btn) { if (!wordId) { cantoSpeak(fallbackText, btn); return; } var xhr = new XMLHttpRequest(); xhr.open('GET', '/api/audio.php?action=word&id=' + encodeURIComponent(wordId), true); xhr.timeout = 2000; xhr.onload = function() { if (xhr.status === 200) { try { var data = JSON.parse(xhr.responseText); cantoSpeak(data.text || fallbackText, btn); } catch(e) { cantoSpeak(fallbackText, btn); } } else { cantoSpeak(fallbackText, btn); } }; xhr.onerror = function() { cantoSpeak(fallbackText, btn); }; xhr.ontimeout = function() { cantoSpeak(fallbackText, btn); }; xhr.send(); }; document.addEventListener('DOMContentLoaded', function() { document.addEventListener('click', function(e) { var btn = e.target.closest('.audio-play'); if (!btn) return; e.preventDefault(); e.stopPropagation(); if (typeof window.stopPlayAll === 'function') window.stopPlayAll(); var text = btn.getAttribute('data-text'); var wordId = btn.getAttribute('data-word-id'); if (wordId) { cantoSpeakWord(wordId, text, btn); } else if (text) { cantoSpeak(text, btn); } }); }); })();