為 AWS Manila Community Day 打造 Tagalog 學習 App 的 Extra Examples 更獨特且可審閱
當 Tagalog 學習 App 成長到 24 個文章頁後,最大的內容風險是重複。靜態頁面可能看起來完整,但許多卡片其實重複使用相同的 extra examples。Python scripts 展示了如何重寫、去重與驗證例句內容,讓 App 更容易審閱,也更適合技術分享。
此文章現在已發布於 AWS 官方 Builder Center。你可以前往官方文章,或關閉此視窗並留在此頁繼續閱讀。
當 Tagalog 學習 App 成長到 24 個文章頁後,最大的內容風險是重複。靜態頁面可能看起來完整,但許多卡片其實重複使用相同的 extra examples。Python scripts 展示了如何重寫、去重與驗證例句內容,讓 App 更容易審閱,也更適合技術分享。
當 Tagalog 學習 App 成長到 24 個文章頁後,最大的內容風險是重複。靜態頁面可能看起來完整,但許多卡片其實重複使用相同的 extra examples。Python scripts 展示了如何重寫、去重與驗證例句內容,讓 App 更容易審閱,也更適合技術分享。
目的:本專案是獨立的教育原型,用於語言學習、社群準備與技術分享。它的設計目標,是協助開發者在參加 AWS Manila Community Day 前練習簡單的 Tagalog。
非商業用途:本專案沒有商業模式、付費存取、廣告計畫、聯盟行銷方案或營利目標。它是為社群準備與開發者教育而建立的學習作品。
不保證正確性:App 可能使用生成式 AI 內容,因此翻譯、發音指南、文法說明與文化註解,在公開使用前都應由 Tagalog 母語者審閱。
範圍:目標不是打造完整的翻譯平台,而是示範如何用清楚的資料結構、可重複的產生邏輯與驗證檢查,將靜態學習網站在地化。
尊重社群:App 應避免刻板印象,並謹慎教導禮貌用語。像 po、opo、kayo、ninyo 這類詞,應被解釋為表達尊重的工具,而不是裝飾。
Natural Tagalog:
Nakalimutan ko ang payong ko.
English:
I forgot my umbrella.
Polite Tagalog:
Nakalimutan ko po ang payong ko po.
Friendly Filipino-English:
Nakalimutan ko ang payong ko, okay po.
Playful Filipino-English:
Uy, Nakalimutan ko ang payong ko, all right.
Tone:
daily
Cultural Context:
這句可用於下雨情境。和警衛、司機、攤販、工作人員、長輩,以及第一次見面的人說話時,先使用禮貌形式。
Context Use:
適合日常 Manila 情境。簡短的 Tagalog 句子加上禮貌標記,在公共場所聽起來自然、溫暖且實用。
nakalimut 相關的地點、物件或動作形式。yong 相關的請求或方向用語。逐字發音可以讀成:nah-kah-lee-moo-tahn koh ahng pah-yohng poh.
內容 QA 腳本:
- rewrite_extras_from_main_examples.py
- force_rewrite_all_extra_examples.py
- dedupe_tagalog_examples.py
主要工作:
- 讀取每個 sentence-card article block
- 抽出 Natural Tagalog
- 當 Natural Tagalog 重複時讓它變得可追蹤
- 為每張卡片建立三個 extra examples
- 加入 English、Natural Tagalog、Polite Tagalog 版本
- 重新產生文法與發音段落
- 確認每篇文章仍有 40 張卡片
- 印出更新檔案數量
說明為什麼主文章頁產生後,extra examples 還需要自己的 QA pass。
說明如何根據當前卡片的 Natural Tagalog 產生 extra examples。
說明當卡片邊界或既有 HTML 結構不一致時,為什麼第二輪 pass 會有幫助。
說明 article number、sentence number 與 example number 如何讓重複內容更容易審閱。
說明簡單 assert 如何保護靜態網站,避免產生破損文章頁。
讓每張卡片都感覺有用,而不是像複製貼上。
這裡的技能是 generated static pages 的內容 QA。產生出的網站可能通過版型檢查,但如果每個 extra example 都重複同一句,學習品質仍然會失敗。
審閱每一張 sentence card。
如果 extra examples 重複或太泛用,就重寫。
每張卡片維持三個 extra examples。
每個 extra example 都應包含:
- Tagalog
- English
- Natural Tagalog
- Polite Tagalog
- Grammatical Breakdown
- Pronunciation Guide
重複內容可能藏在有效 HTML 裡:
<div class="extra-example">
<p><strong>Tagalog:</strong><br><span lang="tl">Ayos, salamat.</span></p>
<p><strong>English:</strong><br>All right, thank you.</p>
</div>
這個區塊結構正確,但如果數百張卡片都使用同一句,學習價值就會下降。
使用卡片目前的 Natural Tagalog 句子,作為相關例句的來源。
rewrite_extras_from_main_examples.py 會抽出主句,並圍繞它建立三個 example blocks。
def extra_block(index: int, main: str) -> str:
examples = [
(
f'Gagamitin ko rin ang linyang "{main}" mamaya.',
f'I will also use the line "{main}" later.',
f'Uulitin ko ang linyang "{main}" nang dahan-dahan.',
f'Pakisuyo, uulitin ko po ang linyang "{main}" nang dahan-dahan.',
),
(
f'Sasabihin ko ang linyang "{main}" sa kausap ko.',
f'I will say the line "{main}" to the person I am talking to.',
f'Ipapaliwanag ko ang linyang "{main}" sa simpleng paraan.',
f'Pakisuyo, ipapaliwanag ko po ang linyang "{main}" sa simpleng paraan.',
),
(
f'Magsanay tayo gamit ang linyang "{main}" ngayon.',
f'Let us practice using the line "{main}" now.',
f'Isusulat ko ang linyang "{main}" sa notes ko.',
f'Pakisuyo, isusulat ko po ang linyang "{main}" sa notes ko.',
),
]
這些例句會連回目前卡片。如果卡片教的是:
Natural Tagalog:
Paki-check kung pumasok ang bayad.
extra examples 就可以說明如何使用、重複、解釋或寫下這句話。這比不相關的填充句更有用。
<div class="extra-example">
<p><strong>Tagalog:</strong><br><span lang="tl">Gagamitin ko rin ang linyang "Paki-check kung pumasok ang bayad" mamaya.</span></p>
<p><strong>English:</strong><br>I will also use the line "Paki-check kung pumasok ang bayad" later.</p>
<p><strong>Natural Tagalog:</strong><br><span lang="tl">Uulitin ko ang linyang "Paki-check kung pumasok ang bayad" nang dahan-dahan.</span></p>
<p><strong>Polite Tagalog:</strong><br><span lang="tl">Pakisuyo, uulitin ko po ang linyang "Paki-check kung pumasok ang bayad" nang dahan-dahan.</span></p>
</div>
處理 regex card matching 或 example boundaries 需要更強 pass 的文章頁。
force_rewrite_all_extra_examples.py 會掃描 sentence-card start tags、切出每張卡片、重寫 extra examples、刷新 helper sections,並檢查卡片數量。
ARTICLE_START = re.compile(r'<article class="sentence-card" id="sentence-\d+">')
def rewrite_cards(path: Path, text: str) -> tuple[str, int]:
starts = [match.start() for match in ARTICLE_START.finditer(text)]
if not starts:
return text, 0
parts = []
cursor = 0
count = 0
for index, start in enumerate(starts):
end = starts[index + 1] if index + 1 < len(starts) else text.find("</section>", start)
card = text[start:end]
natural = field_text(card, "Natural Tagalog:")
card = rewrite_extras(card, natural)
card = refresh_main_sections(card)
parts.append(text[cursor:start])
parts.append(card)
cursor = end
count += 1
parts.append(text[cursor:])
return "".join(parts), count
產生的 HTML 可能有很長的單行、重複區塊或巢狀區塊,讓簡單替換變得脆弱。用卡片切片當工作單位,腳本會更清楚。
腳本可以明確做到:
針對每個文章頁:
- 找出 40 張 sentence cards
- 重寫每張卡片
- 刷新文法與發音
- 如果頁面不是 40 張卡片就失敗
移除重複的 Natural Tagalog 內容,並讓 examples 足夠獨特、方便審閱。
dedupe_tagalog_examples.py 加入兩個重要概念:
1. 追蹤所有文章頁中的重複 Natural Tagalog lines。
2. 用 article number、sentence number、extra example number 產生可追蹤的 extra examples。
def unique_main_text(text: str, article: int, sentence: int, occurrence: int) -> str:
context = f"sa aralin {number_word(article)}, pangungusap {number_word(sentence)}"
clean = text.strip()
if occurrence <= 1:
return clean
if clean.endswith("?"):
return re.sub(r"\?$", f" {context}?", clean)
return re.sub(r"[.!]?$", f" {context}.", clean)
如果同一個 Natural Tagalog 句子出現超過一次,腳本可以讓重複版本可追蹤:
原本:
Salamat sa tulong.
可追蹤的 duplicate-safe 版本:
Salamat sa tulong sa aralin lima, pangungusap dalawa.
這不只是語言變更,也是 QA 訊號。審閱者可以定位重複內容,判斷這個 generated uniqueness 是否可接受,或是否應手動改寫 source content。
dedupe script 也會根據文章群組選擇 example scenes:
def group_for(path: Path) -> str:
if "friendship" in path.name:
return "friendship"
if "manila-daily" in path.name:
return "manila"
return "community"
接著每個群組會得到符合領域的 examples:
Community:
- session
- workshop
- community table
Friendship:
- mahinahong usapan
- tapat na mensahe
- ligtas na pag-uusap
Manila Daily:
- commute
- palengke
- araw-araw na errand
Community example:
Sa aralin apat, pangungusap sampu, gagamitin ko ito sa workshop.
Friendship example:
Sa aralin labing-anim, pangungusap pito, aalagaan ko ang tapat na mensahe.
Manila Daily example:
Sa aralin dalawampu't dalawa, pangungusap tatlo, gagamitin ko ito sa palengke.
大量重寫時,保護產生出的網站結構不被破壞。
腳本使用 card count 的硬性檢查與輸出摘要。
for path in sorted(ROOT.glob("article-*.html"), key=lambda p: article_number(p)):
text = path.read_text(encoding="utf-8")
card_count = 0
def replace_card(match: re.Match[str]) -> str:
nonlocal card_count
card_count += 1
return rewrite_one_card(match.group(0))
updated = CARD_RE.sub(replace_card, text)
if card_count != 40:
raise RuntimeError(f"{path.name}: expected 40 cards, found {card_count}")
rewrite process 變得更安全:
預期:
24 個文章頁
每篇文章 40 張 sentence cards
每張卡片 3 個 extra examples
失敗模式:
raise error,而不是寫出部分破損頁面
背景:Extra examples 不是裝飾,它們教學習者如何重用短句。
目標:讓 examples 連回目前卡片。
Prompt:從卡片的 Natural Tagalog sentence 建立 extra examples。
結果:學習者會看到同一句如何被練習、重複、解釋或放進場景。
Review check:每個 example 是否支援主句,而不是分散注意力?
背景:Generated content 可能在許多卡片中重複。
目標:讓重複句子可見且可追蹤。
Prompt:追蹤所有文章頁的 Natural Tagalog strings,並在重複時加入 lesson context。
結果:審閱者能快速知道重複內容來自哪裡。
Review check:審閱者是否能把 generated example 對回 article number 與 sentence number?
背景:如果 polite field 和 natural field 完全相同,教學價值有限。
目標:適當加入 po、Pakisuyo 或其他尊重句型。
Prompt:如果 Natural Tagalog 與 Polite Tagalog 相同,就建立一個有差異的 polite version。
結果:學習者更容易比較自然語氣與尊重語氣。
Review check:polite example 是否尊重但不生硬?
背景:HTML regex 如果亂用會很脆弱。
目標:只在穩定的 generated markers 周圍使用 regex,並在之後驗證 counts。
Prompt:match 已知 sentence-card blocks,重寫它們,然後 assert 40 cards。
結果:對 generated static HTML 來說,腳本保持實用,也避免 silent corruption。
Review check:當預期 card count 不存在時,腳本是否會失敗?
這個內容 QA flow 很適合開發者分享,因為它展示了一個可信 generated demo 背後的隱藏工作:
Generated article pages
->
detect sentence cards
->
extract Natural Tagalog
->
rewrite three extra examples
->
make duplicates traceable
->
regenerate grammar and pronunciation
->
assert 40 cards
->
write updated files
->
print JSON or count summary
最重要的 lesson 是:generated educational content 需要 QA pipeline,而不只是 prompt。
第一版產生了很多卡片,但 card count 不等於 learning quality。
所以我們加入 content QA pass。
腳本讀取每個 sentence-card block,抽出 Natural Tagalog line,然後重建 extra examples。
如果這句已經出現過,dedupe step 會加入 article 與 sentence context。
重寫後,腳本重新產生 grammar 與 pronunciation helper sections。
接著 assert 每篇文章仍然有 exactly 40 cards。
這帶來兩個好處:
1. 學習者得到更有用的 examples。
2. 開發者得到可量測的 review output。
extra-example rewrite scripts 顯示內容 QA 也是工程問題。專案使用小型 Python 腳本、穩定 HTML markers、escaped output、依群組產生的 example scenes、duplicate tracking、grammar refresh、pronunciation refresh 與硬性 card-count checks。這個流程讓 Tagalog 學習 App 對學習者更有用,也讓技術分享 demo 更有說服力。