昨天第一次使用 Git,終於替「泰語小旅伴」的首頁建立了版本紀錄。
接下來,我想開始加入真正的泰語學習內容。
目前首頁雖然已經有五個旅遊情境,但它們都還只是靜態卡片。使用者可以看到「基本問候」、「購物」、「餐廳點餐」等分類,卻還沒有真正的教材可以學習。
所以今天要處理的問題是:第一份泰語教材應該放在哪裡?
如果直接把中文、泰文和羅馬拼音寫進 HTML,好像也能把內容顯示出來。但之後教材越來越多,甚至還要加入單字卡和測驗,這樣真的合適嗎?
這次我先和 ChatGPT 討論教材該怎麼保存,再交給 Codex 實作。
前面規劃需求時,我們已經把第一版課程限制在五個旅遊情境,但這次不打算一次建立所有教材,而是先從「基本問候」開始。
第一份教材只有四句:
| 中文 | 泰文 | 羅馬拼音 |
|---|---|---|
| 你好 | สวัสดี | sà-wàt-dii |
| 謝謝 | ขอบคุณ | khɔ̀ɔp-khun |
| 對不起 | ขอโทษ | khɔ̌ɔ-thôot |
| 再見 | ลาก่อน | laa-kɔ̀ɔn |
對第一個課程來說,我不需要一開始就放進幾十句泰語。先有四句教材,確認資料可以正常顯示、課程可以操作,之後再增加內容就好。
不過,決定好教材內容之後,還有一個問題需要處理。
這些資料到底要放在哪裡?
Day 4 學 HTML 時,我先把它理解成負責網頁內容與結構。
既然如此,好像可以直接在 HTML 裡面加入教材。
例如,要顯示「你好」,就把中文、泰文和羅馬拼音放進一張教材卡片。
四句教材看起來不算多,直接寫進去似乎也沒什麼問題。
但和 ChatGPT 討論後,我開始理解,現在要考慮的不只是「這四句能不能顯示」,還有之後要怎麼繼續增加課程。
假設未來五個情境都有教材,每個情境又有好幾句泰語,如果把所有內容都直接放進 HTML,之後要修改某一句,就可能得在一大堆畫面結構中尋找。
更重要的是,Day 2 已經規劃了單字卡、小測驗和錯題複習。
同一句泰語,可能會出現在課程裡,也可能成為單字卡或測驗題目。
如果每個地方都各自保存一份教材內容,之後想修改某個句子時,就可能需要改好幾個地方。
所以這次決定換一種做法:
把教材資料和畫面分開保存。
回頭看 Day 4 建立的專案骨架,其實 Codex 當時就已經預留了一個檔案:
data/lessons.js
只是最初它還是空白的預留檔,沒有真正的教材內容。
這次終於要開始使用它了。
根據 Codex 的實作紀錄,lessons.js 加入了基本問候的四句教材。
以下是檔案中 basicGreetings 的資料區塊:
basicGreetings: {
title: "基本問候",
phrases: [
{
id: "greeting-hello",
chinese: "你好",
thai: "สวัสดี",
pronunciation: "sà-wàt-dii"
},
{
id: "greeting-thanks",
chinese: "謝謝",
thai: "ขอบคุณ",
pronunciation: "khɔ̀ɔp-khun"
},
{
id: "greeting-sorry",
chinese: "對不起",
thai: "ขอโทษ",
pronunciation: "khɔ̌ɔ-thôot"
},
{
id: "greeting-goodbye",
chinese: "再見",
thai: "ลาก่อน",
pronunciation: "laa-kɔ̀ɔn"
}
]
},
第一次看到這種寫法,我還需要先理解幾個東西。
首先,最外面的 basicGreetings 是這個課程在資料中的名稱,裡面的 title 則是要顯示給使用者看的課程標題。
接著是 phrases,裡面放著這個課程的所有句子。
在 JavaScript 裡,這裡使用了陣列(Array)來保存多筆教材,而每一句教材則使用物件(Object)來整理相關資訊。
可以先把它想成:
基本問候
│
├── 你好
├── 謝謝
├── 對不起
└── 再見
每一句教材都有相同的欄位:
| 欄位 | 用途 |
|---|---|
id |
用來識別這筆教材 |
chinese |
中文意思 |
thai |
泰文內容 |
pronunciation |
羅馬拼音 |
例如「你好」的 id 是 greeting-hello,泰文則保存在 thai 欄位。
這樣一來,程式之後就可以透過固定的欄位取得需要的內容,不需要把每句泰語的文字都直接寫在 HTML 裡。
而且從這份資料也可以看到,情境分類是透過 basicGreetings 這個課程結構來表示,並不是每一句都另外存放一個情境欄位。
對現在的我來說,還不需要一次搞懂所有 JavaScript 語法,至少先理解:原來可以把相關資料整理成固定的結構,再交給程式使用。
前面 Day 2 討論需求時,我們已經決定每句教材除了中文、泰文和羅馬拼音,還需要能夠播放發音。
但從剛才的程式碼可以發現,教材裡沒有另外保存音訊檔案。
它保存的是泰文字串,例如:
thai: "สวัสดี",
至於「點一下就能聽到泰語」,那是之後要加入的程式功能。
後續規劃發音時,可以直接使用教材中的 thai 欄位,交給瀏覽器的語音功能處理,而不需要另外保存一份重複的泰文。
這也讓我開始理解,把教材整理成資料之後,同一個欄位可以提供給不同功能使用。
不過,這次先專注在教材資料,真正的發音實作會留到 Day 10 再介紹。
這次討論完教材的保存方式後,就把工作交給 Codex。
根據開發紀錄,它實際修改了四個檔案:
index.html
css/style.css
data/lessons.js
js/app.js
其中,data/lessons.js 從原本的空白預留檔,加入了四句基本問候教材。
不過,這次 Codex 並不是只建立資料,也同時完成了課程畫面和基本互動。
也就是說,教材資料和課程功能是在同一輪實作中完成的。
只是對現在的我來說,如果一次研究四個檔案的所有修改,可能很難搞清楚每個部分的用途。
所以今天先把重點放在教材資料,下一篇再看程式怎麼使用這些資料,讓使用者可以從首頁進入課程。
這樣比較容易一步一步理解。
整理這次的修改後,我開始理解,把教材獨立存放不只是為了讓檔案看起來比較整齊。
例如之後發現某句教材需要修改,可以先找到集中保存教材的地方,而不必從整個 HTML 畫面裡尋找。
未來要增加購物、餐廳點餐等情境時,也可以沿用相同的資料結構,逐步加入不同的課程。
更重要的是,Day 2 已經規劃了單字卡和測驗。
假設同一句「謝謝」未來需要出現在課程、單字卡和測驗中,就可以考慮讓不同功能讀取同一份教材,而不是各自保存一份。
這樣有機會減少重複資料,也比較容易維護。
當然,目前只是先建立教材資料,並不代表單字卡和測驗已經完成。
我現在的目標仍然很單純:先讓第一個課程正常運作,再逐步增加功能。
這次還有一件需要特別注意的事情。
因為「泰語小旅伴」是一個語言學習 App,教材本身的正確性也很重要。
對程式來說,只要資料格式符合預期,可能就能正常顯示中文、泰文和羅馬拼音。
但畫面正常顯示,不代表泰語教材一定正確或自然。
例如泰語有聲調,也有不同的禮貌用語和使用情境;羅馬拼音的表示方式,也可能因為採用的轉寫系統不同而有差異。
目前這四句教材已經加入專案,但開發紀錄還沒有顯示它們經過母語者或可信語言資料的完整驗證。
因此,這個階段我會先把完成範圍分清楚:
教材資料已經建立,不等於語言內容已經完成驗證。
之後增加課程時,除了檢查程式能不能正確顯示,也需要進一步確認泰文、翻譯、拼音及使用情境。
這部分不能只靠程式測試通過,就直接當作教材沒有問題。
回頭整理這次的 Codex 紀錄,可以確認 data/lessons.js 已經加入四句基本問候教材,並且成為課程畫面使用的資料來源。
這次也一併完成了基本問候的互動功能,Codex 回報已經測試過進入課程、顯示四句教材,以及返回首頁的流程。
不過,這裡要區分 Codex 的測試回報和我自己親自在瀏覽器完成的操作。
目前開發紀錄可以確認 Codex 有回報相關測試結果,但還沒有足夠紀錄能確認我本人當時已經完整操作過這段流程。
所以今天先把焦點放在教材資料的建立。
至於使用者怎麼點進課程、程式如何產生教材卡片,以及返回首頁的功能,就留到下一篇再整理。
今天最大的收穫,是第一次接觸到「把資料和畫面分開」的概念。
原本只是想讓首頁上的「基本問候」有四句泰語可以學,沒想到真正開始做功能時,還需要先想好教材應該放在哪裡。
現在我至少知道,index.html 不一定要負責保存所有教材。
可以讓 lessons.js 集中管理資料,再由 JavaScript 使用這些資料,顯示到畫面上。
而且透過實際的教材程式碼,我也第一次開始認識 JavaScript 的物件、陣列和欄位。
雖然還沒有完全弄懂所有語法,但至少知道這份資料的用途,以及為什麼要把它獨立出來。
目前第一份基本問候教材已經建立,接下來就是把它真正接到畫面上。
使用者點擊首頁的「基本問候」後,能不能正確顯示四句教材?看完又能不能返回首頁?
下一篇,就來看看 Codex 怎麼把這份教材變成可以操作的課程,讓「泰語小旅伴」不再只有靜態首頁。