AWS Builder 文章

用教育优先的开发提示,为 AWS Manila Community Day 构建 Tagalog 学习应用

将 Tagalog 学习应用做成一个可与 AWS 社区构建者分享的静态 HTML demo。技术重点很务实:保持应用静态、保持内容结构化、让移动端阅读舒适,并用 demo 短语作为可见证据,证明应用支持真实活动沟通。学习者应能在 AWS Manila Community Day 之前和期间实际使用它。静态文件、结构化提示词、移动端优先布局,以及文化上谨慎的句子卡片,足以创建有意义的 demo。

Tagalog 学习应用文章系列

English 繁體中文 简体中文

将 Tagalog 学习应用做成一个可与 AWS 社区构建者分享的静态 HTML demo。技术重点很务实:保持应用静态、保持内容结构化、让移动端阅读舒适,并用 demo 短语作为可见证据,证明应用支持真实活动沟通。学习者应能在 AWS Manila Community Day 之前和期间实际使用它。静态文件、结构化提示词、移动端优先布局,以及文化上谨慎的句子卡片,足以创建有意义的 demo。

免责声明

用途:这个静态应用是用于语言练习和开发者分享的教育原型。它帮助学习者为 AWS Manila Community Day 准备礼貌的 Tagalog 短语。

非商业用途:本项目没有付费功能、广告、注册要求或商业目的。它面向学习、实验和社区准备。

不作保证:生成的语言内容可能包含错误。Tagalog 翻译、语法说明、发音指南和文化注释在投入生产使用前,应由母语者检查。

范围:这个应用不是 AWS 官方产品,也不是官方翻译工具,更不能替代真人语言教学。它是一个包含实用学习内容的技术 demo。

社区尊重:应用应避免刻板印象,并谨慎讲解礼貌用语。像 poopokayoninyo 这样的词,应解释为表达尊重的工具,而不是装饰。


Demo

Umalis tayo nang maaga bukas.

语法拆解

  • Umalis:表示离开或出发。
  • tayo:包容式的“我们”,表示说话者和听者一起。
  • nang:连接动作与方式或时间。
  • maaga:表示“早”。
  • bukas:表示“明天”。

发音指南

可以按词逐个读作:
oo-mah-lees tah-yoh nahng mah-mah-ah-gah boo-kahs.

  • Umalis: oo-mah-lees.
  • tayo: tah-yoh.
  • nang: nahng.
  • maaga: mah-mah-ah-gah.
  • bukas: boo-kahs.
    保持元音开口清晰,用平静语气说出这个计划句。

内容快照

自然 Tagalog:Umalis tayo nang maaga bukas.
礼貌 Tagalog:Umalis po tayo nang maaga bukas.
额外示例 1:Sa sakayan, umalis tayo nang maaga bukas.
额外示例 2:Okay lang, umalis tayo nang maaga bukas.
相关日常示例:Napakainit ng araw ngayon.

目录

第 1 部分:在学习闭环跑通前保持 Demo 静态

这一部分说明为什么第一版使用静态应用就足够。HTML、CSS、JavaScript 和 JSON 可以在不引入账号、服务器或复杂部署的情况下验证句子卡片流程。

第 2 部分:设计移动端阅读顺序

这一部分展示移动端布局规则:内容优先,文章列表放在按钮之后。学习者应先看到当前课程,再跨类别导航。

第 3 部分:构建内容 Schema 和渲染器

这一部分为 Tagalog 句子卡片定义实用内容 schema,并展示如何在问候、工作坊、问路、志愿者和等待短语等类别中渲染同一种卡片形态。

第 4 部分:面向技术分享的提示词 QA

这一部分给出提示词检查和开发检查,让项目可以更稳妥地用于技术分享 session。

第 5 部分:来自 Demo 的现场笔记

这一部分记录可复用的开发提示:静态优先部署、卡片一致性、可访问性、文化 QA 和提示词具体性。


第 1 部分:在学习闭环跑通前保持 Demo 静态

目标

在没有后端的情况下创建一个实用的 Tagalog 学习应用。第一版应证明学习者可以打开页面、选择文章、阅读句子卡片,并练习 AWS Manila Community Day 相关短语。

提示词

创建一个支持暗色模式、移动端响应式的静态 HTML Tagalog 学习应用。

桌面端 UI:
- 左侧:文章列表,包含主题名称和 20 词摘要
- 右侧:文章内容

移动端 UI:
- 顶部:文章内容
- 按钮:打开带主题名称和摘要的文章列表

内容:
- 共 24 篇文章
- 11 篇 AWS Community Day 文章、8 篇 Friendship 文章和 5 篇 Manila Daily 文章
- 每篇文章都有用于问候、问路、工作坊、社交、志愿者、等待时间和告别的句子卡片
- 每张句子卡片包含自然 Tagalog、礼貌 Tagalog、友好的 Filipino-English、轻松玩笑式 Filipino-English、语法、示例和发音

结果

应用可以作为静态文件发布。学习者可以打开 index.html,选择一篇文章,并阅读适合活动现场使用的短语。验证学习体验不需要账号或数据库。

提示

  • 当内容契约清晰时,静态优先并不弱。
  • 快速 demo 可使用一个 CSS 文件或嵌入式 CSS。
  • 为所有句子卡片使用同一个渲染器。
  • 如果目标是便于分享,可让每篇文章都有独立 HTML 页面。
  • 添加可下载 ZIP,方便离线审查。

建议文件结构

/tagalog-community-day-demo
  index.html
  article-1-community-greetings-introductions.html
  article-2-community-directions-registration.html
  article-3-community-workshops-learning.html
  article-4-community-networking-belonging.html
  article-5-community-volunteers-time-goodbye.html
  styles.css
  app.js

第 2 部分:设计移动端阅读顺序

目标

让应用在繁忙的活动场馆内也有用。学习者在移动端应立即看到当前文章内容,只在需要时打开文章列表。

提示词

让移动端版本内容优先。

桌面端:
- 使用双栏布局。
- 将文章导航放在左侧。
- 将文章内容放在右侧。

移动端:
- 将文章内容放在顶部。
- 默认隐藏文章列表。
- 显示“打开文章列表”按钮。
- 在抽屉或面板中显示文章链接。
- 让触控目标足够大,便于单手使用。

结果

学习者会先看到课程,再看到导航。这一点很重要,因为这个应用首先不是目录,而是练习工具。

CSS 草图

.layout {
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: 1.5rem;
}

.sidebar {
  position: sticky;
  top: 1rem;
}

.mobile-menu-button {
  display: none;
}

@media (max-width: 860px) {
  .layout {
    display: flex;
    flex-direction: column;
  }

  .content {
    order: 1;
  }

  .mobile-menu-button {
    display: block;
    order: 2;
  }

  .sidebar {
    display: none;
    position: fixed;
    left: 1rem;
    right: 1rem;
    bottom: 1rem;
    max-height: 72vh;
    overflow: auto;
  }

  .sidebar.open {
    display: block;
  }
}

用于移动端测试的 Demo 示例

Magpahinga muna tayo sa lilim.
Umupo ka sandali kung nahihilo ka.
Paki-check po kung pumasok ang bayad.

如果这三个示例在移动端容易阅读、复制并大声说出来,说明布局方向正确。


第 3 部分:构建内容 Schema 和渲染器

目标

在所有活动类别中使用同一个内容模型。

提示词

为 Tagalog 句子卡片创建一个 JSON schema。
该 schema 必须支持:
- 英文输入
- 自然 Tagalog
- 礼貌 Tagalog
- 友好的 Filipino-English
- 轻松玩笑式 Filipino-English
- 语气
- 文化语境
- 语法拆解
- 额外示例
- 发音指南
- 活动类别

结果

应用可以用同一个组件渲染问候、工作坊问题、志愿者感谢和等待短语。

示例 schema

{
  "articles": [
    {
      "id": "manila-daily-health-safety-weather-money",
      "title": "Manila Daily: Health, Safety, Weather, and Money",
      "summary": "Ask for help, talk about weather, handle payments, describe simple health needs, and stay safe around Manila.",
      "cards": [
        {
          "englishInput": "Sit for a moment if you feel dizzy.",
          "naturalTagalog": "Umupo ka sandali kung nahihilo ka.",
          "politeTagalog": "Umupo po kayo sandali kung nahihilo kayo.",
          "friendlyFilipinoEnglish": "Sit muna po kung dizzy.",
          "playfulFilipinoEnglish": "Umupo muna, easy lang all right.",
          "tone": "caring, practical, health-and-safety-ready",
          "culturalContext": "Use the polite form with guards, staff, drivers, vendors, elders, and first-time contacts.",
          "grammar": [
            { "term": "Umupo", "meaning": "sit down" },
            { "term": "sandali", "meaning": "for a moment" },
            { "term": "nahihilo", "meaning": "feeling dizzy" },
            { "term": "po", "meaning": "politeness marker" }
          ],
          "examples": [
            {
              "tagalog": "Magpahinga muna tayo sa lilim.",
              "english": "Let us rest in the shade first."
            },
            {
              "tagalog": "Umupo ka sandali kung nahihilo ka.",
              "english": "Sit for a moment if you feel dizzy."
            },
            {
              "tagalog": "Paki-check po kung pumasok ang bayad.",
              "english": "Please check if the payment came in."
            }
          ]
        }
      ]
    }
  ]
}

渲染器草图

function renderSentenceCard(card) {
  const grammar = card.grammar
    .map((item) => `<li><strong>${item.term}:</strong> ${item.meaning}</li>`)
    .join("");

  const examples = card.examples
    .map(
      (example) => `
      <li>
        <strong>Tagalog:</strong> ${example.tagalog}<br>
        <strong>English:</strong> ${example.english}
      </li>
    `,
    )
    .join("");

  return `
    <article class="sentence-card">
      <h3>${card.englishInput}</h3>
      <dl>
        <dt>Natural Tagalog:</dt><dd>${card.naturalTagalog}</dd>
        <dt>Polite Tagalog:</dt><dd>${card.politeTagalog}</dd>
        <dt>Friendly Filipino-English:</dt><dd>${card.friendlyFilipinoEnglish}</dd>
        <dt>Playful Filipino-English:</dt><dd>${card.playfulFilipinoEnglish}</dd>
        <dt>Tone:</dt><dd>${card.tone}</dd>
        <dt>Cultural Context:</dt><dd>${card.culturalContext}</dd>
        <dt>Grammatical Breakdown:</dt><dd><ul>${grammar}</ul></dd>
        <dt>Extra Examples:</dt><dd><ol>${examples}</ol></dd>
      </dl>
    </article>
  `;
}

实现

内容 schema 和渲染器部分很关键,因为它把文章元数据、句子卡片结构、响应式 CSS、页面渲染器、文章写入器、ZIP 创建和校验检查连接成一条静态站点构建流水线。

from pathlib import Path
import html
import zipfile
import textwrap
import re
import json
import os

out_dir = Path(".")

# Article metadata with 20-word summaries
# checked by simple whitespace count in code comments/log output.
articles = [
    {
        "id": 1,
        "slug": "community-greetings-introductions",
        "title": "Community Day: Greetings and Respectful Introductions",
        "category": "Community Day",
        "summary": (
            "Practice polite greetings, names, beginner phrases, and warm introductions "
            "for meeting speakers, volunteers, students, and builders in Manila confidently."
        ),
    },
    {
        "id": 2,
        "slug": "community-directions-registration",
        "title": "Community Day: Directions, Venue, and Registration",
        "category": "Community Day",
        "summary": (
            "Learn useful venue phrases for registration, rooms, seats, restrooms, exits, "
            "queues, badges, and polite help requests during the event."
        ),
    },
    {
        "id": 3,
        "slug": "community-workshops-learning",
        "title": "Manila Daily: Health, Safety, Weather, and Money",
        "category": "Community Day",
        "summary": (
            "Ask workshop questions, request repeats, discuss demos, serverless ideas, "
            "AI solutions, cloud labs, and learning goals with respectful Tagalog."
        ),
    },
    {
        "id": 4,
        "slug": "community-networking-belonging",
        "title": "Community Day: Networking, Connect, and Belong",
        "category": "Community Day",
        "summary": (
            "Use friendly phrases to connect with developers, students, leaders, and peers "
            "while expressing excitement, humility, gratitude, and belonging."
        ),
    },
    {
        "id": 5,
        "slug": "community-volunteers-time-goodbye",
        "title": "Community Day: Volunteers, Waiting, Time, and Goodbye",
        "category": "Community Day",
        "summary": (
            "Thank volunteers, manage waiting time, apologize politely, coordinate arrivals, "
            "say goodbye warmly, and respect schedules with practical phrases."
        ),
    },
    {
        "id": 6,
        "slug": "friendship-one-question-one-answer",
        "title": "Friendship Tagalog: One Question, One Gentle Answer",
        "category": "Friendship",
        "summary": (
            "Practice original friendship questions about sincerity, answers, hope, courage, "
            "and honest feelings without copying any copyrighted song lyrics."
        ),
    },
    {
        "id": 7,
        "slug": "friendship-friends-only-feelings",
        "title": "Friendship Tagalog: Friends Only Feelings",
        "category": "Friendship",
        "summary": (
            "Learn gentle phrases about friendship, uncertainty, hope, boundaries, and "
            "emotional clarity using respectful, soft, beginner-friendly Tagalog patterns."
        ),
    },
    {
        "id": 8,
        "slug": "friendship-you-are-my-beloved",
        "title": "Friendship Tagalog: You Are My Beloved",
        "category": "Friendship",
        "summary": (
            "Explore original poetic devotion phrases about care, affection, trust, support, "
            "and choosing someone with warm but simple Tagalog."
        ),
    },
    {
        "id": 9,
        "slug": "friendship-honest-heart-deep-feelings",
        "title": "Friendship Tagalog: Honest Heart and Deep Feelings",
        "category": "Friendship",
        "summary": (
            "Build vocabulary for truthful emotions, nervous hearts, sincere admiration, "
            "quiet longing, and careful confession in natural polite Tagalog."
        ),
    },
    {
        "id": 10,
        "slug": "friendship-distance-hope-promises",
        "title": "Friendship Tagalog: Distance, Hope, and Promises",
        "category": "Friendship",
        "summary": (
            "Practice original phrases about distance, waiting, promises, north and south, "
            "hope, patience, and love that remains steady."
        ),
    },
]

community_sets = {
    1: [
        (
            "I am happy to meet you today.",
            "Masaya akong makilala ka ngayon.",
            "Masaya po akong makilala kayo ngayon.",
            "Happy to meet you today, kumusta!",
            "Masaya akong makilala ka ngayon, all right.",
            "warm, polite, event-ready",
        ),
        (
            "Hello, I am learning Tagalog.",
            "Kumusta, nag-aaral ako ng Tagalog.",
            "Kumusta po, nag-aaral po ako ng Tagalog.",
            "Hello po, learning Tagalog ako.",
            "Kumusta, learning Tagalog na ako, all right.",
            "friendly, beginner-friendly",
        ),
        (
            "My name is Martinez.",
            "Ako si Martinez.",
            "Ako po si Martinez.",
            "Hi po, ako si Martinez.",
            "Ako si Martinez, ready na ako all right.",
            "simple introduction",
        ),
        (
            "This is my first time in Manila.",
            "First time ko sa Manila.",
            "First time ko po sa Manila.",
            "First time ko po sa Manila, excited ako.",
            "First time ko sa Manila, all right amazed.",
            "personal, excited",
        ),
        (
            "I want to greet everyone politely.",
            "Gusto kong bumati sa lahat nang magalang.",
            "Gusto ko pong bumati sa lahat nang magalang.",
            "Gusto ko pong mag-greet sa lahat.",
            "Gusto kong mag-greet sa lahat, polite mode all right.",
            "respectful, practical",
        ),
        (
            "Good morning, everyone.",
            "Magandang umaga sa lahat.",
            "Magandang umaga po sa inyong lahat.",
            "Good morning po sa lahat.",
            "Magandang umaga, ready na tayo all right.",
            "formal greeting",
        ),
        (
            "May I sit here?",
            "Puwede ba akong umupo dito?",
            "Puwede po ba akong umupo dito?",
            "Can I sit here po?",
            "Puwede ba akong umupo dito, all right?",
            "polite request",
        ),
        (
            "I am a beginner, so please speak slowly.",
            "Baguhan ako, kaya pakibagalan.",
            "Baguhan po ako, kaya pakibagalan po.",
            "Beginner po ako, slow lang please.",
            "Beginner ako, slow lang all right please.",
            "humble, practical",
        ),
        (
            "I am excited to join Manila Community Day.",
            "Excited akong sumali sa Manila Community Day.",
            "Excited po akong sumali sa Manila Community Day.",
            "Excited po ako for Manila Community Day.",
            "Excited na ako sa Community Day, all right.",
            "excited, event-ready",
        ),
        (
            "Thank you for welcoming me.",
            "Salamat sa pagtanggap sa akin.",
            "Salamat po sa pagtanggap sa akin.",
            "Thank you po for welcoming me.",
            "Salamat sa welcome, belong na ako all right.",
            "grateful, emotional",
        ),
    ],
    2: [
        (
            "Where is the registration area?",
            "Saan ang registration area?",
            "Saan po ang registration area?",
            "Saan po ang registration area, please?",
            "Saan ang registration area, ready na ako all right.",
            "polite direction",
        ),
        (
            "Where is the workshop room?",
            "Saan ang workshop room?",
            "Saan po ang workshop room?",
            "Saan po ang workshop room, please?",
            "Saan ang workshop room, workshop mode all right.",
            "practical, event-ready",
        ),
        (
            "Could you point me to the entrance?",
            "Puwede mo ba akong ituro sa entrance?",
            "Puwede po ba ninyo akong ituro sa entrance?",
            "Pa-point po sa entrance?",
            "Point me sa entrance, lost na ako all right.",
            "polite help request",
        ),
        (
            "Is this the correct line?",
            "Tamang pila ba ito?",
            "Tamang pila po ba ito?",
            "Correct line po ba ito?",
            "Tamang pila ba ito, checking all right.",
            "queue, practical",
        ),
        (
            "Where can I get my badge?",
            "Saan ko makukuha ang badge ko?",
            "Saan ko po makukuha ang badge ko?",
            "Saan po badge pickup?",
            "Saan badge ko, excited na all right.",
            "registration, polite",
        ),
        (
            "Is there a seat available here?",
            "May bakanteng upuan ba dito?",
            "May bakanteng upuan po ba dito?",
            "May seat po ba dito?",
            "May seat ba dito, sit na ako all right.",
            "polite, seating",
        ),
        (
            "Where is the restroom?",
            "Saan ang restroom?",
            "Saan po ang restroom?",
            "Saan po ang CR?",
            "Saan ang CR, quick lang all right.",
            "practical direction",
        ),
        (
            "What time does the next session start?",
            "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.",
            "time, event-ready",
        ),
        (
            "Please wait for me for a few minutes.",
            "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 ako all right.",
            "waiting, coordination",
        ),
        (
            "Please check if the payment arrived.",
            "Paki-check kung pumasok ang bayad sa venue.",
            "Paki-check po kung pumasok ang bayad sa venue.",
            "Payment received po ba?",
            "Paki-check kung pumasok ang bayad sa venue, all right.",
            "payment check",
        ),
    ],
}

# Expand each 10 base sentences to 40 by making contextual variants.
community_contexts = [
    ("at the morning registration", "sa morning registration"),
    ("before the workshop starts", "bago magsimula ang workshop"),
    ("while meeting a volunteer", "habang may nakikilalang volunteer"),
    ("after the session", "pagkatapos ng session"),
]

friendship_contexts = [
    ("when speaking softly", "kapag marahang nagsasalita"),
    ("while waiting for an answer", "habang naghihintay ng sagot"),
    ("in a sincere message", "sa isang tapat na mensahe"),
    ("with a careful heart", "nang may maingat na puso"),
]


def expand(base, article_id):
    contexts = community_contexts if article_id <= 5 else friendship_contexts
    cards = []

    for i, b in enumerate(base):
        for j, (enctx, tlctx) in enumerate(contexts):
            eng, nat, pol, friendly, playful, tone = b

            # Keep sentence clear; add context in background,
            # not necessarily append to every translation.
            cards.append(
                {
                    "num": len(cards) + 1,
                    "background": (
                        f"Use this sentence {enctx}. It helps connect emotion, culture, "
                        "politeness, and practical communication."
                    ),
                    "english": eng,
                    "natural": nat,
                    "polite": pol,
                    "friendly": friendly,
                    "playful": playful,
                    "tone": tone,
                    "context_en": enctx,
                    "context_tl": tlctx,
                }
            )

    return cards[:40]


for a in articles:
    base = community_sets.get(a["id"]) or friendship_sets.get(a["id"])
    a["cards"] = expand(base, a["id"])


# Simple pronunciation generation for consistent guides.
pron_map = {
    "Kumusta": "koo-MOOS-tah",
    "Salamat": "sah-LAH-maht",
    "Puwede": "PWEH-deh",
    "Saan": "SAH-ahn",
    "Ako": "AH-koh",
    "po": "poh",
    "kayo": "KAH-yoh",
    "ninyo": "NEEN-yoh",
    "n’yo": "nyoh",
    "Gusto": "GOOS-toh",
    "Excited": "ek-SAI-ted",
    "Nandito": "nahn-DEE-toh",
    "Papunta": "pah-POON-tah",
    "Hintayin": "hin-tah-YEEN",
    "Pasensya": "pah-SEN-shah",
    "Mahalaga": "mah-hah-LAH-gah",
    "Sasamahan": "sah-sah-MAH-hahn",
    "Kahit": "kah-HEET",
    "Manila": "mah-NEE-lah",
    "Tagalog": "tah-GAH-log",
    "magtanong": "mag-tah-NONG",
    "pakiulit": "pah-kee-OO-lit",
}


def pronunciation(tl):
    # Provide a compact guide using known phrase starts, plus simple fallback.
    for k, v in pron_map.items():
        if tl.startswith(k) or f" {k}" in tl:
            # Highlight first relevant chunk and add readable text.
            return (
                f"Say it slowly and clearly. Start with: {v}. Keep 'po' soft, "
                "and stress the capital syllables in this guide."
            )

    return (
        "Read each vowel clearly: a as ah, e as eh, i as ee, o as oh, u as oo. "
        "Keep the final syllable clear."
    )


def breakdown(card):
    e = card["english"].lower()
    nat = card["natural"]
    items = []

    def add(tag, meaning):
        items.append((tag, meaning))

    if "thank" in e or "salamat" in nat.lower():
        add("Salamat", "thank you; a core gratitude word")
        add(
            "po",
            "politeness marker used with elders, speakers, organizers, volunteers, or new people",
        )
        add("sa", "for, in, at, or to depending on context")

    elif "where" in e or nat.lower().startswith("saan"):
        add("Saan", "where; asks for a place or direction")
        add("po", "polite marker for respectful questions")
        add("ang", "focus marker before the place or thing being asked about")

    elif "may i" in e or "could" in e or "please" in e:
        add("Puwede / Paki-", "may, can, or please; softens a request")
        add("po", "polite marker")
        add("ba", "question marker used in yes/no questions")

    elif "wait" in e or "way" in e or "late" in e:
        add(
            "Hintayin / Papunta / Pasensya",
            "waiting, on-the-way, and apology words for coordination",
        )
        add("na", "now or all right; often shows change of state")
        add("po", "polite marker")

    elif any(
        w in e
        for w in [
            "heart",
            "love",
            "feel",
            "answer",
            "friends",
            "hope",
            "promise",
            "dear",
            "admire",
        ]
    ):
        add("puso / damdamin", "heart or feelings; emotional vocabulary")
        add("sana", "hope or wish; makes the sentence gentle")
        add(
            "po / kayo / ninyo",
            "respectful forms when the tone should stay careful and polite",
        )

    elif "excited" in e:
        add("Excited ako", "I am excited; common Filipino-English expression")
        add("-ng / akong", "linker form connecting I am to the next action")
        add("sumali / matuto", "to join or to learn")

    else:
        add("Ako / ko", "I or my; marks the speaker")
        add("ka / kayo", "you; kayo is polite or plural")
        add("po", "polite marker used for respect")

    return items[:3]


def examples(card, article_id):
    if article_id <= 5:
        return [
            ("Magpahinga muna tayo sa lilim.", "Let us rest in the shade first."),
            ("Umupo ka sandali kung nahihilo ka.", "Sit for a moment if you feel dizzy."),
            ("Paki-check po kung pumasok ang bayad.", "Please check if the payment came in."),
        ]

    return [
        ("Sana maintindihan mo ako.", "I hope you understand me."),
        ("Makikinig po ako nang may respeto.", "I will listen with respect."),
        ("Tapat ang damdamin ko, all right.", "My feeling is sincere all right."),
    ]


def sentence_card_html(card, article):
    bds = "".join(
        f"<li><strong>{html.escape(k)}:</strong> {html.escape(v)}</li>"
        for k, v in breakdown(card)
    )

    exs = "".join(
        (
            f"<li><strong>Tagalog:</strong> {html.escape(tl)}<br>"
            f"<strong>English:</strong> {html.escape(en)}</li>"
        )
        for tl, en in examples(card, article["id"])
    )

    related = (
        "Event pattern: use the polite version first with speakers, organizers, "
        "volunteers, and people you meet for the first time. Casual and playful styles "
        "are better with peers after rapport."
        if article["id"] <= 5
        else (
            "Emotional pattern: keep the sentence gentle, avoid pressure, and use sana, "
            "po, kayo, or ninyo when respect and careful tone matter."
        )
    )

    return f"""
    <article class="sentence-card" id="sentence-{card['num']}">
      <h3>Sentence {card['num']}</h3>
      <dl class="template">
        <dt>Background context:</dt><dd>{html.escape(card['background'])}</dd>
        <dt>English Input:</dt><dd>{html.escape(card['english'])}</dd>
        <dt>Natural Tagalog:</dt><dd lang="tl">{html.escape(card['natural'])}</dd>
        <dt>Polite Tagalog:</dt><dd lang="tl">{html.escape(card['polite'])}</dd>
        <dt>Friendly Filipino-English:</dt><dd>{html.escape(card['friendly'])}</dd>
        <dt>playful Filipino-English:</dt><dd>{html.escape(card['playful'])}</dd>
        <dt>Tone:</dt><dd>{html.escape(card['tone'])}</dd>
        <dt>Cultural Context:</dt><dd>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.</dd>
        <dt>Grammatical Breakdown:</dt><dd><ul>{bds}</ul></dd>
        <dt>Common Context and Idiomatic Use:</dt><dd>This phrase is useful for {html.escape(card['context_en'])}. It teaches both correct Tagalog and a safe respectful option.</dd>
        <dt>Extra Examples:</dt><dd><ol>{exs}</ol></dd>
        <dt>Pronunciation Guide:</dt><dd>{html.escape(pronunciation(card['polite']))}</dd>
        <dt>Related understand emotional, poetic, polite, and practical sentence patterns:</dt><dd>{html.escape(related)}</dd>
      </dl>
    </article>"""

开发技能

关键开发技能是将内容生成与内容渲染分离。AI 提示词生成结构化内容,UI 渲染这些内容。开发者不应为每个新的短语类别手动重新设计页面。


第 4 部分:面向技术分享的提示词 QA

目标

通过同时展示提示词纪律和代码纪律,让项目适合用于开发者分享。

提示词

审查生成的 Tagalog 学习应用内容。

检查:
- 每张句子卡片是否包含自然 Tagalog?
- 需要时,每张句子卡片是否包含礼貌 Tagalog?
- po、opo、kayo 和 ninyo 是否解释正确?
- 轻松玩笑式 Filipino-English 是否标注为非正式?
- 活动短语对 AWS Manila Community Day 是否有用?
- 是否包含等待和时间相关短语?
- 示例是否足够短,便于移动端阅读?
- 输出是否避免了缺乏依据的文化假设?

结果

审查步骤会成为构建流程的一部分,而不是事后补救。由于 demo 展示了负责任的 AI 使用方式,技术分享的信息也更有说服力。

QA 清单

  • 内容契约存在。
  • 每篇文章都有主题和摘要。
  • 每张句子卡片都使用相同字段顺序。
  • 礼貌 Tagalog 清晰可见。
  • 友好风格和轻松玩笑式风格已分开。
  • 示例包含活动动作。
  • 移动端布局先展示内容。
  • 文章抽屉可以打开和关闭。
  • 暗色模式对比度可读。
  • 仅供提示词使用的备注没有泄漏到最终 UI。

Demo 驱动的 QA 示例

将这些最新 HTML 示例作为回归集合:

1. Magpahinga muna tayo sa lilim.
   检查健康/安全语境和自然的关怀表达模式。

2. Umupo ka sandali kung nahihilo ka.
   检查适合初学者的建议,以及清晰的 Manila 日常表达。

3. Paki-check po kung pumasok ang bayad.
   检查礼貌请求措辞、付款语境和额外示例的唯一性。

第 5 部分:来自 Demo 的现场笔记

现场笔记 1:静态部署

背景:第一版只需要证明句子卡片是有用的。

目标:用最小部署面发布应用。

提示词:创建带暗色模式和移动端响应式行为的静态 HTML 页面。

结果:demo 可以直接在浏览器中打开,并以文件形式分享。

提示:

  • 在需要用户账号或持久化之前,避免后端工作。
  • 使用静态文件获取早期反馈。
  • 保持文件名有意义。
  • 让每篇文章链接都可分享。
  • 将 demo 打包为 ZIP。

现场笔记 2:卡片一致性

背景:如果卡片使用不同标签,每篇文章都可能发生偏移。

目标:让每篇文章都像同一个学习产品的一部分。

提示词:为每张卡片使用相同的句子模板。

结果:学习者可以从问候切换到工作坊内容,而不必重新学习 UI。

提示:

  • 保持标签顺序一致。
  • 使用相同的语气名称。
  • 使用相同的示例数量。
  • 保持语法解释简短。
  • 避免按类别改变卡片形态。

现场笔记 3:把可访问性视为尊重

背景:语言学习应用应让疲惫的活动参与者也能在手机上轻松阅读。

目标:让内容易于扫读、点击和阅读。

提示词:使用可读对比度、大点击区域、语义化标题和简单导航。

结果:应用在不增加复杂度的情况下变得更具包容性。

提示:

  • 使用语义化 HTML 元素。
  • 在暗色模式中保持高对比度。
  • 让按钮清晰可见。
  • 避免在语法部分使用过小文字。
  • 不要只依赖颜色表达状态。

现场笔记 4:文化 QA

背景:礼貌是产品要求,不是可选备注。

目标:帮助学习者避免在刚认识的人面前显得过于直接。

提示词:解释什么时候可以使用随意表达,什么时候使用尊重表达更稳妥。

结果:应用同时教授语言和社交语境。

提示:

  • 用适合初学者的语言解释 po
  • kayo 表示尊重或复数的“你/你们”。
  • ninyo 表示尊重或复数的“你的/你们的”。
  • 将轻松玩笑式 Filipino-English 明确保持为非正式。
  • 请母语者审查最终内容。

现场笔记 5:技术分享结构

背景:只有 demo 已经有用,但技术演讲还需要构建路线图。

目标:解释提示词如何变成文件、schema、组件和 QA 规则。

提示词:用目标、提示词、结果、提示、证据和审查检查来撰写博客文章。

结果:这篇文章会成为可复用的教学材料,供想创建类似学习工具的构建者参考。

提示:

  • 展示提示词。
  • 展示 schema。
  • 展示 UI 代码片段。
  • 展示 demo 示例。
  • 以构建者可复用的清单收尾。

结语反思

这个 Tagalog 学习应用最好的版本,不是最复杂的版本,而是学习者能在 AWS Manila Community Day 之前和期间真正使用的版本。静态文件、结构化提示词、移动端优先布局,以及文化上谨慎的句子卡片,足以创建有意义的 demo。小步构建,检查语言,让社区学习目标引导技术设计。