深色模式與 i18n
互動示範(與本規範網站人類閱讀版相同):
/docs/dark-mode-i18n
示範對應規則
以下章節與人類版頁面互動示範所涵蓋的規則一致(文字版,供 Agent 複製)。
Dark Mode
核心規則
- Token 化:semantic token 切換 light / dark value,元件不寫死色(見
19-design-tokens.md)。 - 不用純黑
#000:用深灰底(本指南網站:#0A0E14content、#0F141Csidebar),降低眼睛疲勞。 - 不用純白
#FFFFFF當文字:用#E2E8F0等淺灰,避免螢光感。 - Elevation 越高越亮(不靠 shadow,用 surface tone 變化;與
styles/globals.css同步)。- base bg:
#0A0E14 - card / surface:
#11161F - hover surface:
#1A212C - border:
#1E2530
- base bg:
- 飽和色降 saturation 10–20%(避免螢光感)。
- 維持 WCAG 4.5:1 對比。
Surface tone vs Shadow
Light mode 用 shadow 表示 elevation:
white bg + box-shadow → 視覺浮起
Dark mode 用 brighter surface:
#0F1115 base
↑
#1A1D23 card(變亮)
↑
#252830 modal(再亮)
陰影在深底幾乎看不到,所以靠亮度差別。
Color 調整
- Primary brand color 可能需要在 dark mode 加亮(淺一階)。
- Status colors 同樣需要:
- Success: light
#16A34A/ dark#22C55E - Warning: light
#CA8A04/ dark#EAB308 - Error: light
#DC2626/ dark#EF4444
- Success: light
Image & 圖示
- 圖示在 dark 模式可能要替換版本(black logo → white logo)。
- 圖片內嵌淺色背景在深底會突兀,提供 dark 版或半透明處理。
- 僅 SVG 向量圖(禁止 emoji);
currentColor跟隨文字色;本指南用@untitledui/icons。
切換 UI
- Settings → Appearance → Light / Dark / System。
- 預設跟隨 system(
prefers-color-scheme)。 - 使用者選擇後持久化(localStorage / cookie / DB)。
- 切換要全 app 同步,避免半邊 light 半邊 dark。
App shell 語意色
元件與版面禁止寫死 light 色;用 semantic token,在 .dark(或 data-theme="dark")一次切換:
| Token | Light 示意 | Dark 示意 | 用途 |
|---|---|---|---|
sidebar | #F9FAFB | #1A1D23 | 左側導覽底 |
content | #FFFFFF | #0F1115 | 主內容底 |
text-primary | #101828 | #E6E8EB | 標題、正文強調 |
text-secondary | #475467 | #94969C | 內文、說明 |
border | #E4E7EC | #2E323A | 分隔線 |
brand-subtle | 淺藍底 | 深藍底 | active nav、提示條 |
- 深色模式下 sidebar、topbar、prose 內文、表格、inline code 皆須可讀(對比 ≥ 4.5:1)。
- 勿在 dark 模式保留
hover:bg-white等 light-only 寫法。
本指南網站:
styles/globals.css的:root/.darkCSS 變數驅動全站。
過渡動畫
- 切換時用
transition: background 200ms,避免閃。 - 或用
no-transitionclass 切換瞬間,避免奇怪 lerp。
i18n
核心規則
- 預留文字 30–40% 延伸空間:英文短、德文 / 芬蘭文長 35%。
- 設計時用 1.5–2 倍英文字串長度檢查 layout。
- 不寫死寬度 在 button / nav item / label。
- 不串接字串:用 ICU message format。
- 支援 RTL(阿拉伯文、希伯來文):mirror layout、icon、padding。
- 日期、時間、數字、貨幣用 locale-aware formatter(
Intl.*)。 - Pluralization 用 CLDR plural rules(zero/one/few/many/other)。
- 字體要支援目標語系字符集(CJK 字數遠超拉丁字)。
字串長度預留範例
| 語言 | 相對英文長度 |
|---|---|
| 英文 | 100%(baseline) |
| 中文(繁/簡) | 70–80%(更短) |
| 日文 | 80–100% |
| 德文 | 130–140%(最長) |
| 芬蘭文 | 130%+ |
| 法文 | 115–125% |
| 韓文 | 95–105% |
| 阿拉伯文 | 110–130% + RTL |
不串接字串
❌ 不好(無法翻譯):
"You have " + n + " items in your cart";
✅ 好:
t("cart.itemCount", { count: n });
// → "You have {count} items"
// 中文 → "您的購物車有 {count} 件商品"
ICU Message Format
{count, plural,
zero {No items}
one {# item}
other {# items}
}
中文沒有單複數,但德文有 6 種 plural form,用 ICU 統一處理。
日期 / 時間 / 數字 / 貨幣
用 Intl API:
new Intl.DateTimeFormat("zh-TW").format(date);
// → "2026/5/29"
new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(1234.5);
// → "$1,234.50"
不要 hardcode:
- ❌
date.toISOString().slice(0, 10)然後 display - ❌
"NT$" + price.toLocaleString()
RTL
支援阿拉伯文、希伯來文時:
- 整體 layout mirror(sidebar 變右側、breadcrumb 反向)。
- Icon 方向反轉(← → 互換、回上一頁的箭頭、播放按鈕也反)。
- 但數字、英文、商標不反。
- CSS 用
direction: rtl+ logical properties(padding-inline-start而非padding-left)。
字體
- 不同語系可能需要不同字體:
- 拉丁文:Inter / Helvetica
- 中文:PingFang TC / Noto Sans TC
- 日文:Hiragino / Noto Sans JP
- 阿拉伯文:Noto Sans Arabic
- Web font 用
font-display: swap避免白屏。
翻譯流程
- 用 i18n library:
react-intl/i18next/Lingui。 - 翻譯 key 用語義命名:
button.save/cart.empty.title。 - 翻譯放獨立 json / yaml 檔,前端建置時注入。
- 用翻譯服務 / vendor:Crowdin / Lokalise / Transifex。
- Context 文字給翻譯者("Used as button on settings page")。
Locale 偵測 / 切換
- 預設用瀏覽器
navigator.language或 serverAccept-Languageheader。 - Settings 提供手動切換(語言下拉)。
- 切換後立刻套用(不需 reload)。
- URL 可帶 locale prefix(
/zh-tw/settings)SEO / 分享友善。
不要做的事
- ❌ 用 flag 圖示代表語言(國旗 ≠ 語言)。
- ❌ 把 "EN" / "中" 字串 hardcode 在按鈕。
- ❌ 用機器翻譯放上 production(除非標註「machine-translated」)。
- ❌ 假設 LTR 永遠成立。