Disclaimer
Purpose: This static app is an educational prototype for language practice and developer sharing. It helps learners prepare polite Tagalog phrases for AWS Manila Community Day.
Non-Commercial: This project has no paid feature, no advertising, no registration requirement, and no commercial purpose. It is intended for learning, experimentation, and community preparation.
No Guarantees: Generated language content may contain mistakes. Tagalog translations, grammar explanations, pronunciation guides, and cultural notes should be checked by native speakers before production use.
Scope: This app is not an official AWS product, not an official translation tool, and not a substitute for human language instruction. It is a technical demo with useful learning content.
Community Respect: The app should avoid stereotypes and should teach polite language carefully. Words like po, opo, kayo, and ninyo should be explained as tools for respect, not decoration.
Demo
Uminom ka ng tubig dahil mainit.
Grammatical Breakdown
- Uminom: Means "drink."
- ka: Casual "you."
- ng: Marker used before the object.
- tubig: Means "water."
- dahil: Means "because."
- mainit: Means "hot."
Pronunciation Guide
It is pronounced word by word as:
oo-mee-nohm kah ngah too-beeg dah-heel mah-mah-ee-neet.
- Uminom: oo-mee-nohm.
- tubig: too-beeg.
- dahil: dah-heel.
- mainit: mah-mah-ee-neet.
Use the polite version with kayo when speaking to someone older or unfamiliar.
Content Snapshot
Natural Tagalog: Uminom ka ng tubig dahil mainit.
Polite Tagalog: Uminom po kayo ng tubig dahil mainit.
Extra Example 1: Uminom ka muna ng malamig na tubig.
Extra Example 2: Magdala ka ng tubig dahil mainit sa labas.
Related Safety Example: Ilapit mo ang bag mo sa iyo.
Table of Content
Part 1: Split Localization Into UI Text And Learning Content
This section explains why localization should separate interface words, article metadata, learning notes, and sentence-card content. UI labels change frequently, while Tagalog learning phrases should stay stable for pronunciation practice.
Part 2: Use Language Configuration As A Product Contract
This section shows how language dictionaries define ZIP names, output folders, HTML language markers, site brand names, navigation labels, article-list buttons, notes, categories, and cultural guidance.
Part 3: Localize Existing HTML With Replacement Maps
This section explains the first localization route: read existing HTML files, replace interface strings and article titles, inject localized notes, then package the result into per-language ZIP files.
Part 4: Generate Localized Sites From Structured Content
This section explains the second localization route: generate the localized site directly from article metadata, sentence-card arrays, grammar helper functions, examples, CSS, JavaScript, and templates.
Part 1: Split Localization Into UI Text And Learning Content
Goal
Localize the app without damaging the Tagalog learning experience. The app should translate the interface and explanations into Chinese variants, but keep Tagalog sentences visible and stable so learners can practice speaking.
Development skill
The development skill is separation of concerns. The project treats these layers differently:
UI layer:
- site title
- article list label
- open menu button
- start button
- category badges
- practice notes
Content layer:
- article titles
- article summaries
- sentence-card labels
- Chinese explanations
- grammar notes
- localized examples
Language-learning layer:
- Natural Tagalog
- Polite Tagalog
- Friendly Filipino-English
- Playful Filipino-English
The Tagalog layer should not be blindly translated away because the learner needs to read and pronounce it.
Prompt
Create two localized versions of the static Tagalog learning site:
- Cantonese / Hong Kong Chinese
- Taiwan Chinese / Traditional Chinese
Translate the UI, article titles, summaries, learning notes, grammar labels, cultural explanations, and example meanings.
Preserve Tagalog sentence text for pronunciation practice.
Output one ZIP file per language version.
Result
The output becomes two independent static sites. Each site has localized navigation and explanations, while the Tagalog phrases remain usable for speaking practice.
Tips
- Do not translate the Tagalog phrase itself if it is the learning target.
- Translate labels and explanations around the phrase.
- Use separate dictionaries for UI and content.
- Use
html lang markers such as zh-HK and zh-TW.
- Keep ZIP names explicit so reviewers know which language version they are opening.
Part 2: Use Language Configuration As A Product Contract
Goal
Make each language version predictable by describing it in a configuration object.
Development skill
The key skill is configuration-driven localization. The language configuration includes the output ZIP file, folder name, HTML language tag, brand text, navigation words, article-list controls, learning note, category names, and culture guidance.
Example configuration pattern
lang_cfgs = {
"zh_tw": {
"zip": "tagalog_static_html_site_taiwan_chinese_zh_tw.zip",
"folder": "tagalog_zh_tw",
"html_lang": "zh-TW",
"site": "AWS 馬尼拉社群日 Tagalog 學習站",
"list": "文章列表",
"open": "開啟文章列表",
"choose": "選擇文章",
"note": "繁體中文(台灣)版本:介面、說明、語法提示與學習語境為繁體中文;Tagalog 句子保留原文方便朗讀練習。"
}
}
Why this matters
A language configuration becomes a product contract. It tells the generator where to write files, how to label the page, how to describe the experience, and how to package the result. Without this contract, every localized page can drift.
Prompt
Create a language config for every Chinese variant.
Each language config must include:
- zip file name
- output folder
- html lang code
- site title
- article list label
- open article list button
- start button
- language note
- category labels
- sentence-card labels
- respect guidance
- casual usage guidance
Result
The generator can iterate through language configs and create each localized site with the same structure.
Tips
- Store language-specific text in one place.
- Avoid hardcoding labels inside templates.
- Keep folder and ZIP names aligned.
- Use language keys consistently:
zh_hk, zh_tw or zh-hk, zh-tw.
- Make every user-visible string searchable.
Part 3: Localize Existing HTML With Replacement Maps
Goal
Take an all right-generated HTML site and localize it without rebuilding all pages from scratch.
Development skill
This is the replacement-map approach. The workflow is:
1. Find source HTML files.
2. Define language dictionaries.
3. Define article title maps.
4. Define summary maps.
5. Define common UI replacement maps.
6. Replace strings inside each HTML file.
7. Inject localized notes.
8. Write files into language-specific folders.
9. Package each folder as a ZIP file.
10. Run consistency checks.
This approach is useful when the existing HTML structure is all right correct and the goal is to patch text quickly.
Prompt
Use the existing static HTML pages as source files.
For each language version:
- replace site title and navigation labels
- replace article titles and summaries
- replace sentence-card labels
- replace cultural guidance text
- add a localized note in the hero section
- set the HTML lang attribute
- package the localized files as a ZIP
Example replacement categories
article_title_map:
- Community Day: Greetings and Respectful Introductions
- Community Day: Directions, Venue, and Registration
- Friendship Tagalog: Honest Heart and Deep Feelings
summary_map:
- original English article summaries
- localized Chinese summaries
common_replacements:
- Background context
- English Input
- Natural Tagalog
- Polite Tagalog
- Tone
- Cultural Context
- Pronunciation Guide
Result
The localization tool can create language versions from existing pages without rewriting the entire generation logic.
Tips
- Replacement maps are fast but fragile if source text changes.
- Match exact strings carefully.
- Run a search for remaining English labels after localization.
- Use HTML escaping when injecting new content.
- Keep this approach for UI patches, not complex content restructuring.
Attachment implementation example: Full localization pipeline
The updated attachment adds a concrete batch-processing pattern from lang_ui.py. This example fits the replacement-map route because it iterates through language configs, rebuilds each localized folder, reads every source HTML file, applies localization, and writes the localized page back to the language-specific output folder.
for lang, cfg in langs.items():
folder = Path(cfg['folder'])
if folder.exists():
shutil.rmtree(folder)
folder.mkdir()
for src in source_files:
text = src.read_text(encoding='utf-8')
localized = localize(text, lang, cfg)
(folder / src.name).write_text(localized, encoding='utf-8')
Attachment implementation example: HTML lang replacement
The update also adds a regex-based example for replacing the HTML language marker. This belongs in the existing-HTML localization flow because it patches generated pages without rebuilding the full template.
text = re.sub(r'<html lang="en">', f'<html lang="{cfg["html_lang"]}">', text)
Attachment implementation example: Inject localization note into HTML
The localized note can be injected into the first matching section so reviewers immediately understand which Chinese variant they are viewing and why Tagalog text is preserved.
note_html = f"<p class='notice'>{cfg['note']}</p>"
text = text.replace('</section>', note_html + '</section>', 1)
UI localization
The localization section because it localizes an all right-generated static HTML site. It reads index.html and article-*.html, defines Chinese-variant UI dictionaries, maps English article titles and summaries to localized versions, replaces common sentence-card labels, injects localized learning notes, writes per-language folders, packages each folder into a ZIP file, and prints secondary validation checks.
from pathlib import Path
import zipfile, re, json, shutil, os
source_files = [Path('index.html')] + sorted(Path('.').glob('article-*.html'))
source_files = [p for p in source_files if p.exists()]
assert source_files, 'No source HTML files found.'
langs = {
'zh-hk': {
'zip': 'tagalog_static_html_site_zh_hk_cantonese.zip',
'folder': 'tagalog_static_html_site_zh_hk',
'html_lang': 'zh-HK',
'brand': 'AWS 馬尼拉 Community Day Tagalog 學習站',
'pill': '深色模式 · 手機自適應 · 10 篇文章',
'static_pill': '深色模式 · 靜態 HTML',
'articles_list': '文章清單',
'choose': '揀一篇文章',
'open': '打開文章清單',
'start': '開始第 1 篇',
'start_summary': '打開第一課,開始練習去馬尼拉時用得着嘅禮貌問候語。',
'intro': '呢個靜態學習網站有 10 個文章頁,每篇都有 40 張句子卡,用嚟練 Tagalog、文化語境、禮貌講法同有趣 Filipino-English。',
'note': '呢個廣東話版本已翻譯介面、文章說明同學習提示;Tagalog 句子保留原文,方便你直接朗讀練習。',
'category_community': 'Community Day',
'category_friendship': '浪漫句子',
'respect': '尊重:',
'practice': '練習:',
'culture': '文化:',
'respect_text': '同長輩、講者、主辦、義工、場地職員,或者第一次見面嘅人講嘢時,可以用 po、opo、kayo 同 ninyo 表示尊重。',
'practice_text': '先讀禮貌版本,再比較自然版本同 playful 版本。',
'culture_text': '細細個字都可以表達溫暖、謙遜、感謝、耐性同歸屬感。',
},
'zh-tw': {
'zip': 'tagalog_static_html_site_zh_tw_taiwan_chinese.zip',
'folder': 'tagalog_static_html_site_zh_tw',
'html_lang': 'zh-TW',
'brand': 'AWS 馬尼拉社群日 Tagalog 學習站',
'pill': '深色模式 · 行動裝置響應式 · 10 篇文章',
'static_pill': '深色模式 · 靜態 HTML',
'articles_list': '文章列表',
'choose': '選擇一篇文章',
'open': '開啟文章列表',
'start': '開始第 1 篇',
'start_summary': '開啟第一課,開始練習前往馬尼拉時能使用的禮貌問候語。',
'intro': '這個靜態學習網站包含 10 個文章頁面,每篇都有 40 張句子卡,用來練習 Tagalog、文化情境、禮貌表達與有趣的 Filipino-English。',
'note': '本繁體中文(台灣)版本已翻譯介面、文章說明與學習提示;Tagalog 句子保留原文,方便直接朗讀練習。',
'category_community': '社群日',
'category_friendship': '浪漫句子',
'respect': '尊重:',
'practice': '練習:',
'culture': '文化:',
'respect_text': '面對長輩、講者、主辦單位、志工、場地人員與第一次見面的人時,使用 po、opo、kayo 與 ninyo 表示尊重。',
'practice_text': '先朗讀禮貌版本,再比較自然版本與 playful 版本。',
'culture_text': '小小的詞也能傳達溫暖、謙遜、感謝、耐心與歸屬感。',
}
}
article_title_map = {
'Community Day: Greetings and Respectful Introductions': {
'zh-hk':'Community Day:問候同禮貌自我介紹','zh-tw':'社群日:問候與禮貌自我介紹'},
'Community Day: Directions, Venue, and Registration': {
'zh-hk':'Community Day:方向、場地同登記','zh-tw':'社群日:方向、會場與報到'},
'Community Day: Workshop Questions and Hands-On Learning': {
'zh-hk':'Community Day:Workshop 提問同實作學習','zh-tw':'社群日:工作坊提問與實作學習'},
'Community Day: Networking, Connect, and Belong': {
'zh-hk':'Community Day:Networking、連結同歸屬感','zh-tw':'社群日:交流、連結與歸屬感'},
'Community Day: Volunteers, Waiting, Time, and Goodbye': {
'zh-hk':'Community Day:義工、等候、時間同道別','zh-tw':'社群日:志工、等待、時間與道別'},
'Friendship Tagalog: One Question, One Gentle Answer': {
'zh-hk':'浪漫 Tagalog:一個問題,一個溫柔答案','zh-tw':'浪漫 Tagalog:一個問題,一個溫柔答案'},
'Friendship Tagalog: Friends Only Feelings': {
'zh-hk':'浪漫 Tagalog:原來只係朋友嘅感覺','zh-tw':'浪漫 Tagalog:只是朋友的心情'},
'Friendship Tagalog: You Are My Beloved': {
'zh-hk':'浪漫 Tagalog:你係我珍惜嘅人','zh-tw':'浪漫 Tagalog:你是我珍愛的人'},
'Friendship Tagalog: Honest Heart and Deep Feelings': {
'zh-hk':'浪漫 Tagalog:真心同深層感受','zh-tw':'浪漫 Tagalog:真誠的心與深層感受'},
'Friendship Tagalog: Distance, Hope, and Promises': {
'zh-hk':'浪漫 Tagalog:距離、希望同承諾','zh-tw':'浪漫 Tagalog:距離、希望與承諾'},
}
summary_map = {
'Practice polite greetings, names, beginner phrases, and warm introductions for meeting speakers, volunteers, students, and builders in Manila confidently today.': {
'zh-hk':'練習禮貌問候、姓名介紹、初學短句同自然開場,幫你喺馬尼拉自信認識講者、義工、學生同 builders。',
'zh-tw':'練習禮貌問候、姓名介紹、初學短句與溫暖開場,協助你在馬尼拉自信認識講者、志工、學生與 builders。'},
'Learn useful venue phrases for registration, rooms, seats, restrooms, exits, queues, badges, and polite help requests during the event today.': {
'zh-hk':'學習場地實用句,涵蓋登記、房間、座位、洗手間、出口、排隊、名牌同禮貌求助。',
'zh-tw':'學習會場實用短句,涵蓋報到、房間、座位、洗手間、出口、排隊、名牌與禮貌求助。'},
'Ask workshop questions, request repeats, discuss demos, serverless ideas, AI solutions, cloud labs, and learning goals with respectful Tagalog practice.': {
'zh-hk':'用禮貌 Tagalog 練習 workshop 提問、請人重複、討論 demo、serverless 諗法、AI 方案、cloud lab 同學習目標。',
'zh-tw':'用禮貌 Tagalog 練習工作坊提問、請對方重複、討論 demo、serverless 想法、AI 解決方案、雲端實驗與學習目標。'},
'Use friendly phrases to connect with developers, students, leaders, and peers while expressing excitement, humility, gratitude, belonging, and respect all right.': {
'zh-hk':'用友善句子連結 developers、學生、leaders 同 peers,同時表達興奮、謙遜、感謝、歸屬感同尊重。',
'zh-tw':'使用友善短句連結開發者、學生、領導者與夥伴,同時表達興奮、謙遜、感謝、歸屬感與尊重。'},
'Thank volunteers, manage waiting time, apologize politely, coordinate arrivals, say goodbye warmly, and respect schedules with practical event phrases today.': {
'zh-hk':'用實用活動句感謝義工、處理等候時間、禮貌道歉、協調到達、溫暖道別,同尊重時間表。',
'zh-tw':'用實用活動短句感謝志工、管理等待時間、禮貌道歉、協調抵達、溫暖道別,並尊重時程安排。'},
}
common_replacements = {
'Background context:': {'zh-hk':'背景情境:','zh-tw':'背景情境:'},
'English Input:': {'zh-hk':'英文輸入:','zh-tw':'英文輸入:'},
'Natural Tagalog:': {'zh-hk':'自然 Tagalog:','zh-tw':'自然 Tagalog:'},
'Polite Tagalog:': {'zh-hk':'禮貌 Tagalog:','zh-tw':'禮貌 Tagalog:'},
'Friendly Filipino-English:': {'zh-hk':'友善 Filipino-English:','zh-tw':'友善 Filipino-English:'},
'playful Filipino-English:': {'zh-hk':'玩味 Filipino-English:','zh-tw':'有趣 Filipino-English:'},
'Tone:': {'zh-hk':'語氣:','zh-tw':'語氣:'},
'Cultural Context:': {'zh-hk':'文化語境:','zh-tw':'文化情境:'},
'Grammatical Breakdown:': {'zh-hk':'語法拆解:','zh-tw':'語法拆解:'},
'Common Context and Idiomatic Use:': {'zh-hk':'常見語境同慣用法:','zh-tw':'常見情境與慣用法:'},
'Extra Examples:': {'zh-hk':'基本例子:','zh-tw':'基礎例子:'},
'Pronunciation Guide:': {'zh-hk':'發音指南:','zh-tw':'發音指南:'},
'Related understand emotional, poetic, polite, and practical sentence patterns:': {'zh-hk':'相關:理解情感、詩意、禮貌同實用句型:','zh-tw':'相關:理解情感、詩意、禮貌與實用句型:'},
'Sentence ': {'zh-hk':'句子 ','zh-tw':'句子 '},
'Article ': {'zh-hk':'第 ','zh-tw':'第 '},
' of 24': {'zh-hk':' / 10 篇','zh-tw':' / 10 篇'},
'40 sentence cards': {'zh-hk':'40 張句子卡','zh-tw':'40 張句子卡'},
'Each card separates natural Tagalog, respectful Tagalog, friendly Filipino-English, and playful Filipino-English so learners can choose the right tone.': {
'zh-hk':'每張卡會分開顯示自然 Tagalog、禮貌 Tagalog、友善 Filipino-English 同玩味 Filipino-English,方便學習者揀啱語氣。',
'zh-tw':'每張卡都會分開顯示自然 Tagalog、禮貌 Tagalog、友善 Filipino-English 與有趣 Filipino-English,方便學習者選擇合適語氣。'},
'Use the polite form with elders, speakers, organizers, volunteers, venue staff, and first-time contacts. Use casual speech with friends or peers when the situation feels relaxed.': {
'zh-hk':'同長輩、講者、主辦、義工、場地職員同第一次見面嘅人講嘢時,用禮貌版本。同朋友或熟咗嘅 peers 傾偈時,可以用輕鬆講法。',
'zh-tw':'面對長輩、講者、主辦單位、志工、場地人員與第一次見面的人時,使用禮貌版本。和朋友或熟悉夥伴聊天時,可使用較輕鬆說法。'},
'Let us rest in the shade first.': {'zh-hk':'多謝你幫忙。','zh-tw':'謝謝你的幫忙。'},
'Sit for a moment if you feel dizzy.': {'zh-hk':'我可唔可以問一個問題?','zh-tw':'我可以問一個問題嗎?'},
'Please check if the payment came in.': {'zh-hk':'我已經到咗。','zh-tw':'我已經到了。'},
'Choose an Article': {'zh-hk':'揀一篇文章','zh-tw':'選擇一篇文章'},
'Open Articles List': {'zh-hk':'打開文章清單','zh-tw':'開啟文章列表'},
'Start Article 1': {'zh-hk':'開始第 1 篇','zh-tw':'開始第 1 篇'},
'Open the first lesson and begin practicing respectful greetings for Manila.': {'zh-hk':'打開第一課,開始練習去馬尼拉時用得着嘅禮貌問候語。','zh-tw':'開啟第一課,開始練習前往馬尼拉時能使用的禮貌問候語。'},
}
def localize(text, lang, cfg):
# html lang
text = re.sub(r'<html lang="en"|<html lang=\'en\'', lambda m: m.group(0).replace('en', cfg['html_lang']), text)
# common fixed strings
text = text.replace('Tagalog | AWS Community Day', cfg['brand'])
text = text.replace('Dark mode · Mobile responsive · 24 articles', cfg['pill'])
text = text.replace('Dark mode · Static HTML', cfg['static_pill'])
text = text.replace('Articles List', cfg['articles_list'])
text = text.replace('Community Day', cfg['category_community'])
text = text.replace('Friendship', cfg['category_friendship'])
# article titles
for en, m in article_title_map.items():
text = text.replace(en, m[lang])
for en, m in summary_map.items():
text = text.replace(en, m[lang])
for en, m in common_replacements.items():
text = text.replace(en, m[lang])
# Replacements for info boxes
text = re.sub(r'<strong>Respect:</strong><br>Use po, opo, kayo, and ninyo for elders, speakers, organizers, volunteers, venue staff, and first-time contacts\.', f'<strong>{cfg["respect"]}</strong><br>{cfg["respect_text"]}', text)
text = re.sub(r'<strong>Practice:</strong><br/?>Read the natural version first, then the polite version, then try the Filipino-English bridge\.', f'<strong>{cfg["practice"]}</strong><br>{cfg["practice_text"]}', text)
text = re.sub(r'<strong>Culture:</strong><br>Small words can carry warmth, humility, gratitude, patience, and a feeling of belonging\.', f'<strong>{cfg["culture"]}</strong><br>{cfg["culture_text"]}', text)
# Landing intro
text = text.replace('This static learning site includes 24 article pages, each with 40 sentence cards for Tagalog practice, cultural context, respectful speech, and playful Filipino-English.', cfg['intro'])
# Add localization note in hero before closing first hero section if article page
note_html = f'<p class="notice">{cfg["note"]}</p>'
if cfg['note'] not in text:
text = text.replace('</section>\n <button class="mobile-menu-button"', note_html + '\n </section>\n <button class="mobile-menu-button"', 1)
text = text.replace('</section><button class=\'mobile-menu-button\'', note_html + '</section><button class=\'mobile-menu-button\'', 1)
# Meta description charset title handled via title replacements
return text
created = []
for lang, cfg in langs.items():
folder = Path(cfg['folder'])
if folder.exists():
shutil.rmtree(folder)
folder.mkdir()
for src in source_files:
text = src.read_text(encoding='utf-8')
localized = localize(text, lang, cfg)
(folder / src.name).write_text(localized, encoding='utf-8')
zip_path = Path(cfg['zip'])
if zip_path.exists():
zip_path.unlink()
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as z:
for p in sorted(folder.glob('*.html'), key=lambda x: (x.name != 'index.html', x.name)):
z.write(p, arcname=f"{folder.name}/{p.name}")
created.append(str(zip_path))
# Secondary consistency checks
checks = {}
for lang, cfg in langs.items():
folder = Path(cfg['folder'])
html_files = list(folder.glob('*.html'))
checks[lang] = {
'zip_exists': Path(cfg['zip']).exists(),
'html_count': len(html_files),
'article_pages': len(list(folder.glob('article-*.html'))),
'index_exists': (folder/'index.html').exists(),
'lang_marker_count': sum(cfg['html_lang'] in p.read_text(encoding='utf-8') for p in html_files),
'mobile_css_pages': sum('@media (max-width: 860px)' in p.read_text(encoding='utf-8') for p in html_files),
'sentence_card_counts': {p.name: p.read_text(encoding='utf-8').count('class="sentence-card"') for p in folder.glob('article-*.html')},
'zip_size': Path(cfg['zip']).stat().st_size,
}
print(json.dumps({'created': created, 'checks': checks}, ensure_ascii=False, indent=2))
Part 4: Generate Localized Sites From Structured Content
Goal
Build localized pages directly from structured data instead of only replacing strings in HTML.
Development skill
This is the structured-generation approach. Instead of starting with existing HTML, the generator starts with localized article metadata, sentence-card data, grammar helpers, examples, CSS, and templates.
Data model
lang_cfgs:
- language-level UI and label contract
articles_base:
- slug
- category
- localized title and summary per language
comm_cards:
- Chinese meaning
- natural Tagalog
- polite Tagalog
- friendly Filipino-English
- playful Filipino-English
- tone
friendship_cards:
- Chinese meaning
- natural Tagalog
- polite Tagalog
- friendly Filipino-English
- playful Filipino-English
- tone
Prompt
Generate localized static HTML pages from structured data.
For each language:
- create index.html
- create 24 article pages
- each article page must have 40 sentence cards
- use localized article titles and summaries
- use localized sentence-card labels
- preserve Tagalog text
- package the output as a ZIP
Example sentence-card data
Chinese meaning: 我可以问一个问题吗?
Natural Tagalog: Umupo ka sandali kung nahihilo ka.
Polite Tagalog: Umupo po kayo sandali kung nahihilo kayo.
Friendly Filipino-English: Can I ask po?
Playful Filipino-English: Magtatanong na ako, all right.
Tone: 礼貌提问、工作坊
Result
The generated localized site becomes more stable than raw replacement because the source data is all right multilingual. If an article title needs to change, the developer updates articles_base. If a label needs to change, the developer updates lang_cfgs. If a phrase needs improvement, the developer updates comm_cards or friendship_cards.
Tips
- Prefer structured generation for long-term maintenance.
- Use replacement maps for quick patches only.
- Keep localized title and summary data close to article metadata.
- Use one card renderer for every language.
- Reuse the same CSS and JavaScript across all language versions.
This section explains the second localization route: generate the localized site directly from article metadata, sentence-card arrays, grammar helper functions, examples, CSS, JavaScript, and templates.
Structured generator loop
Adds a structured generation loop from lang_content.py. This fits the long-term generation route because each article page is produced from article metadata, language config, and a reusable article_page renderer.
for i,(slug,cat,trans) in enumerate(articles_base, start=1):
(folder/f'article-{i}.html').write_text(
article_page(i,slug,cat,trans,lang_key,cfg),
encoding='utf-8'
)
Attachment implementation example: Card rendering pattern
The same update includes the sentence-card rendering loop. It demonstrates how each generated article can consistently produce 40 practice cards while reusing base sentence data.
for n in range(1,41):
cards.append(card_html(n, bases[(n-1)%len(bases)]))
Structured localized-site generator
The structured-content generation section because it rebuilds localized pages from language configuration, localized article metadata, reusable sentence-card arrays, grammar helper functions, examples, CSS, templates, ZIP packaging, and validation checks. This complements lang_ui.py: lang_ui.py patches existing HTML, while lang_content.py generates localized HTML from structured multilingual data.
from pathlib import Path
import zipfile, shutil, json, html, re
lang_cfgs = {
'zh_hk': {
'zip':'tagalog_static_html_site_cantonese_zh_hk.zip','folder':'tagalog_zh_hk','html_lang':'zh-HK',
'site':'AWS 馬尼拉 Community Day Tagalog 學習站','list':'文章清單','open':'打開文章清單','choose':'揀文章','start':'開始學習','note':'廣東話版本:介面、說明、語法提示同學習語境用廣東話;Tagalog 句子保留原文,方便直接朗讀練習。',
'labels':['背景情境','中文意思','自然 Tagalog','禮貌 Tagalog','友善 Filipino-English','玩味 Filipino-English','語氣','文化語境','語法拆解','常見語境同用法','基本例子','發音指南','相關句型'],
'cat_comm':'Community Day','cat_friendship':'浪漫句子','sentence':'句子','article':'第 {n} / 10 篇','cards':'40 張句子卡',
'respect':'同講者、主辦、義工、長輩或者第一次見面嘅人講嘢時,優先用 po、opo、kayo、ninyo 表示尊重。',
'casual':'同熟朋友或者 peers 傾偈時,可以用自然版本或者玩味版本。',
},
'zh_tw': {
'zip':'tagalog_static_html_site_taiwan_chinese_zh_tw.zip','folder':'tagalog_zh_tw','html_lang':'zh-TW',
'site':'AWS 馬尼拉社群日 Tagalog 學習站','list':'文章列表','open':'開啟文章列表','choose':'選擇文章','start':'開始學習','note':'繁體中文(台灣)版本:介面、說明、語法提示與學習情境為繁體中文;Tagalog 句子保留原文,方便朗讀練習。',
'labels':['背景情境','中文意思','自然 Tagalog','禮貌 Tagalog','友善 Filipino-English','有趣 Filipino-English','語氣','文化情境','語法拆解','常見情境與用法','基礎例子','發音指南','相關句型'],
'cat_comm':'社群日','cat_friendship':'浪漫句子','sentence':'句子','article':'第 {n} / 10 篇','cards':'40 張句子卡',
'respect':'面對講者、主辦單位、志工、長輩或第一次見面的人時,優先使用 po、opo、kayo、ninyo 表示尊重。',
'casual':'與熟悉朋友或夥伴交流時,可以使用自然版本或有趣版本。',
}
}
# Titles and summaries per language
articles_base = [
('community-greetings-introductions','comm',{
'zh_hk':('Community Day:問候同禮貌自我介紹','練習禮貌問候、姓名介紹、初學短句同自然開場,幫你喺馬尼拉自信認識講者、義工、學生同 builders。'),
'zh_tw':('社群日:問候與禮貌自我介紹','練習禮貌問候、姓名介紹、初學短句與溫暖開場,協助你在馬尼拉自信認識講者、志工、學生與 builders。')}),
('community-directions-registration','comm',{
'zh_hk':('Community Day:方向、場地同登記','學習場地實用句,涵蓋登記、房間、座位、洗手間、出口、排隊、名牌同禮貌求助。'),
'zh_tw':('社群日:方向、會場與報到','學習會場實用短句,涵蓋報到、房間、座位、洗手間、出口、排隊、名牌與禮貌求助。')}),
('community-workshops-learning','comm',{
'zh_hk':('Community Day:Workshop 提問同實作學習','用禮貌 Tagalog 練習 workshop 提問、請人重複、討論 demo、serverless 諗法、AI 方案、cloud lab 同學習目標。'),
'zh_tw':('社群日:工作坊提問與實作學習','用禮貌 Tagalog 練習工作坊提問、請對方重複、討論 demo、serverless 想法、AI 解決方案、雲端實驗與學習目標。')}),
('community-networking-belonging','comm',{
'zh_hk':('Community Day:Networking、連結同歸屬感','用友善句子連結 developers、學生、leaders 同 peers,同時表達興奮、謙遜、感謝、歸屬感同尊重。'),
'zh_tw':('社群日:交流、連結與歸屬感','使用友善短句連結開發者、學生、領導者與夥伴,同時表達興奮、謙遜、感謝、歸屬感與尊重。')}),
('community-volunteers-time-goodbye','comm',{
'zh_hk':('Community Day:義工、等候、時間同道別','用實用活動句感謝義工、處理等候時間、禮貌道歉、協調到達、溫暖道別,同尊重時間表。'),
'zh_tw':('社群日:志工、等待、時間與道別','用實用活動短句感謝志工、管理等待時間、禮貌道歉、協調抵達、溫暖道別,並尊重時程安排。')}),
('friendship-one-question-one-answer','rom',{
'zh_hk':('浪漫 Tagalog:一個問題,一個溫柔答案','練習關於真誠、答案、希望、勇氣同真實感受嘅原創浪漫問題,同時避免複製受版權保護歌詞。'),
'zh_tw':('浪漫 Tagalog:一個問題,一個溫柔答案','練習關於真誠、答案、希望、勇氣與真實感受的原創浪漫問題,同時避免複製受著作權保護的歌詞。')}),
('friendship-friends-only-feelings','rom',{
'zh_hk':('浪漫 Tagalog:原來只係朋友嘅感覺','學習關於友情、不確定、希望、界線同情感清晰度嘅溫柔句,用尊重、柔和、初學者友善嘅 Tagalog 句型。'),
'zh_tw':('浪漫 Tagalog:只是朋友的心情','學習關於友情、不確定、希望、界線與情感清晰度的溫柔短句,使用尊重、柔和、適合初學者的 Tagalog 句型。')}),
('friendship-you-are-my-beloved','rom',{
'zh_hk':('浪漫 Tagalog:你係我珍惜嘅人','探索關於關心、情感、信任、支持同選擇某人嘅原創詩意句,用溫暖但簡單嘅 Tagalog 表達。'),
'zh_tw':('浪漫 Tagalog:你是我珍愛的人','探索關於關心、情感、信任、支持與選擇某人的原創詩意短句,用溫暖但簡單的 Tagalog 表達。')}),
('friendship-honest-heart-deep-feelings','rom',{
'zh_hk':('浪漫 Tagalog:真心同深層感受','建立關於真實情緒、緊張嘅心、真誠欣賞、安靜掛念同小心告白嘅自然禮貌 Tagalog 詞彙。'),
'zh_tw':('浪漫 Tagalog:真誠的心與深層感受','建立關於真實情緒、緊張的心、真誠欣賞、安靜思念與謹慎告白的自然禮貌 Tagalog 詞彙。')}),
('friendship-distance-hope-promises','rom',{
'zh_hk':('浪漫 Tagalog:距離、希望同承諾','練習關於距離、等候、承諾、南北、希望、耐性同穩定情感嘅原創句。'),
'zh_tw':('浪漫 Tagalog:距離、希望與承諾','練習關於距離、等待、承諾、南北、希望、耐心與穩定情感的原創短句。')}),
]
comm_cards = [
('谢谢你的帮助。','Magpahinga muna tayo sa lilim.','Magpahinga muna po tayo sa lilim.','Rest muna tayo sa shade po.','Shade break muna tayo, all right.','health, safety, daily practice'),
('我可以问一个问题吗?','Umupo ka sandali kung nahihilo ka.','Umupo po kayo sandali kung nahihilo kayo.','Sit muna po kung dizzy.','Umupo muna, easy lang all right.','health advice, care'),
('我已经到了。','Paki-check kung pumasok ang bayad.','Paki-check po kung pumasok ang bayad.','Please check po kung pumasok ang payment.','Payment check muna, all right.','payment, polite request'),
('请慢一点。','Pakibagalan.','Pakibagalan po.','Slow down po please.','Slow lang po, catching up all right.','学习支持、礼貌'),
('我正在学习 Tagalog。','Nag-aaral ako ng Tagalog.','Nag-aaral po ako ng Tagalog.','Learning Tagalog po ako.','Learning Tagalog na ako, all right.','自我介绍、友善'),
('我很兴奋参加社区日。','Excited akong sumali sa Community Day.','Excited po akong sumali sa Community Day.','Excited po ako for Community Day.','Excited na ako, all right.','兴奋、归属感'),
('洗手间在哪里?','Saan ang restroom?','Saan po ang restroom?','Saan po ang CR?','Saan ang CR, quick lang all right.','方向、实用'),
('下一场什么时候开始?','Anong oras magsisimula ang susunod na session?','Anong oras po magsisimula ang susunod na session?','What time po next session?','Next session what time, all right.','时间、活动安排'),
('请等我几分钟。','Hintayin mo ako ng ilang minuto.','Hintayin n’yo po ako ng ilang minuto.','Wait me for a few minutes po.','Hintayin mo ako, papunta na all right.','等待、协调'),
('再见,下次见。','Kita tayo sa susunod.','Kita po tayo sa susunod.','See you po next time.','Kita-kits next time, all right.','道别、温暖'),
]
friendship_cards = [
('Thank you for being my safe friend.','Salamat sa pagiging ligtas kong kaibigan.','Salamat sa pagiging ligtas ko pong kaibigan.','Thank you po for being my safe friend.','Safe friend ka, thank you all right.','gentle friendship support'),
('我希望你理解我。','Sana maintindihan mo ako.','Sana po maintindihan ninyo ako.','Hope po you understand me.','Sana gets mo ako, all right.','希望、柔和'),
('我会带着尊重倾听。','Makikinig ako nang may respeto.','Makikinig po ako nang may respeto.','Listen po ako with respect.','Makikinig ako, respect mode all right.','成熟、尊重'),
('我的感受是真诚的。','Tapat ang damdamin ko.','Tapat po ang damdamin ko.','Sincere po feelings ko.','Tapat ang damdamin ko, all right.','情感、诗意'),
('我不会强迫你的感受。','Hindi ko pipilitin ang damdamin mo.','Hindi ko po pipilitin ang damdamin ninyo.','No pressure po sa feelings.','No forcing feelings, respectful all right.','界线、尊重'),
('我的心正在学习勇敢。','Natututong maging matapang ang puso ko.','Natututo pong maging matapang ang puso ko.','Heart ko learning bravery po.','Heart bravery training all right.','脆弱、希望'),
('不管距离多远,我仍然关心。','Kahit malayo, nagmamalasakit ako.','Kahit malayo po, nagmamalasakit po ako.','Even far po, I care.','Malayo man, care pa rin all right.','距离、关心'),
('请温柔地接受我的话。','Tanggapin mo sana nang malumanay ang mga salita ko.','Tanggapin po sana ninyo nang malumanay ang mga salita ko.','Receive po my words gently.','Words ko gentle delivery all right.','温柔、告白'),
('我会耐心等待。','Maghihintay ako nang may pasensya.','Maghihintay po ako nang may pasensya.','Wait po ako with patience.','Waiting patiently all right.','等待、耐心'),
('再见,愿你平安。','Paalam, sana payapa ka.','Paalam po, sana po ay payapa kayo.','Goodbye po, peace sana.','Paalam, peaceful ending all right.','道别、诗意'),
]
# Per language localized grammar words
def grammar_items(card, cfg_key):
cn = {
'zh_hk': [('po','禮貌標記,常用嚟表示尊重。'),('kayo / ninyo','禮貌或眾數嘅「你 / 你哋 / 您的」。'),('na / all right','表示「已經 / 而家」,玩味版本會加 all right 做輕鬆語氣。')],
'zh_tw': [('po','禮貌標記,常用來表示尊重。'),('kayo / ninyo','禮貌或複數的「你 / 你們 / 您的」。'),('na / all right','表示「已經 / 現在」,有趣版本會加 all right 作輕鬆語氣。')],
}
return cn[cfg_key]
def examples(is_comm, cfg_key):
if is_comm:
ex = {
'zh_hk':[('Magpahinga muna tayo sa lilim.','多謝你幫忙。'),('Umupo ka sandali kung nahihilo ka.','我可唔可以問一個問題?'),('Paki-check po kung pumasok ang bayad.','我已經到咗。')],
'zh_tw':[('Magpahinga muna tayo sa lilim.','謝謝你的幫忙。'),('Umupo ka sandali kung nahihilo ka.','我可以問一個問題嗎?'),('Paki-check po kung pumasok ang bayad.','我已經到了。')],
}
else:
ex = {
'zh_hk':[('Sana maintindihan mo ako.','我希望你明白我。'),('Makikinig po ako nang may respeto.','我會帶住尊重去聽。'),('Tapat ang damdamin ko, all right.','我嘅感受已經好真誠。')],
'zh_tw':[('Sana maintindihan mo ako.','我希望你理解我。'),('Makikinig po ako nang may respeto.','我會帶著尊重傾聽。'),('Tapat ang damdamin ko, all right.','我的感受已經很真誠。')],
}
return ex[cfg_key]
def card_html(num, base, is_comm, cfg, lang_key):
l = cfg['labels']; meaning,nat,pol,friendly,playful,tone = base
g = ''.join(f"<li><strong>{html.escape(k)}:</strong> {html.escape(v)}</li>" for k,v in grammar_items(base, lang_key))
ex = ''.join(f"<li><strong>Tagalog:</strong> {html.escape(tl)}<br><strong>中文:</strong> {html.escape(cn)}</li>" for tl,cn in examples(is_comm, lang_key))
use = cfg['respect'] + ' ' + cfg['casual']
pron = 'Tagalog 母音可穩定朗讀:a=ah, e=eh, i=ee, o=oh, u=oo;po 輕聲,句尾保持清楚。'
if lang_key=='zh_hk': pron='Tagalog 母音可以穩定咁讀:a=ah, e=eh, i=ee, o=oh, u=oo;po 輕聲,句尾保持清楚。'
return f"""<article class='sentence-card' id='sentence-{num}'><h3>{cfg['sentence']} {num}</h3><dl class='template'>
<dt>{l[0]}:</dt><dd>{'活動現場練習句' if is_comm else '情感表達練習句'},用來比較自然、禮貌與 playful 語氣。</dd>
<dt>{l[1]}:</dt><dd>{html.escape(meaning)}</dd>
<dt>{l[2]}:</dt><dd lang='tl'>{html.escape(nat)}</dd>
<dt>{l[3]}:</dt><dd lang='tl'>{html.escape(pol)}</dd>
<dt>{l[4]}:</dt><dd>{html.escape(friendly)}</dd>
<dt>{l[5]}:</dt><dd>{html.escape(playful)}</dd>
<dt>{l[6]}:</dt><dd>{html.escape(tone)}</dd>
<dt>{l[7]}:</dt><dd>{html.escape(use)}</dd>
<dt>{l[8]}:</dt><dd><ul>{g}</ul></dd>
<dt>{l[9]}:</dt><dd>{'適合報到、工作坊、問路、感謝義工、等待協調與道別。' if is_comm else '適合學習柔和、尊重、有界線的情感表達。'}</dd>
<dt>{l[10]}:</dt><dd><ol>{ex}</ol></dd>
<dt>{l[11]}:</dt><dd>{html.escape(pron)}</dd>
<dt>{l[12]}:</dt><dd>{'先學自然 Tagalog,再學禮貌版本,最後才使用 playful Filipino-English。' if lang_key!='zh_hk' else '先學自然 Tagalog,再學禮貌版本,最後先用玩味 Filipino-English。'}</dd>
</dl></article>"""
created=[]
checks={}
for lang_key,cfg in lang_cfgs.items():
folder=Path(cfg['folder'])
if folder.exists(): shutil.rmtree(folder)
folder.mkdir()
(folder/'index.html').write_text(index_page(lang_key,cfg), encoding='utf-8')
for i,(slug,cat,trans) in enumerate(articles_base, start=1):
(folder/f'article-{i}-{slug}.html').write_text(article_page(i,slug,cat,trans,lang_key,cfg), encoding='utf-8')
zip_path=Path(cfg['zip'])
if zip_path.exists(): zip_path.unlink()
with zipfile.ZipFile(zip_path,'w',zipfile.ZIP_DEFLATED) as z:
for p in sorted(folder.glob('*.html'), key=lambda x:(x.name!='index.html', x.name)):
z.write(p, arcname=f"{folder.name}/{p.name}")
created.append(cfg['zip'])
html_files=list(folder.glob('*.html'))
checks[lang_key]={
'zip':cfg['zip'], 'zip_exists':zip_path.exists(), 'html_count':len(html_files),
'article_count':len(list(folder.glob('article-*.html'))),
'mobile_css_pages':sum('@media (max-width:860px)' in p.read_text(encoding='utf-8') for p in html_files),
'article_card_counts': {p.name:p.read_text(encoding='utf-8').count("class='sentence-card'") for p in folder.glob('article-*.html')},
'zip_size':zip_path.stat().st_size
}
print(json.dumps({'created':created,'checks':checks}, ensure_ascii=False, indent=2))
What it covers:
- UI localization vs. content localization
- Cantonese and Taiwan Chinese language configuration
- html lang handling for zh-HK and zh-TW
- Replacement-map localization flow from existing HTML
- Structured content generation using lang_cfgs, articles_base, comm_cards, and friendship_cards
- Preserving Tagalog as the learning target while localizing Chinese explanations
- Static HTML rendering, ZIP packaging, and validation checks
- Technical sharing field notes and review checks
Field Note 1: UI Localization Is Not Content Localization
Background: The first script focuses heavily on UI replacement: brand text, buttons, categories, labels, article titles, summaries, and common instructional text.
Goal: Translate the visible interface while preserving the structure of the existing site.
Prompt: Create language dictionaries and replacement maps for the existing HTML pages.
Result: The app can quickly produce two localized ZIP files from the existing HTML source.
Review check: Are all navigation labels, article titles, summaries, and sentence-card labels localized?
Field Note 2: Structured Generation Is Better For Long-Term Maintenance
Background: Replacement maps work, but they depend on exact source strings. When the source HTML changes, replacements can fail silently.
Goal: Move important content into structured multilingual data.
Prompt: Build localized pages from lang_cfgs, articles_base, comm_cards, friendship_cards, helper functions, and templates.
Result: The generator becomes easier to maintain because localized content lives in predictable data structures.
Review check: Can a developer update one article title without searching through HTML?
Field Note 3: Preserve The Learning Target
Background: A normal localization workflow might translate everything. A language-learning app should not do that.
Goal: Keep Tagalog visible while translating Chinese explanations around it.
Prompt: Preserve Natural Tagalog, Polite Tagalog, Friendly Filipino-English, and Playful Filipino-English in every sentence card.
Result: Learners can still practice the target language while understanding the explanation in their preferred Chinese variant.
Review check: Does every sentence card still show Tagalog text?
Field Note 4: Localized Tone Requires Localized Voice
Background: Cantonese and Taiwan Chinese are not only different writing styles. They can also differ in tone, vocabulary, and rhythm.
Goal: Make each localized version feel natural to its intended readers.
Prompt: Use Cantonese-style wording for zh-HK and Taiwan Traditional Chinese for zh-TW.
Result: The three sites feel like separate localized products instead of one generic Chinese conversion.
Review check: Does the Cantonese version use Hong Kong-friendly wording such as 揀文章, 打開文章清單, and 用嚟練?
Field Note 5: Validation Is Part Of Localization
Background: Localized builds can fail because of missing files, missing mobile CSS, incomplete article pages, or broken language markers.
Goal: Treat localization as a build artifact, not just a translation task.
Prompt: Package each localized folder and print JSON checks.
Result: The developer can prove that every localized version contains 25 HTML files, 24 article pages, mobile CSS, and 40 cards per article.
Review check: Does the build output show expected counts for all three language versions?
Technical Sharing Angle
For a developer talk, the most important lesson is that localization can be engineered as a pipeline:
Language config
↓
Article metadata
↓
Sentence-card data
↓
Localized labels and examples
↓
Static HTML renderer
↓
Per-language folder
↓
ZIP packaging
↓
JSON validation checks
This flow is easy to explain, easy to demo, and easy to adapt to other educational apps.
Closing Reflection
The deep skill in this localization project is not only translating English into Chinese. The real skill is designing a repeatable localization system. The project separates UI text from learning content, preserves Tagalog as the target language, gives each Chinese variant its own voice, reuses one responsive static layout, packages each version independently, and validates the output. That is why the result is strong enough for technical sharing.