系列:30 天用 Google AI 打造臺灣防災速報 App(Day 13/30)
在臺灣生活、工作和旅行的外籍人士很多,災害發生時,看不懂中文警報的人最需要資訊。今天把 Day 8 的速報擴充成中、英、日、韓四種語言。
先產生中文再翻譯三次,要呼叫模型四次,等待時間也會累加。這裡用 Day 9 的 Structured Output,一次呼叫就拿到四種語言。以下是第一輪的基本版本,規則後面會一條一條加:
from google import genai
from pydantic import BaseModel
client = genai.Client()
class MultilingualAlert(BaseModel):
zh: str # 繁體中文(原文照用)
en: str # English
ja: str # 日本語
ko: str # 한국어
BASE = """把下面這則臺灣的防災速報寫成四種語言:繁體中文(原文照用)、英文、日文、韓文。
規則:
- 時間、地點、數字必須和原文完全一致,不得增加或省略資訊。
- 依各語言的習慣表達,不必逐字翻譯。"""
# alert 是一則速報的文字,見下方的三則測試速報
resp = client.models.generate_content(
model="gemini-3.1-flash-lite",
contents=BASE + f"\n\n速報:\n{alert}",
config={"response_mime_type": "application/json",
"response_schema": MultilingualAlert},
)
out = resp.parsed # out.en、out.ja、out.ko
測試用三則速報。第一則是 Day 8 定稿版的真實輸出;後兩則是我為了測試術語寫的文字,開頭標了「(測試文字)」:
2026年8月22日11時40分,臺灣東部海域發生規模5.1地震,宜蘭縣與花蓮縣最大震度3級。
(測試文字)2026年9月21日14時30分,嘉義縣發生規模6.1地震,嘉義縣與臺南市最大震度5弱。
(測試文字)中央氣象署發布豪雨特報:屏東縣山區今日有局部豪雨,24小時累積雨量可能達200毫米,請注意坍方與落石。
三則的時間、地點、數字都正確,英文的句子讀起來也通順。問題出在防災術語:
5-weak。中央氣象署英文網頁的寫法是 5 Lower(地震報告頁簡寫成 5-)。heavy rain advisory。依中央氣象署的英文分級,Heavy Rain 對應的是「大雨」,「豪雨」是 Extremely Heavy Rain。英文版的雨量等級因此比原文低了一級。英文句子讀起來很自然,不對照官方用語根本看不出問題。防災術語不能讓模型自己決定。
我查了中央氣象署的英文網頁(地震報告頁、大雨特報頁與地震測報中心的英文震度表,2026-09-21、24 查閱),把查得到的官方用語整理成對照表:
| 中文 | English(中央氣象署英文網頁) | 日本語 | 한국어 |
|---|---|---|---|
| 規模 | magnitude | マグニチュード | 규모 |
| 震度 | intensity | 震度 | 진도 |
| 5 弱、5 強 | 5 Lower、5 Upper(報告頁簡寫成 5-) | 5弱、5強 | 5약、5강 |
| 大雨 | Heavy Rain | ||
| 豪雨 | Extremely Heavy Rain | 豪雨 | 호우 |
| 大豪雨 | Torrential Rain | ||
| 超大豪雨 | Extremely Torrential Rain | ||
| 特報 | Advisory | 特報 | 특보 |
| 中央氣象署 | Central Weather Administration (CWA) | 中央気象署 | 중앙기상서 |
有兩點要說明。第一,中央氣象署的地震報告頁把 5 弱簡寫成 5-,我一開始就照這個寫,並比照推出 5+;後來在地震測報中心的英文震度表查到全名是 5 Lower、5 Upper,外國讀者不會把 5- 誤讀成範圍或負號,術語表改用全名。第二,日文和韓文沒有官方對照表,改依臺灣官方媒體的日文版(中央社「フォーカス台湾」)和韓文版(央廣 Rti)報導防災新聞時的慣用寫法,例如日文的「豪雨」照臺灣的用語寫,不用日本氣象廳形容雨勢的「非常に激しい雨」(那是每小時雨量的分級,定義不同);韓文的「臺灣」依 Rti 寫「타이완」。這兩欄還沒有請母語者逐句審核,上線前要補這一步。
另外有兩條在地化的規則:
加上術語表之後先執行一次,5- 和 Extremely Heavy Rain Advisory 都正確了。但第三則的三種語言都漏掉了開頭的「(測試文字)」,日文版的語氣也和原文不同(後面「驗收」一節說明)。所以我加了兩條規則再執行一次:一條是「原文的語氣強弱要保留:『可能』不得寫成『預計』或『將會』」,另一條是「原文開頭如果有括號標記(例如「(測試文字)」),每一種語言都要保留」。
保留標記的那條規則帶來兩個新問題:
(Disaster Alert)、(防災速報)、(방재 속보)。(測試文字),沒有翻譯。這和 Day 8 遇到的情況一樣:規則裡出現的東西,模型會認為輸出裡也應該要有。
固定的標記其實不需要模型處理。改成由程式處理:送出之前先把標記從原文拿掉,四種語言產生之後,再由程式加上事先寫好的譯文。
TEST_TAG = "(測試文字)"
TAGS = {"zh": "(測試文字)", "en": "(Test message) ", "ja": "(テスト)", "ko": "(테스트) "}
tagged = alert.startswith(TEST_TAG)
body = alert[len(TEST_TAG):] if tagged else alert
# ……用 body 產生四種語言,得到 out ……
if tagged:
for lang, tag in TAGS.items():
# getattr 讀出某個欄位的值、setattr 寫回去,等於依序處理 out.zh、out.en、out.ja、out.ko
setattr(out, lang, tag + getattr(out, lang))
標記的問題解決了。第二則速報(嘉義地震)卻多了一句原文沒有的話:英文版結尾是 as reported by the Central Weather Administration (CWA),日文版和韓文版的結尾也各多了一句「中央気象署発表」「중앙기상서 발표」。原文完全沒有提到中央氣象署。
原因還是一樣。術語表裡有「中央氣象署=Central Weather Administration」這一條,模型就把它用上了。
修正方式是不再把整份術語表交給模型。每一條術語附上「原文出現哪些詞才需要這一條」,由程式檢查原文,只挑出用得到的條目:
GLOSSARY_ITEMS = [
(("規模",), "規模=magnitude/マグニチュード/규모;規模後面不加「級」。"),
(("5弱", "5強", "6弱", "6強"), "5弱、6弱的英文照中央氣象署寫成 \"5-\"、\"6-\"……"),
(("大雨", "豪雨"), "雨量分級的英文照中央氣象署:大雨 Heavy Rain、豪雨 Extremely Heavy Rain……"),
(("中央氣象署",), "中央氣象署=Central Weather Administration (CWA)/中央気象署/중앙기상서。"),
# ……其餘條目……
]
def glossary_for(text: str) -> str:
rules = [rule for keys, rule in GLOSSARY_ITEMS if any(k in text for k in keys)]
return "\n術語與地名規則(必須遵守):\n" + "\n".join(f"- {r}" for r in rules) if rules else ""
en: (Test message) At 14:30 on September 21, 2026, a magnitude 6.1 earthquake occurred in Chiayi County.
The maximum intensity (Taiwan intensity scale) in Chiayi County and Tainan City was 5-.
ja: (テスト)2026年9月21日14時30分、嘉義県でマグニチュード6.1の地震が発生しました。
嘉義県と台南市の最大震度(台湾の震度階級)は5弱でした。
ko: (테스트) 2026년 9월 21일 14시 30분, 자이현(Chiayi County)에서 규모 6.1의 지진이 발생했습니다.
자이현과 타이난시(Tainan City)의 최대 진도(대만 진도 기준)는 5약입니다.
三則速報都沒有再出現原文以外的句子,術語和加註大致照規則。這一輪留下三個問題,是把譯文和術語逐項對照臺灣官方媒體的日、韓文版之後找出來的:
(Chiayi County),Rti 的慣例是不附。is occurring、日文版「降っており」、韓文版「내리고 있으며」,三種語言都變成了「正在下」。依查證結果修改術語表和規則:英文的 5 弱、5 強改用全名 5 Lower、5 Upper;日文的豪雨改寫「豪雨」;韓文的臺灣依 Rti 的慣例改寫「타이완」,震度的加註也跟著改;縣市名稱的規則加上「韓文後面不附英文或漢字」;BASE 加兩條規則,「原文是預報就維持預報語氣,不得寫成正在發生」和「日文用です・ます体、韓文用합니다体,三則之間文體一致」。到這裡 BASE 一共五條規則:
- 時間、地點、數字必須和原文完全一致,不得增加或省略資訊。
- 原文的語氣強弱要保留:「可能」不得寫成「預計」或「將會」。
- 原文是預報(例如「今日有」「可能」)就維持預報語氣,不得寫成正在發生。
- 日文用です・ます体,韓文用합니다体(敬體),三則之間文體要一致。
- 依各語言的習慣表達,不必逐字翻譯。
再執行一次,三則的數字核對都通過。第二則的英文和韓文:
en: (Test message) At 14:30 on September 21, 2026, a magnitude 6.1 earthquake occurred in Chiayi County,
with a maximum intensity of 5 Lower (Taiwan intensity scale) in Chiayi County and Tainan City.
ko: (테스트) 2026년 9월 21일 14시 30분, 자이현에서 규모 6.1의 지진이 발생했습니다.
자이현과 타이난시에서 최대 진도 5약(타이완 진도 기준)을 기록했습니다.
第三則的結果:
en: (Test message) The Central Weather Administration (CWA) has issued an Extremely Heavy Rain Advisory:
Today, there will be localized Extremely Heavy Rain in the mountainous areas of Pingtung County,
and the 24-hour accumulated rainfall may reach 200 mm. Please be aware of landslides and falling rocks.
ja: (テスト)中央気象署は豪雨特報を発表しました:本日、屏東県山間部では局地的な豪雨の恐れがあり、
24時間の累積雨量が200ミリに達する可能性があります。土砂崩れや落石に注意してください。
ko: (테스트) 중앙기상서에서 호우 특보를 발표했습니다: 금일 핑둥현 산간 지역에는 국지성 호우가 예상되며,
24시간 누적 강수량이 200mm에 달할 가능성이 있으니 산사태와 낙석에 유의하시기 바랍니다.
三個問題都解決了:韓文的縣市名稱後面沒有再附英文;第三則三種語言都是預報的語氣;三則的日文、韓文都是敬體。
術語對了,還要考慮讀的人。美國國家氣象局(NWS)做過使用者研究,發現 Watch、Warning、Advisory 三個詞裡,Advisory 最不容易被看懂,所以他們正在把 Advisory 改成白話的標題,格式是「危害:影響+時間」(NWS Hazard Simplification)。另外,NWS 的 heavy rain 指的是每小時雨量(NWS 詞彙表),和臺灣以 24 小時累積雨量分級的定義不同,外國讀者看到 Heavy Rain 會套用自己的定義。臺灣官方媒體的英文版報導同一場 8/22 地震時,也是用白話描述震度(中央社英文版)。依這些習慣,英文版加了四條規則:
EXTREMELY HEAVY RAIN: Localized extremely heavy rain is possible in the mountains of Pingtung County today.,接著才是特報的正式內容;特報的產品名稱照中央氣象署英文寫。intensity 3 (light shaking) on Taiwan's intensity scale,描述詞取自中央氣象署英文震度表:3 light、4 moderate、5 strong、6 violent、7 extreme。11:40 on August 22, 2026 (Taiwan time, UTC+8)。外國人的手機常設在別的時區。有一項沒有採用:NWS 和臺灣官方媒體的英文版都用 12 小時制,但 14:30 寫成 2:30 p.m. 之後,數字核對會把 14 判成不見了。改用 24 小時制加時區,外國讀者也不會誤讀。
執行之後又找到兩個問題(整套執行一次,再把前兩則各執行三次,輸出都有存檔)。第一,舊的震度規則要英文版加註 (Taiwan intensity scale),和新規則衝突:六次裡有兩次兩種寫法同時出現,第二則有兩次沒有照新規則寫描述詞,還有一次地震報告被加上了只給特報用的標題。把舊規則裡英文的部分刪掉,並寫明只有特報才加標題,才穩定。第二個問題和英文無關,卻是這幾輪最嚴重的:第一則的日文,四次裡有四次把「花蓮縣」寫成「花蓮市」,有一次還自己在後面註「(原文為縣)」。縣和市是不同的行政區,這種錯誤數字核對看不出來。處理方式有兩個:規則加上「縣和市照原文,不得互換」;程式再加一道核對,原文裡的每一個縣市,日文版都要出現同名的漢字加上對應的「県」或「市」。
改完再執行,三則全部通過;前兩則再各執行三次,描述詞、加註、標題、日文縣市、數字全部正確(輸出有存檔)。第一則和第三則的英文:
en: At 11:40 on August 22, 2026 (Taiwan time, UTC+8), a magnitude 5.1 earthquake occurred in the waters
east of Taiwan. The maximum intensity was 3 (light shaking) on Taiwan's intensity scale in Yilan County
and Hualien County.
en: (Test message) EXTREMELY HEAVY RAIN: Localized extremely heavy rain is possible in the mountains of
Pingtung County today.
Central Weather Administration (CWA) has issued an Extremely Heavy Rain Advisory. Localized extremely
heavy rain is possible in the mountains of Pingtung County today, with 24-hour accumulated rainfall
possibly reaching 200 mm (about 8 in). Please remain vigilant for landslides and falling rocks.
補一句規模的說明:中央氣象署的地震報告用的是芮氏規模(ML),美國地質調查所事後公布的通常是地震矩規模(Mw),同一個地震兩邊的數字可能不同。速報照官方報告寫,不需要換算,但讀者對照國外的數字時要知道這一點。
譯文對不對,用三種方式檢查。
數字用程式核對。 把原文和各語言版本裡的數字取出來,排序之後比對,有任何一個不一致就標示為不通過。取出之前先做兩件事:英文的月份換回數字,時區標示 UTC+8 不算內容數字;英寸換算是在核對通過之後才由程式加上的,所以不會影響核對。這個方法只能找出數字增加、減少或被改掉的情況;如果兩個數字互相對調(例如日期和時間),它看不出來。第一次執行時,兩則地震速報的英文版都被判定為不一致。檢查之後發現是 AI 寫的程式有缺陷:英文把 8 月寫成 August,數字「8」就不見了。補上把英文月份換回數字的處理之後,每一次執行的輸出都通過核對。
import re # Python 內建的套件,用來依照指定的規則搜尋或取代文字(這種規則稱為正規表達式)
MONTHS = {"January": "1", "February": "2", "August": "8", "September": "9"} # 節錄,實際有 12 個月
def numbers(text: str) -> list[str]:
for name, num in MONTHS.items(): # August → 8
text = re.sub(rf"\b{name}\b", num, text)
text = re.sub(r"UTC[+-]\d+", "", text) # 時區標示不算內容數字
return sorted(re.findall(r"\d+(?:\.\d+)?", text))
縣市用程式核對。 原文裡的每一個縣市,日文版都要出現同名漢字加對應的「県」或「市」,缺了或縣市互換就標示為不通過。這一道是第六輪發現「花蓮縣」被寫成「花蓮市」之後加的;韓文是音譯,目前還沒有做同樣的核對。
語氣靠翻回中文檢查。 請模型把日文版和韓文版逐句直譯回中文,再和原文對照。這個方法在加上術語表後的第一次執行,就找到一個數字核對找不到的問題:原文是「累積雨量可能達 200 毫米」,日文版寫成「200ミリに達する見込みです」,翻回中文是「預計將達到 200 毫米」,語氣比原文肯定。所以規則裡加了一條「可能不得寫成預計或將會」,之後幾輪的日文版都改成「達する可能性があります」。
翻回中文只是粗略的檢查,因為翻譯和回譯用的是同一個模型,它自己的誤解有可能來回都看不出來。第四輪那個「預報變成正在下」的問題就是例子:日文翻回中文是「有局部性非常強烈的雨」,韓文翻回中文是「有豪雨發生」,都看不出時態,因為中文的動詞不標時態。這類錯誤回譯找不出來,要另外寫規則。回譯只能協助找出明顯的語意偏差,不能確認譯文是否自然、是否符合當地防災的慣用說法。正式上線前,日文和韓文還是要請母語者看過。
(本篇實測於 2026-09-21,術語查證與第五到第七輪於 2026-09-24;模型 gemini-3.1-flash-lite,溫度維持預設值。)
明天 Day 14 是第二週回顧:整理摘要、分級、問答、多語四項 AI 功能目前的狀態。